2.3 KiB
sign1
Purpose
COSE_Sign1 (RFC 9052 §4.2) — single-signer COSE message in CBOR tag 18.
WebAuthn attestation, COSE-signed firmware, and CWT signature flows all
land here. This module ships the encode/decode/verify triple plus a typed
CoseSign1 view.
Features
encodeCoseSign1produces both tagged (default) and tagless wire forms.decodeCoseSign1accepts either form transparently.verifyCoseSign1wires@suaveplan/crypto-curve(ES256, EdDSA) and uses the canonicalSig_structure1fromsig-structure.ts.- Public-key argument is polymorphic: typed
Ec2Key/OkpKey(the helper builds the wire-level point form internally) OR a raw byte-string key for callers that already have a primitive shape. nullpayload (detached signature) decodes correctly; verify rejects with a clear "not yet supported" error.
Usage
import { decodeCoseSign1, encodeCoseSign1, verifyCoseSign1 } from "@suaveplan/cbor/cose";
import { buildSign1Structure } from "@suaveplan/cbor/cose";
import * as ed25519 from "@suaveplan/crypto-curve/ed25519";
// Sign
const draft = decodeCoseSign1(
encodeCoseSign1({ protectedHeader: { alg: "EdDSA" }, payload, signature: new Uint8Array(64) }),
);
const tbs = buildSign1Structure(draft.protectedRaw, new Uint8Array(0), payload);
const sig = ed25519.sign(tbs, privateKey);
const wire = encodeCoseSign1({ protectedHeader: { alg: "EdDSA" }, payload, signature: sig });
// Verify
const msg = decodeCoseSign1(wire);
const ok = verifyCoseSign1(msg, publicKey);
API
encodeCoseSign1(input: EncodeCoseSign1Input): Uint8ArraydecodeCoseSign1(bytes: Uint8Array): CoseSign1verifyCoseSign1(msg: CoseSign1, key: Ec2Key | OkpKey | Uint8Array, options?): booleanCOSE_SIGN1_TAG = 18
CoseSign1 carries protectedRaw (the serialised inner-map bytes) so
callers can recompute Sig_structure1 verbatim — critical when verifying a
message they did not produce.
Notes
ES256 uses noble-p256's compact (r||s) signature form and consumes a
SHA-256 digest of the TBS bytes (matches RFC 9053 §2.1). EdDSA verifies
the raw TBS bytes directly per RFC 8032 §5.1.7. ES384 and ES512 throw
"not implemented" today — @suaveplan/crypto-curve does not ship the P-384
or P-521 primitives yet, and the bridge surfaces the gap rather than
silently falling back.