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}