first commit
This commit is contained in:
71
docs/foundation/flow/cbor/src/cose/cose-key.md
Normal file
71
docs/foundation/flow/cbor/src/cose/cose-key.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# `cose-key`
|
||||
|
||||
## Purpose
|
||||
|
||||
Decodes and encodes RFC 9052 §7 `COSE_Key` structures. The decoder maps an
|
||||
RFC-encoded CBOR map onto a typed discriminated union (`Ec2Key | OkpKey |
|
||||
RsaKey | SymmetricKey`); the encoder reverses the mapping with deterministic
|
||||
encoding so two keys with identical fields always produce byte-identical
|
||||
output. WebAuthn attestation public keys, COSE_Sign1 signing keys, and CWT
|
||||
verification keys all flow through this module.
|
||||
|
||||
## Features
|
||||
|
||||
- Discriminated union by `kty` — TypeScript narrows on `key.kty === "EC2"`
|
||||
etc. without explicit casts.
|
||||
- Per-key-type field validation: EC2 (`crv` + `x` + `y` + optional `d`),
|
||||
OKP (`crv` + `x` + optional `d`), RSA (`n` + `e` + optional `d`/`p`/`q`/
|
||||
`dP`/`dQ`/`qInv`), Symmetric (`k`).
|
||||
- Common fields (`alg`, `kid`, `key_ops`, `baseIV`) parsed once and applied
|
||||
uniformly across all key types.
|
||||
- Throws `CborError(UNEXPECTED_TYPE)` for malformed maps, unknown labels,
|
||||
wrong inner types, and missing required fields.
|
||||
- Encoder uses RFC 8949 §4.2 deterministic encoding so the byte output is
|
||||
stable across runs — required for COSE structures that include the key
|
||||
bytes in signed/verified payloads.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { decodeCoseKey, encodeCoseKey } from "@suaveplan/cbor/cose";
|
||||
|
||||
const key = decodeCoseKey(bytes);
|
||||
if (key.kty === "EC2") {
|
||||
console.log("ES256 public key", key.x, key.y);
|
||||
}
|
||||
const wire = encodeCoseKey(key);
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { decodeCoseKey } from "@suaveplan/cbor/cose";
|
||||
import { coseAlgToCryptoAlg } from "@suaveplan/cbor/cose";
|
||||
|
||||
// WebAuthn attestation flow
|
||||
const attestationKey = decodeCoseKey(authData.credentialPublicKey);
|
||||
if (attestationKey.kty !== "EC2") {
|
||||
throw new Error("expected EC2 attestation key");
|
||||
}
|
||||
const cryptoAlg = coseAlgToCryptoAlg(attestationKey.alg ?? "ES256");
|
||||
// Hand off to @suaveplan/crypto-curve to verify the signature.
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `decodeCoseKey(bytes: Uint8Array): CoseKey` — decode a CBOR-encoded
|
||||
`COSE_Key` byte string into the typed union. Throws `CborError` for any
|
||||
structural defect.
|
||||
- `encodeCoseKey(key: CoseKey): Uint8Array` — deterministic-encode the key.
|
||||
- See `cose.types.ts` for `CoseKey`, `Ec2Key`, `OkpKey`, `RsaKey`,
|
||||
`SymmetricKey`, `CoseAlg`, `CoseCurve`, `CoseKeyOp`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The decoder tolerates extra map entries — RFC 9052 §7.1 explicitly permits
|
||||
forward-compatible additions, and rejecting unknown labels would break
|
||||
forward compatibility. The encoder, by contrast, emits only the fields
|
||||
defined in the typed shape so it cannot accidentally leak extension data
|
||||
that was never modelled. Common fields are read once into a small `CommonOut`
|
||||
record and spread into every key shape — this avoids drift between the four
|
||||
per-kty readers when a new common field is added in the future.
|
||||
Reference in New Issue
Block a user