2.0 KiB
2.0 KiB
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
encodeCoseMacbuilds 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.).decodeCoseMacrecovers the typedCoseMacview. Each recipient lands inmsg.recipients[]with its ownprotectedRawbyte string ready for any per-recipient verification flow that needs it.findRecipientByKiddoes a constant-time-ish byte compare over the recipient'skid(consulted in protected then unprotected headers).- Empty recipient arrays are rejected — RFC 9052 §6.1 requires at least one.
Usage
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.