# Attestation-object parser ## Purpose Decodes the CTAP 2.1 §6.5 attestation-object envelope returned by `navigator.credentials.create()`. The envelope is a top-level CBOR map with `fmt` (format identifier), `authData` (the opaque authenticator-data byte string the signature was made over), and `attStmt` (the format-specific attestation statement). The parser returns the parsed structure plus the already-decoded `ParsedAuthData` so per-format verifiers do not re-parse the authenticator data. ## Features - Strict CBOR major-type checking — top level MUST be a map, `fmt` MUST be a text-string, `authData` MUST be a byte-string, `attStmt` MUST be a map. - Non-string `attStmt` keys reject with `WEBAUTHN.MALFORMED_RESPONSE` — only string-keyed maps are valid per CTAP 2.1. - Embedded `authData` is parsed via the universal authenticator-data parser; the per-format verifier consumes both the raw bytes (for signature verification) and the parsed structure (for flag inspection). - Zod schema validation on `ParsedAttestationStmt` so the public contract is stable. ## Usage: Basic Example ```ts import { parseAttestationObject } from "@suaveplan/webauthn/parser"; const env = parseAttestationObject(attestationObjectBytes); console.log(env.fmt, env.parsedAuthData.flags.userVerified); ``` ## Usage: Advanced Example ```ts import { parseAttestationObject } from "@suaveplan/webauthn/parser"; const env = parseAttestationObject(attestationObjectBytes); switch (env.fmt) { case "packed": return verifyPacked(env, clientDataHash); case "tpm": return verifyTpm(env, clientDataHash); case "none": return verifyNone(env); default: throw new Error("unsupported attestation format"); } ``` ## API Reference - `ParsedAttestationObject` — `{ fmt: string, authData: Uint8Array, parsedAuthData: ParsedAuthData, attStmt: ParsedAttestationStmt }`. - `parseAttestationObject(bytes: Uint8Array): ParsedAttestationObject` — full decode + structural validation; throws `WEBAUTHN.MALFORMED_RESPONSE` on every failure mode. ## Implementation Notes - The `authData` byte string is kept raw on the returned envelope because every per-format verifier signs over the exact bytes the authenticator emitted — re-serialising via `serializeAuthenticatorData` would produce canonical bytes that may not match the authenticator's wire encoding. - `decode` from `@suaveplan/cbor` is used in strict mode (default) so trailing bytes after the top-level map are rejected. This is intentional — a well-formed attestation object has no padding. - The parser is universal; it imports zero DOM types and can be consumed server-side by relying-party verifiers.