encoding.cose: add COSE (RFC 9052) and CWT (RFC 8392) modules#27111
encoding.cose: add COSE (RFC 9052) and CWT (RFC 8392) modules#27111davlgd wants to merge 2 commits into
Conversation
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 60bfca67ea
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| fn check_critical(h Headers) ! { | ||
| for label in h.critical { | ||
| if label !in [label_alg, label_crit, label_content_type, label_kid, label_iv, | ||
| label_partial_iv] { | ||
| return MalformedMessage{ |
There was a problem hiding this comment.
Enforce protected-only semantics for
crit labels
check_critical only validates that each entry is a known integer label, but it never enforces RFC 9052's fatal conditions that crit must be in the protected bucket and that every listed label must also be present there. Because verification paths call this helper only on protected headers, a message can place crit (or the referenced header) in unprotected headers and still verify, which allows required-to-understand semantics to be bypassed.
Useful? React with 👍 / 👎.
| if alg := algorithm_from_int(code) { | ||
| h.algorithm = alg | ||
| } else { |
There was a problem hiding this comment.
Reject duplicate header labels during header-map decode
Header-map decoding does not track already-seen labels, so repeated labels are silently accepted and later values overwrite earlier ones (for example, duplicate alg entries repeatedly assign h.algorithm). RFC 9052 requires duplicate labels to be treated as malformed; accepting them can create parser ambiguity and cross-implementation verification differences on crafted inputs.
Useful? React with 👍 / 👎.
This PR adds two complementary modules to the standard library:
encoding.cose— CBOR Object Signing and Encryption, signing + MAC subset of RFC 9052 and RFC 9053.encoding.cwt— CBOR Web Tokens (RFC 8392) built on top ofcose.Both modules sit alongside
encoding.cbor(merged in #27018) and use its codec under the hood. No new C code, no new third-party crypto: everything is built on the primitives already invlib/crypto(ecdsa,ed25519,hmac,sha256,sha512).Why
CBOR is everywhere: WebAuthn / FIDO2 attestations, IETF SUIT (firmware updates over LWM2M), Matter (smart home), CoAP / OSCORE, EDHOC, the European Digital Identity Wallet… All of them serialise their tokens as COSE or CWT.
What's covered
COSE_Sign1COSE_SignCOSE_Mac0COSE_MacES256ES384ES512EdDSAHMAC 256/64HMAC 256/256HMAC 384/384HMAC 512/512CWT models the seven RFC 8392 §3 standard claims (
iss,sub,aud,exp,nbf,iat,cti) plus pass-through for application claims, and handles the optional outer CBOR tag 61 wrapper.Module surface
A complete example program lives at
examples/cose_cwt.v.Conformance / test vectors
The
cose-wg/Examplesrepository is the canonical interop corpus. Its relevant fixtures are vendored undervlib/encoding/cose/tests/cose_wg/andvlib/encoding/cwt/tests/rfc8392/, and run as part ofv test. For deterministic algorithms (EdDSA, all HMAC variants) the V output is validated byte-for-byte; for ECDSA (randomised signatures) each reference message is verified. The negative*-fail-*vectors exercise the verifier's rejection paths against externally produced bad messages.ecdsa-sig-01ecdsa-sig-02ecdsa-sig-03eddsa-sig-01eddsa-01sign1-fail-01..04sign1-pass-02HMac-01HMac-04HMac-05HMac-enc-01HMac-enc-02HMac-enc-03HMac-enc-05In addition to the public corpus:
ec_signature_test.v— DER ↔ R‖S conversion edge cases (leading zeros, MSB-set sign disambiguation, P-521 long-form lengths).structures_test.v—Sig_structure/MAC_structurebyte output matches RFC 9052 §4.4 / §6.3.headers_test.v— canonical key sorting (RFC 8949 §4.2.1), empty-protected-as-zero-length-bstr rule, unknown-label preservation.sign1_test.v/sign_test.v/mac0_test.v/mac_test.v— sign/verify roundtrip per algorithm; tampered-payload and wrong-key rejection paths; detached-payload and external-AAD modes; sanity caps on signer/recipient array counts; unknowncritlabel rejection per RFC 9052 §3.1.cwt_test.v— Claims Set encoding, theaudtstr-vs-array form rule from RFC 7519/8392, optional tag-61 wrapper, RFC 8392 A.3 and A.4 reproduction,nbf/expvalidity-window helper.I've also tested these modules against lib in other languages to check interop.
Out of scope (deliberate)
COSE_Encrypt0/COSE_Encrypt) — needs AES-GCM, AES-CCM, ChaCha20-Poly1305 invlib/crypto, which is a separate effort. Adding the message types later is purely additive.PS256/384/512andRS256/384/512(legacy). Adding them is mechanical ifvlib/cryptoships RSA-PSS, but the demand is small relative to ECDSA + EdDSA.