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    #[serde(default)]
128    pub metadata: Option<RootRequestMetadata>,
129    pub shard_pid: Principal,
130    pub scopes: Vec<String>,
131    pub aud: DelegationAudience,
132    pub cert_ttl_secs: u64,
133}
134
135//
136// DelegatedTokenIssueRequest
137//
138
139#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
140pub struct DelegatedTokenIssueRequest {
141    #[serde(default)]
142    pub metadata: Option<RootRequestMetadata>,
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    #[serde(default)]
158    pub metadata: Option<RootRequestMetadata>,
159    pub subject: Principal,
160    pub aud: DelegationAudience,
161    pub scopes: Vec<String>,
162    pub token_ttl_secs: u64,
163    pub cert_ttl_secs: u64,
164    pub nonce: [u8; 16],
165}
166
167//
168// RoleAttestationRequest
169//
170
171#[derive(CandidType, Clone, Debug, Deserialize)]
172pub struct RoleAttestationRequest {
173    pub subject: Principal,
174    pub role: CanisterRole,
175    #[serde(default)]
176    pub subnet_id: Option<Principal>,
177    pub audience: Principal,
178    pub ttl_secs: u64,
179    pub epoch: u64,
180    #[serde(default)]
181    pub metadata: Option<RootRequestMetadata>,
182}
183
184//
185// RoleAttestation
186//
187
188#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
189pub struct RoleAttestation {
190    pub subject: Principal,
191    pub role: CanisterRole,
192    #[serde(default)]
193    pub subnet_id: Option<Principal>,
194    pub audience: Principal,
195    pub issued_at: u64,
196    pub expires_at: u64,
197    pub epoch: u64,
198}
199
200//
201// SignedRoleAttestation
202//
203
204#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
205pub struct SignedRoleAttestation {
206    pub payload: RoleAttestation,
207    pub signature: Vec<u8>,
208    pub key_id: u32,
209}
210
211//
212// InternalInvocationProofRequest
213//
214
215#[derive(CandidType, Clone, Debug, Deserialize)]
216pub struct InternalInvocationProofRequest {
217    pub subject: Principal,
218    pub role: CanisterRole,
219    #[serde(default)]
220    pub subnet_id: Option<Principal>,
221    pub audience: Principal,
222    pub audience_method: String,
223    pub ttl_secs: u64,
224    #[serde(default)]
225    pub metadata: Option<RootRequestMetadata>,
226}
227
228//
229// InternalInvocationProofPayloadV1
230//
231
232#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
233pub struct InternalInvocationProofPayloadV1 {
234    pub subject: Principal,
235    pub role: CanisterRole,
236    #[serde(default)]
237    pub subnet_id: Option<Principal>,
238    pub audience: Principal,
239    pub audience_method: String,
240    pub issued_at: u64,
241    pub expires_at: u64,
242    pub epoch: u64,
243}
244
245//
246// SignedInternalInvocationProofV1
247//
248
249#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
250pub struct SignedInternalInvocationProofV1 {
251    pub payload: InternalInvocationProofPayloadV1,
252    pub signature: Vec<u8>,
253    pub key_id: u32,
254}
255
256//
257// CanicInternalCallHeaderV1
258//
259
260#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
261pub struct CanicInternalCallHeaderV1 {
262    pub target_canister: Principal,
263    pub target_method: String,
264}
265
266//
267// CanicInternalCallEnvelopeV1
268//
269
270#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
271pub struct CanicInternalCallEnvelopeV1 {
272    pub version: u16,
273    pub header: CanicInternalCallHeaderV1,
274    pub proof: SignedInternalInvocationProofV1,
275    pub args: Vec<u8>,
276}
277
278//
279// AttestationKeyStatus
280//
281
282#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
283pub enum AttestationKeyStatus {
284    Current,
285    Previous,
286}
287
288//
289// AttestationKey
290//
291
292#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
293pub struct AttestationKey {
294    pub key_id: u32,
295    pub public_key: Vec<u8>,
296    pub key_name: String,
297    pub key_hash: [u8; 32],
298    pub status: AttestationKeyStatus,
299    #[serde(default)]
300    pub valid_from: Option<u64>,
301    #[serde(default)]
302    pub valid_until: Option<u64>,
303}
304
305//
306// AttestationKeySet
307//
308
309#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
310pub struct AttestationKeySet {
311    pub root_pid: Principal,
312    pub generated_at: u64,
313    pub keys: Vec<AttestationKey>,
314}
315
316#[cfg(test)]
317mod tests {
318    #[test]
319    fn auth_dtos_remain_passive_boundary_types() {
320        let source = include_str!("auth.rs");
321        let production_source = source
322            .split("#[cfg(test)]")
323            .next()
324            .expect("production source exists");
325
326        for marker in [
327            "impl DelegatedToken",
328            "impl DelegatedTokenClaims",
329            "impl RoleAttestation",
330            "impl SignedRoleAttestation",
331            "impl InternalInvocationProofPayloadV1",
332            "impl SignedInternalInvocationProofV1",
333            "impl CanicInternalCallEnvelopeV1",
334            "fn verify",
335            "fn sign",
336            "fn resolve",
337            "fn replay",
338            "fn consume",
339            "fn policy",
340            "fn validate",
341        ] {
342            assert!(
343                !production_source.contains(marker),
344                "auth DTOs must stay passive; found marker `{marker}`"
345            );
346        }
347    }
348}