coset

Rust types for building and parsing CBOR Object Signing and Encryption (COSE) messages

Library
Cargo
v0.4.2
47stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
25/100Needs Attention
Development Activity4
Maintenance0
Community24
Maturity60
Momentum12

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
72/100Good
Architecture80
Code Quality82
Innovation70
Learning Curve55

coset is a Google-maintained Rust crate providing a set of types for working with CBOR Object Signing and Encryption (COSE) objects as defined in RFC 8152 (and its successor RFC 9052/9053). It covers the full family of COSE message structures — CoseSign1, CoseSign, CoseEncrypt0, CoseEncrypt, CoseMac0, CoseMac, and CoseKey — along with COSE headers, algorithm/key-type IANA registries, and CBOR Web Token (CWT) claim structures.

The crate builds on ciborium for the underlying CBOR encoding, is no_std-compatible (using only alloc), and deliberately stays cryptography-agnostic: callers supply their own signing, verification, encryption, and decryption operations as closures, so coset handles only the message framing, header encoding, and signature/MAC construction mandated by the COSE spec.

What You Get

  • Builder types (CoseSign1Builder, CoseSignBuilder, CoseEncrypt0Builder, CoseEncryptBuilder, CoseMac0Builder, CoseMacBuilder, CoseKeyBuilder, HeaderBuilder) for constructing every core COSE message shape
  • A CborSerializable trait giving every COSE type to_vec() / from_slice() round-tripping to and from CBOR bytes
  • Closure-based create_signature/verify_signature (and MAC/encrypt equivalents) so any signing or crypto library can be plugged in without coset depending on it
  • A comprehensive iana module mirroring the IANA COSE algorithm, key-type, header-parameter, and elliptic-curve registries as typed Rust enums
  • CBOR Web Token (cwt) claim-set types for building and parsing COSE-secured CWTs
  • no_std + alloc support so it can be used in embedded and constrained environments

Common Use Cases

  • Signing and verifying CBOR-encoded payloads (e.g. firmware manifests, attestation statements) using COSE_Sign1/COSE_Sign structures
  • Building CBOR Web Tokens (CWTs) for constrained IoT and embedded authentication flows
  • Implementing COSE-based encryption (COSE_Encrypt0/COSE_Encrypt) for confidential CBOR message exchange
  • Representing and serializing cryptographic keys with CoseKey for interoperable key exchange (e.g. WebAuthn/FIDO2, Android Keystore attestation)

Under The Hood

Architecture: coset organizes each COSE message family (sign, encrypt, mac, key, header, cwt, context) into its own module under src/, each exposing a plain data struct plus a matching *Builder. Wire-format conversion is centralized through the AsCborValue trait (to_cbor_value/from_cbor_value) and the CborSerializable marker trait, which together give every public type to_vec()/from_slice() round-tripping without duplicating CBOR array/map handling in each module; lib.rs re-exports these modules flatly so coset::CoseSign1Builder etc. form the public surface. Cryptographic operations are never implemented directly — sign/verify/encrypt/decrypt/MAC all take caller-supplied closures, keeping the crate a pure message-framing layer over RFC 8152.

Tech Stack: Pure Rust, edition 2018, MSRV 1.81, no_std with alloc. The only runtime dependencies are ciborium (re-exported as coset::cbor) for CBOR encoding and ciborium-io for the alloc-based I/O traits; hex is a dev-dependency for examples/tests. No build step beyond cargo build; CI (GitHub Actions) runs tests, Clippy, rustfmt, and cargo-deny per CONTRIBUTING.md.

Code Quality: Each module (sign, encrypt, mac, key, header, common, context, cwt, util, iana) ships a co-located tests.rs (10 test files across the crate, ~11.4k total lines of source+tests), and the project enforces house rules via CI: builds must be Clippy-warning-free, rustfmt-formatted per .rustfmt.toml, and every panic!/unwrap/expect call must carry a // safe: reason comment justifying it — an unusually disciplined convention for panic-safety auditing. Fuzz targets exist under fuzz/, and CoseError is a explicit, enumerated error type rather than stringly-typed errors.

API Design: The builder pattern (CoseSign1Builder::new().protected(...).payload(...).create_signature(aad, |pt| signer.sign(pt)).build()) reads close to the RFC’s own structure, and the crate documents a worked end-to-end sign/verify example directly in lib.rs doctests. The closure-based crypto injection keeps the API decoupled from any one crypto crate, at the cost of requiring callers to already understand COSE/CBOR concepts (protected vs. unprotected headers, AAD) — the README itself flags the crate as still evolving (“API…may change without warning”), which tempers an otherwise clean, idiomatic Rust surface.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search