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