Skip to main content

cratestack_cose/
opened.rs

1//! What a successful open returns.
2
3use std::fmt;
4
5use bytes::Bytes;
6
7use crate::alg::CoseAlg;
8use crate::thumbprint::KID_LEN;
9
10/// A message that verified.
11///
12/// This is the typed result behind [`CratestackEnvelope::open`]: the axum
13/// layer (cratestack#1006) runs before any `CratestackContext` exists, so it
14/// needs the verified facts as values rather than as a side effect on a
15/// context. `payload` and `cti` are zero-copy slices of the received body;
16/// `kid` is a copy, so a caller that keeps only the signer's identity does
17/// not keep the body alive.
18///
19/// `Debug` prints the payload's length, not its bytes: a verified body is
20/// application data (a payment, a token), and `{:?}` on a result is how it
21/// would otherwise end up in a log.
22///
23/// `#[non_exhaustive]` so the `auth` feature can add the device or service
24/// id a resolver maps the key to without a breaking change.
25///
26/// [`CratestackEnvelope::open`]: cratestack_core::CratestackEnvelope::open
27#[derive(Clone, PartialEq, Eq)]
28#[non_exhaustive]
29pub struct Opened {
30    /// The payload, exactly as signed, for `codec.decode`.
31    pub payload: Bytes,
32    /// The `kid` from the protected header. It is the verifying key's own
33    /// `kid`: a candidate whose `kid` differs is never tried.
34    pub kid: [u8; KID_LEN],
35    /// The algorithm the message was verified with.
36    pub alg: CoseAlg,
37    /// The RFC 9679 thumbprint of the key that verified. Two keys can share
38    /// a `kid` (8 bytes collide at about 2³² keys; `tests/replay.rs` uses a
39    /// real pair), so this, not the `kid`, identifies the signer
40    /// unambiguously; a principal derived from a verified message should use
41    /// it. The trait path records it as the context's
42    /// `VerifiedSigner::thumbprint`, the same name.
43    pub thumbprint: [u8; 32],
44    /// `iat`, seconds. `Some` for a request, `None` for a response.
45    pub iat: Option<u64>,
46    /// `cti`. `Some` for a request, `None` for a response.
47    pub cti: Option<Bytes>,
48}
49
50impl fmt::Debug for Opened {
51    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52        f.debug_struct("Opened")
53            .field("payload_len", &self.payload.len())
54            .field("kid", &self.kid)
55            .field("alg", &self.alg)
56            .field("thumbprint", &self.thumbprint)
57            .field("iat", &self.iat)
58            .field("cti", &self.cti)
59            .finish()
60    }
61}