first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,54 @@
# 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<Result>`).
- `AttestationFormatRegistry = Map<string, AttestationFormatVerifier>` — 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<Result>`.
- `AttestationFormatRegistry` — `Map<string, AttestationFormatVerifier>`.
- `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).