# Attestation format registry ## Purpose Defines the pluggable contract every per-format attestation verifier implements (`AttestationFormatVerifier`), the shared input bundle (`AttestationVerifierInput`), and the canonical result shape (`AttestationVerifyResult`). Consumers can `registerAttestationFormat(registry, name, verifier)` to add a new IANA-registered format (e.g. `apple-appattest`) or override a built-in without forking the package. ## Features - Three-type public contract: `AttestationType` (`basic | self | attCA | anonCA | none`), `AttestationVerifyResult` (`{ trusted, attestationType, trustPath }`), `AttestationFormatVerifier` (`(input) => Result | Promise`). - `AttestationFormatRegistry = Map` — opaque mutable handle the dispatcher consumes. - Last-write-wins registration so `registerAttestationFormat(registry, "packed", custom)` cleanly replaces the built-in. - Allows synchronous or async verifiers — `none` is synchronous, `tpm` is async, callers do not need to know the difference. ## Usage: Basic Example ```ts import { defaultAttestationRegistry, registerAttestationFormat, } from "@suaveplan/webauthn/verifier"; const registry = defaultAttestationRegistry(); registerAttestationFormat(registry, "apple-appattest", customVerifier); ``` ## Usage: Advanced Example ```ts import { type AttestationFormatVerifier, registerAttestationFormat, } from "@suaveplan/webauthn/verifier"; const counted: AttestationFormatVerifier = async (input) => { metrics.count(input.attestationObject.fmt); return builtin(input); }; registerAttestationFormat(registry, "packed", counted); ``` ## API Reference - `AttestationType` — literal union. - `AttestationVerifyResult` — `{ trusted: boolean, attestationType: AttestationType, trustPath: readonly Uint8Array[] }`. - `AttestationVerifierInput` — `{ attestationObject, clientDataHash, expectedRpIdHash }`. - `AttestationFormatVerifier` — `(input) => Result | Promise`. - `AttestationFormatRegistry` — `Map`. - `registerAttestationFormat(registry, name, verifier)` — register or override. ## Implementation Notes - `trustPath` is the leaf-first X.509 chain as raw DER byte strings. Empty when the format does not provide a chain (`self`, `none`). Consumers feed the chain into their own metadata-trust source (FIDO MDS3, attestation-CA allow-list) — the verifier is intentionally agnostic about which roots to trust. - The registry is a plain `Map` rather than a custom class so consumers can iterate / inspect / serialise it freely. The contract is the value types, not the container. - Returning a discriminated `attestationType` rather than a boolean lets the caller adjust policy: `basic` and `attCA` are stronger than `self`, and `none` is the weakest (but still acceptable when the RP's policy permits anonymous registration).