1use crate::dto::{prelude::*, rpc::RootRequestMetadata};
2
3#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
8pub enum SignatureAlgorithm {
9 EcdsaP256Sha256,
10}
11
12#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
17pub enum DelegationAudience {
18 Roles(Vec<CanisterRole>),
19 Principals(Vec<Principal>),
20 RolesOrPrincipals {
21 roles: Vec<CanisterRole>,
22 principals: Vec<Principal>,
23 },
24}
25
26#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
31pub struct RootPublicKey {
32 pub root_pid: Principal,
33 pub key_id: String,
34 pub alg: SignatureAlgorithm,
35 pub public_key_sec1: Vec<u8>,
36 pub key_hash: [u8; 32],
37 pub not_before: u64,
38 pub not_after: Option<u64>,
39}
40
41#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
46pub struct RootTrustAnchor {
47 pub root_pid: Principal,
48 pub root_key: RootPublicKey,
49}
50
51#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
56pub enum ShardKeyBinding {
57 IcThresholdEcdsa {
58 key_name_hash: [u8; 32],
59 derivation_path_hash: [u8; 32],
60 },
61}
62
63#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
68pub struct DelegationCert {
69 pub version: u16,
70 pub root_pid: Principal,
71 pub root_key_id: String,
72 pub root_key_hash: [u8; 32],
73 pub alg: SignatureAlgorithm,
74 pub shard_pid: Principal,
75 pub shard_key_id: String,
76 pub shard_public_key_sec1: Vec<u8>,
77 pub shard_key_hash: [u8; 32],
78 pub shard_key_binding: ShardKeyBinding,
79 pub issued_at: u64,
80 pub expires_at: u64,
81 pub max_token_ttl_secs: u64,
82 pub scopes: Vec<String>,
83 pub aud: DelegationAudience,
84 pub verifier_role_hash: Option<[u8; 32]>,
85}
86
87#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
92pub struct DelegationProof {
93 pub cert: DelegationCert,
94 pub root_sig: Vec<u8>,
95}
96
97#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
102pub struct DelegatedTokenClaims {
103 pub version: u16,
104 pub subject: Principal,
105 pub issuer_shard_pid: Principal,
106 pub cert_hash: [u8; 32],
107 pub issued_at: u64,
108 pub expires_at: u64,
109 pub aud: DelegationAudience,
110 pub scopes: Vec<String>,
111 pub nonce: [u8; 16],
112}
113
114#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
119pub struct DelegatedToken {
120 pub claims: DelegatedTokenClaims,
121 pub proof: DelegationProof,
122 pub shard_sig: Vec<u8>,
123}
124
125#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
130pub struct DelegationProofIssueRequest {
131 pub shard_pid: Principal,
132 pub scopes: Vec<String>,
133 pub aud: DelegationAudience,
134 pub cert_ttl_secs: u64,
135}
136
137#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
142pub struct DelegatedTokenIssueRequest {
143 pub proof: DelegationProof,
144 pub subject: Principal,
145 pub aud: DelegationAudience,
146 pub scopes: Vec<String>,
147 pub ttl_secs: u64,
148 pub nonce: [u8; 16],
149}
150
151#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
156pub struct DelegatedTokenMintRequest {
157 pub subject: Principal,
158 pub aud: DelegationAudience,
159 pub scopes: Vec<String>,
160 pub token_ttl_secs: u64,
161 pub cert_ttl_secs: u64,
162 pub nonce: [u8; 16],
163}
164
165#[derive(CandidType, Clone, Debug, Deserialize)]
170pub struct RoleAttestationRequest {
171 pub subject: Principal,
172 pub role: CanisterRole,
173 #[serde(default)]
174 pub subnet_id: Option<Principal>,
175 pub audience: Principal,
176 pub ttl_secs: u64,
177 pub epoch: u64,
178 #[serde(default)]
179 pub metadata: Option<RootRequestMetadata>,
180}
181
182#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
187pub struct RoleAttestation {
188 pub subject: Principal,
189 pub role: CanisterRole,
190 #[serde(default)]
191 pub subnet_id: Option<Principal>,
192 pub audience: Principal,
193 pub issued_at: u64,
194 pub expires_at: u64,
195 pub epoch: u64,
196}
197
198#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
203pub struct SignedRoleAttestation {
204 pub payload: RoleAttestation,
205 pub signature: Vec<u8>,
206 pub key_id: u32,
207}
208
209#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
214pub enum AttestationKeyStatus {
215 Current,
216 Previous,
217}
218
219#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
224pub struct AttestationKey {
225 pub key_id: u32,
226 pub public_key: Vec<u8>,
227 pub key_name: String,
228 pub key_hash: [u8; 32],
229 pub status: AttestationKeyStatus,
230 #[serde(default)]
231 pub valid_from: Option<u64>,
232 #[serde(default)]
233 pub valid_until: Option<u64>,
234}
235
236#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
241pub struct AttestationKeySet {
242 pub root_pid: Principal,
243 pub generated_at: u64,
244 pub keys: Vec<AttestationKey>,
245}
246
247#[cfg(test)]
248mod tests {
249 #[test]
250 fn auth_dtos_remain_passive_boundary_types() {
251 let source = include_str!("auth.rs");
252 let production_source = source
253 .split("#[cfg(test)]")
254 .next()
255 .expect("production source exists");
256
257 for marker in [
258 "impl DelegatedToken",
259 "impl DelegatedTokenClaims",
260 "impl RoleAttestation",
261 "impl SignedRoleAttestation",
262 "fn verify",
263 "fn sign",
264 "fn resolve",
265 "fn replay",
266 "fn consume",
267 "fn policy",
268 "fn validate",
269 ] {
270 assert!(
271 !production_source.contains(marker),
272 "auth DTOs must stay passive; found marker `{marker}`"
273 );
274 }
275 }
276}