zeroclaw-labs/zeroclaw · error · anyhow::Error

Unable to extract public key from attestation object ({} byt

Error message

Unable to extract public key from attestation object ({} bytes)

What it means

During finish_registration, extract_public_key_from_attestation walks the CBOR attestation object looking for a COSE key; if none is found (or the layout is unexpected) it bails, reporting the attestation byte length (webauthn.rs:643-649). Registration cannot proceed without the public key.

Source

Thrown at crates/zeroclaw-runtime/src/security/webauthn.rs:648

            attestation_bytes[36],
        ]);

        // Check if attested credential data is present (bit 6 of flags)
        let flags = attestation_bytes[32];
        if flags & 0x40 != 0 && attestation_bytes.len() > 55 {
            // AAGUID (16) + credIdLen (2) + credId (variable) + COSE key
            let cred_id_len =
                u16::from_be_bytes([attestation_bytes[53], attestation_bytes[54]]) as usize;
            let cose_key_start = 55 + cred_id_len;
            if attestation_bytes.len() > cose_key_start {
                let cose_key = &attestation_bytes[cose_key_start..];
                let pk = extract_p256_from_cose(cose_key)?;
                return Ok((pk, sign_count));
            }
        }
    }

    anyhow::bail!(
        "Unable to extract public key from attestation object ({} bytes)",
        attestation_bytes.len()
    )
}

/// Simplified attestation object for the enrollment UI.
#[derive(Deserialize)]
struct AttestationObject {
    /// Base64url-encoded public key (uncompressed P-256 or DER SPKI).
    public_key: String,
    /// Initial sign counter.
    sign_count: Option<u32>,
}

fn extract_p256_from_cose(cose: &[u8]) -> Result<Vec<u8>> {
    // If it starts with 0x04 and is 65 bytes, it's already uncompressed P-256
    if cose.len() >= 65 && cose[0] == 0x04 {
        return Ok(cose[..65].to_vec());

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Log the attestation format identifier ('fmt') and byte length, then retry registration — many authenticators work on retry with a different format
  2. Ensure the client passes the raw base64url attestationObject without re-encoding
  3. If one authenticator model always fails, capture its attestation object and check whether the COSE key is embedded in a different CBOR layout
Defensive patterns

Strategy: try-catch

Try / catch

Catch around finish_registration, return a user-facing 'registration failed — try again or use another passkey/security key', and log the attestation format and byte length (not the raw object) for diagnostics.

Prevention

When it happens

Trigger: finish_registration with an attestation object that lacks a COSE key in the expected position: a truncated authenticator response, or an attestation statement layout the extractor does not traverse.

Common situations: A browser/authenticator pair produces an attestation format outside the parsed paths; upstream base64url decoding dropped bytes; the client deserialized and re-serialized the response incorrectly.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/663ed118b2b525d5. Report an issue: GitHub.