Skip to main content

canic_core/dto/
auth.rs

1use crate::dto::{prelude::*, rpc::RootRequestMetadata};
2
3//
4// SignatureAlgorithm
5//
6
7#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
8pub enum SignatureAlgorithm {
9    EcdsaP256Sha256,
10}
11
12//
13// DelegationAudience
14//
15
16#[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//
27// RootPublicKey
28//
29
30#[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//
42// RootTrustAnchor
43//
44
45#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
46pub struct RootTrustAnchor {
47    pub root_pid: Principal,
48    pub root_key: RootPublicKey,
49}
50
51//
52// ShardKeyBinding
53//
54
55#[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//
64// DelegationCert
65//
66
67#[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//
88// DelegationProof
89//
90
91#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
92pub struct DelegationProof {
93    pub cert: DelegationCert,
94    pub root_sig: Vec<u8>,
95}
96
97//
98// DelegatedTokenClaims
99//
100
101#[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//
115// DelegatedToken
116//
117
118#[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//
126// DelegationProofIssueRequest
127//
128
129#[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//
138// DelegatedTokenIssueRequest
139//
140
141#[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//
152// DelegatedTokenMintRequest
153//
154
155#[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//
166// RoleAttestationRequest
167//
168
169#[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//
183// RoleAttestation
184//
185
186#[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//
199// SignedRoleAttestation
200//
201
202#[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//
210// InternalInvocationProofRequest
211//
212
213#[derive(CandidType, Clone, Debug, Deserialize)]
214pub struct InternalInvocationProofRequest {
215    pub subject: Principal,
216    pub role: CanisterRole,
217    #[serde(default)]
218    pub subnet_id: Option<Principal>,
219    pub audience: Principal,
220    pub audience_method: String,
221    pub ttl_secs: u64,
222    #[serde(default)]
223    pub metadata: Option<RootRequestMetadata>,
224}
225
226//
227// InternalInvocationProofPayloadV1
228//
229
230#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
231pub struct InternalInvocationProofPayloadV1 {
232    pub subject: Principal,
233    pub role: CanisterRole,
234    #[serde(default)]
235    pub subnet_id: Option<Principal>,
236    pub audience: Principal,
237    pub audience_method: String,
238    pub issued_at: u64,
239    pub expires_at: u64,
240    pub epoch: u64,
241}
242
243//
244// SignedInternalInvocationProofV1
245//
246
247#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
248pub struct SignedInternalInvocationProofV1 {
249    pub payload: InternalInvocationProofPayloadV1,
250    pub signature: Vec<u8>,
251    pub key_id: u32,
252}
253
254//
255// CanicInternalCallHeaderV1
256//
257
258#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
259pub struct CanicInternalCallHeaderV1 {
260    pub target_canister: Principal,
261    pub target_method: String,
262}
263
264//
265// CanicInternalCallEnvelopeV1
266//
267
268#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
269pub struct CanicInternalCallEnvelopeV1 {
270    pub version: u16,
271    pub header: CanicInternalCallHeaderV1,
272    pub proof: SignedInternalInvocationProofV1,
273    pub args: Vec<u8>,
274}
275
276//
277// AttestationKeyStatus
278//
279
280#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
281pub enum AttestationKeyStatus {
282    Current,
283    Previous,
284}
285
286//
287// AttestationKey
288//
289
290#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
291pub struct AttestationKey {
292    pub key_id: u32,
293    pub public_key: Vec<u8>,
294    pub key_name: String,
295    pub key_hash: [u8; 32],
296    pub status: AttestationKeyStatus,
297    #[serde(default)]
298    pub valid_from: Option<u64>,
299    #[serde(default)]
300    pub valid_until: Option<u64>,
301}
302
303//
304// AttestationKeySet
305//
306
307#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
308pub struct AttestationKeySet {
309    pub root_pid: Principal,
310    pub generated_at: u64,
311    pub keys: Vec<AttestationKey>,
312}
313
314#[cfg(test)]
315mod tests {
316    #[test]
317    fn auth_dtos_remain_passive_boundary_types() {
318        let source = include_str!("auth.rs");
319        let production_source = source
320            .split("#[cfg(test)]")
321            .next()
322            .expect("production source exists");
323
324        for marker in [
325            "impl DelegatedToken",
326            "impl DelegatedTokenClaims",
327            "impl RoleAttestation",
328            "impl SignedRoleAttestation",
329            "impl InternalInvocationProofPayloadV1",
330            "impl SignedInternalInvocationProofV1",
331            "impl CanicInternalCallEnvelopeV1",
332            "fn verify",
333            "fn sign",
334            "fn resolve",
335            "fn replay",
336            "fn consume",
337            "fn policy",
338            "fn validate",
339        ] {
340            assert!(
341                !production_source.contains(marker),
342                "auth DTOs must stay passive; found marker `{marker}`"
343            );
344        }
345    }
346}