Files
suaveplan/packages/foundation/flow/cbor/src/cose/sign1.md
2026-05-27 23:47:53 +01:00

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

  • encodeCoseSign1 produces both tagged (default) and tagless wire forms.
  • decodeCoseSign1 accepts either form transparently.
  • verifyCoseSign1 wires @suaveplan/crypto-curve (ES256, EdDSA) and uses the canonical Sig_structure1 from sig-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.
  • null payload (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): Uint8Array
  • decodeCoseSign1(bytes: Uint8Array): CoseSign1
  • verifyCoseSign1(msg: CoseSign1, key: Ec2Key | OkpKey | Uint8Array, options?): boolean
  • COSE_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.