first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,55 @@
# `mac`
## Purpose
`COSE_Mac` (RFC 9052 §6.1) — multi-recipient MAC message in CBOR tag 97.
Each recipient gets a wrapped copy of the content-MAC key (CMK); the body
itself carries one MAC computed over the payload using the CMK. This module
ships encode/decode of the wire shape plus a kid-based recipient lookup.
## Features
- `encodeCoseMac` builds the 5-tuple `[bodyProtected, bodyUnprotected,
payload, tag, recipients]`. Per-recipient triples
`[recipientProtected, recipientUnprotected, encryptedKey]` carry the
wrapped-key bytes verbatim — wrap/unwrap is delegated to whatever scheme
the recipient header declares (direct, KEK, ECDH-ES, etc.).
- `decodeCoseMac` recovers the typed `CoseMac` view. Each recipient lands
in `msg.recipients[]` with its own `protectedRaw` byte string ready for
any per-recipient verification flow that needs it.
- `findRecipientByKid` does a constant-time-ish byte compare over the
recipient's `kid` (consulted in protected then unprotected headers).
- Empty recipient arrays are rejected — RFC 9052 §6.1 requires at least one.
## Usage
```ts
import { encodeCoseMac, decodeCoseMac, findRecipientByKid } from "@suaveplan/cbor/cose";
const wire = encodeCoseMac({
protectedHeader: { alg: "HS256" },
payload,
tag: macTag,
recipients: [
{ unprotectedHeader: { kid: kidA }, encryptedKey: wrapped },
{ unprotectedHeader: { kid: kidB }, encryptedKey: wrappedB },
],
});
const msg = decodeCoseMac(wire);
const mine = findRecipientByKid(msg, kidA);
```
## API
- `encodeCoseMac(input)` / `decodeCoseMac(bytes)`.
- `findRecipientByKid(msg, kid): CoseRecipient | undefined`.
- `COSE_MAC_TAG = 97`.
## Notes
The body's `tag` is computed over the canonical `MAC_structure` (RFC 9052
§6.3) using the CMK. This module does not implement the wrapping/unwrapping
of the CMK to each recipient — that lives one layer up, where the recipient-
specific algorithm (`A128KW`, `direct`, `ECDH-ES + A256KW`, …) is dispatched.
The helper here gives a typed shape for callers to plug those wraps into.