From abe66f138508505d7682ad5fa20912c3445a5d35 Mon Sep 17 00:00:00 2001 From: Dain Nilsson Date: Wed, 18 May 2022 09:20:53 +0200 Subject: [PATCH] Add enterprise attestation. --- fido2/client.py | 19 +++++++++++++++++++ fido2/ctap2/base.py | 2 ++ fido2/ctap2/config.py | 7 +++++++ tests/test_client.py | 1 + 4 files changed, 29 insertions(+) diff --git a/fido2/client.py b/fido2/client.py index e9bbd2c..5b89845 100644 --- a/fido2/client.py +++ b/fido2/client.py @@ -43,6 +43,7 @@ from .webauthn import ( UserVerificationRequirement, AuthenticatorAttestationResponse, AuthenticatorAssertionResponse, + AttestationConveyancePreference, ) from .cose import ES256 from .rpid import verify_rp_id @@ -326,12 +327,14 @@ class _Ctap1ClientBackend(_ClientBackend): extensions, rk, user_verification, + enterprise_attestation, event, ): if ( rk or user_verification == UserVerificationRequirement.REQUIRED or ES256.ALGORITHM not in [p.alg for p in key_params] + or enterprise_attestation ): raise CtapError(CtapError.ERR.UNSUPPORTED_OPTION) @@ -553,6 +556,7 @@ class _Ctap2ClientBackend(_ClientBackend): extensions, rk, user_verification, + enterprise_attestation, event, ): if exclude_list: @@ -609,6 +613,7 @@ class _Ctap2ClientBackend(_ClientBackend): options, pin_auth, pin_protocol.VERSION if pin_protocol else None, + enterprise_attestation, event=event, on_keepalive=on_keepalive, ) @@ -717,6 +722,9 @@ class Fido2Client(WebAuthnClient, _BaseClient): ): super().__init__(origin, verify) + # TODO: Decide how to configure this list. + self._enterprise_rpid_list: Optional[Sequence[str]] = None + try: self._backend: _ClientBackend = _Ctap2ClientBackend( device, user_interaction, extension_types @@ -769,6 +777,16 @@ class Fido2Client(WebAuthnClient, _BaseClient): ) selection = options.authenticator_selection or AuthenticatorSelectionCriteria() + enterprise_attestation = None + if options.attestation == AttestationConveyancePreference.ENTERPRISE: + if self.info.options.get("ep"): + if self._enterprise_rpid_list is not None: + # Platform facilitated + if rp.id in self._enterprise_rpid_list: + enterprise_attestation = 2 + else: + # Vendor facilitated + enterprise_attestation = 1 try: return self._backend.do_make_credential( @@ -780,6 +798,7 @@ class Fido2Client(WebAuthnClient, _BaseClient): options.extensions, selection.require_resident_key, selection.user_verification, + enterprise_attestation, event, ) except CtapError as e: diff --git a/fido2/ctap2/base.py b/fido2/ctap2/base.py index 9a8b75d..c342c55 100644 --- a/fido2/ctap2/base.py +++ b/fido2/ctap2/base.py @@ -337,6 +337,7 @@ class Ctap2: options: Optional[Mapping[str, Any]] = None, pin_uv_param: Optional[bytes] = None, pin_uv_protocol: Optional[int] = None, + enterprise_attestation: Optional[int] = None, *, event: Optional[Event] = None, on_keepalive: Optional[Callable[[int], None]] = None, @@ -371,6 +372,7 @@ class Ctap2: options, pin_uv_param, pin_uv_protocol, + enterprise_attestation, ), event=event, on_keepalive=on_keepalive, diff --git a/fido2/ctap2/config.py b/fido2/ctap2/config.py index 31da9aa..8714444 100644 --- a/fido2/ctap2/config.py +++ b/fido2/ctap2/config.py @@ -96,6 +96,13 @@ class Config: pin_uv_param = None return self.ctap.config(sub_cmd, params, pin_uv_protocol, pin_uv_param) + def enable_enterprise_attestation(self) -> None: + """Enables Enterprise Attestation. + + If already enabled, this command is ignored. + """ + self._call(Config.CMD.ENABLE_ENTERPRISE_ATT) + def toggle_always_uv(self) -> None: """Toggle the alwaysUV setting. diff --git a/tests/test_client.py b/tests/test_client.py index 594bf0a..d801a88 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -153,6 +153,7 @@ class TestFido2Client(unittest.TestCase): None, None, None, + None, event=mock.ANY, on_keepalive=mock.ANY, )