first commit
This commit is contained in:
54
docs/identity/auth/webauthn/src/verifier/registry.md
Normal file
54
docs/identity/auth/webauthn/src/verifier/registry.md
Normal 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).
|
||||
Reference in New Issue
Block a user