def test_verify_ec2(crv: EC2Curve.Value, alg: COSEAlgorithmIdentifier.Value,
                    data: bytes):
    private_key = generate_ec2_private_key(crv)

    clen = curve_coordinate_byte_length(crv)
    public_key = private_key.public_key()
    public_numbers = public_key.public_numbers()

    ec2_public_key = EC2CredentialPublicKey(
        kty=COSEKeyType.Value.EC2,
        crv=crv,
        alg=alg,
        x=public_numbers.x.to_bytes(clen, 'big'),
        y=public_numbers.y.to_bytes(clen, 'big'),
    )

    signature_algorithm = ECDSA(ec2_hash_algorithm(alg))
    signature = private_key.sign(data, signature_algorithm)

    verify(ec2_public_key, signature, data)

    errors = single_byte_errors(signature)
    for error in errors:
        with pytest.raises(VerificationError):
            verify(ec2_public_key, error, data)
Example #2
0
def verify_ec2_public_key(credential_public_key: EC2CredentialPublicKey,
                          signature: bytes, data: bytes) -> None:
    """Verify the a signature over data using an `EC2CredentialPublicKey`.

    Args:
      credential_public_key (EC2CredentialPublicKey): The credential public key
        to use for verification.
      signature (bytes): The signature to verify.
      data (bytes): The data over which to compute the signature.

    Raises:
      VerificationError: If the provided signature is not correct.
      UnimplementedError: If the logic to verify using the given type of key is
        not implemented.
    """
    public_key = cast(EC2PublicKey,
                      cryptography_public_key(credential_public_key))
    if credential_public_key.alg is None:
        raise VerificationError('alg must not be None')

    signature_algorithm = ECDSA(ec2_hash_algorithm(credential_public_key.alg))

    try:
        public_key.verify(signature, data, signature_algorithm)
    except cryptography.exceptions.InvalidSignature:
        raise VerificationError('EC2 verification failure')
Example #3
0
def test_credentials_backend_request_success():
    backend = CredentialsBackend(SuccessCredentialsRegistrar())

    challenge = b'challenge'
    credential_id = b'credential-id'
    auth_data = authenticator_data(
        TEST_RP_ID_HASH,
        (AuthenticatorDataFlag.UP.value | AuthenticatorDataFlag.AT.value
         | AuthenticatorDataFlag.ED.value), b'\x00' * 4,
        attested_credential_data(
            b'z' * 16,
            len(credential_id),
            credential_id,
            cbor2.dumps({
                -3: TEST_CREDENTIAL_PUBLIC_KEY.y,
                -2: TEST_CREDENTIAL_PUBLIC_KEY.x,
                -1: TEST_CREDENTIAL_PUBLIC_KEY.crv.value,
                1: TEST_CREDENTIAL_PUBLIC_KEY.kty.value,
                3: TEST_CREDENTIAL_PUBLIC_KEY.alg.value,
            }),
        ), cbor2.dumps({
            'appid': True,
        }))
    client_data_JSON = json_bytes({
        'type': 'webauthn.get',
        'challenge': base64s(challenge),
        'origin': TEST_RP_ORIGIN,
    })

    signature_algorithm = ECDSA(ec2_hash_algorithm(TEST_COSE_ALG))
    signature = TEST_CRYPTOGRAPHY_PRIVATE_KEY.sign(
        auth_data + hashlib.sha256(client_data_JSON).digest(),
        signature_algorithm,
    )

    public_key_credential = PublicKeyCredential(
        id=base64s(credential_id),
        type='credential-type',
        raw_id=credential_id,
        response=AuthenticatorAssertionResponse(
            client_data_JSON=client_data_JSON,
            authenticator_data=auth_data,
            signature=signature,
        ))

    expected_challenge = challenge

    backend.handle_credential_assertion(
        credential=public_key_credential,
        user=TEST_USER,
        rp=TEST_RP,
        expected_challenge=expected_challenge,
        expected_origin=TEST_RP_ORIGIN,
    )
