Skip to content

Commit

Permalink
Don't use cached CTAP2 info
Browse files Browse the repository at this point in the history
  • Loading branch information
dainnilsson committed Jan 16, 2025
1 parent 850ffd1 commit 226c4d0
Showing 1 changed file with 39 additions and 21 deletions.
60 changes: 39 additions & 21 deletions fido2/client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,19 +500,25 @@ def __init__(
extensions: Sequence[Ctap2Extension],
):
self.ctap2 = Ctap2(device)
self.info = self.ctap2.info
self._extensions = extensions
self.user_interaction = user_interaction

@property
def info(self):
return self.ctap2.info

def _filter_creds(
self, rp_id, cred_list, pin_protocol, pin_token, event, on_keepalive
):
# Use fresh info
info = self.ctap2.get_info()

# Filter out credential IDs which are too long
max_len = self.info.max_cred_id_length
max_len = info.max_cred_id_length
if max_len:
cred_list = [c for c in cred_list if len(c.id) <= max_len]

max_creds = self.info.max_creds_in_list or 1
max_creds = info.max_creds_in_list or 1
chunks = [
cred_list[i : i + max_creds] for i in range(0, len(cred_list), max_creds)
]
Expand Down Expand Up @@ -553,7 +559,7 @@ def _filter_creds(
return None

def selection(self, event):
if "FIDO_2_1" in self.info.versions:
if "FIDO_2_1" in self.ctap2.info.versions:
self.ctap2.selection(event=event)
else:
# Selection not supported, make dummy credential instead
Expand All @@ -575,12 +581,10 @@ def selection(self, event):
return
raise

def _should_use_uv(self, user_verification, permissions):
uv_supported = any(
k in self.info.options for k in ("uv", "clientPin", "bioEnroll")
)
def _should_use_uv(self, info, user_verification, permissions):
uv_supported = any(k in info.options for k in ("uv", "clientPin", "bioEnroll"))
uv_configured = any(
self.info.options.get(k) for k in ("uv", "clientPin", "bioEnroll")
info.options.get(k) for k in ("uv", "clientPin", "bioEnroll")
)
mc = ClientPin.PERMISSION.MAKE_CREDENTIAL & permissions != 0
additional_perms = permissions & ~(
Expand All @@ -593,25 +597,32 @@ def _should_use_uv(self, user_verification, permissions):
user_verification in (UserVerificationRequirement.PREFERRED, None)
and uv_supported
)
or self.info.options.get("alwaysUv")
or info.options.get("alwaysUv")
):
if not uv_configured:
raise ClientError.ERR.CONFIGURATION_UNSUPPORTED(
"User verification not configured/supported"
)
return True
elif mc and uv_configured and not self.info.options.get("makeCredUvNotRqd"):
elif mc and uv_configured and not info.options.get("makeCredUvNotRqd"):
return True
elif uv_configured and additional_perms:
return True
return False

def _get_token(
self, client_pin, permissions, rp_id, event, on_keepalive, allow_internal_uv
self,
info,
client_pin,
permissions,
rp_id,
event,
on_keepalive,
allow_internal_uv,
):
# Prefer UV
if self.info.options.get("uv"):
if ClientPin.is_token_supported(self.info):
if info.options.get("uv"):
if ClientPin.is_token_supported(info):
if self.user_interaction.request_uv(permissions, rp_id):
return client_pin.get_uv_token(
permissions, rp_id, event, on_keepalive
Expand All @@ -621,7 +632,7 @@ def _get_token(
return None # No token, use uv=True

# PIN if UV not supported/allowed.
if self.info.options.get("clientPin"):
if info.options.get("clientPin"):
pin = self.user_interaction.request_pin(permissions, rp_id)
if pin:
return client_pin.get_pin_token(pin, permissions, rp_id)
Expand All @@ -635,11 +646,11 @@ def _get_token(
def _get_auth_params(
self, pin_protocol, rp_id, user_verification, permissions, event, on_keepalive
):
self.info = self.ctap2.get_info() # Make sure we have "fresh" info
info = self.ctap2.get_info()

pin_token = None
internal_uv = False
if self._should_use_uv(user_verification, permissions):
if self._should_use_uv(info, user_verification, permissions):
client_pin = ClientPin(self.ctap2, pin_protocol)
allow_internal_uv = (
permissions
Expand All @@ -650,7 +661,13 @@ def _get_auth_params(
== 0
)
pin_token = self._get_token(
client_pin, permissions, rp_id, event, on_keepalive, allow_internal_uv
info,
client_pin,
permissions,
rp_id,
event,
on_keepalive,
allow_internal_uv,
)
if not pin_token:
internal_uv = True
Expand All @@ -672,11 +689,12 @@ def do_make_credential(
user_verification = selection.user_verification

on_keepalive = _user_keepalive(self.user_interaction)
info = self.ctap2.get_info()

# Handle enterprise attestation
enterprise_attestation = None
if options.attestation == AttestationConveyancePreference.ENTERPRISE:
if self.info.options.get("ep"):
if info.options.get("ep"):
if enterprise_rpid_list is not None:
# Platform facilitated
if rp_id in enterprise_rpid_list:
Expand All @@ -687,7 +705,7 @@ def do_make_credential(

# Negotiate PIN/UV protocol version
for proto in ClientPin.PROTOCOLS:
if proto.VERSION in self.info.pin_uv_protocols:
if proto.VERSION in info.pin_uv_protocols:
pin_protocol: PinProtocol | None = proto()
break
else:
Expand Down Expand Up @@ -733,7 +751,7 @@ def _do_make():
except ValueError as e:
raise ClientError.ERR.CONFIGURATION_UNSUPPORTED(e)

can_rk = self.info.options.get("rk")
can_rk = info.options.get("rk")
rk = selection.resident_key == ResidentKeyRequirement.REQUIRED or (
selection.resident_key == ResidentKeyRequirement.PREFERRED and can_rk
)
Expand Down

0 comments on commit 226c4d0

Please sign in to comment.