Skip to main content

canic_core/dto/
auth.rs

1use crate::{
2    dto::{prelude::*, rpc::RootRequestMetadata},
3    ids::BuildNetwork,
4};
5
6//
7// DelegationAudience
8//
9
10#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
11pub enum DelegationAudience {
12    Canister(Principal),
13    CanicSubnet(Principal),
14    Project(String),
15}
16
17//
18// DelegatedRoleGrant
19//
20
21#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
22pub struct DelegatedRoleGrant {
23    pub target: CanisterRole,
24    pub scopes: Vec<String>,
25}
26
27//
28// RootProof
29//
30
31#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
32pub enum RootProof {
33    IcChainKeyBatchSignatureV1(IcChainKeyBatchSignatureProofV1),
34}
35
36//
37// RootProofMode
38//
39
40#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
41pub enum RootProofMode {
42    ChainKeyBatch,
43}
44
45//
46// IssuerProof
47//
48
49#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
50pub enum IssuerProof {
51    IcCanisterSignatureV1(IcCanisterSignatureProofV1),
52}
53
54//
55// IcCanisterSignatureProofV1
56//
57
58#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
59pub struct IcCanisterSignatureProofV1 {
60    pub signature_cbor: Vec<u8>,
61    pub public_key_der: Vec<u8>,
62}
63
64//
65// ChainKeyAlgorithm
66//
67
68#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
69pub enum ChainKeyAlgorithm {
70    EcdsaSecp256k1,
71}
72
73//
74// ChainKeyKeyId
75//
76
77#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
78pub struct ChainKeyKeyId {
79    pub name: String,
80}
81
82//
83// RootKeyPolicyV1
84//
85
86#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
87pub struct RootKeyPolicyV1 {
88    pub root_canister_id: Principal,
89    pub proof_mode: RootProofMode,
90    pub algorithm: ChainKeyAlgorithm,
91    pub key_id: ChainKeyKeyId,
92    pub derivation_path_hash: [u8; 32],
93    pub public_key: Vec<u8>,
94    pub key_version: u64,
95    pub min_accepted_key_version: u64,
96    pub min_accepted_proof_epoch: u64,
97    pub min_accepted_registry_epoch: u64,
98    pub max_revocation_latency_ns: u64,
99    pub valid_from_ns: u64,
100    pub accept_until_ns: u64,
101    pub build_network: BuildNetwork,
102}
103
104//
105// DelegatedAuthRegistrySnapshotV1
106//
107
108#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
109pub struct DelegatedAuthRegistrySnapshotV1 {
110    pub schema_version: u16,
111    pub root_canister_id: Principal,
112    pub registry_epoch: u64,
113    pub proof_mode: RootProofMode,
114    pub root_key_policy_hash: [u8; 32],
115    pub issuer_policies: Vec<DelegatedAuthIssuerPolicySnapshotV1>,
116}
117
118//
119// DelegatedAuthIssuerPolicySnapshotV1
120//
121
122#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
123pub struct DelegatedAuthIssuerPolicySnapshotV1 {
124    pub issuer_canister_id: Principal,
125    pub enabled: bool,
126    pub preferred_proof_mode: RootProofMode,
127    pub allowed_audiences: Vec<DelegationAudience>,
128    pub allowed_grants: Vec<DelegatedRoleGrant>,
129    pub max_root_proof_ttl_ns: u64,
130    pub max_token_ttl_ns: u64,
131    pub issuer_proof_algorithm: IssuerProofAlgorithm,
132    pub issuer_proof_binding_hash: [u8; 32],
133    pub renewal_template_hash: [u8; 32],
134}
135
136//
137// IcChainKeyBatchSignatureProofV1
138//
139
140#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
141pub struct IcChainKeyBatchSignatureProofV1 {
142    pub header: ChainKeyBatchHeaderV1,
143    pub delegation_cert: ChainKeyDelegationCertV1,
144    pub issuer_witness: ChainKeyBatchWitnessV1,
145    pub signature: ChainKeyRootSignatureV1,
146}
147
148//
149// ChainKeyBatchHeaderV1
150//
151
152#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
153pub struct ChainKeyBatchHeaderV1 {
154    pub schema_version: u16,
155    pub root_canister_id: Principal,
156    pub batch_id: [u8; 32],
157    pub proof_epoch: u64,
158    pub registry_epoch: u64,
159    pub registry_hash: [u8; 32],
160    pub tree_root: [u8; 32],
161    pub not_before_ns: u64,
162    pub expires_at_ns: u64,
163    pub algorithm: ChainKeyAlgorithm,
164    pub key_id: ChainKeyKeyId,
165    pub derivation_path_hash: [u8; 32],
166    pub key_version: u64,
167}
168
169//
170// ChainKeyDelegationCertV1
171//
172
173#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
174pub struct ChainKeyDelegationCertV1 {
175    pub root_canister_id: Principal,
176    pub issuer_canister_id: Principal,
177    pub proof_epoch: u64,
178    pub issuer_proof_algorithm: IssuerProofAlgorithm,
179    pub issuer_proof_binding_hash: [u8; 32],
180    pub issuer_proof_binding: IssuerProofBinding,
181    pub max_token_ttl_ns: u64,
182    pub audience: DelegationAudience,
183    pub grants: Vec<DelegatedRoleGrant>,
184    pub not_before_ns: u64,
185    pub expires_at_ns: u64,
186    pub registry_epoch: u64,
187    pub registry_hash: [u8; 32],
188}
189
190//
191// ChainKeyRootSignatureV1
192//
193
194#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
195pub struct ChainKeyRootSignatureV1 {
196    pub algorithm: ChainKeyAlgorithm,
197    pub key_id: ChainKeyKeyId,
198    pub derivation_path: Vec<Vec<u8>>,
199    pub public_key: Vec<u8>,
200    pub signature: Vec<u8>,
201}
202
203//
204// ChainKeyBatchWitnessV1
205//
206
207#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
208pub struct ChainKeyBatchWitnessV1 {
209    pub steps: Vec<ChainKeyBatchWitnessStepV1>,
210}
211
212//
213// ChainKeyBatchWitnessStepV1
214//
215
216#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
217pub enum ChainKeyBatchWitnessStepV1 {
218    LeftSibling([u8; 32]),
219    RightSibling([u8; 32]),
220}
221
222//
223// IssuerProofAlgorithm
224//
225
226#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
227pub enum IssuerProofAlgorithm {
228    IcCanisterSignatureV1,
229}
230
231//
232// IssuerProofBinding
233//
234
235#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
236pub enum IssuerProofBinding {
237    IcCanisterSignatureV1 { seed_hash: [u8; 32] },
238}
239
240//
241// DelegationCert
242//
243
244#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
245pub struct DelegationCert {
246    pub root_pid: Principal,
247    pub issuer_pid: Principal,
248    pub issuer_proof_alg: IssuerProofAlgorithm,
249    pub issuer_proof_binding_hash: [u8; 32],
250    pub issuer_proof_binding: IssuerProofBinding,
251    pub issued_at_ns: u64,
252    pub not_before_ns: u64,
253    pub expires_at_ns: u64,
254    pub max_token_ttl_ns: u64,
255    pub aud: DelegationAudience,
256    pub grants: Vec<DelegatedRoleGrant>,
257}
258
259//
260// DelegationProof
261//
262
263#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
264pub struct DelegationProof {
265    pub cert: DelegationCert,
266    pub root_proof: RootProof,
267}
268
269//
270// ActiveDelegationProof
271//
272
273#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
274pub struct ActiveDelegationProof {
275    pub proof: DelegationProof,
276    pub cert_hash: [u8; 32],
277    pub not_before_ns: u64,
278    pub expires_at_ns: u64,
279    pub refresh_after_ns: u64,
280    pub installed_at_ns: u64,
281    pub installed_by: Principal,
282}
283
284//
285// InstallActiveDelegationProofRequest
286//
287
288#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
289pub struct InstallActiveDelegationProofRequest {
290    pub proof: DelegationProof,
291}
292
293//
294// InstallActiveDelegationProofResponse
295//
296
297#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
298pub struct InstallActiveDelegationProofResponse {
299    pub active_proof: ActiveDelegationProof,
300}
301
302//
303// ActiveDelegationProofStatus
304//
305
306#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
307pub enum ActiveDelegationProofStatus {
308    Missing,
309    Valid,
310    RefreshNeeded,
311    Expired,
312}
313
314//
315// ActiveDelegationProofStatusResponse
316//
317
318#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
319pub struct ActiveDelegationProofStatusResponse {
320    pub status: ActiveDelegationProofStatus,
321    pub root_pid: Option<Principal>,
322    pub issuer_pid: Option<Principal>,
323    pub cert_hash: Option<[u8; 32]>,
324    pub expires_at_ns: Option<u64>,
325    pub refresh_after_ns: Option<u64>,
326}
327
328//
329// DelegatedTokenClaims
330//
331
332#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
333pub struct DelegatedTokenClaims {
334    pub subject: Principal,
335    pub issuer_pid: Principal,
336    pub cert_hash: [u8; 32],
337    pub issued_at_ns: u64,
338    pub expires_at_ns: u64,
339    pub aud: DelegationAudience,
340    pub grants: Vec<DelegatedRoleGrant>,
341    pub nonce: [u8; 16],
342    #[serde(default)]
343    pub ext: Option<Vec<u8>>,
344}
345
346//
347// DelegatedToken
348//
349
350#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
351pub struct DelegatedToken {
352    pub claims: DelegatedTokenClaims,
353    pub proof: DelegationProof,
354    pub issuer_proof: IssuerProof,
355}
356
357//
358// AuthRequestMetadata
359//
360
361#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
362pub struct AuthRequestMetadata {
363    pub request_id: [u8; 32],
364    pub ttl_ns: u64,
365}
366
367//
368// RootDelegationProofBatchProofRef
369//
370
371#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
372pub struct RootDelegationProofBatchProofRef {
373    pub issuer_pid: Principal,
374    pub cert_hash: [u8; 32],
375}
376
377//
378// RootDelegationProofBatchProof
379//
380
381#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
382pub struct RootDelegationProofBatchProof {
383    pub issuer_pid: Principal,
384    pub cert_hash: [u8; 32],
385    pub proof: DelegationProof,
386}
387
388//
389// RootDelegationProofBatchInstallRequest
390//
391
392#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
393pub struct RootDelegationProofBatchInstallRequest {
394    pub batch_id: [u8; 32],
395    pub proofs: Vec<RootDelegationProofBatchProof>,
396}
397
398//
399// RootDelegationProofInstallOutcome
400//
401
402#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
403pub enum RootDelegationProofInstallOutcome {
404    Installed,
405    AlreadyInstalled,
406    RejectedBySigner,
407    CallFailed,
408    ProofMismatch,
409    ExpiredOrSuperseded,
410}
411
412//
413// RootIssuerPolicyUpsertRequest
414//
415
416#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
417pub struct RootIssuerPolicyUpsertRequest {
418    pub issuer_pid: Principal,
419    pub enabled: bool,
420    pub allowed_audiences: Vec<DelegationAudience>,
421    pub allowed_grants: Vec<DelegatedRoleGrant>,
422    pub max_cert_ttl_ns: u64,
423    pub refresh_after_ratio_bps: u16,
424}
425
426//
427// RootIssuerPolicyView
428//
429
430#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
431pub struct RootIssuerPolicyView {
432    pub issuer_pid: Principal,
433    pub enabled: bool,
434    pub allowed_audiences: Vec<DelegationAudience>,
435    pub allowed_grants: Vec<DelegatedRoleGrant>,
436    pub max_cert_ttl_ns: u64,
437    pub refresh_after_ratio_bps: u16,
438}
439
440//
441// RootIssuerPolicyResponse
442//
443
444#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
445pub struct RootIssuerPolicyResponse {
446    pub issuer: RootIssuerPolicyView,
447}
448
449//
450// RootIssuerRenewalTemplateUpsertRequest
451//
452
453#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
454pub struct RootIssuerRenewalTemplateUpsertRequest {
455    pub issuer_pid: Principal,
456    pub enabled: bool,
457    pub aud: DelegationAudience,
458    pub grants: Vec<DelegatedRoleGrant>,
459    pub cert_ttl_ns: u64,
460}
461
462//
463// RootIssuerRenewalTemplateView
464//
465
466#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
467pub struct RootIssuerRenewalTemplateView {
468    pub issuer_pid: Principal,
469    pub enabled: bool,
470    pub aud: DelegationAudience,
471    pub grants: Vec<DelegatedRoleGrant>,
472    pub cert_ttl_ns: u64,
473}
474
475//
476// RootIssuerRenewalTemplateResponse
477//
478
479#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
480pub struct RootIssuerRenewalTemplateResponse {
481    pub template: RootIssuerRenewalTemplateView,
482}
483
484//
485// RootIssuerRenewalStatusRequest
486//
487
488#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
489pub struct RootIssuerRenewalStatusRequest {
490    pub issuer_pid: Principal,
491}
492
493//
494// RootIssuerRenewalOutcome
495//
496
497#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
498pub enum RootIssuerRenewalOutcome {
499    AlreadyInstalled,
500    DriftDetected,
501    InstallDeadlineExpired,
502    Installed,
503    IssuerCallFailed,
504    NeverRun,
505    PolicyRejected,
506    ProofMismatch,
507    QuotaExceeded,
508    RejectedByIssuer,
509    RetrievalExpired,
510    TemplateChanged,
511    TemplateDisabled,
512}
513
514//
515// RootIssuerRenewalAttemptStatus
516//
517
518#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
519pub enum RootIssuerRenewalAttemptStatus {
520    Prepared,
521    Installing,
522    Installed,
523    FailedRetryable,
524    FailedTerminal,
525    Disabled,
526    Expired,
527}
528
529//
530// RootIssuerRenewalAttemptView
531//
532
533#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
534pub struct RootIssuerRenewalAttemptView {
535    pub attempt_id: [u8; 32],
536    pub issuer_pid: Principal,
537    pub template_fingerprint: [u8; 32],
538    pub batch_id: [u8; 32],
539    pub proof_ref: RootDelegationProofBatchProofRef,
540    pub status: RootIssuerRenewalAttemptStatus,
541    pub prepared_at_ns: u64,
542    pub retrieval_expires_at_ns: u64,
543    pub install_deadline_ns: u64,
544    pub prepared_cert_hash: [u8; 32],
545    pub prepared_expires_at_ns: u64,
546    pub prepared_refresh_after_ns: u64,
547    pub failure: Option<RootIssuerRenewalOutcome>,
548}
549
550//
551// RootIssuerRenewalStateView
552//
553
554#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
555pub struct RootIssuerRenewalStateView {
556    pub issuer_pid: Principal,
557    pub template_fingerprint: [u8; 32],
558    pub last_installed_cert_hash: Option<[u8; 32]>,
559    pub last_installed_expires_at_ns: Option<u64>,
560    pub last_installed_refresh_after_ns: Option<u64>,
561    pub active_attempt_id: Option<[u8; 32]>,
562    pub last_outcome: RootIssuerRenewalOutcome,
563    pub consecutive_failures: u32,
564    pub next_attempt_after_ns: u64,
565    pub updated_at_ns: u64,
566}
567
568//
569// RootIssuerRenewalStatusResponse
570//
571
572#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
573pub struct RootIssuerRenewalStatusResponse {
574    pub template: Option<RootIssuerRenewalTemplateView>,
575    pub state: Option<RootIssuerRenewalStateView>,
576    pub active_attempt: Option<RootIssuerRenewalAttemptView>,
577}
578
579//
580// DelegatedTokenPrepareRequest
581//
582
583#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
584pub struct DelegatedTokenPrepareRequest {
585    #[serde(default)]
586    pub metadata: Option<AuthRequestMetadata>,
587    pub subject: Principal,
588    pub aud: DelegationAudience,
589    pub grants: Vec<DelegatedRoleGrant>,
590    pub ttl_ns: u64,
591    #[serde(default)]
592    pub ext: Option<Vec<u8>>,
593}
594
595//
596// DelegatedTokenPrepareResponse
597//
598
599#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
600pub struct DelegatedTokenPrepareResponse {
601    pub claims: DelegatedTokenClaims,
602    pub claims_hash: [u8; 32],
603    pub retrieval_expires_at_ns: u64,
604}
605
606//
607// DelegatedTokenGetRequest
608//
609
610#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
611pub struct DelegatedTokenGetRequest {
612    pub claims_hash: [u8; 32],
613}
614
615//
616// RoleAttestationRequest
617//
618
619#[derive(CandidType, Clone, Debug, Deserialize)]
620pub struct RoleAttestationRequest {
621    pub subject: Principal,
622    pub role: CanisterRole,
623    #[serde(default)]
624    pub subnet_id: Option<Principal>,
625    pub audience: Principal,
626    pub ttl_ns: u64,
627    pub epoch: u64,
628    #[serde(default)]
629    pub metadata: Option<RootRequestMetadata>,
630}
631
632//
633// RoleAttestation
634//
635
636#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
637pub struct RoleAttestation {
638    pub subject: Principal,
639    pub role: CanisterRole,
640    #[serde(default)]
641    pub subnet_id: Option<Principal>,
642    pub audience: Principal,
643    pub issued_at_ns: u64,
644    pub expires_at_ns: u64,
645    pub epoch: u64,
646}
647
648//
649// RoleAttestationRootProof
650//
651
652#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
653pub enum RoleAttestationRootProof {
654    IcCanisterSignatureV1(IcCanisterSignatureProofV1),
655}
656
657//
658// RoleAttestationPrepareResponse
659//
660
661#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
662pub struct RoleAttestationPrepareResponse {
663    pub payload: RoleAttestation,
664    pub payload_hash: [u8; 32],
665    pub retrieval_expires_at_ns: u64,
666}
667
668//
669// RoleAttestationGetRequest
670//
671
672#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
673pub struct RoleAttestationGetRequest {
674    pub payload_hash: [u8; 32],
675}
676
677//
678// SignedRoleAttestation
679//
680
681#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
682pub struct SignedRoleAttestation {
683    pub payload: RoleAttestation,
684    pub root_proof: RoleAttestationRootProof,
685}
686
687// -----------------------------------------------------------------------------
688// Tests
689// -----------------------------------------------------------------------------
690
691#[cfg(test)]
692mod tests {
693    #[test]
694    fn auth_dtos_remain_passive_boundary_types() {
695        let source = include_str!("auth.rs");
696        let production_source = source
697            .split("#[cfg(test)]")
698            .next()
699            .expect("production source exists");
700
701        for marker in [
702            "impl DelegatedToken",
703            "impl DelegatedTokenClaims",
704            "impl RoleAttestation",
705            "impl SignedRoleAttestation",
706            "fn verify",
707            "fn sign",
708            "fn resolve",
709            "fn replay",
710            "fn consume",
711            "fn policy",
712            "fn validate",
713        ] {
714            assert!(
715                !production_source.contains(marker),
716                "auth DTOs must stay passive; found marker `{marker}`"
717            );
718        }
719    }
720}