Example #4
0
def attest_android_key(
        att_stmt: AndroidKeyAttestationStatement, att_obj: AttestationObject,
        auth_data: bytes,
        client_data_hash: bytes) -> Tuple[AttestationType, TrustedPath]:
    """Attest an android key.

    Args:
      att_stmt (AndroidKeyAttestationStatement): The attestation statment.
      att_obj (AttestationObject): The attestation object.
      auth_data (bytes): The raw authenticator data.
      client_data_hash (bytes): The client data hash.

    Returns:
      The attestation type and trusted path.
    
    References:
      * https://www.w3.org/TR/webauthn/#android-key-attestation
      * https://source.android.com/security/keystore/attestation
      * https://developer.android.com/training/articles/security-key-attestation
    """
    if len(att_stmt.x5c) == 0:
        raise AttestationError('Must have at least 1 X509 certificate')

    credential_certificate = cryptography.x509.load_der_x509_certificate(
        att_stmt.x5c[0], default_backend())
    cred_cert_pk = credential_certificate.public_key()
    if not isinstance(
            cred_cert_pk,
        (EllipticCurvePublicKey, Ed25519PublicKey, Ed448PublicKey)):
        raise AttestationError(
            'Android key attestation failed: must use an Elliptic Curve Public Key'
        )

    assert att_obj.auth_data is not None
    assert att_obj.auth_data.attested_credential_data is not None

    cpk = cryptography_public_key(
        att_obj.auth_data.attested_credential_data.credential_public_key)

    verification_data = auth_data + client_data_hash
    assert att_stmt.sig is not None

    try:
        if isinstance(cred_cert_pk, (Ed25519PublicKey, Ed448PublicKey)):
            cred_cert_pk.verify(att_stmt.sig, verification_data)
        else:
            assert isinstance(cred_cert_pk, EllipticCurvePublicKey)
            assert att_stmt.alg is not None

            hash_algorithm = ECDSA(ec2_hash_algorithm(att_stmt.alg))
            cred_cert_pk.verify(att_stmt.sig, verification_data,
                                hash_algorithm)
    except cryptography.exceptions.InvalidSignature:
        raise AttestationError(
            'Android Key attestation failed: invalid signature')

    cpk_public_bytes = cpk.public_bytes(Encoding.DER,
                                        PublicFormat.SubjectPublicKeyInfo)
    cred_cert_public_bytes = cred_cert_pk.public_bytes(
        Encoding.DER, PublicFormat.SubjectPublicKeyInfo)
    if cpk_public_bytes != cred_cert_public_bytes:
        raise AttestationError(
            ('Android key attestation failed: certificate public key in '
             'attestation statement must match the '
             'provided credential public key'))

    try:
        extension = credential_certificate.extensions.get_extension_for_oid(
            ObjectIdentifier('1.3.6.1.4.1.11129.2.1.17'))
        assert isinstance(extension.value, UnrecognizedExtension)
    except cryptography.x509.ExtensionNotFound:
        raise AttestationError(
            'Android key attestation failed: could not find android key '
            'attestation certificate extension data')

    try:
        key_description, _ = decode(extension.value.value, KeyDescription())
    except PyAsn1Error:
        raise AttestationError(
            'Android key attestation failed: unable to decode DER-encoded '
            'Android Key Description')

    attestation_challenge = key_description['attestationChallenge'].asOctets()
    if attestation_challenge != client_data_hash:
        raise AttestationError(
            'Android key attestation failed: client data hash does not match '
            'value of attestation extension data')

    all_apps_se = key_description['softwareEnforced']['allApplications']
    all_apps_tee = key_description['teeEnforced']['allApplications']
    if all_apps_se.hasValue() or all_apps_tee.hasValue():
        raise AttestationError(
            'Android key attestation failed: the allApplications field must not be '
            'present in the android key description')

    # TODO: Consider selecting the appropriate AuthorizationList.
    tee_origin = key_description['teeEnforced']['origin']
    tee_purpose = key_description['teeEnforced']['purpose']
    if not tee_origin.hasValue() or int(tee_origin) != KM_ORIGIN_GENERATED:
        raise AttestationError((
            'Android key attestation failed: the teeEnforced origin field must '
            'equal KM_ORIGIN_GENERATED={}').format(KM_ORIGIN_GENERATED))

    # TODO: Determine if other purposes are also allowed in this set.
    if not tee_purpose.hasValue() or tee_purpose.count(KM_PURPOSE_SIGN) == 0:
        raise AttestationError((
            'Android key attestation failed: the teeEnforced purpose field must '
            'contain KM_PURPOSE_SIGN={}').format(KM_PURPOSE_SIGN))

    return AttestationType.BASIC, [credential_certificate]
