def store_resident_credential(cred: Fido2Credential) -> bool: slot = None for i in range( _RESIDENT_CREDENTIAL_START_KEY, _RESIDENT_CREDENTIAL_START_KEY + _MAX_RESIDENT_CREDENTIALS, ): stored_cred_data = common._get(common._APP_FIDO2, i) if stored_cred_data is None: if slot is None: slot = i continue stored_rp_id_hash = stored_cred_data[:32] stored_cred_id = stored_cred_data[32:] if cred.rp_id_hash != stored_rp_id_hash: # Stored credential is not for this RP ID. continue stored_cred = Fido2Credential.from_cred_id(stored_cred_id, stored_rp_id_hash) if stored_cred is None: # Stored credential is not for this RP ID. continue # If a credential for the same RP ID and user ID already exists, then overwrite it. if stored_cred.user_id == cred.user_id: slot = i break if slot is None: return False common._set(common._APP_FIDO2, slot, cred.rp_id_hash + cred.id) return True
def get_passphrase_source() -> int: b = common._get(_NAMESPACE, _PASSPHRASE_SOURCE) if b == b"\x01": return 1 elif b == b"\x02": return 2 else: return 0
def set_flags(flags: int) -> None: b = common._get(_NAMESPACE, _FLAGS) if b is None: i = 0 else: i = int.from_bytes(b, "big") flags = (flags | i) & 0xFFFFFFFF if flags != i: common._set(_NAMESPACE, _FLAGS, flags.to_bytes(4, "big"))
def _migrate_from_version_01() -> None: # Make the U2F counter public and writable even when storage is locked. # U2F counter wasn't public, so we are intentionally not using storage.device module. counter = common._get(common._APP_DEVICE, device._U2F_COUNTER) if counter is not None: device.set_u2f_counter(int.from_bytes(counter, "big")) # Delete the old, non-public U2F_COUNTER. common._delete(common._APP_DEVICE, device._U2F_COUNTER) set_current_version()
def get_resident_credentials(rp_id_hash: Optional[bytes]) -> List[Credential]: creds = [] # type: List[Credential] for i in range( _RESIDENT_CREDENTIAL_START_KEY, _RESIDENT_CREDENTIAL_START_KEY + _MAX_RESIDENT_CREDENTIALS, ): stored_cred_data = common._get(common._APP_FIDO2, i) if stored_cred_data is None: continue stored_rp_id_hash = stored_cred_data[:32] stored_cred_id = stored_cred_data[32:] if rp_id_hash is not None and rp_id_hash != stored_rp_id_hash: # Stored credential is not for this RP ID. continue stored_cred = Fido2Credential.from_cred_id(stored_cred_id, stored_rp_id_hash) if stored_cred is not None: creds.append(stored_cred) return creds
def get_homescreen() -> Optional[bytes]: return common._get(_NAMESPACE, _HOMESCREEN, True) # public
def get_mnemonic_secret() -> Optional[bytes]: return common._get(_NAMESPACE, _MNEMONIC_SECRET)
def get_label() -> Optional[str]: label = common._get(_NAMESPACE, _LABEL, True) # public if label is None: return None return label.decode()
def get_rotation() -> int: rotation = common._get(_NAMESPACE, _ROTATION, True) # public if not rotation: return 0 return int.from_bytes(rotation, "big")
def get_device_id() -> str: dev_id = common._get(_NAMESPACE, _DEVICE_ID, True) # public if not dev_id: dev_id = _new_device_id().encode() common._set(_NAMESPACE, _DEVICE_ID, dev_id, True) # public return dev_id.decode()
def get_version() -> Optional[bytes]: return common._get(_NAMESPACE, _VERSION)
def is_version_stored() -> bool: return bool(common._get(_NAMESPACE, _VERSION))
def get_autolock_delay_ms() -> int: b = common._get(_NAMESPACE, _AUTOLOCK_DELAY_MS) if b is None: return 10 * 60 * 1000 else: return int.from_bytes(b, "big")
def get_flags() -> int: b = common._get(_NAMESPACE, _FLAGS) if b is None: return 0 else: return int.from_bytes(b, "big")
def get(index: int) -> Optional[str]: m = common._get(common._APP_RECOVERY_SHARES, index) if m: return m.decode() return None
def get(index: int) -> Optional[str]: m = common._get(common._APP_SLIP39_MNEMONICS, index) if m: return m.decode() return None