Files
suaveplan/packages/security-stack/security/tpm-struct/src/public/public.md
2026-05-27 23:47:53 +01:00

103 lines
4.6 KiB
Markdown

# `public/public` — `TPMT_PUBLIC` parser
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs --> - serialize — `serializeTpmtPublic` re-emits a parsed…
- [serialize](./serialize.md) — `serializeTpmtPublic` re-emits a parsed `TpmtPublic` value as the TCG-canonical byte string per Library Part 2 §12.2. I…
- serialize — `serializeTpmtPublic` re-emits a parsed…
- [serialize](./serialize.md) — `serializeTpmtPublic` re-emits a parsed `TpmtPublic` value as the TCG-canonical byte string per Library Part 2 §12.2. I…
- serialize — `serializeTpmtPublic` re-emits a parsed…
- [serialize](./serialize.md) — `serializeTpmtPublic` re-emits a parsed `TpmtPublic` value as the TCG-canonical byte string per Library Part 2 §12.2. I…
- serialize — `serializeTpmtPublic` re-emits a parsed…
- [serialize](./serialize.md) — `serializeTpmtPublic` re-emits a parsed `TpmtPublic` value as the TCG-canonical byte string per Library Part 2 §12.2. I…
- [serialize](./serialize.md) — `serializeTpmtPublic` re-emits a parsed `TpmtPublic` value as the TCG-canonical byte string per Library Part 2 §12.2. I…
## Purpose
`parseTpmtPublic` decodes a TCG TPM 2.0 `TPMT_PUBLIC` byte string per
Library Part 2 §12.2 into a discriminated-union value keyed on the
`TPMI_ALG_PUBLIC` `type` field. The four supported branches —
`TPM_ALG_RSA`, `TPM_ALG_ECC`, `TPM_ALG_KEYEDHASH`, `TPM_ALG_SYMCIPHER` —
each decode their own `TPMS_*_PARMS` parameter substructure and matching
`TPMU_PUBLIC_ID` unique slot. The parser is the central seam between the
on-the-wire byte format and every downstream consumer of TPM public
areas: `computeTpmtPublicName` re-emits the bytes through
`serializeTpmtPublic` and hashes them for the canonical Part 1 §16 name
digest, while the WebAuthn `tpm`-format verifier validates the `pubArea`
against the credential public key in `authData.attestedCredentialData`.
## Features
- Full §12.2 field order enforcement (`type` → `nameAlg` →
`objectAttributes` → `authPolicy` → `parameters` → `unique`).
- RSA-2048/3072/4096 with default-exponent (`0` → `65537`) normalisation
per §12.2.3.5 plus a `rawExponent` slot preserved for round-trip
fidelity.
- ECC P-256/P-384/P-521/BN-256/BN-638/SM2-256 with `curveID` lookup via
the §11.2.5 registry; unknown curves raise `CURVE_UNSUPPORTED`.
- KEYEDHASH NULL / HMAC / XOR schemes per §12.2.3.3.
- SYMCIPHER with full `TPMT_SYM_DEF_OBJECT` decoding per §12.2.3.4.
- `objectAttributes` decoded into raw `uint32` + typed flag struct;
reserved bits non-zero raise `OBJECT_ATTRIBUTES_RESERVED_NONZERO`.
- Boundary Zod schema (`TpmtPublicSchema`) validates the constructed
result before returning — malformed parser output raises `MALFORMED`.
- OTel histograms (`tpm_struct.parse_tpmt_public_duration_ms{type,outcome}`)
- counters (`tpm_struct.parse_total{kind="public",outcome}` and
`tpm_struct.parse_errors_total{code}`).
## Usage: Basic Example
```ts
import { parseTpmtPublic } from "@suaveplan/tpm-struct/public";
const pub = parseTpmtPublic(pubAreaBytes);
if (pub.type === "TPM_ALG_RSA") {
console.log(pub.parameters.keyBits, pub.parameters.exponent);
console.log(pub.unique.modulus.byteLength);
}
```
## Usage: Advanced Example
```ts
import { createHash } from "node:crypto";
import {
computeTpmtPublicName,
parseTpmtPublic,
} from "@suaveplan/tpm-struct";
const pub = parseTpmtPublic(pubAreaBytes);
if (pub.nameAlg === "TPM_ALG_SHA256" && pub.type === "TPM_ALG_ECC") {
const name = computeTpmtPublicName(pub, {
digest: (b) => new Uint8Array(createHash("sha256").update(b).digest()),
});
// `name` is `0x000b || sha256(serializeTpmtPublic(pub))` — feed this
// into the WebAuthn `tpm`-attestation name-match step (W3C WebAuthn
// L3 §8.3 step 5).
}
```
## API Reference
- **`parseTpmtPublic(bytes: Uint8Array): TpmtPublic`** — returns a
discriminated-union value. Throws `TpmStructError` with one of
`ALG_UNSUPPORTED`, `CURVE_UNSUPPORTED`, `OBJECT_ATTRIBUTES_RESERVED_NONZERO`,
`PARAMETERS_INVALID`, `TRUNCATED`, or `MALFORMED`.
- **`TpmtPublic`** — discriminator union over `type`. Each branch carries
`nameAlg`, `objectAttributes`, `authPolicy`, `parameters`, `unique`.
## Implementation Notes
The parser is deliberately straight-line: every field decode advances the
underlying `TpmBufferReader`'s cursor by exactly the bytes named in the
spec. `assertEnd()` is called at the end of every successful parse so a
trailing byte is reported as `TRUNCATED` rather than silently dropped.
The exponent-zero normalisation rule is preserved alongside `rawExponent`
because re-serialisation must emit the original bytes so the §16 name
digest stays stable.