diff --git a/src/apps/common/storage.py b/src/apps/common/storage.py index 1135cb5df9..07dc272249 100644 --- a/src/apps/common/storage.py +++ b/src/apps/common/storage.py @@ -16,6 +16,7 @@ _USE_PASSPHRASE = const(0x05) # 0x01 or empty _HOMESCREEN = const(0x06) # bytes _NEEDS_BACKUP = const(0x07) # 0x01 or empty _FLAGS = const(0x08) # int +_U2F_COUNTER = const(0x09) # int def get_device_id() -> str: @@ -96,6 +97,20 @@ def set_flags(flags: int) -> None: config.set(_APP, _FLAGS, flags.to_bytes(4, 'big')) +def next_u2f_counter() -> int: + b = config.get(_APP, _U2F_COUNTER) + if b is None: + b = 0 + else: + b = int.from_bytes(b, 'big') + 1 + set_u2f_counter(b) + return b + + +def set_u2f_counter(cntr: int): + config.set(_APP, _FLAGS, cntr.to_bytes(4, 'big')) + + def wipe(): config.wipe() cache.clear() diff --git a/src/apps/fido_u2f/__init__.py b/src/apps/fido_u2f/__init__.py index 23e95c35ca..37f8ef58fe 100644 --- a/src/apps/fido_u2f/__init__.py +++ b/src/apps/fido_u2f/__init__.py @@ -15,6 +15,8 @@ from trezor.crypto import hashlib from trezor.crypto import hmac from trezor.crypto import random from trezor.crypto.curve import nist256p1 +from apps.common import storage + _HID_RPT_SIZE = const(64) _CID_BROADCAST = const(0xffffffff) # broadcast channel id @@ -668,20 +670,12 @@ def msg_authenticate_genkey(app_id: bytes, keyhandle: bytes): return node -# TODO: persistent counter -_authenticate_ctr = 0 - - def msg_authenticate_sign(challenge: bytes, app_id: bytes, privkey: bytes) -> bytes: - - global _authenticate_ctr - flags = bytes([_AUTH_FLAG_TUP]) # get next counter - ctr = _authenticate_ctr + ctr = storage.next_u2f_counter() ctrbuf = ustruct.pack('>L', ctr) - _authenticate_ctr += 1 # hash input data together with counter dig = hashlib.sha256() diff --git a/src/apps/management/__init__.py b/src/apps/management/__init__.py index 725624c38d..de61707bad 100644 --- a/src/apps/management/__init__.py +++ b/src/apps/management/__init__.py @@ -1,7 +1,7 @@ from trezor.wire import register, protobuf_workflow from trezor.utils import unimport from trezor.messages.wire_types import \ - LoadDevice, ResetDevice, BackupDevice, WipeDevice, RecoveryDevice, ApplySettings, ApplyFlags, ChangePin + LoadDevice, ResetDevice, BackupDevice, WipeDevice, RecoveryDevice, ApplySettings, ApplyFlags, ChangePin, SetU2FCounter @unimport @@ -52,6 +52,12 @@ def dispatch_ChangePin(*args, **kwargs): return change_pin(*args, **kwargs) +@unimport +def dispatch_SetU2FCounter(*args, **kwargs): + from .set_u2f_counter import set_u2f_counter + return set_u2f_counter(*args, **kwargs) + + def boot(): # only enable LoadDevice in debug builds if __debug__: @@ -63,3 +69,4 @@ def boot(): register(ApplySettings, protobuf_workflow, dispatch_ApplySettings) register(ApplyFlags, protobuf_workflow, dispatch_ApplyFlags) register(ChangePin, protobuf_workflow, dispatch_ChangePin) + register(SetU2FCounter, protobuf_workflow, dispatch_SetU2FCounter) diff --git a/src/apps/management/set_u2f_counter.py b/src/apps/management/set_u2f_counter.py new file mode 100644 index 0000000000..3114340340 --- /dev/null +++ b/src/apps/management/set_u2f_counter.py @@ -0,0 +1,22 @@ +from trezor import ui, wire +from trezor.messages import ButtonRequestType, FailureType +from trezor.messages.Success import Success +from trezor.ui.text import Text +from apps.common import storage +from apps.common.confirm import require_confirm + + +async def set_u2f_counter(ctx, msg): + if msg.u2f_counter is None: + raise wire.FailureError(FailureType.ProcessError, 'No value provided provided') + + await require_confirm(ctx, Text( + 'Set U2F counter', ui.ICON_CONFIG, + 'Do you really want to', + 'set the U2F counter', + ui.BOLD, 'to %d?' % msg.u2f_counter), + code=ButtonRequestType.ProtectCall) + + storage.set_u2f_counter(msg.u2f_counter) + + return Success(message='U2F counter set')