Example #5
0
def test_credentials_backend_request_error():
    backend = CredentialsBackend(SuccessCredentialsRegistrar())

    challenge = b'challenge'
    credential_id = b'credential-id'
    auth_data = authenticator_data(
        TEST_RP_ID_HASH,
        (AuthenticatorDataFlag.UP.value | AuthenticatorDataFlag.AT.value
         | AuthenticatorDataFlag.ED.value), b'\x00' * 4,
        attested_credential_data(
            b'z' * 16,
            len(credential_id),
            credential_id,
            cbor2.dumps({
                -3: TEST_CREDENTIAL_PUBLIC_KEY.y,
                -2: TEST_CREDENTIAL_PUBLIC_KEY.x,
                -1: TEST_CREDENTIAL_PUBLIC_KEY.crv.value,
                1: TEST_CREDENTIAL_PUBLIC_KEY.kty.value,
                3: TEST_CREDENTIAL_PUBLIC_KEY.alg.value,
            }),
        ), cbor2.dumps({
            'appid': True,
        }))
    client_data_JSON = json_bytes({
        'type': 'webauthn.get',
        'challenge': base64s(challenge),
        'origin': TEST_RP_ORIGIN,
    })

    signature_algorithm = ECDSA(ec2_hash_algorithm(TEST_COSE_ALG))
    signature = TEST_CRYPTOGRAPHY_PRIVATE_KEY.sign(
        auth_data + hashlib.sha256(client_data_JSON).digest(),
        signature_algorithm,
    )

    public_key_credential = PublicKeyCredential(
        id=base64s(credential_id),
        type='credential-type',
        raw_id=credential_id,
        response=AuthenticatorAssertionResponse(
            client_data_JSON=client_data_JSON,
            authenticator_data=auth_data,
            signature=signature,
        ))

    expected_challenge = challenge

    with pytest.raises(CredentialNotAllowedError):
        backend.handle_credential_assertion(
            credential=public_key_credential,
            user=TEST_USER,
            rp=TEST_RP,
            expected_challenge=expected_challenge,
            expected_origin=TEST_RP_ORIGIN,
            allow_credentials=[
                PublicKeyCredentialDescriptor(
                    type=PublicKeyCredentialType.PUBLIC_KEY,
                    id=b'cred-id',
                )
            ])

    backend = CredentialsBackend(ExceptionCredentialsRegistrar())
    with pytest.raises(RegistrationError):
        backend.handle_credential_assertion(
            credential=public_key_credential,
            user=TEST_USER,
            rp=TEST_RP,
            expected_challenge=expected_challenge,
            expected_origin=TEST_RP_ORIGIN,
        )

    class TestCredentialsRegistrar(SuccessCredentialsRegistrar):
        def get_credential_data(
                self, credential_id: bytes) -> Optional[CredentialData]:
            return None

    backend = CredentialsBackend(TestCredentialsRegistrar())
    with pytest.raises(CredentialDataError):
        backend.handle_credential_assertion(
            credential=public_key_credential,
            user=TEST_USER,
            rp=TEST_RP,
            expected_challenge=expected_challenge,
            expected_origin=TEST_RP_ORIGIN,
        )

    class TestCredentialsRegistrar(SuccessCredentialsRegistrar):
        def get_credential_data(
                self, credential_id: bytes) -> Optional[CredentialData]:
            return CredentialData(TEST_CREDENTIAL_PUBLIC_KEY,
                                  None,
                                  user_entity=PublicKeyCredentialUserEntity(
                                      name='user',
                                      id=b'user-id-mismatch',
                                      display_name='username'))

    backend = CredentialsBackend(TestCredentialsRegistrar())
    with pytest.raises(UserIDError):
        backend.handle_credential_assertion(
            credential=public_key_credential,
            user=TEST_USER,
            rp=TEST_RP,
            expected_challenge=expected_challenge,
            expected_origin=TEST_RP_ORIGIN,
        )

    backend = CredentialsBackend(SuccessCredentialsRegistrar())
    with pytest.raises(UserHandleError):
        backend.handle_credential_assertion(
            credential=public_key_credential,
            rp=TEST_RP,
            expected_challenge=expected_challenge,
            expected_origin=TEST_RP_ORIGIN,
        )

    backend = CredentialsBackend(SuccessCredentialsRegistrar())
    with pytest.raises(RPNotFoundError):
        backend.handle_credential_assertion(
            credential=public_key_credential,
            user=TEST_USER,
            expected_challenge=expected_challenge,
            expected_origin=TEST_RP_ORIGIN,
        )

    class TestCredentialsRegistrar(SuccessCredentialsRegistrar):
        def get_credential_data(
                self, credential_id: bytes) -> Optional[CredentialData]:
            return CredentialData(TEST_CREDENTIAL_PUBLIC_KEY,
                                  None,
                                  TEST_USER,
                                  rp_entity=PublicKeyCredentialRpEntity(
                                      name='example.com', id='mismatch'))

    backend = CredentialsBackend(TestCredentialsRegistrar())
    with pytest.raises(RPIDError):
        backend.handle_credential_assertion(
            credential=public_key_credential,
            user=TEST_USER,
            rp=TEST_RP,
            expected_challenge=expected_challenge,
            expected_origin=TEST_RP_ORIGIN,
        )

    class TestCredentialsRegistrar(SuccessCredentialsRegistrar):
        def get_credential_data(
                self, credential_id: bytes) -> Optional[CredentialData]:
            return CredentialData(TEST_CREDENTIAL_PUBLIC_KEY, None, TEST_USER,
                                  TEST_RP)

    backend = CredentialsBackend(TestCredentialsRegistrar())
    backend.handle_credential_assertion(
        credential=public_key_credential,
        user=TEST_USER,
        expected_challenge=expected_challenge,
        expected_origin=TEST_RP_ORIGIN,
    )

    public_key_credential_error = PublicKeyCredential(
        id=base64s(credential_id),
        type='credential-type',
        raw_id=credential_id,
        response=AuthenticatorAssertionResponse(
            client_data_JSON=client_data_JSON,
            authenticator_data=auth_data,
            signature=signature,
            user_handle=b'mismatch',
        ))

    backend = CredentialsBackend(SuccessCredentialsRegistrar())
    with pytest.raises(UserHandleError):
        backend.handle_credential_assertion(
            credential=public_key_credential_error,
            user=TEST_USER,
            rp=TEST_RP,
            expected_challenge=expected_challenge,
            expected_origin=TEST_RP_ORIGIN,
        )

    client_data_JSON = json_bytes({
        'type': 'webauthn.create',
        'challenge': base64s(challenge),
        'origin': TEST_RP_ORIGIN,
    })

    signature_algorithm = ECDSA(ec2_hash_algorithm(TEST_COSE_ALG))
    signature = TEST_CRYPTOGRAPHY_PRIVATE_KEY.sign(
        auth_data + hashlib.sha256(client_data_JSON).digest(),
        signature_algorithm,
    )

    public_key_credential = PublicKeyCredential(
        id=base64s(credential_id),
        type='credential-type',
        raw_id=credential_id,
        response=AuthenticatorAssertionResponse(
            client_data_JSON=client_data_JSON,
            authenticator_data=auth_data,
            signature=signature,
        ))

    backend = CredentialsBackend(SuccessCredentialsRegistrar())
    with pytest.raises(ClientDataTypeError):
        backend.handle_credential_assertion(
            credential=public_key_credential,
            user=TEST_USER,
            rp=TEST_RP,
            expected_challenge=expected_challenge,
            expected_origin=TEST_RP_ORIGIN,
        )

    client_data_JSON = json_bytes({
        'type': 'webauthn.get',
        'challenge': '\x90\x91\x92',
        'origin': TEST_RP_ORIGIN,
    })

    signature_algorithm = ECDSA(ec2_hash_algorithm(TEST_COSE_ALG))
    signature = TEST_CRYPTOGRAPHY_PRIVATE_KEY.sign(
        auth_data + hashlib.sha256(client_data_JSON).digest(),
        signature_algorithm,
    )

    public_key_credential = PublicKeyCredential(
        id=base64s(credential_id),
        type='credential-type',
        raw_id=credential_id,
        response=AuthenticatorAssertionResponse(
            client_data_JSON=client_data_JSON,
            authenticator_data=auth_data,
            signature=signature,
        ))

    backend = CredentialsBackend(SuccessCredentialsRegistrar())
    with pytest.raises(DecodingError):
        backend.handle_credential_assertion(
            credential=public_key_credential,
            user=TEST_USER,
            rp=TEST_RP,
            expected_challenge=expected_challenge,
            expected_origin=TEST_RP_ORIGIN,
        )

    client_data_JSON = json_bytes({
        'type': 'webauthn.get',
        'challenge': 'mismatch',
        'origin': TEST_RP_ORIGIN,
    })

    signature_algorithm = ECDSA(ec2_hash_algorithm(TEST_COSE_ALG))
    signature = TEST_CRYPTOGRAPHY_PRIVATE_KEY.sign(
        auth_data + hashlib.sha256(client_data_JSON).digest(),
        signature_algorithm,
    )

    public_key_credential = PublicKeyCredential(
        id=base64s(credential_id),
        type='credential-type',
        raw_id=credential_id,
        response=AuthenticatorAssertionResponse(
            client_data_JSON=client_data_JSON,
            authenticator_data=auth_data,
            signature=signature,
        ))

    backend = CredentialsBackend(SuccessCredentialsRegistrar())
    with pytest.raises(ChallengeError):
        backend.handle_credential_assertion(
            credential=public_key_credential,
            user=TEST_USER,
            rp=TEST_RP,
            expected_challenge=expected_challenge,
            expected_origin=TEST_RP_ORIGIN,
        )

    client_data_JSON = json_bytes({
        'type': 'webauthn.get',
        'challenge': base64s(challenge),
        'origin': TEST_RP_ORIGIN,
    })

    signature_algorithm = ECDSA(ec2_hash_algorithm(TEST_COSE_ALG))
    signature = TEST_CRYPTOGRAPHY_PRIVATE_KEY.sign(
        auth_data + hashlib.sha256(client_data_JSON).digest(),
        signature_algorithm,
    )

    public_key_credential = PublicKeyCredential(
        id=base64s(credential_id),
        type='credential-type',
        raw_id=credential_id,
        response=AuthenticatorAssertionResponse(
            client_data_JSON=client_data_JSON,
            authenticator_data=auth_data,
            signature=signature,
        ))

    backend = CredentialsBackend(SuccessCredentialsRegistrar())
    with pytest.raises(OriginError):
        backend.handle_credential_assertion(
            credential=public_key_credential,
            user=TEST_USER,
            rp=TEST_RP,
            expected_challenge=expected_challenge,
            expected_origin='https://mismatch',
        )

    with pytest.raises(TokenBindingError):
        backend.handle_credential_assertion(
            credential=public_key_credential,
            user=TEST_USER,
            rp=TEST_RP,
            expected_challenge=expected_challenge,
            expected_origin=TEST_RP_ORIGIN,
            token_binding=TokenBinding(status=TokenBindingStatus.SUPPORTED))

    client_data_JSON = json_bytes({
        'type': 'webauthn.get',
        'challenge': base64s(challenge),
        'origin': TEST_RP_ORIGIN,
        'tokenBinding': {
            'status': 'supported'
        }
    })

    signature_algorithm = ECDSA(ec2_hash_algorithm(TEST_COSE_ALG))
    signature = TEST_CRYPTOGRAPHY_PRIVATE_KEY.sign(
        auth_data + hashlib.sha256(client_data_JSON).digest(),
        signature_algorithm,
    )

    public_key_credential = PublicKeyCredential(
        id=base64s(credential_id),
        type='credential-type',
        raw_id=credential_id,
        response=AuthenticatorAssertionResponse(
            client_data_JSON=client_data_JSON,
            authenticator_data=auth_data,
            signature=signature,
        ))

    with pytest.raises(TokenBindingError):
        backend.handle_credential_assertion(
            credential=public_key_credential,
            user=TEST_USER,
            rp=TEST_RP,
            expected_challenge=expected_challenge,
            expected_origin=TEST_RP_ORIGIN,
            token_binding=TokenBinding(
                status=TokenBindingStatus.PRESENT,
                id='token-binding-id',
            ))

    client_data_JSON = json_bytes({
        'type': 'webauthn.get',
        'challenge': base64s(challenge),
        'origin': TEST_RP_ORIGIN,
        'tokenBinding': {
            'status': 'present',
            'id': 'token-binding-id-mismatch',
        }
    })

    signature_algorithm = ECDSA(ec2_hash_algorithm(TEST_COSE_ALG))
    signature = TEST_CRYPTOGRAPHY_PRIVATE_KEY.sign(
        auth_data + hashlib.sha256(client_data_JSON).digest(),
        signature_algorithm,
    )

    public_key_credential = PublicKeyCredential(
        id=base64s(credential_id),
        type='credential-type',
        raw_id=credential_id,
        response=AuthenticatorAssertionResponse(
            client_data_JSON=client_data_JSON,
            authenticator_data=auth_data,
            signature=signature,
        ))

    with pytest.raises(TokenBindingError):
        backend.handle_credential_assertion(
            credential=public_key_credential,
            user=TEST_USER,
            rp=TEST_RP,
            expected_challenge=expected_challenge,
            expected_origin=TEST_RP_ORIGIN,
            token_binding=TokenBinding(
                status=TokenBindingStatus.PRESENT,
                id='token-binding-id',
            ))

    with pytest.raises(TokenBindingError):
        backend.handle_credential_assertion(
            credential=public_key_credential,
            user=TEST_USER,
            rp=TEST_RP,
            expected_challenge=expected_challenge,
            expected_origin=TEST_RP_ORIGIN,
        )

    auth_data = authenticator_data(
        TEST_RP_ID_HASH, (AuthenticatorDataFlag.AT.value
                          | AuthenticatorDataFlag.ED.value), b'\x00' * 4,
        attested_credential_data(
            b'z' * 16,
            len(credential_id),
            credential_id,
            cbor2.dumps({
                -3: TEST_CREDENTIAL_PUBLIC_KEY.y,
                -2: TEST_CREDENTIAL_PUBLIC_KEY.x,
                -1: TEST_CREDENTIAL_PUBLIC_KEY.crv.value,
                1: TEST_CREDENTIAL_PUBLIC_KEY.kty.value,
                3: TEST_CREDENTIAL_PUBLIC_KEY.alg.value,
            }),
        ), cbor2.dumps({
            'appid': True,
        }))

    client_data_JSON = json_bytes({
        'type': 'webauthn.get',
        'challenge': base64s(challenge),
        'origin': TEST_RP_ORIGIN,
        'tokenBinding': {
            'status': 'present',
            'id': 'token-binding-id',
        }
    })

    signature_algorithm = ECDSA(ec2_hash_algorithm(TEST_COSE_ALG))
    signature = TEST_CRYPTOGRAPHY_PRIVATE_KEY.sign(
        auth_data + hashlib.sha256(client_data_JSON).digest(),
        signature_algorithm,
    )

    public_key_credential = PublicKeyCredential(
        id=base64s(credential_id),
        type='credential-type',
        raw_id=credential_id,
        response=AuthenticatorAssertionResponse(
            client_data_JSON=client_data_JSON,
            authenticator_data=auth_data,
            signature=signature,
        ))

    class TestCredentialsRegistrar(SuccessCredentialsRegistrar):
        def get_credential_data(
                self, credential_id: bytes) -> Optional[CredentialData]:
            return CredentialData(
                TEST_CREDENTIAL_PUBLIC_KEY,
                None,
                TEST_USER,
                TEST_RP,
            )

    backend = CredentialsBackend(TestCredentialsRegistrar())
    with pytest.raises(RPIDError):
        backend.handle_credential_assertion(
            credential=public_key_credential,
            user=TEST_USER,
            rp=PublicKeyCredentialRpEntity(name='example.com',
                                           id='mismatch.example.com'),
            expected_challenge=expected_challenge,
            expected_origin=TEST_RP_ORIGIN,
            token_binding=TokenBinding(
                status=TokenBindingStatus.PRESENT,
                id='token-binding-id',
            ),
        )

    backend = CredentialsBackend(SuccessCredentialsRegistrar())
    with pytest.raises(UserPresenceError):
        backend.handle_credential_assertion(
            credential=public_key_credential,
            user=TEST_USER,
            rp=TEST_RP,
            expected_challenge=expected_challenge,
            expected_origin=TEST_RP_ORIGIN,
            token_binding=TokenBinding(
                status=TokenBindingStatus.PRESENT,
                id='token-binding-id',
            ))

    auth_data = authenticator_data(
        TEST_RP_ID_HASH,
        (AuthenticatorDataFlag.UP.value | AuthenticatorDataFlag.AT.value
         | AuthenticatorDataFlag.ED.value), b'\x00' * 4,
        attested_credential_data(
            b'z' * 16,
            len(credential_id),
            credential_id,
            cbor2.dumps({
                -3: TEST_CREDENTIAL_PUBLIC_KEY.y,
                -2: TEST_CREDENTIAL_PUBLIC_KEY.x,
                -1: TEST_CREDENTIAL_PUBLIC_KEY.crv.value,
                1: TEST_CREDENTIAL_PUBLIC_KEY.kty.value,
                3: TEST_CREDENTIAL_PUBLIC_KEY.alg.value,
            }),
        ), cbor2.dumps({
            'appid': True,
        }))

    signature_algorithm = ECDSA(ec2_hash_algorithm(TEST_COSE_ALG))
    signature = TEST_CRYPTOGRAPHY_PRIVATE_KEY.sign(
        auth_data + hashlib.sha256(client_data_JSON).digest(),
        signature_algorithm,
    )

    public_key_credential = PublicKeyCredential(
        id=base64s(credential_id),
        type='credential-type',
        raw_id=credential_id,
        response=AuthenticatorAssertionResponse(
            client_data_JSON=client_data_JSON,
            authenticator_data=auth_data,
            signature=signature,
        ))

    with pytest.raises(UserVerificationError):
        backend.handle_credential_assertion(
            credential=public_key_credential,
            user=TEST_USER,
            rp=TEST_RP,
            expected_challenge=expected_challenge,
            expected_origin=TEST_RP_ORIGIN,
            token_binding=TokenBinding(
                status=TokenBindingStatus.PRESENT,
                id='token-binding-id',
            ),
            require_user_verification=True,
        )

    with pytest.raises(ExtensionError):
        backend.handle_credential_assertion(
            credential=public_key_credential,
            user=TEST_USER,
            rp=TEST_RP,
            expected_challenge=expected_challenge,
            expected_origin=TEST_RP_ORIGIN,
            token_binding=TokenBinding(
                status=TokenBindingStatus.PRESENT,
                id='token-binding-id',
            ),
            expected_extensions={ExtensionIdentifier.TX_AUTH_SIMPLE},
        )

    class TestCredentialsRegistrar(SuccessCredentialsRegistrar):
        def get_credential_data(
                self, credential_id: bytes) -> Optional[CredentialData]:
            return CredentialData(
                TEST_CREDENTIAL_PUBLIC_KEY,
                10,
                TEST_USER,
            )

    backend = CredentialsBackend(TestCredentialsRegistrar())
    with pytest.raises(SignatureCountError):
        backend.handle_credential_assertion(
            credential=public_key_credential,
            user=TEST_USER,
            rp=TEST_RP,
            expected_challenge=expected_challenge,
            expected_origin=TEST_RP_ORIGIN,
            token_binding=TokenBinding(
                status=TokenBindingStatus.PRESENT,
                id='token-binding-id',
            ),
        )

    class TestCredentialsRegistrar(SuccessCredentialsRegistrar):
        def register_credential_assertion(
                self, credential: PublicKeyCredential,
                authenticator_data: AuthenticatorData,
                user: PublicKeyCredentialUserEntity,
                rp: PublicKeyCredentialRpEntity) -> Any:
            raise Exception()

    backend = CredentialsBackend(TestCredentialsRegistrar())
    with pytest.raises(RegistrationError):
        backend.handle_credential_assertion(
            credential=public_key_credential,
            user=TEST_USER,
            rp=TEST_RP,
            expected_challenge=expected_challenge,
            expected_origin=TEST_RP_ORIGIN,
            token_binding=TokenBinding(
                status=TokenBindingStatus.PRESENT,
                id='token-binding-id',
            ),
        )

    class TestCredentialsRegistrar(SuccessCredentialsRegistrar):
        def register_credential_assertion(
                self, credential: PublicKeyCredential,
                authenticator_data: AuthenticatorData,
                user: PublicKeyCredentialUserEntity,
                rp: PublicKeyCredentialRpEntity) -> Any:
            return 'Error'

    backend = CredentialsBackend(TestCredentialsRegistrar())
    with pytest.raises(RegistrationError):
        backend.handle_credential_assertion(
            credential=public_key_credential,
            user=TEST_USER,
            rp=TEST_RP,
            expected_challenge=expected_challenge,
            expected_origin=TEST_RP_ORIGIN,
            token_binding=TokenBinding(
                status=TokenBindingStatus.PRESENT,
                id='token-binding-id',
            ),
        )
Example #6
0
def test_ec2_hash_algorithm_error(alg):
    with pytest.raises(AssertionError):
        ec2_hash_algorithm(alg)
Example #7
0
def test_ec2_hash_algorithm_success(alg):
    ec2_hash_algorithm(alg)