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.
82 lines
2.3 KiB
82 lines
2.3 KiB
![]()
5 years ago
|
from micropython import const
|
||
|
|
||
|
import storage.webauthn
|
||
|
from storage.webauthn import MAX_RESIDENT_CREDENTIALS
|
||
|
|
||
|
from apps.webauthn.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.webauthn.get_resident_credential(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.webauthn.get_resident_credential(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 get_resident_credential(index: int) -> Optional[Fido2Credential]:
|
||
|
if not (0 <= index < MAX_RESIDENT_CREDENTIALS):
|
||
|
return None
|
||
|
|
||
|
data = storage.webauthn.get_resident_credential(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):
|
||
|
data = storage.webauthn.get_resident_credential(index)
|
||
|
if data is None:
|
||
|
# found candidate empty slot
|
||
|
if slot is None:
|
||
|
slot = index
|
||
|
continue
|
||
|
|
||
|
if cred.rp_id_hash != data[:RP_ID_HASH_LENGTH]:
|
||
|
# slot is occupied by a different rp_id_hash
|
||
|
continue
|
||
|
|
||
|
stored_cred = _credential_from_data(index, 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.webauthn.set_resident_credential(slot, cred_data)
|
||
|
return True
|