{"record":{"id":"1c3fa8687ff45a76","repo":"zeroclaw-labs/zeroclaw","slug":"unsupported-cose-key-format-expected-uncompressed","errorCode":null,"errorMessage":"Unsupported COSE key format (expected uncompressed P-256, got {} bytes starting with 0x{:02x})","messagePattern":"Unsupported COSE key format \\(expected uncompressed P-256, got (.+?) bytes starting with 0x(.+?)\\)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-runtime/src/security/webauthn.rs","lineNumber":669,"sourceCode":"    )\n}\n\n/// Simplified attestation object for the enrollment UI.\n#[derive(Deserialize)]\nstruct AttestationObject {\n    /// Base64url-encoded public key (uncompressed P-256 or DER SPKI).\n    public_key: String,\n    /// Initial sign counter.\n    sign_count: Option<u32>,\n}\n\nfn extract_p256_from_cose(cose: &[u8]) -> Result<Vec<u8>> {\n    // If it starts with 0x04 and is 65 bytes, it's already uncompressed P-256\n    if cose.len() >= 65 && cose[0] == 0x04 {\n        return Ok(cose[..65].to_vec());\n    }\n\n    anyhow::bail!(\n        \"Unsupported COSE key format (expected uncompressed P-256, got {} bytes starting with 0x{:02x})\",\n        cose.len(),\n        cose.first().copied().unwrap_or(0)\n    )\n}\n\n// ── Signature verification ──────────────────────────────────────\n\nfn verify_es256_signature(public_key: &[u8], message: &[u8], sig: &[u8]) -> Result<()> {\n    // ring's UnparsedPublicKey expects the raw uncompressed point for P-256\n    // (not wrapped in SPKI). If we have SPKI, we'd need to extract the point.\n    // For our use case the stored key is always the raw uncompressed point.\n    let pk = signature::UnparsedPublicKey::new(&signature::ECDSA_P256_SHA256_ASN1, public_key);\n\n    pk.verify(message, sig).map_err(|_| {\n        ::zeroclaw_log::record!(\n            WARN,\n            ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Reject)","sourceCodeStart":651,"sourceCodeEnd":687,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/security/webauthn.rs#L651-L687","documentation":"extract_p256_from_cose accepts only a 65-byte uncompressed EC2 P-256 point starting with 0x04 (webauthn.rs:661-671); anything else — compressed points, P-384/Ed25519/RSA COSE keys, or short buffers — is rejected. The message includes length and first byte so you can identify the actual key type.","triggerScenarios":"finish_registration with an authenticator that used ES384 or EdDSA, or a COSE key serialized as separate x/y coordinates instead of the 0x04||x||y form.","commonSituations":"The WebAuthn creation options allow broader algorithms than ES256 (alg -7); some platform authenticators default to other curves; a custom client builds the COSE structure by hand.","solutions":["Request only ES256 (alg -7, EC2, P-256) in your WebAuthn creation options","Read the reported length and first byte: 33 bytes starting 0x02/0x03 means compressed; 97 bytes starting 0x04 suggests P-384","If you must support other key types, extend the extractor — current code intentionally supports only uncompressed P-256"],"exampleFix":"// before: broad algorithm set\nconst creationOptions = {\n  pubKeyCredParams: [\n    { type: \"public-key\", alg: -7 },\n    { type: \"public-key\", alg: -8 },   // EdDSA\n    { type: \"public-key\", alg: -257 }, // RS256\n  ],\n};\n\n// after: only ES256 / uncompressed P-256, which the server can extract\nconst creationOptions = {\n  pubKeyCredParams: [{ type: \"public-key\", alg: -7 }],\n};","handlingStrategy":"validation","validationCode":"// Browser side: restrict creation options so non-ES256 credentials are never made\nconst creationOptions = {\n  pubKeyCredParams: [{ type: \"public-key\", alg: -7 }], // ES256 only\n  authenticatorSelection: { userVerification: \"preferred\" },\n};","typeGuard":null,"tryCatchPattern":"Catch around finish_registration, read the reported byte length/first byte to classify the key type, and tell the user to enroll a credential with a standard passkey (ES256); log the key shape for support triage.","preventionTips":["Request only alg -7 (ES256) in navigator.credentials.create options","Reject non-ES256 credentials at enrollment with a clear message","Track which authenticator models emit unsupported COSE keys and steer users away from them"],"tags":["webauthn","cose","p-256","cryptography","rust"],"backgroundTag":"unsupported-cose-key-format","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}