first commit
This commit is contained in:
70
docs/foundation/flow/cbor/src/cose/jwk.md
Normal file
70
docs/foundation/flow/cbor/src/cose/jwk.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# `jwk`
|
||||
|
||||
## Purpose
|
||||
|
||||
Round-trip converter between RFC 9052 `COSE_Key` instances and RFC 7517 JWK
|
||||
shapes. WebAuthn attestation flows often need to hand a public key to a
|
||||
WebCrypto-style verifier that consumes JWK; conversely, server-issued
|
||||
JWK-formatted keys may need to land in a CBOR-encoded COSE structure. The
|
||||
two conversions preserve every field that has a defined cross-format
|
||||
mapping.
|
||||
|
||||
## Features
|
||||
|
||||
- `coseKeyToJwk(key)` — accepts any `CoseKey` discriminant (EC2, OKP, RSA,
|
||||
Symmetric) and emits the matching JWK (`EC`, `OKP`, `RSA`, `oct`).
|
||||
- `jwkToCoseKey(jwk)` — reverse mapping with full byte-string round-trip.
|
||||
- Byte-string fields use RFC 4648 §5 base64url encoding without padding.
|
||||
- `kid` is treated as UTF-8 bytes on the COSE side and a string on the JWK
|
||||
side; conversion is lossy only if a non-UTF-8 kid is in play (rare, and
|
||||
RFC 9052 §3.1 documents the convention).
|
||||
- `alg` round-trips through a fixed COSE↔JWK label table so the typed
|
||||
algorithm lands consistently on either side.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { coseKeyToJwk, jwkToCoseKey } from "@suaveplan/cbor/cose";
|
||||
|
||||
const jwk = coseKeyToJwk(coseKey);
|
||||
const back = jwkToCoseKey(jwk);
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { decodeCoseKey, coseKeyToJwk } from "@suaveplan/cbor/cose";
|
||||
|
||||
// Attestation key from CTAP2
|
||||
const cose = decodeCoseKey(attestationKeyBytes);
|
||||
const jwk = coseKeyToJwk(cose);
|
||||
|
||||
// Hand off to WebCrypto
|
||||
const cryptoKey = await crypto.subtle.importKey(
|
||||
"jwk",
|
||||
jwk,
|
||||
{ name: "ECDSA", namedCurve: "P-256" },
|
||||
false,
|
||||
["verify"],
|
||||
);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `coseKeyToJwk(key: CoseKey): Jwk` — discriminator-aware conversion to JWK.
|
||||
- `jwkToCoseKey(jwk: Jwk): CoseKey` — reverse conversion.
|
||||
- `Jwk = Ec2Jwk | OkpJwk | RsaJwk | SymmetricJwk` (typed union).
|
||||
|
||||
Throws `CborError(UNEXPECTED_TYPE)` for incompatible curves (EC2 with a
|
||||
non-P curve, OKP with a non-Ed/X curve), unknown JWK `alg` strings, and
|
||||
malformed base64url input via the underlying `atob`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
base64url encoding is implemented inline with `btoa`/`atob` rather than
|
||||
pulling in `@suaveplan/crypto-utils` so this module stays free of crypto
|
||||
deps. Standard base64 padding (`=`) is stripped on output and re-padded on
|
||||
input — the RFC 4648 §5 spec allows omission of padding and major JWK
|
||||
producers do strip it. RSA JWKs use lowercase param names (`dp`, `dq`, `qi`)
|
||||
per RFC 7518 §6.3.2; COSE_Key uses the labels from RFC 8230 §4 (`-6`, `-7`,
|
||||
`-8`). The bridge preserves the field-by-field correspondence.
|
||||
Reference in New Issue
Block a user