Skip to main content

canic_core/dto/
auth.rs

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