async def add_resident_credential( ctx: wire.Context, msg: WebAuthnAddResidentCredential ) -> Success: if not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") if not msg.credential_id: raise wire.ProcessError("Missing credential ID parameter.") try: cred = Fido2Credential.from_cred_id(bytes(msg.credential_id), None) except Exception: text = Text("Import credential", ui.ICON_WRONG, ui.RED) text.normal( "The credential you are", "trying to import does", "not belong to this", "authenticator.", ) await require_confirm(ctx, text, confirm=None, cancel="Close") raise wire.ActionCancelled content = ConfirmContent(ConfirmAddCredential(cred)) await require_confirm(ctx, content) if store_resident_credential(cred): return Success(message="Credential added") else: raise wire.ProcessError("Internal credential storage is full.")
async def add_resident_credential( ctx: wire.Context, msg: WebAuthnAddResidentCredential) -> Success: if not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") if not msg.credential_id: raise wire.ProcessError("Missing credential ID parameter.") try: cred = Fido2Credential.from_cred_id(bytes(msg.credential_id), None) except Exception: await show_error_and_raise( ctx, "warning_credential", header="Import credential", button="Close", content= "The credential you are trying to import does\nnot belong to this authenticator.", red=True, ) if not await confirm_webauthn(ctx, ConfirmAddCredential(cred)): raise wire.ActionCancelled if store_resident_credential(cred): return Success(message="Credential added") else: raise wire.ProcessError("Internal credential storage is full.")
async def apply_settings(ctx: wire.Context, msg: ApplySettings): if not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") if ( msg.homescreen is None and msg.label is None and msg.use_passphrase is None and msg.passphrase_always_on_device is None and msg.display_rotation is None and msg.auto_lock_delay_ms is None and msg.safety_checks is None ): raise wire.ProcessError("No setting provided") if msg.homescreen is not None: validate_homescreen(msg.homescreen) await require_confirm_change_homescreen(ctx) try: storage.device.set_homescreen(msg.homescreen) except ValueError: raise wire.DataError("Invalid homescreen") if msg.label is not None: await require_confirm_change_label(ctx, msg.label) storage.device.set_label(msg.label) if msg.use_passphrase is not None: await require_confirm_change_passphrase(ctx, msg.use_passphrase) storage.device.set_passphrase_enabled(msg.use_passphrase) if msg.passphrase_always_on_device is not None: if not storage.device.is_passphrase_enabled(): raise wire.DataError("Passphrase is not enabled") await require_confirm_change_passphrase_source( ctx, msg.passphrase_always_on_device ) storage.device.set_passphrase_always_on_device(msg.passphrase_always_on_device) if msg.auto_lock_delay_ms is not None: if msg.auto_lock_delay_ms < storage.device.AUTOLOCK_DELAY_MINIMUM: raise wire.ProcessError("Auto-lock delay too short") if msg.auto_lock_delay_ms > storage.device.AUTOLOCK_DELAY_MAXIMUM: raise wire.ProcessError("Auto-lock delay too long") await require_confirm_change_autolock_delay(ctx, msg.auto_lock_delay_ms) storage.device.set_autolock_delay_ms(msg.auto_lock_delay_ms) # use the value that was stored, not the one that was supplied by the user workflow.idle_timer.set(storage.device.get_autolock_delay_ms(), lock_device) if msg.safety_checks is not None: await require_confirm_safety_checks(ctx, msg.safety_checks) storage.device.set_unsafe_prompts_allowed( msg.safety_checks == SafetyCheckLevel.Prompt ) if msg.display_rotation is not None: await require_confirm_change_display_rotation(ctx, msg.display_rotation) storage.device.set_rotation(msg.display_rotation) ui.display.orientation(storage.device.get_rotation()) return Success(message="Settings applied")
async def get_keychain(ctx: wire.Context, namespaces: list) -> Keychain: if not storage.is_initialized(): raise wire.NotInitialized("Device is not initialized") seed = cache.get(cache.APP_COMMON_SEED) if seed is None: passphrase = await get_passphrase(ctx) seed = mnemonic.get_seed(passphrase) cache.set(cache.APP_COMMON_SEED, seed) keychain = Keychain(seed, namespaces) return keychain
def _check_state(msg: RecoveryDevice) -> None: if not msg.dry_run and storage.is_initialized(): raise wire.UnexpectedMessage("Already initialized") if msg.dry_run and not storage.is_initialized(): raise wire.NotInitialized("Device is not initialized") if msg.enforce_wordlist is False: raise wire.ProcessError( "Value enforce_wordlist must be True, Trezor Core enforces words automatically." )
async def apply_settings(ctx: wire.Context, msg: ApplySettings): if not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") if ( msg.homescreen is None and msg.label is None and msg.use_passphrase is None and msg.passphrase_always_on_device is None and msg.display_rotation is None and msg.auto_lock_delay_ms is None ): raise wire.ProcessError("No setting provided") if msg.homescreen is not None: if len(msg.homescreen) > storage.device.HOMESCREEN_MAXSIZE: raise wire.DataError("Homescreen is too complex") await require_confirm_change_homescreen(ctx) if msg.label is not None: await require_confirm_change_label(ctx, msg.label) if msg.use_passphrase is not None: await require_confirm_change_passphrase(ctx, msg.use_passphrase) if msg.passphrase_always_on_device is not None: await require_confirm_change_passphrase_source( ctx, msg.passphrase_always_on_device ) if msg.display_rotation is not None: await require_confirm_change_display_rotation(ctx, msg.display_rotation) if msg.auto_lock_delay_ms is not None: if msg.auto_lock_delay_ms < storage.device.AUTOLOCK_DELAY_MINIMUM: raise wire.ProcessError("Auto-lock delay too short") if msg.auto_lock_delay_ms > storage.device.AUTOLOCK_DELAY_MAXIMUM: raise wire.ProcessError("Auto-lock delay too long") await require_confirm_change_autolock_delay(ctx, msg.auto_lock_delay_ms) storage.device.load_settings( label=msg.label, use_passphrase=msg.use_passphrase, homescreen=msg.homescreen, passphrase_always_on_device=msg.passphrase_always_on_device, display_rotation=msg.display_rotation, autolock_delay_ms=msg.auto_lock_delay_ms, ) if msg.display_rotation is not None: ui.display.orientation(storage.device.get_rotation()) # use the value that was stored, not the one that was supplied by the user workflow.idle_timer.set(storage.device.get_autolock_delay_ms(), lock_device) return Success(message="Settings applied")
async def get_next_u2f_counter(ctx: wire.Context, msg: GetNextU2FCounter) -> NextU2FCounter: if not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") text = Text("Get next U2F counter", ui.ICON_CONFIG) text.normal("Do you really want to") text.bold("increase and retrieve") text.normal("the U2F counter?") await require_confirm(ctx, text, code=ButtonRequestType.ProtectCall) return NextU2FCounter(u2f_counter=storage.device.next_u2f_counter())
async def _get_keychain_bip39(ctx: wire.Context) -> Keychain: if not device.is_initialized(): raise wire.NotInitialized("Device is not initialized") # ask for passphrase, loading from cache if necessary passphrase = await _get_passphrase(ctx) # derive the root node from mnemonic and passphrase via Cardano Icarus algorithm secret_bytes = mnemonic.get_secret() assert secret_bytes is not None root = bip32.from_mnemonic_cardano(secret_bytes.decode(), passphrase.decode()) return Keychain(root)
async def sd_protect(ctx: wire.Context, msg: SdProtect) -> Success: if not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") if msg.operation == SdProtectOperationType.ENABLE: return await sd_protect_enable(ctx, msg) elif msg.operation == SdProtectOperationType.DISABLE: return await sd_protect_disable(ctx, msg) elif msg.operation == SdProtectOperationType.REFRESH: return await sd_protect_refresh(ctx, msg) else: raise wire.ProcessError("Unknown operation")
async def get_keychain(ctx: wire.Context, namespaces: list) -> Keychain: if not storage.is_initialized(): raise wire.NotInitialized("Device is not initialized") seed = storage.cache.get_seed() if seed is None: passphrase = storage.cache.get_passphrase() if passphrase is None: passphrase = await protect_by_passphrase(ctx) storage.cache.set_passphrase(passphrase) seed = mnemonic.get_seed(passphrase) storage.cache.set_seed(seed) keychain = Keychain(seed, namespaces) return keychain
async def set_u2f_counter(ctx: wire.Context, msg: SetU2FCounter) -> Success: if not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") if msg.u2f_counter is None: raise wire.ProcessError("No value provided") text = Text("Set U2F counter", ui.ICON_CONFIG) text.normal("Do you really want to", "set the U2F counter") text.bold("to %d?" % msg.u2f_counter) await require_confirm(ctx, text, code=ButtonRequestType.ProtectCall) storage.device.set_u2f_counter(msg.u2f_counter) return Success(message="U2F counter set")
def _check_state(msg: RecoveryDevice) -> None: if not msg.dry_run and storage.is_initialized(): raise wire.UnexpectedMessage("Already initialized") if msg.dry_run and not storage.is_initialized(): raise wire.NotInitialized("Device is not initialized") if storage.recovery.is_in_progress(): raise RuntimeError( "Function recovery_device should not be invoked when recovery is already in progress" ) if msg.enforce_wordlist is False: raise wire.ProcessError( "Value enforce_wordlist must be True, Trezor Core enforces words automatically." )
async def get_keychain(ctx: wire.Context) -> Keychain: if not device.is_initialized(): raise wire.NotInitialized("Device is not initialized") passphrase = await get_passphrase(ctx) if mnemonic.is_bip39(): # derive the root node from mnemonic and passphrase via Cardano Icarus algorithm root = bip32.from_mnemonic_cardano(mnemonic.get_secret().decode(), passphrase) else: # derive the root node via SLIP-0023 seed = mnemonic.get_seed(passphrase) root = bip32.from_seed(seed, "ed25519 cardano seed") keychain = Keychain(root) return keychain
async def get_next_u2f_counter(ctx: wire.Context, msg: GetNextU2FCounter) -> NextU2FCounter: if not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") await confirm_action( ctx, "get_u2f_counter", title="Get next U2F counter", description= "Do you really want to increase and retrieve\nthe U2F counter?", icon=ui.ICON_CONFIG, br_code=ButtonRequestType.ProtectCall, ) return NextU2FCounter(u2f_counter=storage.device.next_u2f_counter())
async def get_keychain(ctx: wire.Context) -> Keychain: if not device.is_initialized(): raise wire.NotInitialized("Device is not initialized") if mnemonic.is_bip39(): passphrase = await get_passphrase(ctx) # derive the root node from mnemonic and passphrase via Cardano Icarus algorithm secret_bytes = mnemonic.get_secret() assert secret_bytes is not None root = bip32.from_mnemonic_cardano(secret_bytes.decode(), passphrase) else: # derive the root node via SLIP-0023 https://github.com/satoshilabs/slips/blob/master/slip-0022.md seed = await get_seed(ctx) root = bip32.from_seed(seed, "ed25519 cardano seed") keychain = Keychain(root) return keychain
async def remove_resident_credential( ctx: wire.Context, msg: WebAuthnRemoveResidentCredential) -> Success: if not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") if msg.index is None: raise wire.ProcessError("Missing credential index parameter.") cred = get_resident_credential(msg.index) if cred is None: raise wire.ProcessError("Invalid credential index.") if not await confirm_webauthn(ctx, ConfirmRemoveCredential(cred)): raise wire.ActionCancelled assert cred.index is not None storage.resident_credentials.delete(cred.index) return Success(message="Credential removed")
def _validate(msg: RecoveryDevice) -> None: if not msg.dry_run and storage.is_initialized(): raise wire.UnexpectedMessage("Already initialized") if msg.dry_run and not storage.is_initialized(): raise wire.NotInitialized("Device is not initialized") if msg.enforce_wordlist is False: raise wire.ProcessError( "Value enforce_wordlist must be True, Trezor Core enforces words automatically." ) if msg.dry_run: # check that only allowed fields are set for key, value in msg.__dict__.items(): if key not in DRY_RUN_ALLOWED_FIELDS and value is not None: raise wire.ProcessError( "Forbidden field set in dry-run: {}".format(key))
async def backup_device(ctx, msg): if not storage.is_initialized(): raise wire.NotInitialized("Device is not initialized") if not storage.device.needs_backup(): raise wire.ProcessError("Seed already backed up") mnemonic_secret, mnemonic_type = mnemonic.get() storage.device.set_unfinished_backup(True) storage.device.set_backed_up() await backup_seed(ctx, mnemonic_type, mnemonic_secret) storage.device.set_unfinished_backup(False) await layout.show_backup_success(ctx) return Success(message="Seed successfully backed up")
async def change_pin(ctx: wire.Context, msg: ChangePin) -> Success: if not is_initialized(): raise wire.NotInitialized("Device is not initialized") # confirm that user wants to change the pin await require_confirm_change_pin(ctx, msg) # get old pin curpin, salt = await request_pin_and_sd_salt(ctx, "Enter old PIN") # if changing pin, pre-check the entered pin before getting new pin if curpin and not msg.remove: if not config.check_pin(pin_to_int(curpin), salt): await show_pin_invalid(ctx) raise wire.PinInvalid("PIN invalid") # get new pin if not msg.remove: newpin = await request_pin_confirm(ctx) else: newpin = "" # write into storage if not config.change_pin(pin_to_int(curpin), pin_to_int(newpin), salt, salt): if newpin: await show_pin_matches_wipe_code(ctx) else: await show_pin_invalid(ctx) raise wire.PinInvalid("PIN invalid") if newpin: if curpin: msg_screen = "changed your PIN." msg_wire = "PIN changed" else: msg_screen = "enabled PIN protection." msg_wire = "PIN enabled" else: msg_screen = "disabled PIN protection." msg_wire = "PIN removed" await show_success(ctx, ("You have successfully", msg_screen)) return Success(message=msg_wire)
async def set_u2f_counter(ctx: wire.Context, msg: SetU2FCounter) -> Success: if not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") if msg.u2f_counter is None: raise wire.ProcessError("No value provided") await confirm_action( ctx, "set_u2f_counter", title="Set U2F counter", description="Do you really want to\nset the U2F counter\nto {}?", description_param=str(msg.u2f_counter), icon=ui.ICON_CONFIG, br_code=ButtonRequestType.ProtectCall, ) storage.device.set_u2f_counter(msg.u2f_counter) return Success(message="U2F counter set")
async def change_wipe_code(ctx: wire.Context, msg: ChangeWipeCode) -> Success: if not is_initialized(): raise wire.NotInitialized("Device is not initialized") # Confirm that user wants to set or remove the wipe code. has_wipe_code = config.has_wipe_code() await _require_confirm_action(ctx, msg, has_wipe_code) # Get the unlocking PIN. pin, salt = await request_pin_and_sd_salt(ctx) if not msg.remove: # Pre-check the entered PIN. if config.has_pin() and not config.check_pin(pin_to_int(pin), salt): await show_pin_invalid(ctx) raise wire.PinInvalid("PIN invalid") # Get new wipe code. wipe_code = await _request_wipe_code_confirm(ctx, pin) else: wipe_code = "" # Write into storage. if not config.change_wipe_code(pin_to_int(pin), salt, pin_to_int(wipe_code)): await show_pin_invalid(ctx) raise wire.PinInvalid("PIN invalid") if wipe_code: if has_wipe_code: msg_screen = "changed the wipe code." msg_wire = "Wipe code changed" else: msg_screen = "set the wipe code." msg_wire = "Wipe code set" else: msg_screen = "disabled the wipe code." msg_wire = "Wipe code removed" await show_success(ctx, ("You have successfully", msg_screen)) return Success(message=msg_wire)
async def _get_keychain_bip39( ctx: wire.Context, derivation_type: CardanoDerivationType) -> Keychain: if not device.is_initialized(): raise wire.NotInitialized("Device is not initialized") if derivation_type == CardanoDerivationType.LEDGER: seed = await get_seed(ctx) return Keychain(cardano.from_seed_ledger(seed)) if not cache.get(cache.APP_COMMON_DERIVE_CARDANO): raise wire.ProcessError( "Cardano derivation is not enabled for this session") if derivation_type == CardanoDerivationType.ICARUS: cache_entry = cache.APP_CARDANO_ICARUS_SECRET else: cache_entry = cache.APP_CARDANO_ICARUS_TREZOR_SECRET secret = await _get_secret(ctx, cache_entry) root = cardano.from_secret(secret) return Keychain(root)
async def get_keychain(ctx: wire.Context) -> Keychain: if not storage.is_initialized(): raise wire.NotInitialized("Device is not initialized") if mnemonic.is_bip39(): # derive the root node from mnemonic and passphrase passphrase = await _get_passphrase(ctx) root = bip32.from_mnemonic_cardano(mnemonic.get_secret().decode(), passphrase) else: seed = storage.cache.get_seed() if seed is None: passphrase = await _get_passphrase(ctx) seed = mnemonic.get_seed(passphrase) storage.cache.set_seed(seed) root = bip32.from_seed(seed, "ed25519 cardano seed") # derive the namespaced root node for i in SEED_NAMESPACE: root.derive_cardano(i) keychain = Keychain(SEED_NAMESPACE, root) return keychain
async def derive_and_store_roots(ctx: wire.Context) -> None: if not device.is_initialized(): raise wire.NotInitialized("Device is not initialized") need_seed = not cache.is_set(cache.APP_COMMON_SEED) need_cardano_secret = cache.get( cache.APP_COMMON_DERIVE_CARDANO ) and not cache.is_set(cache.APP_CARDANO_ICARUS_SECRET) if not need_seed and not need_cardano_secret: return passphrase = await get_passphrase(ctx) if need_seed: common_seed = mnemonic.get_seed(passphrase) cache.set(cache.APP_COMMON_SEED, common_seed) if need_cardano_secret: from apps.cardano.seed import derive_and_store_secrets derive_and_store_secrets(passphrase)
async def apply_flags(ctx: wire.GenericContext, msg: ApplyFlags) -> Success: if not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") set_flags(msg.flags) return Success(message="Flags applied")
async def apply_settings(ctx: wire.Context, msg: ApplySettings) -> Success: if not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") if ( msg.homescreen is None and msg.label is None and msg.use_passphrase is None and msg.passphrase_always_on_device is None and msg.display_rotation is None and msg.auto_lock_delay_ms is None and msg.safety_checks is None and msg.experimental_features is None ): raise wire.ProcessError("No setting provided") if msg.homescreen is not None: validate_homescreen(msg.homescreen) await require_confirm_change_homescreen(ctx) try: storage.device.set_homescreen(msg.homescreen) except ValueError: raise wire.DataError("Invalid homescreen") if msg.label is not None: if len(msg.label) > storage.device.LABEL_MAXLENGTH: raise wire.DataError("Label too long") await require_confirm_change_label(ctx, msg.label) storage.device.set_label(msg.label) if msg.use_passphrase is not None: await require_confirm_change_passphrase(ctx, msg.use_passphrase) storage.device.set_passphrase_enabled(msg.use_passphrase) if msg.passphrase_always_on_device is not None: if not storage.device.is_passphrase_enabled(): raise wire.DataError("Passphrase is not enabled") await require_confirm_change_passphrase_source( ctx, msg.passphrase_always_on_device ) storage.device.set_passphrase_always_on_device(msg.passphrase_always_on_device) if msg.auto_lock_delay_ms is not None: if msg.auto_lock_delay_ms < storage.device.AUTOLOCK_DELAY_MINIMUM: raise wire.ProcessError("Auto-lock delay too short") if msg.auto_lock_delay_ms > storage.device.AUTOLOCK_DELAY_MAXIMUM: raise wire.ProcessError("Auto-lock delay too long") await require_confirm_change_autolock_delay(ctx, msg.auto_lock_delay_ms) storage.device.set_autolock_delay_ms(msg.auto_lock_delay_ms) if msg.safety_checks is not None: await require_confirm_safety_checks(ctx, msg.safety_checks) safety_checks.apply_setting(msg.safety_checks) if msg.display_rotation is not None: await require_confirm_change_display_rotation(ctx, msg.display_rotation) storage.device.set_rotation(msg.display_rotation) if msg.experimental_features is not None: await require_confirm_experimental_features(ctx, msg.experimental_features) storage.device.set_experimental_features(msg.experimental_features) reload_settings_from_storage() return Success(message="Settings applied")
async def apply_flags(ctx, msg): if not storage.device.is_initialized(): raise wire.NotInitialized("Device is not initialized") set_flags(msg.flags) return Success(message="Flags applied")
async def _get_seed(ctx: wire.Context) -> bytes: if not device.is_initialized(): raise wire.NotInitialized("Device is not initialized") passphrase = await get_passphrase(ctx) return mnemonic.get_seed(passphrase)