canic_core/dto/auth.rs
1//! Delegated signing DTOs.
2//!
3//! These types define the **data model and trust boundaries** for delegated
4//! authorization using **IC canister signatures only**.
5//!
6//! High-level design:
7//! - A single root authority canister is the trust anchor.
8//! - The root delegates signing authority to signer canisters via certificates.
9//! - Signer canisters issue authorization tokens.
10//! - Tokens are verified **locally** with no directory, registry, or topology calls.
11//!
12//! This model enables:
13//! - Offline / deterministic verification
14//! - No runtime dependency on external canisters
15//! - Clear, auditable trust chains
16//!
17//! Any change to these structures is **security-sensitive** and must be
18//! evaluated against the trust model below.
19
20use crate::dto::prelude::*;
21
22/// ---------------------------------------------------------------------------
23/// Trust model summary
24/// ---------------------------------------------------------------------------
25///
26/// - The **root authority canister** is the only long-term trust anchor.
27/// - The root signs `DelegationCert` objects using IC canister signatures.
28/// - A `DelegationCert` grants limited signing authority to a signer canister.
29/// - Signer canisters sign `DelegatedToken` objects.
30/// - Verifiers trust a token **only if**:
31/// - The delegation certificate is root-signed
32/// - The token signature matches the delegated signer
33/// - All temporal, scope, and audience constraints hold
34///
35/// No canister calls occur during verification.
36/// All trust is established cryptographically.
37///
38/// ---------------------------------------------------------------------------
39
40///
41/// DelegationCert
42///
43/// A root-signed certificate that delegates token-signing authority
44/// to a signer canister.
45///
46/// WHY THIS EXISTS
47/// ----------------
48/// This is the *only* object signed by the root authority canister.
49/// It is the **trust anchor** for all delegated tokens.
50///
51/// If this object is valid and trusted:
52/// - The signer canister is authorized to issue tokens
53/// - But *only* within the audiences, scopes, and lifetime specified here
54///
55/// Anything not explicitly allowed here is forbidden.
56///
57#[derive(CandidType, Clone, Debug, Deserialize, Serialize)]
58pub struct DelegationCert {
59 /// Version of the delegation certificate format.
60 ///
61 /// WHY:
62 /// - Allows forward-compatible evolution of fields and semantics
63 /// - Prevents silent misinterpretation during upgrades
64 pub v: u16,
65
66 /// Principal of the delegated signer canister.
67 ///
68 /// Tokens must be signed by this canister.
69 /// No other signer is valid under this certificate.
70 pub signer_pid: Principal,
71
72 /// Audiences the delegated signer is allowed to issue tokens for.
73 ///
74 /// Token `claims.aud` MUST be a member of this set.
75 /// This prevents a signer from issuing tokens for unrelated services.
76 pub audiences: Vec<String>,
77
78 /// Scopes the delegated signer is allowed to assert.
79 ///
80 /// Token `claims.scopes` MUST be a subset of this set.
81 /// This ensures least-privilege delegation.
82 pub scopes: Vec<String>,
83
84 /// Time (seconds since epoch) when this delegation was issued.
85 ///
86 /// Used for auditing and temporal validation.
87 pub issued_at: u64,
88
89 /// Absolute expiration time of this delegation.
90 ///
91 /// Tokens MUST NOT outlive this value, regardless of token TTL.
92 /// Rotation invalidates all tokens bound to an expired certificate.
93 pub expires_at: u64,
94}
95
96///
97/// DelegationProof
98///
99/// Cryptographic proof that a `DelegationCert` was authorized by the root.
100///
101/// WHY THIS EXISTS
102/// ----------------
103/// The `DelegationCert` alone is just data.
104/// This struct binds it to a **root canister signature**, establishing
105/// a verifiable trust chain:
106///
107/// root authority -> signer canister
108///
109/// Verifiers validate `cert_sig` using:
110/// - the root authority’s public key
111/// - a fixed domain separator
112///
113#[derive(CandidType, Clone, Debug, Deserialize, Serialize)]
114pub struct DelegationProof {
115 /// The delegated certificate describing signer authority.
116 pub cert: DelegationCert,
117
118 /// Root authority signature over the DelegationCert hash.
119 ///
120 /// This signature:
121 /// - Authenticates the certificate
122 /// - Prevents forgery or tampering
123 /// - Anchors the delegation chain
124 pub cert_sig: Vec<u8>,
125}
126
127///
128/// DelegatedTokenClaims
129///
130/// Claims asserted by a delegated signer.
131///
132/// IMPORTANT:
133/// -----------
134/// All fields in this struct are **untrusted input** until:
135/// - the delegation proof is verified
136/// - the token signature is verified
137///
138/// Authorization derives from *both* the claims AND the delegation.
139/// Claims alone are never sufficient.
140///
141#[derive(CandidType, Clone, Debug, Deserialize, Serialize)]
142pub struct DelegatedTokenClaims {
143 /// Subject of the token (e.g. user principal).
144 pub sub: Principal,
145
146 /// Intended audience of the token.
147 ///
148 /// MUST match one of `DelegationCert.audiences`.
149 /// This prevents cross-service token reuse.
150 pub aud: String,
151
152 /// Scopes asserted by this token.
153 ///
154 /// MUST be a subset of `DelegationCert.scopes`.
155 /// The signer cannot exceed delegated authority.
156 pub scopes: Vec<String>,
157
158 /// Issued-at timestamp.
159 ///
160 /// Used to enforce token freshness and TTL constraints.
161 pub iat: u64,
162
163 /// Expiration timestamp.
164 ///
165 /// MUST be:
166 /// - >= iat
167 /// - <= DelegationCert.expires_at
168 pub exp: u64,
169
170 /// Optional nonce for replay protection or correlation.
171 ///
172 /// Semantics are intentionally undefined at this layer.
173 /// Consumers may use it for replay detection or tracing.
174 pub nonce: Option<Vec<u8>>,
175}
176
177///
178/// DelegatedToken
179///
180/// A signed authorization token issued by a delegated signer.
181///
182/// Verification steps (normative):
183/// 1. Validate token version.
184/// 2. Verify the root signature on the delegation certificate.
185/// 3. Validate time bounds and scope/audience constraints.
186/// 4. Verify the token signature using the signer canister.
187///
188/// Design constraints:
189/// - No directory or registry lookup is required.
190/// - No topology or environment inspection is required.
191/// - All verification is local and deterministic.
192///
193#[derive(CandidType, Clone, Debug, Deserialize, Serialize)]
194pub struct DelegatedToken {
195 /// Version of the delegated token format.
196 ///
197 /// Allows format evolution without ambiguity.
198 pub v: u16,
199
200 /// Claims asserted by the signer.
201 pub claims: DelegatedTokenClaims,
202
203 /// Delegation proof binding signer authority to root trust.
204 pub proof: DelegationProof,
205
206 /// Signature over canonicalized claims and delegation hash.
207 ///
208 /// Produced by the delegated signer canister.
209 pub token_sig: Vec<u8>,
210}
211
212///
213/// DelegationAdminCommand
214///
215/// Administrative commands for managing delegation rotation.
216///
217/// These commands are expected to be root-authorized and are
218/// intentionally narrow in scope.
219///
220#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
221pub enum DelegationAdminCommand {
222 /// Start periodic delegation rotation.
223 ///
224 /// `interval_secs` defines how frequently new certificates are issued.
225 StartRotation { interval_secs: u64 },
226
227 /// Stop delegation rotation.
228 StopRotation,
229}
230
231///
232/// DelegationAdminResponse
233///
234/// Result of executing a delegation admin command.
235///
236#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
237pub enum DelegationAdminResponse {
238 RotationStarted,
239 RotationAlreadyRunning,
240 RotationStopped,
241 RotationNotRunning,
242}