cratestack_cose/claims/types.rs
1//! The values a claim object carries in and out.
2
3use std::fmt;
4
5use crate::alg::CoseAlg;
6use crate::thumbprint::KID_LEN;
7
8/// The longest `aud` (bytes of UTF-8) a claim object carries.
9pub const MAX_AUD_LEN: usize = 256;
10/// The longest `typ` (bytes of UTF-8) a claim object carries.
11pub const MAX_TYP_LEN: usize = 128;
12/// The longest `cti` (bytes) a claim object carries.
13pub const MAX_CTI_LEN: usize = 64;
14
15/// The CWT claims (RFC 8392 ยง3.1) a claim object may carry in protected
16/// label `15` (RFC 9597). Only the claims that are `Some` are written.
17///
18/// All four are optional and none is interpreted by this crate: neither
19/// [`sign_claims`](crate::sign_claims) nor [`open_claims`](crate::open_claims)
20/// compares `exp` or `iat` with a clock, or remembers a `cti`. `exp` and
21/// `iat` are whole seconds since the Unix epoch (`NumericDate`; fractional
22/// and negative dates are not written and are refused when read).
23///
24/// ```
25/// use cratestack_cose::CwtClaims;
26///
27/// let claims = CwtClaims { exp: Some(1_790_003_600), ..CwtClaims::default() };
28/// assert_eq!(claims.aud, None);
29/// ```
30#[derive(Debug, Clone, Default, PartialEq, Eq)]
31pub struct CwtClaims {
32 /// `aud` (3): who the object is for, a single non-empty string of at most
33 /// [`MAX_AUD_LEN`] bytes. The array form of RFC 8392 is not accepted.
34 pub aud: Option<String>,
35 /// `exp` (4): the last second the object is meant to be honoured. The
36 /// consumer enforces it.
37 pub exp: Option<u64>,
38 /// `iat` (6): when it was issued, by the issuer's clock.
39 pub iat: Option<u64>,
40 /// `cti` (7): a unique id of 1 to [`MAX_CTI_LEN`] bytes, for a consumer
41 /// that records ids it has accepted.
42 pub cti: Option<Vec<u8>>,
43}
44
45/// A claim object whose signature verified.
46///
47/// **Verified is not fresh.** Nothing here says the object is unexpired,
48/// issued for this audience or seen for the first time: that is the
49/// caller's to decide from [`claims`](Self::claims). `Debug` prints the
50/// payload's length, not its bytes.
51///
52/// `#[non_exhaustive]`: read it, never build it.
53#[derive(Clone, PartialEq, Eq)]
54#[non_exhaustive]
55pub struct OpenedClaims {
56 /// The `kid` from the protected header; the verifying key's own `kid`.
57 pub kid: [u8; KID_LEN],
58 /// The algorithm the object was verified with (a signature algorithm).
59 pub alg: CoseAlg,
60 /// The RFC 9679 thumbprint of the key that verified. Two keys can share
61 /// a `kid`, so this, not the `kid`, identifies the signer.
62 pub key_thumbprint: [u8; 32],
63 /// The claims from the protected header.
64 pub claims: CwtClaims,
65 /// The payload, exactly as signed.
66 pub payload: Vec<u8>,
67}
68
69impl fmt::Debug for OpenedClaims {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 f.debug_struct("OpenedClaims")
72 .field("kid", &self.kid)
73 .field("alg", &self.alg)
74 .field("key_thumbprint", &self.key_thumbprint)
75 .field("claims", &self.claims)
76 .field("payload_len", &self.payload.len())
77 .finish()
78 }
79}