You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/core/src/apps/webauthn/resident_credentials.py

90 lines
2.6 KiB

from micropython import const
import storage.resident_credentials
from storage.resident_credentials import MAX_RESIDENT_CREDENTIALS
from .credential import Fido2Credential
if False:
from typing import Iterator, Optional
RP_ID_HASH_LENGTH = const(32)
def _credential_from_data(index: int, data: bytes) -> Fido2Credential:
rp_id_hash = data[:RP_ID_HASH_LENGTH]
cred_id = data[RP_ID_HASH_LENGTH:]
cred = Fido2Credential.from_cred_id(cred_id, rp_id_hash)
cred.index = index
return cred
def find_all() -> Iterator[Fido2Credential]:
for index in range(MAX_RESIDENT_CREDENTIALS):
data = storage.resident_credentials.get(index)
if data is not None:
yield _credential_from_data(index, data)
def find_by_rp_id_hash(rp_id_hash: bytes) -> Iterator[Fido2Credential]:
for index in range(MAX_RESIDENT_CREDENTIALS):
data = storage.resident_credentials.get(index)
if data is None:
# empty slot
continue
if data[:RP_ID_HASH_LENGTH] != rp_id_hash:
# rp_id_hash mismatch
continue
yield _credential_from_data(index, data)
def find_by_cred_id(cred_id: bytes) -> Optional[Fido2Credential]:
for index in range(MAX_RESIDENT_CREDENTIALS):
data = storage.resident_credentials.get(index)
if data is not None and data[RP_ID_HASH_LENGTH:] == cred_id:
return _credential_from_data(index, data)
return None
def get_resident_credential(index: int) -> Optional[Fido2Credential]:
if not (0 <= index < MAX_RESIDENT_CREDENTIALS):
return None
data = storage.resident_credentials.get(index)
if data is None:
return None
return _credential_from_data(index, data)
def store_resident_credential(cred: Fido2Credential) -> bool:
slot = None
for index in range(MAX_RESIDENT_CREDENTIALS):
stored_data = storage.resident_credentials.get(index)
if stored_data is None:
# found candidate empty slot
if slot is None:
slot = index
continue
if cred.rp_id_hash != stored_data[:RP_ID_HASH_LENGTH]:
# slot is occupied by a different rp_id_hash
continue
stored_cred = _credential_from_data(index, stored_data)
# 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 = index
break
if slot is None:
return False
cred_data = cred.rp_id_hash + cred.id
storage.resident_credentials.set(slot, cred_data)
return True