Initial Commit
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
# `attest/serialize` — `TPMS_ATTEST` canonical serialiser
|
||||
|
||||
## Purpose
|
||||
|
||||
`serializeTpmsAttest` re-emits a parsed `TpmsAttest` value as the
|
||||
TCG-canonical byte string per Library Part 2 §10.12. The serialiser is
|
||||
the inverse of `parseTpmsAttest`: for any input the parser accepts,
|
||||
`serialize(parse(bytes))` returns the same bytes. This invariant is
|
||||
load-bearing for two downstream uses: signature verification (the TPM
|
||||
endorsement key signed these exact bytes — a re-serialisation that
|
||||
differed by a single bit would silently fail every signature check) and
|
||||
proxy / replay use cases that want to forward a verified attest blob
|
||||
without trusting the originating wire to preserve the formatting.
|
||||
|
||||
## Features
|
||||
|
||||
- Byte-identical round-trip across all eight `TPMU_ATTEST` variants.
|
||||
- Re-emits the 32-bit `magic` prefix regardless of source — the
|
||||
serialiser is the authoritative encoder, not a passthrough.
|
||||
- Re-emits `TPM2B_*` size prefixes from the decoded payload length so a
|
||||
mutated stored size is silently ignored.
|
||||
- Renders the 17-byte `clockInfo` substructure exactly per §10.10.
|
||||
- Per-variant attested encoder for `CERTIFY`, `QUOTE`, `SESSION_AUDIT`,
|
||||
`COMMAND_AUDIT`, `TIME`, `CREATION`, `NV`, `NV_DIGEST`.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import {
|
||||
parseTpmsAttest,
|
||||
serializeTpmsAttest,
|
||||
} from "@suaveplan/tpm-struct/attest";
|
||||
|
||||
const att = parseTpmsAttest(bytes);
|
||||
const re = serializeTpmsAttest(att);
|
||||
// `re` equals `bytes` byte-for-byte.
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import {
|
||||
parseTpmsAttest,
|
||||
serializeTpmsAttest,
|
||||
} from "@suaveplan/tpm-struct/attest";
|
||||
|
||||
// Proxy / verifier-of-verifiers pattern: validate, normalise, forward.
|
||||
function relayAttestation(raw: Uint8Array, verifySig: (b: Uint8Array) => boolean) {
|
||||
const att = parseTpmsAttest(raw);
|
||||
const canonical = serializeTpmsAttest(att);
|
||||
if (!verifySig(canonical)) {
|
||||
throw new Error("attestation signature did not verify");
|
||||
}
|
||||
return { att, canonical };
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- **`serializeTpmsAttest(att: TpmsAttest): Uint8Array`** — returns a
|
||||
fresh byte string. Does not throw on any well-typed input — the
|
||||
caller must construct `att` through `parseTpmsAttest` (or a Zod-
|
||||
validated synthetic constructor) so the input is structurally valid.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The serialiser dispatches on `att.type` via a `switch` that the
|
||||
TypeScript compiler verifies as exhaustive. Each per-variant encoder
|
||||
walks the §10.11 / §10.12 field order using `TpmBufferWriter` so size
|
||||
prefixes and big-endian conventions stay locked to the reader semantics.
|
||||
The serialiser writes into a single growing buffer to avoid the cost of
|
||||
multiple `Uint8Array` allocations on the encoder hot path.
|
||||
Reference in New Issue
Block a user