Skip to content

Commit

Permalink
Filter allow/exclude lists to only matched ids
Browse files Browse the repository at this point in the history
  • Loading branch information
dainnilsson committed Oct 15, 2024
1 parent 2ce5bf7 commit f87a358
Showing 1 changed file with 44 additions and 25 deletions.
69 changes: 44 additions & 25 deletions fido2/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,37 @@ def __init__(
self.extensions = extensions
self.user_interaction = user_interaction

def _filter_creds(self, rp_id, cred_list, event, on_keepalive):
# Filter out credential IDs which are too long
max_len = self.info.max_cred_id_length
if max_len:
cred_list = [e for e in cred_list if len(e) <= max_len]

max_creds = self.info.max_creds_in_list or 1
chunks = [
cred_list[i : i + max_creds] for i in range(0, len(cred_list), max_creds)
]

matches = []
for chunk in chunks:
assertions = self.ctap2.get_assertions(
rp_id,
b"\0" * 32,
_cbor_list(chunk),
None,
{"up": False},
None,
None,
event=event,
on_keepalive=on_keepalive,
)
matches.extend([a.credential for a in assertions])

if len(matches) > max_creds:
# Too many matches? Just return as many as we can handle
return matches[:max_creds]
return matches

def selection(self, event):
if "FIDO_2_1" in self.info.versions:
self.ctap2.selection(event=event)
Expand Down Expand Up @@ -575,16 +606,12 @@ def do_make_credential(
enterprise_attestation,
event,
):
if exclude_list:
# Filter out credential IDs which are too long
max_len = self.info.max_cred_id_length
if max_len:
exclude_list = [e for e in exclude_list if len(e) <= max_len]
on_keepalive = _user_keepalive(self.user_interaction)

# Reject the request if too many credentials remain.
max_creds = self.info.max_creds_in_list
if max_creds and len(exclude_list) > max_creds:
raise ClientError.ERR.BAD_REQUEST("exclude_list too long")
if exclude_list:
cred_list = self._filter_creds(rp.id, exclude_list, event, on_keepalive)
else:
cred_list = None

# Process extensions
client_inputs = extensions or {}
Expand All @@ -603,8 +630,6 @@ def do_make_credential(
except ValueError as e:
raise ClientError.ERR.CONFIGURATION_UNSUPPORTED(e)

on_keepalive = _user_keepalive(self.user_interaction)

# Handle auth
pin_protocol, pin_token, pin_auth, internal_uv = self._get_auth_params(
client_data, rp.id, user_verification, permissions, event, on_keepalive
Expand All @@ -624,7 +649,7 @@ def do_make_credential(
_as_cbor(rp),
_as_cbor(user),
_cbor_list(key_params),
_cbor_list(exclude_list),
cred_list,
extension_inputs or None,
options,
pin_auth,
Expand Down Expand Up @@ -662,18 +687,14 @@ def do_get_assertion(
user_verification,
event,
):
on_keepalive = _user_keepalive(self.user_interaction)

if allow_list:
# Filter out credential IDs which are too long
max_len = self.info.max_cred_id_length
if max_len:
allow_list = [e for e in allow_list if len(e) <= max_len]
if not allow_list:
cred_list = self._filter_creds(rp_id, allow_list, event, on_keepalive)
if not cred_list:
raise CtapError(CtapError.ERR.NO_CREDENTIALS)

# Reject the request if too many credentials remain.
max_creds = self.info.max_creds_in_list
if max_creds and len(allow_list) > max_creds:
raise ClientError.ERR.BAD_REQUEST("allow_list too long")
else:
cred_list = None

# Process extensions
client_inputs = extensions or {}
Expand All @@ -692,8 +713,6 @@ def do_get_assertion(
except ValueError as e:
raise ClientError.ERR.CONFIGURATION_UNSUPPORTED(e)

on_keepalive = _user_keepalive(self.user_interaction)

pin_protocol, pin_token, pin_auth, internal_uv = self._get_auth_params(
client_data, rp_id, user_verification, permissions, event, on_keepalive
)
Expand All @@ -702,7 +721,7 @@ def do_get_assertion(
assertions = self.ctap2.get_assertions(
rp_id,
client_data.hash,
_cbor_list(allow_list),
cred_list,
extension_inputs or None,
options,
pin_auth,
Expand Down

0 comments on commit f87a358

Please sign in to comment.