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    Role(CanisterRole),
19    Principal(Principal),
20}
21
22//
23// RootPublicKey
24//
25
26#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
27pub struct RootPublicKey {
28    pub root_pid: Principal,
29    pub key_id: String,
30    pub alg: SignatureAlgorithm,
31    pub public_key_sec1: Vec<u8>,
32    pub key_hash: [u8; 32],
33    pub not_before: u64,
34    pub not_after: Option<u64>,
35}
36
37//
38// RootTrustAnchor
39//
40
41#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
42pub struct RootTrustAnchor {
43    pub root_pid: Principal,
44    pub root_key: RootPublicKey,
45}
46
47//
48// ShardKeyBinding
49//
50
51#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
52pub enum ShardKeyBinding {
53    IcThresholdEcdsa {
54        key_name_hash: [u8; 32],
55        derivation_path_hash: [u8; 32],
56    },
57}
58
59//
60// DelegationCert
61//
62
63#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
64pub struct DelegationCert {
65    pub version: u16,
66    pub root_pid: Principal,
67    pub root_key_id: String,
68    pub root_key_hash: [u8; 32],
69    pub alg: SignatureAlgorithm,
70    pub shard_pid: Principal,
71    pub shard_key_id: String,
72    pub shard_public_key_sec1: Vec<u8>,
73    pub shard_key_hash: [u8; 32],
74    pub shard_key_binding: ShardKeyBinding,
75    pub issued_at: u64,
76    pub expires_at: u64,
77    pub max_token_ttl_secs: u64,
78    pub scopes: Vec<String>,
79    pub aud: DelegationAudience,
80    pub verifier_role_hash: Option<[u8; 32]>,
81}
82
83//
84// DelegationProof
85//
86
87#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
88pub struct DelegationProof {
89    pub cert: DelegationCert,
90    pub root_sig: Vec<u8>,
91}
92
93//
94// DelegatedTokenClaims
95//
96
97#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
98pub struct DelegatedTokenClaims {
99    pub version: u16,
100    pub subject: Principal,
101    pub issuer_shard_pid: Principal,
102    pub cert_hash: [u8; 32],
103    pub issued_at: u64,
104    pub expires_at: u64,
105    pub aud: DelegationAudience,
106    pub scopes: Vec<String>,
107    pub nonce: [u8; 16],
108}
109
110//
111// DelegatedToken
112//
113
114#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
115pub struct DelegatedToken {
116    pub claims: DelegatedTokenClaims,
117    pub proof: DelegationProof,
118    pub shard_sig: Vec<u8>,
119}
120
121//
122// DelegationProofIssueRequest
123//
124
125#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
126pub struct DelegationProofIssueRequest {
127    pub shard_pid: Principal,
128    pub scopes: Vec<String>,
129    pub aud: DelegationAudience,
130    pub cert_ttl_secs: u64,
131}
132
133//
134// DelegatedTokenIssueRequest
135//
136
137#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
138pub struct DelegatedTokenIssueRequest {
139    pub proof: DelegationProof,
140    pub subject: Principal,
141    pub aud: DelegationAudience,
142    pub scopes: Vec<String>,
143    pub ttl_secs: u64,
144    pub nonce: [u8; 16],
145}
146
147//
148// DelegatedTokenMintRequest
149//
150
151#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
152pub struct DelegatedTokenMintRequest {
153    pub subject: Principal,
154    pub aud: DelegationAudience,
155    pub scopes: Vec<String>,
156    pub token_ttl_secs: u64,
157    pub cert_ttl_secs: u64,
158    pub nonce: [u8; 16],
159}
160
161//
162// RoleAttestationRequest
163//
164
165#[derive(CandidType, Clone, Debug, Deserialize)]
166pub struct RoleAttestationRequest {
167    pub subject: Principal,
168    pub role: CanisterRole,
169    #[serde(default)]
170    pub subnet_id: Option<Principal>,
171    pub audience: Principal,
172    pub ttl_secs: u64,
173    pub epoch: u64,
174    #[serde(default)]
175    pub metadata: Option<RootRequestMetadata>,
176}
177
178//
179// RoleAttestation
180//
181
182#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
183pub struct RoleAttestation {
184    pub subject: Principal,
185    pub role: CanisterRole,
186    #[serde(default)]
187    pub subnet_id: Option<Principal>,
188    pub audience: Principal,
189    pub issued_at: u64,
190    pub expires_at: u64,
191    pub epoch: u64,
192}
193
194//
195// SignedRoleAttestation
196//
197
198#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
199pub struct SignedRoleAttestation {
200    pub payload: RoleAttestation,
201    pub signature: Vec<u8>,
202    pub key_id: u32,
203}
204
205//
206// InternalInvocationProofRequest
207//
208
209#[derive(CandidType, Clone, Debug, Deserialize)]
210pub struct InternalInvocationProofRequest {
211    pub subject: Principal,
212    pub role: CanisterRole,
213    #[serde(default)]
214    pub subnet_id: Option<Principal>,
215    pub audience: Principal,
216    pub audience_method: String,
217    pub ttl_secs: u64,
218    #[serde(default)]
219    pub metadata: Option<RootRequestMetadata>,
220}
221
222//
223// InternalInvocationProofPayloadV1
224//
225
226#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
227pub struct InternalInvocationProofPayloadV1 {
228    pub subject: Principal,
229    pub role: CanisterRole,
230    #[serde(default)]
231    pub subnet_id: Option<Principal>,
232    pub audience: Principal,
233    pub audience_method: String,
234    pub issued_at: u64,
235    pub expires_at: u64,
236    pub epoch: u64,
237}
238
239//
240// SignedInternalInvocationProofV1
241//
242
243#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
244pub struct SignedInternalInvocationProofV1 {
245    pub payload: InternalInvocationProofPayloadV1,
246    pub signature: Vec<u8>,
247    pub key_id: u32,
248}
249
250//
251// CanicInternalCallHeaderV1
252//
253
254#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
255pub struct CanicInternalCallHeaderV1 {
256    pub target_canister: Principal,
257    pub target_method: String,
258}
259
260//
261// CanicInternalCallEnvelopeV1
262//
263
264#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
265pub struct CanicInternalCallEnvelopeV1 {
266    pub version: u16,
267    pub header: CanicInternalCallHeaderV1,
268    pub proof: SignedInternalInvocationProofV1,
269    pub args: Vec<u8>,
270}
271
272//
273// AttestationKeyStatus
274//
275
276#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
277pub enum AttestationKeyStatus {
278    Current,
279    Previous,
280}
281
282//
283// AttestationKey
284//
285
286#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
287pub struct AttestationKey {
288    pub key_id: u32,
289    pub public_key: Vec<u8>,
290    pub key_name: String,
291    pub key_hash: [u8; 32],
292    pub status: AttestationKeyStatus,
293    #[serde(default)]
294    pub valid_from: Option<u64>,
295    #[serde(default)]
296    pub valid_until: Option<u64>,
297}
298
299//
300// AttestationKeySet
301//
302
303#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
304pub struct AttestationKeySet {
305    pub root_pid: Principal,
306    pub generated_at: u64,
307    pub keys: Vec<AttestationKey>,
308}
309
310#[cfg(test)]
311mod tests {
312    #[test]
313    fn auth_dtos_remain_passive_boundary_types() {
314        let source = include_str!("auth.rs");
315        let production_source = source
316            .split("#[cfg(test)]")
317            .next()
318            .expect("production source exists");
319
320        for marker in [
321            "impl DelegatedToken",
322            "impl DelegatedTokenClaims",
323            "impl RoleAttestation",
324            "impl SignedRoleAttestation",
325            "impl InternalInvocationProofPayloadV1",
326            "impl SignedInternalInvocationProofV1",
327            "impl CanicInternalCallEnvelopeV1",
328            "fn verify",
329            "fn sign",
330            "fn resolve",
331            "fn replay",
332            "fn consume",
333            "fn policy",
334            "fn validate",
335        ] {
336            assert!(
337                !production_source.contains(marker),
338                "auth DTOs must stay passive; found marker `{marker}`"
339            );
340        }
341    }
342}