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,81 @@
# `extra-data` — `TPMS_ATTEST.extraData` constant-time match
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`extraDataMatches` compares a TPM-emitted `extraData` blob (the value the
TPM signed alongside the attest body) against the relying-party-recomputed
`attToBeSigned` digest per W3C WebAuthn Level 3 §8.3 step 8. The function
is intentionally tiny: it short-circuits on length mismatch (length is
public, not a secret) and then delegates the content comparison to a
caller-injected constant-time equality function. Keeping the constant-
time primitive injectable lets `@suaveplan/tpm-struct` stay universal-
tier (no `@suaveplan/crypto-utils` runtime dep) while letting consumers
wire in whichever hardened equality their crypto stack ships.
## Features
- Length short-circuit (length is not a secret).
- Pluggable equality function via the `ConstantTimeEqual` type.
- Zero-allocation: works directly over the supplied `Uint8Array`s.
## Usage: Basic Example
```ts
import { extraDataMatches } from "@suaveplan/tpm-struct/extra-data";
declare const constantTimeEqual: (a: Uint8Array, b: Uint8Array) => boolean;
if (extraDataMatches(att.extraData, recomputedDigest, constantTimeEqual)) {
// attToBeSigned matched.
}
```
## Usage: Advanced Example
```ts
import { constantTimeEqual } from "@suaveplan/crypto-utils";
import { extraDataMatches } from "@suaveplan/tpm-struct/extra-data";
// Compose with the rest of the WebAuthn `tpm`-attestation chain.
function verifyExtraDataAndName(
att: { extraData: Uint8Array; attested: { name: Uint8Array } },
recomputedAttToBeSigned: Uint8Array,
recomputedName: Uint8Array
): { extraDataOk: boolean; nameOk: boolean } {
return {
extraDataOk: extraDataMatches(
att.extraData,
recomputedAttToBeSigned,
constantTimeEqual
),
nameOk: extraDataMatches(
att.attested.name,
recomputedName,
constantTimeEqual
),
};
}
```
## API Reference
- **`extraDataMatches(actual: Uint8Array, expected: Uint8Array, equal: ConstantTimeEqual): boolean`**
— `true` if and only if `actual.length === expected.length` and
`equal(actual, expected)` returns true. Returns `false` on length
mismatch without invoking `equal`.
- **`ConstantTimeEqual`** — `(a: Uint8Array, b: Uint8Array) => boolean`.
Implementations MUST NOT short-circuit on first byte mismatch — the
wall-time MUST depend only on the longer input's length.
## Implementation Notes
The function deliberately does not own a constant-time-equality fallback.
A naive `for` loop short-circuiting on mismatch would leak content
equality through timing; a sample implementation that XOR-accumulates
every byte is correct but lives in `@suaveplan/crypto-utils`. By keeping
the primitive injectable, this module avoids importing a crypto package
from a universal parser while still surfacing the right API shape
for the WebAuthn step 8 check.