Skip to content

Commit

Permalink
Improve handling of RP ID when omitted from options
Browse files Browse the repository at this point in the history
  • Loading branch information
dainnilsson committed Nov 18, 2024
1 parent 8c6bd5e commit 0561bdb
Showing 1 changed file with 45 additions and 20 deletions.
65 changes: 45 additions & 20 deletions fido2/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
Aaguid,
AttestationObject,
CollectedClientData,
PublicKeyCredentialRpEntity,
PublicKeyCredentialDescriptor,
PublicKeyCredentialCreationOptions,
PublicKeyCredentialRequestOptions,
Expand All @@ -57,7 +58,6 @@
from .utils import sha256
from enum import IntEnum, unique
from urllib.parse import urlparse
from dataclasses import replace
from threading import Timer, Event
from typing import (
Type,
Expand Down Expand Up @@ -303,11 +303,25 @@ def selection(self, event: Optional[Event]) -> None:
raise NotImplementedError()

@abc.abstractmethod
def do_make_credential(self, *args) -> AuthenticatorAttestationResponse:
def do_make_credential(
self,
options: PublicKeyCredentialCreationOptions,
client_data: CollectedClientData,
rp: PublicKeyCredentialRpEntity,
rp_id: str,
enterprise_rpid_list: Optional[Sequence[str]],
event: Event,
) -> AuthenticatorAttestationResponse:
raise NotImplementedError()

@abc.abstractmethod
def do_get_assertion(self, *args) -> AssertionSelection:
def do_get_assertion(
self,
options: PublicKeyCredentialRequestOptions,
client_data: CollectedClientData,
rp_id: str,
event: Event,
) -> AssertionSelection:
raise NotImplementedError()


Expand All @@ -333,6 +347,7 @@ def do_make_credential(
options,
client_data,
rp,
rp_id,
enterprise_rpid_list,
event,
):
Expand All @@ -350,7 +365,7 @@ def do_make_credential(
):
raise CtapError(CtapError.ERR.UNSUPPORTED_OPTION)

app_param = sha256(rp.id.encode())
app_param = sha256(rp_id.encode())

dummy_param = b"\0" * 32
for cred in exclude_list or []:
Expand Down Expand Up @@ -391,9 +406,9 @@ def do_get_assertion(
self,
options,
client_data,
rp_id,
event,
):
rp_id = options.rp_id
allow_list = options.allow_credentials
user_verification = options.user_verification

Expand Down Expand Up @@ -636,6 +651,7 @@ def do_make_credential(
options,
client_data,
rp,
rp_id,
enterprise_rpid_list,
event,
):
Expand All @@ -653,7 +669,7 @@ def do_make_credential(
if self.info.options.get("ep"):
if enterprise_rpid_list is not None:
# Platform facilitated
if rp.id in enterprise_rpid_list:
if rp_id in enterprise_rpid_list:
enterprise_attestation = 2
else:
# Vendor facilitated
Expand All @@ -676,12 +692,12 @@ def do_make_credential(
def _do_make():
# Handle auth
pin_protocol, pin_token, internal_uv = self._get_auth_params(
rp.id, user_verification, permissions, event, on_keepalive
rp_id, user_verification, permissions, event, on_keepalive
)

if exclude_list:
exclude_cred = self._filter_creds(
rp.id, exclude_list, pin_protocol, pin_token, event, on_keepalive
rp_id, exclude_list, pin_protocol, pin_token, event, on_keepalive
)
# We know the request will fail if exclude_cred is not None here
# BUT DO NOT FAIL EARLY! We still need to prompt for UP, so we keep
Expand Down Expand Up @@ -719,7 +735,7 @@ def _do_make():

# Calculate pin_auth
client_data_hash = client_data.hash
if pin_token:
if pin_protocol and pin_token:
pin_auth = pin_protocol.authenticate(pin_token, client_data_hash)
else:
pin_auth = None
Expand Down Expand Up @@ -790,6 +806,7 @@ def do_get_assertion(
self,
options,
client_data,
rp_id,
event,
):
rp_id = options.rp_id
Expand Down Expand Up @@ -939,6 +956,17 @@ def selection(self, event: Optional[Event] = None) -> None:
except CtapError as e:
raise _ctap2client_err(e)

def _get_rp_id(self, rp_id: Optional[str]) -> str:
if rp_id is None:
url = urlparse(self.origin)
if url.scheme != "https" or not url.netloc:
raise ClientError.ERR.BAD_REQUEST(
"RP ID required for non-https origin."
)
return url.netloc
else:
return rp_id

def make_credential(
self,
options: PublicKeyCredentialCreationOptions,
Expand All @@ -958,16 +986,10 @@ def make_credential(
timer.start()

rp = options.rp
if rp.id is None:
url = urlparse(self.origin)
if url.scheme != "https" or not url.netloc:
raise ClientError.ERR.BAD_REQUEST(
"RP ID required for non-https origin."
)
rp = replace(rp, id=url.netloc)
rp_id = self._get_rp_id(rp.id)

logger.debug(f"Register a new credential for RP ID: {rp.id}")
self._verify_rp_id(rp.id)
logger.debug(f"Register a new credential for RP ID: {rp_id}")
self._verify_rp_id(rp_id)

client_data = self._build_client_data(
CollectedClientData.TYPE.CREATE, options.challenge
Expand All @@ -978,6 +1000,7 @@ def make_credential(
options,
client_data,
rp,
rp_id,
self._enterprise_rpid_list,
event,
)
Expand Down Expand Up @@ -1005,8 +1028,9 @@ def get_assertion(
timer.daemon = True
timer.start()

logger.debug(f"Assert a credential for RP ID: {options.rp_id}")
self._verify_rp_id(options.rp_id)
rp_id = self._get_rp_id(options.rp_id)
logger.debug(f"Assert a credential for RP ID: {rp_id}")
self._verify_rp_id(rp_id)

client_data = self._build_client_data(
CollectedClientData.TYPE.GET, options.challenge
Expand All @@ -1016,6 +1040,7 @@ def get_assertion(
return self._backend.do_get_assertion(
options,
client_data,
rp_id,
event,
)
except CtapError as e:
Expand Down

0 comments on commit 0561bdb

Please sign in to comment.