ic_auth/portable/verified.rs
1#[cfg(any(
2 feature = "portable-signature-verification",
3 feature = "certified-proof-verification"
4))]
5use super::PortableClaimsContext;
6use crate::session_request::{SessionRequest, SessionRequestError, SessionTtlPolicy};
7use ic_auth_protocol_types::{AuthRole, PortableClaims};
8
9/// Claims authenticated by one complete portable proof verifier at a host clock.
10/// Read-only and not deserializable; decoding or editing claims cannot forge this
11/// result. It is not a session, enrollment approval or resource authorization.
12/// Consume it under the same host transaction/authority snapshot as verification;
13/// matching time alone does not establish that authority is still current.
14///
15/// ```compile_fail
16/// use ic_auth::portable::VerifiedPortableClaims;
17/// use ic_auth_protocol_types::PortableClaims;
18/// fn forge(claims: PortableClaims) -> VerifiedPortableClaims { claims.into() }
19/// ```
20#[derive(Clone, Debug, Eq, PartialEq)]
21pub struct VerifiedPortableClaims {
22 claims: PortableClaims,
23 fingerprint: [u8; 32],
24 verified_at_ns: u64,
25 authority_expires_at_ns: u64,
26 enrollment_expires_at_ns: u64,
27}
28
29impl VerifiedPortableClaims {
30 #[cfg(any(
31 feature = "portable-signature-verification",
32 feature = "certified-proof-verification"
33 ))]
34 pub(crate) fn new(
35 claims: PortableClaims,
36 fingerprint: [u8; 32],
37 context: &PortableClaimsContext<'_>,
38 ) -> Self {
39 Self {
40 claims,
41 fingerprint,
42 verified_at_ns: context.authority.now_ns,
43 authority_expires_at_ns: context.authority.authority_expires_at_ns,
44 enrollment_expires_at_ns: context.authority.enrollment_expires_at_ns,
45 }
46 }
47
48 /// Exclusive lease deadline for admission at this verification snapshot.
49 /// Proof expiry limits new admission, not the resulting lease. The signed
50 /// login deadline and protected key/enrollment deadlines cap the lease.
51 /// Persist this result once; refreshing enrollment never extends stored leases.
52 /// The role comes from protected receiver configuration, never the request.
53 /// Requested scopes must narrow that role's grant; other roles cannot supply
54 /// missing scopes. This does not check replay, revocation or current authority
55 /// after verification, and does not create or authorize a session.
56 pub fn session_expires_at_ns(
57 &self,
58 request: &SessionRequest,
59 role: &AuthRole,
60 policy: SessionTtlPolicy,
61 ) -> Result<u64, SessionRequestError> {
62 let requested = request.evaluate(&self.claims.grants, role, self.verified_at_ns, policy)?;
63 Ok(requested
64 .min(self.claims.login_deadline_ns)
65 .min(self.authority_expires_at_ns)
66 .min(self.enrollment_expires_at_ns))
67 }
68
69 pub fn claims(&self) -> &PortableClaims {
70 &self.claims
71 }
72
73 /// Canonical claims digest, independent of alternate proof/signature bytes.
74 pub fn fingerprint(&self) -> [u8; 32] {
75 self.fingerprint
76 }
77
78 pub fn verified_at_ns(&self) -> u64 {
79 self.verified_at_ns
80 }
81}