87 lines
3.6 KiB
Markdown
87 lines
3.6 KiB
Markdown
# `buffer` — TPM 2.0 octet-stream reader and writer
|
|
|
|
<!-- begin:auto-docs -->
|
|
_(no submodules)_
|
|
<!-- end:auto-docs -->
|
|
## Purpose
|
|
|
|
The `buffer` module provides the lowest layer of `@suaveplan/tpm-struct`: a
|
|
strictly-bounded, big-endian byte reader (`TpmBufferReader`) and a matching
|
|
growing-array writer (`TpmBufferWriter`) shaped to the TCG TPM 2.0 Library
|
|
Part 2 §10.1 octet-stream conventions. Every higher-level parser in the
|
|
package (the `TPMS_ATTEST` decoder, the `TPMT_PUBLIC` decoder, the name
|
|
serialiser) builds on these primitives, which is why they receive their
|
|
own subpath export. Keeping bounds enforcement, big-endian semantics, and
|
|
the `TPM2B_*` size-prefix protocol in one place means the rest of the
|
|
package can be written as straight-line code without per-field bounds
|
|
checks or accidental little-endian reads.
|
|
|
|
## Features
|
|
|
|
- Big-endian readers for UINT8/16/32/64 (the 64-bit form returns a
|
|
`bigint` so it never silently truncates).
|
|
- `TPM2B_*` size-prefix reader and writer (UINT16 length + payload).
|
|
- Cursor-stable error path: out-of-bounds reads raise
|
|
`TpmStructError(TPM_STRUCT.TRUNCATED)` carrying `cursor` and `requested`
|
|
on the cause chain so log adapters can format the failure.
|
|
- `assertEnd()` rejects trailing bytes — guards against silent length
|
|
drift between the wire format and consumers.
|
|
- Constant-time-safe `peek(n)` (no advancing, never throws on clip).
|
|
- Growing writer with geometric reallocation hint via `initialCapacity`.
|
|
|
|
## Usage: Basic Example
|
|
|
|
```ts
|
|
import { TpmBufferReader } from "@suaveplan/tpm-struct/buffer";
|
|
|
|
const reader = new TpmBufferReader(new Uint8Array([0x00, 0x04, 0xde, 0xad, 0xbe, 0xef]));
|
|
const payload = reader.readTpm2b(); // Uint8Array[0xde, 0xad, 0xbe, 0xef]
|
|
reader.assertEnd();
|
|
```
|
|
|
|
## Usage: Advanced Example
|
|
|
|
```ts
|
|
import { TpmBufferReader, TpmBufferWriter } from "@suaveplan/tpm-struct/buffer";
|
|
|
|
// Encode then decode an arbitrary TPMS_CLOCK_INFO substructure.
|
|
const w = new TpmBufferWriter({ initialCapacity: 17 });
|
|
w.writeUint64Be(100n); // clock
|
|
w.writeUint32Be(5); // resetCount
|
|
w.writeUint32Be(3); // restartCount
|
|
w.writeUint8(1); // safe = true
|
|
const bytes = w.toUint8Array();
|
|
|
|
const r = new TpmBufferReader(bytes);
|
|
const clock = r.readUint64Be();
|
|
const reset = r.readUint32Be();
|
|
const restart = r.readUint32Be();
|
|
const safe = r.readUint8() !== 0;
|
|
r.assertEnd();
|
|
```
|
|
|
|
## API Reference
|
|
|
|
- **`new TpmBufferReader(bytes, { cursor? })`** — construct over a
|
|
`Uint8Array`. Out-of-range `cursor` raises `TPM_STRUCT.TRUNCATED`.
|
|
- **`readUint8 / readUint16Be / readUint32Be`** — return `number`.
|
|
- **`readUint64Be()`** — returns `bigint`.
|
|
- **`readBytes(n)`** — returns a fresh `Uint8Array` copy (never aliases).
|
|
- **`readTpm2b()`** / **`readTpm2bWithSize()`** — TCG `TPM2B_*` size-prefix.
|
|
- **`peek(n)` / `remaining()` / `cursor()` / `assertEnd()`** — read-only
|
|
introspection.
|
|
- **`new TpmBufferWriter({ initialCapacity? })`** — growing writer.
|
|
- **`writeUint8 / 16Be / 32Be / 64Be / Bytes / Tpm2b`** — mirror writes.
|
|
- **`toUint8Array()`** — finalise into a fresh `Uint8Array`.
|
|
|
|
## Implementation Notes
|
|
|
|
The reader holds a single `DataView` over the supplied `Uint8Array`'s
|
|
backing buffer and advances a private cursor by the exact bytes consumed.
|
|
`readTpm2b` rewinds the cursor to the start of the size prefix on a
|
|
short-read failure so callers can produce diagnostic dumps from the
|
|
failing position. The writer grows its backing array by powers of two
|
|
starting at `initialCapacity` (default 256) and reuses the same buffer
|
|
across writes. Numeric range checks reject out-of-range writes at the
|
|
boundary — this is cheaper than letting `DataView` truncate silently.
|