odoo/odoo · error · InvalidRegistrationResponse

Attestation statement was missing x5c (Android Key)

Error message

Attestation statement was missing x5c (Android Key)

What it means

Android Key attestation requires an X.509 certificate chain (x5c) whose leaf carries the KeyDescription extension 1.3.6.1.4.1.11129.2.1.17. The verifier raises this when attStmt['x5c'] is absent or empty, because without the chain it can neither validate the chain to Google's hardware attestation roots nor extract the key-description extension.

Source

Thrown at addons/auth_passkey/_vendor/webauthn/registration/formats/android_key.py:64

) -> bool:
    """Verify an "android-key" attestation statement

    See https://www.w3.org/TR/webauthn-2/#sctn-android-key-attestation

    Also referenced: https://source.android.com/security/keystore/attestation
    """
    if not attestation_statement.sig:
        raise InvalidRegistrationResponse(
            "Attestation statement was missing signature (Android Key)"
        )

    if not attestation_statement.alg:
        raise InvalidRegistrationResponse(
            "Attestation statement was missing algorithm (Android Key)"
        )

    if not attestation_statement.x5c:
        raise InvalidRegistrationResponse("Attestation statement was missing x5c (Android Key)")

    # Validate certificate chain
    try:
        # Include known root certificates for this attestation format
        pem_root_certs_bytes.append(google_hardware_attestation_root_1)
        pem_root_certs_bytes.append(google_hardware_attestation_root_2)

        validate_certificate_chain(
            x5c=attestation_statement.x5c,
            pem_root_certs_bytes=pem_root_certs_bytes,
        )
    except InvalidCertificateChain as err:
        raise InvalidRegistrationResponse(f"{err} (Android Key)")

    # Extract attStmt bytes from attestation_object
    attestation_dict = parse_cbor(attestation_object)
    authenticator_data_bytes = attestation_dict["authData"]

View on GitHub (pinned to 1e661df964)

Solutions

  1. Dump attestation_object and check fmt == 'android-key' actually matches the device output
  2. Ensure the client passes the full attestation response (clientDataJSON + raw attestationObject) unmodified — no base64/JSON round-trips that drop binary fields
  3. Re-register on a device that supports key attestation so x5c is populated by the keystore
  4. If the device cannot produce x5c, stop requesting android-key attestation (use attestation='none' or 'direct' and accept the produced format)

Example fix

# before
result = verify_registration_response(..., attestation="android-key")

# after: let the verifier handle whatever format the device emitted
result = verify_registration_response(..., attestation=None)
Defensive patterns

Strategy: validation

Validate before calling

import cbor2

def attestation_has_x5c(attestation_object: bytes) -> bool:
    att = cbor2.loads(attestation_object)
    x5c = (att.get("attStmt") or {}).get("x5c")
    return isinstance(x5c, list) and len(x5c) > 0 and all(isinstance(c, bytes) for c in x5c)

Type guard

def has_x5c_chain(att: dict) -> bool:
    stmt = att.get("attStmt") or {}
    return isinstance(stmt.get("x5c"), list) and len(stmt["x5c"]) >= 1

Try / catch

try:
    verify_registration_response(...)
except InvalidRegistrationResponse as e:
    if "missing x5c (Android Key)" in str(e):
        return error_response("device did not provide an attestation chain", retry=True)
    raise

Prevention

When it happens

Trigger: verify_android_key_attestation() receives attStmt with sig and alg but no 'x5c' array. Happens with self-attestation-style statements mislabeled as android-key, or when the response was built from keystore attestation bytes without the certificate chain.

Common situations: Using Android Keystore attestation API directly and forwarding only the signature; test fixtures built from partial device output; authenticators that fall back to a format the RP did not expect; RP requested attestation='android-key' but the device produced 'packed' and code forced the format string.

Related errors


AI-assisted analysis of odoo/odoo@1e661df964 (2026-08-15). Data as JSON: /api/errors/4323c4d4ca6aad88. Report an issue: GitHub.