Handle authenticators with UV that do not support ClientPin.

This commit is contained in:
Dain Nilsson 2023-06-26 12:37:45 +02:00
parent cbe72665e1
commit 2d6c067689
No known key found for this signature in database
GPG Key ID: F04367096FBA95E8
2 changed files with 22 additions and 7 deletions

View File

@ -502,7 +502,7 @@ class _Ctap2ClientBackend(_ClientBackend):
):
# Prefer UV
if self.info.options.get("uv"):
if self.info.options.get("pinUvAuthToken"):
if ClientPin.is_token_supported(self.info):
if self.user_interaction.request_uv(permissions, rp_id):
return client_pin.get_uv_token(
permissions, rp_id, event, on_keepalive

View File

@ -251,12 +251,19 @@ class ClientPin:
@staticmethod
def is_supported(info):
"""Checks if ClientPin functionality is supported.
Note that the ClientPin function is still usable without support for client
PIN functionality, as UV token may still be supported.
"""
return "clientPin" in info.options
def __init__(self, ctap: Ctap2, protocol: Optional[PinProtocol] = None):
if not self.is_supported(ctap.info):
raise ValueError("Authenticator does not support ClientPin")
@staticmethod
def is_token_supported(info):
"""Checks if pinUvAuthToken is supported."""
return info.options.get("pinUvAuthToken") is True
def __init__(self, ctap: Ctap2, protocol: Optional[PinProtocol] = None):
self.ctap = ctap
if protocol is None:
for proto in ClientPin.PROTOCOLS:
@ -267,7 +274,6 @@ class ClientPin:
raise ValueError("No compatible PIN/UV protocols supported!")
else:
self.protocol = protocol
self._supports_permissions = ctap.info.options.get("pinUvAuthToken")
def _get_shared_secret(self):
resp = self.ctap.client_pin(
@ -290,12 +296,15 @@ class ClientPin:
:param permissions_rpid: The permissions RPID to associate with the token.
:return: A PIN/UV token.
"""
if not ClientPin.is_supported(self.ctap.info):
raise ValueError("Authenticator does not support get_pin_token")
key_agreement, shared_secret = self._get_shared_secret()
pin_hash = sha256(pin.encode())[:16]
pin_hash_enc = self.protocol.encrypt(shared_secret, pin_hash)
if self._supports_permissions and permissions:
if ClientPin.is_token_supported(self.ctap.info) and permissions:
cmd = ClientPin.CMD.GET_TOKEN_USING_PIN
else:
cmd = ClientPin.CMD.GET_TOKEN_USING_PIN_LEGACY
@ -335,7 +344,7 @@ class ClientPin:
consecutive keep-alive messages with the same status.
:return: A PIN/UV token.
"""
if not self.ctap.info.options.get("pinUvAuthToken"):
if not ClientPin.is_token_supported(self.ctap.info):
raise ValueError("Authenticator does not support get_uv_token")
key_agreement, shared_secret = self._get_shared_secret()
@ -387,6 +396,9 @@ class ClientPin:
:param pin: A PIN to set.
"""
if not ClientPin.is_supported(self.ctap.info):
raise ValueError("Authenticator does not support ClientPin")
key_agreement, shared_secret = self._get_shared_secret()
pin_enc = self.protocol.encrypt(shared_secret, _pad_pin(pin))
@ -409,6 +421,9 @@ class ClientPin:
:param old_pin: The currently set PIN.
:param new_pin: The new PIN to set.
"""
if not ClientPin.is_supported(self.ctap.info):
raise ValueError("Authenticator does not support ClientPin")
key_agreement, shared_secret = self._get_shared_secret()
pin_hash = sha256(old_pin.encode())[:16]