cose2 0.2.0

A Rust library for CBOR Object Signing and Encryption (COSE, RFC 9052) and CBOR Web Token (CWT, RFC 8392), built on cbor2.
Documentation
# AGENTS.md

Guidance for AI coding agents working **in this repository**. If you are an
agent trying to **use `cose2` as a dependency**, read
[docs/agent-guide.md](docs/agent-guide.md) first — it has the per-task API
decision table and the protocol rules you should not guess.

## What this is

`cose2` is a Rust library for COSE ([RFC 9052][cose]) and CWT
([RFC 8392][cwt]), built on [`cbor2`][cbor2]. It models the wire structures and
delegates cryptography to caller-supplied trait implementations, so the default
build has **no cryptographic dependencies**.

- Edition 2021, MSRV **1.85** (`rust-version` in `Cargo.toml`).
- `#![forbid(unsafe_code)]`.

## Setup and verification

There is no codegen or build step beyond Cargo. Run these before proposing any
change; CI (`.github/workflows/ci.yml`) runs the same set:

```sh
cargo fmt --all --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --workspace --all-targets --all-features
RUSTDOCFLAGS='-D warnings' cargo doc --workspace --all-features --no-deps
```

Quick example smoke test:

```sh
cargo run --example custom_crypto_traits
cargo run --example sign1_ring --features crypto-ring
```

## Feature flags

- `default = []` — no crypto backend. The pluggable traits are always available.
- `crypto-ring``ring`-based `RingSigner` / `RingVerifier` / `RingMacer` /
  `RingEncryptor` (module `crypto`).
- `crypto` — aggregate alias that currently enables `crypto-ring`.

## Repository layout

| Path | Contents |
| --- | --- |
| `src/lib.rs` | Crate root and public re-exports. |
| `src/iana.rs` | IANA registry constants (algorithms, key params, claims, tags). |
| `src/label.rs`, `src/map.rs` | `Label` (`int`/`tstr`) and the shared `CoseMap`. |
| `src/header.rs`, `src/key.rs` | `Header`; `Key` / `KeySet`. |
| `src/sign1.rs`, `src/sign.rs` | `Sign1Message`; `SignMessage` / `Signature`. |
| `src/mac0.rs`, `src/mac.rs` | `Mac0Message`; `MacMessage`. |
| `src/encrypt0.rs`, `src/encrypt.rs` | `Encrypt0Message`; `EncryptMessage`. |
| `src/recipient.rs`, `src/context.rs` | `Recipient`; `KdfContext` / `PartyInfo` / `SuppPubInfo`. |
| `src/traits.rs` | `Signer` / `Verifier` / `Macer` / `Encryptor`. |
| `src/cwt.rs` | `Claims` / `ClaimsMap` / `Validator`. |
| `src/crypto.rs` | `ring` providers (feature `crypto-ring`). |
| `src/error.rs`, `src/tag.rs`, `src/util.rs` | `Error`; CBOR-tag helpers; internal helpers. |
| `examples/`, `tests/`, `docs/` | Runnable examples, integration tests, the consumer agent guide. |

## Invariants to preserve

Do not regress these — they are correctness/compatibility contracts, and several
are load-bearing for cryptographic soundness:

1. **No `unsafe`.** The crate is `#![forbid(unsafe_code)]`.
2. **Default build stays crypto-free.** Any crypto dependency must live behind a
   feature flag (`crypto-ring`). Never add an always-on crypto dep.
3. **Reuse decoded protected-header bytes verbatim.** The raw protected header
   captured on decode is fed back into `Sig_structure` / `MAC_structure` /
   `Enc_structure` so signatures over non-canonical encodings still verify. Do
   not re-encode it.
4. **Newly built protected headers and keys serialize canonically** (RFC 8949
   §4.2.1) via `cbor2::to_canonical_vec`.
5. **The crate generates no randomness or nonces.** Encryption takes a full `IV`,
   or a `Partial IV` combined with `Encryptor::base_iv`.
6. **`external_aad: None` means an empty byte string**, not "ignore AAD". It must
   match on create and verify/decrypt.
7. **Detached payload / detached ciphertext are explicit APIs** (`*_detached*`).
   Do not hand-encode `nil` and call the embedded helpers.
8. **Keep tests green and coverage high.** The suite targets 100% of lines and
   functions (`cargo llvm-cov`); the only uncovered arms are unreachable
   serialization error paths. New code paths need tests in `tests/` or inline.
9. **`clippy -D warnings`, `rustdoc -D warnings`, and `rustfmt` must all pass.**

## Adding a `ring` algorithm

The provider→algorithm mapping lives in the helper functions at the bottom of
`src/crypto.rs` (`hmac_algorithm`, `aead_algorithm`, `ecdsa_verification_algorithm`,
`rsa_signing_algorithm`, `rsa_verification_algorithm`). Unsupported algorithms
must return an explicit `unsupported_alg(...)` error rather than silently falling
back to a different primitive. Add the algorithm to
[docs/agent-guide.md](docs/agent-guide.md#crypto-ring-algorithm-recipes) and a
round-trip test in `tests/crypto_ring.rs`.

[cose]: https://datatracker.ietf.org/doc/html/rfc9052
[cwt]: https://datatracker.ietf.org/doc/html/rfc8392
[cbor2]: https://crates.io/crates/cbor2