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