basil-cose 0.6.1

Strict deterministic COSE (RFC 9052/9053) profile for basil sealed invocations: signed, sealed, and seal-only constructions with in-place signer/recipient traits
Documentation

basil-cose

A strict, deterministic COSE (RFC 9052/9053) profile for basil's sealed invocations. Broker-free and publishable, it is shared by the basil broker, the basil client crate, and basil users.

Constructions

Construction Shape Build Verify / open
Signed bare COSE_Sign1 (tag 18) build_signed verify_signed
Sealed COSE_Sign1 over an embedded tagged COSE_Encrypt build_sealed verify_sealed, then VerifiedSealed::open
Seal-only bare COSE_Encrypt (tag 96) build_encrypted decode_encrypted, then EncryptedMessage::open

Algorithms: EdDSA (−8, Ed25519) or ES256 (−7, ECDSA P-256 + SHA-256) signatures; ECDH-ES + HKDF-256 (−25) with X25519 key agreement; A256GCM (3) or ChaCha20-Poly1305 (24) content encryption. The content algorithm is a parameter of every encrypting entry point. ES256 signing is deterministic (RFC 6979), so both signature algorithms re-sign byte-identically.

Profile guarantees

  • Deterministic encoding by construction (in-tree codec over minicbor: canonical map-key order, definite lengths, minimal integer heads), plus an RFC 8949 §4.2 re-encode-and-compare check on every decode, release builds included.
  • Strict decode: rejects untagged/wrong-tag structures, indefinite lengths, non-minimal or otherwise non-deterministic encodings, duplicate or unknown labels, text labels, wrong CBOR types, unknown algorithm codepoints, crit violations, claims in unprotected headers, and recipient arrays with length ≠ 1. Error enums are closed and diagnostic, with no forward-compatible Unknown arms, and no secret bytes in any error.
  • Secure by construction: nonces and X25519 ephemerals are generated by the library (getrandom): there is no caller-supplied-nonce path. Every secret intermediate (private keys, ECDH shared secret, derived CEK, recovered plaintext) is Zeroizing. Low-order (non-contributory) ephemeral keys are rejected before key derivation. Ed25519 verification uses verify_strict.
  • Caller-supplied external_aad on both Sig_structure and Enc_structure, and KDF PartyU/PartyV identities carried in the recipient protected headers (−21/−24) with the RFC 9053 §5.2 COSE_KDF_Context as the HKDF info, so an opener that is not the sealer (for example a broker unseal-in-place RPC) can rebuild the KDF context from the message alone, and may pin expected identities.

Claims

Claims ride in the protected header as a CWT map (header 15) plus the basil private labels (-70001..=-70005, module label): in-reply-to, request hash (SHA3-256, helper request_hash), sender key id (must equal the outer kid), response key id, and response subject. MessageRole (request/response/peer) validators enforce claim shape; ValidationParams parameterizes clock skew, TTL bounds, and the audience allow-list (now is injected, never sampled: the crate is state-free and owns no time policy).

Keys

Key material stays behind the AFIT traits Signer, Verifier, and Recipient (async so broker-backed implementations can await an RPC; the shipped local implementations complete synchronously): Ed25519Signer, Ed25519Verifier, X25519Recipient (+ X25519RecipientPublic as the seal target).

no_std

The crate is #![no_std] + alloc and obtains production randomness through getrandom.

Features

  • fixtures: deterministic build variants (build_sealed_with_parts, build_encrypted_with_parts) that accept caller-supplied ephemeral/nonce parts, for test vectors only. Never enable on production paths.

Wire API

The COSE api is described in Sealed invocations and is accessible from both Rust and Go clients.