pub async fn sign_claims(
signer: &(dyn CoseSigner + 'static),
typ: &str,
claims: &CwtClaims,
payload: &[u8],
external_aad: &[u8],
) -> Result<Vec<u8>, ClaimsError>Expand description
Sign payload as a claim object: a tagged COSE_Sign1 (tag 18) whose
protected header is {1: alg, 4: kid, ? 15: claims, 16: typ}, whose
unprotected header is empty and whose payload is embedded.
typ(RFC 9596, label 16) names what the object is. It is signed, andopen_claimsrefuses any other, so an object minted for one purpose cannot be replayed as another. It is also what keeps a claim object from opening as a transport envelope, and the reverse. Non-empty, at mostMAX_TYP_LENbytes.claimsare written only when present; seeCwtClaimsfor the bounds.external_aadis signed but not sent: the opener must supply the same bytes. Put in it what the object is bound to but does not carry, such as a tenant or a purpose; empty is fine.
The encoding is deterministic (RFC 8949 ยง4.2.1) and an ESP256 signature
is low-s, the rules the transport envelope enforces. signer must be
a signature signer (Ed25519 or ESP256); an HMAC signer is refused with
ClaimsError::Misuse. Nothing is read from a clock: exp and iat
are whatever the caller put in.
use cratestack_cose::{CwtClaims, Ed25519Signer, sign_claims};
let signer = Ed25519Signer::from_seed(&[7; 32]);
let claims = CwtClaims { exp: Some(1_790_003_600), ..CwtClaims::default() };
let bytes = sign_claims(&signer, "application/vnd.example.grant+cwt", &claims, b"grant", b"")
.await
.unwrap();
assert_eq!(bytes[0], 0xd2); // tag 18