{"record":{"id":"4323c4d4ca6aad88","repo":"odoo/odoo","slug":"attestation-statement-was-missing-x5c-android-key","errorCode":null,"errorMessage":"Attestation statement was missing x5c (Android Key)","messagePattern":"Attestation statement was missing x5c \\(Android Key\\)","errorType":"exception","errorClass":"InvalidRegistrationResponse","httpStatus":null,"severity":"error","filePath":"addons/auth_passkey/_vendor/webauthn/registration/formats/android_key.py","lineNumber":64,"sourceCode":") -> bool:\n    \"\"\"Verify an \"android-key\" attestation statement\n\n    See https://www.w3.org/TR/webauthn-2/#sctn-android-key-attestation\n\n    Also referenced: https://source.android.com/security/keystore/attestation\n    \"\"\"\n    if not attestation_statement.sig:\n        raise InvalidRegistrationResponse(\n            \"Attestation statement was missing signature (Android Key)\"\n        )\n\n    if not attestation_statement.alg:\n        raise InvalidRegistrationResponse(\n            \"Attestation statement was missing algorithm (Android Key)\"\n        )\n\n    if not attestation_statement.x5c:\n        raise InvalidRegistrationResponse(\"Attestation statement was missing x5c (Android Key)\")\n\n    # Validate certificate chain\n    try:\n        # Include known root certificates for this attestation format\n        pem_root_certs_bytes.append(google_hardware_attestation_root_1)\n        pem_root_certs_bytes.append(google_hardware_attestation_root_2)\n\n        validate_certificate_chain(\n            x5c=attestation_statement.x5c,\n            pem_root_certs_bytes=pem_root_certs_bytes,\n        )\n    except InvalidCertificateChain as err:\n        raise InvalidRegistrationResponse(f\"{err} (Android Key)\")\n\n    # Extract attStmt bytes from attestation_object\n    attestation_dict = parse_cbor(attestation_object)\n    authenticator_data_bytes = attestation_dict[\"authData\"]\n","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/odoo/odoo/blob/1e661df964b1b264c9cef3ab28430d4785be3fda/addons/auth_passkey/_vendor/webauthn/registration/formats/android_key.py#L46-L82","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Dump attestation_object and check fmt == 'android-key' actually matches the device output","Ensure the client passes the full attestation response (clientDataJSON + raw attestationObject) unmodified — no base64/JSON round-trips that drop binary fields","Re-register on a device that supports key attestation so x5c is populated by the keystore","If the device cannot produce x5c, stop requesting android-key attestation (use attestation='none' or 'direct' and accept the produced format)"],"exampleFix":"# before\nresult = verify_registration_response(..., attestation=\"android-key\")\n\n# after: let the verifier handle whatever format the device emitted\nresult = verify_registration_response(..., attestation=None)","handlingStrategy":"validation","validationCode":"import cbor2\n\ndef attestation_has_x5c(attestation_object: bytes) -> bool:\n    att = cbor2.loads(attestation_object)\n    x5c = (att.get(\"attStmt\") or {}).get(\"x5c\")\n    return isinstance(x5c, list) and len(x5c) > 0 and all(isinstance(c, bytes) for c in x5c)","typeGuard":"def has_x5c_chain(att: dict) -> bool:\n    stmt = att.get(\"attStmt\") or {}\n    return isinstance(stmt.get(\"x5c\"), list) and len(stmt[\"x5c\"]) >= 1","tryCatchPattern":"try:\n    verify_registration_response(...)\nexcept InvalidRegistrationResponse as e:\n    if \"missing x5c (Android Key)\" in str(e):\n        return error_response(\"device did not provide an attestation chain\", retry=True)\n    raise","preventionTips":["Don't force attestation='android-key' on devices that may not support it","Forward binary attestation fields without re-encoding","Log fmt + attStmt keys on failure for quick triage"],"tags":["webauthn","android-key","attestation","x5c","registration"],"backgroundTag":null,"analyzedSha":"1e661df964b1b264c9cef3ab28430d4785be3fda","analyzedAt":"2026-08-15T05:22:16.142Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}