103 lines
4.6 KiB
Markdown
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.
|