core/webauthn: Implement U2F unlocking from softlock.

pull/971/head
Andrew Kozlik 4 years ago committed by matejcik
parent 06aed7135a
commit c8ae5c157e

@ -12,6 +12,7 @@ from trezor.ui.confirm import CONFIRMED, Confirm, ConfirmPageable, Pageable
from trezor.ui.popup import Popup
from trezor.ui.text import Text
from apps.base import set_homescreen
from apps.common import cbor
from apps.webauthn import common
from apps.webauthn.confirm import ConfirmContent, ConfirmInfo
@ -710,6 +711,28 @@ class U2fConfirmAuthenticate(U2fState):
)
class U2fUnlock(State):
def keepalive_status(self) -> int:
return _KEEPALIVE_STATUS_NONE
def timeout_ms(self) -> int:
return _U2F_CONFIRM_TIMEOUT_MS
async def confirm_dialog(self) -> bool:
from trezor.wire import PinCancelled, PinInvalid
from apps.common.request_pin import verify_user_pin
try:
await verify_user_pin()
set_homescreen()
except (PinCancelled, PinInvalid):
return False
return True
def __eq__(self, other: object) -> bool:
return isinstance(other, U2fUnlock)
class Fido2State(State):
def __init__(self, cid: int, iface: io.HID) -> None:
super().__init__(cid, iface)
@ -975,15 +998,11 @@ class DialogManager:
return True
def compare(self, state: State) -> bool:
if self.state != state:
return False
if utime.ticks_ms() >= self.deadline:
self.reset()
return False
return True
def set_state(self, state: State) -> bool:
if self.state == state and utime.ticks_ms() < self.deadline:
self.reset_timeout()
return True
if self.is_busy():
return False
@ -999,7 +1018,7 @@ class DialogManager:
async def keepalive_loop(self) -> None:
try:
if not isinstance(self.state, (U2fState, Fido2State)):
if not isinstance(self.state, (U2fState, U2fUnlock, Fido2State)):
return
while utime.ticks_ms() < self.deadline:
if self.state.keepalive_status() != _KEEPALIVE_STATUS_NONE:
@ -1161,6 +1180,11 @@ def cmd_wink(req: Cmd) -> Cmd:
def msg_register(req: Msg, dialog_mgr: DialogManager) -> Cmd:
if not config.is_unlocked():
new_state = U2fUnlock(req.cid, dialog_mgr.iface) # type: State
dialog_mgr.set_state(new_state)
return msg_error(req.cid, _SW_CONDITIONS_NOT_SATISFIED)
if not storage.is_initialized():
if __debug__:
log.warning(__name__, "not initialized")
@ -1182,10 +1206,8 @@ def msg_register(req: Msg, dialog_mgr: DialogManager) -> Cmd:
# check equality with last request
new_state = U2fConfirmRegister(req.cid, dialog_mgr.iface, req.data, cred)
if not dialog_mgr.compare(new_state):
if not dialog_mgr.set_state(new_state):
return msg_error(req.cid, _SW_CONDITIONS_NOT_SATISFIED)
dialog_mgr.reset_timeout()
if not dialog_mgr.set_state(new_state):
return msg_error(req.cid, _SW_CONDITIONS_NOT_SATISFIED)
# wait for a button or continue
if dialog_mgr.result == _RESULT_NONE:
@ -1239,6 +1261,11 @@ def msg_register_sign(challenge: bytes, cred: U2fCredential) -> bytes:
def msg_authenticate(req: Msg, dialog_mgr: DialogManager) -> Cmd:
if not config.is_unlocked():
new_state = U2fUnlock(req.cid, dialog_mgr.iface) # type: State
dialog_mgr.set_state(new_state)
return msg_error(req.cid, _SW_CONDITIONS_NOT_SATISFIED)
if not storage.is_initialized():
if __debug__:
log.warning(__name__, "not initialized")
@ -1280,10 +1307,8 @@ def msg_authenticate(req: Msg, dialog_mgr: DialogManager) -> Cmd:
# check equality with last request
new_state = U2fConfirmAuthenticate(req.cid, dialog_mgr.iface, req.data, cred)
if not dialog_mgr.compare(new_state):
if not dialog_mgr.set_state(new_state):
return msg_error(req.cid, _SW_CONDITIONS_NOT_SATISFIED)
dialog_mgr.reset_timeout()
if not dialog_mgr.set_state(new_state):
return msg_error(req.cid, _SW_CONDITIONS_NOT_SATISFIED)
# wait for a button or continue
if dialog_mgr.result == _RESULT_NONE:

Loading…
Cancel
Save