1#![cfg_attr(not(feature = "std"), no_std)]
19#![expect(clippy::clone_on_copy, reason = "Comes from Substrate")]
21
22#[cfg(feature = "runtime-benchmarks")]
23mod benchmarking;
24#[cfg(test)]
25mod tests;
26pub mod weights;
27
28extern crate alloc;
29
30#[cfg(not(feature = "std"))]
31use alloc::collections::BTreeSet;
32#[cfg(not(feature = "std"))]
33use alloc::vec::Vec;
34use frame_support::dispatch::{DispatchResult, DispatchResultWithPostInfo};
35use frame_support::ensure;
36use frame_support::traits::Time;
37use frame_support::weights::Weight;
38pub use pallet::*;
39use parity_scale_codec::{Decode, DecodeWithMemTracking, Encode};
40use scale_info::TypeInfo;
41use sp_auto_id::auto_id_runtime_interface::{decode_tbs_certificate, verify_signature};
42use sp_auto_id::{DerVec, SignatureVerificationRequest, Validity};
43use sp_core::{H256, U256, blake2_256};
44#[cfg(feature = "std")]
45use std::collections::BTreeSet;
46use subspace_runtime_primitives::Moment;
47pub use weights::WeightInfo;
48
49pub type Identifier = H256;
51
52pub type Serial = U256;
54
55#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
57pub struct X509Certificate {
58 pub issuer_id: Option<Identifier>,
60 pub serial: U256,
62 pub subject_common_name: Vec<u8>,
64 pub subject_public_key_info: DerVec,
66 pub validity: Validity,
68 pub raw: DerVec,
70 pub issued_serials: BTreeSet<Serial>,
73 pub nonce: U256,
75}
76
77#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
79pub enum Certificate {
80 X509(X509Certificate),
81}
82
83impl Certificate {
84 #[cfg(test)]
86 fn subject_common_name(&self) -> Vec<u8> {
87 match self {
88 Certificate::X509(cert) => cert.subject_common_name.clone(),
89 }
90 }
91
92 fn subject_public_key_info(&self) -> DerVec {
94 match self {
95 Certificate::X509(cert) => cert.subject_public_key_info.clone(),
96 }
97 }
98
99 fn issue_certificate_serial<T: Config>(&mut self, serial: U256) -> DispatchResult {
100 match self {
101 Certificate::X509(cert) => {
102 ensure!(
103 !cert.issued_serials.contains(&serial),
104 Error::<T>::CertificateSerialAlreadyIssued
105 );
106 cert.issued_serials.insert(serial);
107 Ok(())
108 }
109 }
110 }
111
112 fn issuer_id(&self) -> Option<Identifier> {
113 match self {
114 Certificate::X509(cert) => cert.issuer_id,
115 }
116 }
117
118 fn serial(&self) -> Serial {
119 match self {
120 Certificate::X509(cert) => cert.serial,
121 }
122 }
123
124 fn issued_serials(&self) -> BTreeSet<Serial> {
125 match self {
126 Certificate::X509(cert) => cert.issued_serials.clone(),
127 }
128 }
129
130 pub(crate) fn is_valid_at(&self, time: Moment) -> bool {
132 match self {
133 Certificate::X509(cert) => cert.validity.is_valid_at(time),
134 }
135 }
136
137 fn derive_identifier(&self) -> Identifier {
142 match &self {
143 Certificate::X509(cert) => {
144 if let Some(issuer_id) = cert.issuer_id {
145 let mut data = issuer_id.to_fixed_bytes().to_vec();
146
147 data.extend_from_slice(cert.subject_common_name.as_ref());
148
149 blake2_256(&data).into()
150 } else {
151 blake2_256(cert.subject_common_name.as_ref()).into()
153 }
154 }
155 }
156 }
157
158 fn nonce(&self) -> U256 {
159 match self {
160 Certificate::X509(cert) => cert.nonce,
161 }
162 }
163
164 fn inc_nonce<T: Config>(&mut self) -> DispatchResult {
165 match self {
166 Certificate::X509(cert) => {
167 cert.nonce = cert
168 .nonce
169 .checked_add(U256::one())
170 .ok_or(Error::<T>::NonceOverflow)?;
171 Ok(())
172 }
173 }
174 }
175}
176
177#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
179pub struct AutoId {
180 pub certificate: Certificate,
182}
183
184#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, DecodeWithMemTracking)]
186pub enum RegisterAutoIdX509 {
187 Root {
188 certificate: DerVec,
189 signature_algorithm: DerVec,
190 signature: Vec<u8>,
191 },
192 Leaf {
193 issuer_id: Identifier,
194 certificate: DerVec,
195 signature_algorithm: DerVec,
196 signature: Vec<u8>,
197 },
198}
199
200#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, DecodeWithMemTracking)]
202pub enum RenewAutoId {
203 X509(RenewX509Certificate),
204}
205
206#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, DecodeWithMemTracking)]
208pub struct RenewX509Certificate {
209 issuer_id: Option<Identifier>,
210 certificate: DerVec,
211 signature_algorithm: DerVec,
212 signature: Vec<u8>,
213}
214
215#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, DecodeWithMemTracking)]
217pub struct Signature {
218 pub signature_algorithm: DerVec,
219 pub value: Vec<u8>,
220}
221
222#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, DecodeWithMemTracking)]
224pub enum RegisterAutoId {
225 X509(RegisterAutoIdX509),
226}
227
228#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
230pub enum CertificateActionType {
231 RevokeCertificate,
232 DeactivateAutoId,
233}
234
235#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
237pub struct CertificateAction {
238 pub id: Identifier,
240 pub nonce: U256,
242 pub action_type: CertificateActionType,
244}
245
246#[frame_support::pallet]
247mod pallet {
248 use super::*;
249 use crate::weights::WeightInfo;
250 use crate::{AutoId, Identifier, RegisterAutoId, Serial, Signature};
251 use frame_support::pallet_prelude::*;
252 use frame_support::traits::Time;
253 use frame_system::pallet_prelude::*;
254
255 #[pallet::config]
256 pub trait Config: frame_system::Config<RuntimeEvent: From<Event<Self>>> {
257 type Time: Time<Moment = subspace_runtime_primitives::Moment>;
258 type Weights: WeightInfo;
259 }
260
261 #[pallet::pallet]
262 #[pallet::without_storage_info]
263 pub struct Pallet<T>(_);
264
265 #[pallet::storage]
267 pub(super) type AutoIds<T> = StorageMap<_, Identity, Identifier, AutoId, OptionQuery>;
268
269 #[pallet::storage]
274 pub(super) type CertificateRevocationList<T> =
275 StorageMap<_, Identity, Identifier, BTreeSet<Serial>, OptionQuery>;
276
277 #[pallet::error]
278 pub enum Error<T> {
279 UnknownIssuer,
281 UnknownAutoId,
283 InvalidCertificate,
285 InvalidSignature,
287 CertificateSerialAlreadyIssued,
289 ExpiredCertificate,
291 CertificateRevoked,
293 CertificateAlreadyRevoked,
295 NonceOverflow,
297 AutoIdIdentifierAlreadyExists,
299 AutoIdIdentifierMismatch,
301 PublicKeyMismatch,
303 }
304
305 #[pallet::event]
306 #[pallet::generate_deposit(pub (super) fn deposit_event)]
307 pub enum Event<T: Config> {
308 NewAutoIdRegistered(Identifier),
310 CertificateRevoked(Identifier),
312 AutoIdDeactivated(Identifier),
314 AutoIdRenewed(Identifier),
316 }
317
318 #[pallet::call]
319 impl<T: Config> Pallet<T> {
320 #[pallet::call_index(0)]
322 #[pallet::weight(Pallet::<T>::max_register_auto_id_weight())]
323 pub fn register_auto_id(
324 origin: OriginFor<T>,
325 req: RegisterAutoId,
326 ) -> DispatchResultWithPostInfo {
327 ensure_signed(origin)?;
328 Self::do_register_auto_id(req)
329 }
330
331 #[pallet::call_index(1)]
335 #[pallet::weight(Pallet::<T>::max_revoke_auto_id_weight())]
336 pub fn revoke_certificate(
337 origin: OriginFor<T>,
338 auto_id_identifier: Identifier,
339 signature: Signature,
340 ) -> DispatchResultWithPostInfo {
341 ensure_signed(origin)?;
342 Self::do_revoke_certificate(auto_id_identifier, signature)
343 }
344
345 #[pallet::call_index(2)]
347 #[pallet::weight(<T as Config>::Weights::deactivate_auto_id())]
348 pub fn deactivate_auto_id(
349 origin: OriginFor<T>,
350 auto_id_identifier: Identifier,
351 signature: Signature,
352 ) -> DispatchResult {
353 ensure_signed(origin)?;
354 Self::do_deactivate_auto_id(auto_id_identifier, signature)?;
355 Ok(())
356 }
357
358 #[pallet::call_index(3)]
360 #[pallet::weight(Pallet::<T>::max_renew_auto_id_weight())]
361 pub fn renew_auto_id(
362 origin: OriginFor<T>,
363 auto_id_identifier: Identifier,
364 req: RenewAutoId,
365 ) -> DispatchResultWithPostInfo {
366 ensure_signed(origin)?;
367 Self::do_renew_auto_id_certificate(auto_id_identifier, req)
368 }
369 }
370}
371
372impl<T: Config> Pallet<T> {
373 pub(crate) fn do_register_auto_id(req: RegisterAutoId) -> DispatchResultWithPostInfo {
374 let current_time = T::Time::now();
375 let (certificate, weight) = match req {
376 RegisterAutoId::X509(x509_req) => match x509_req {
377 RegisterAutoIdX509::Root {
378 certificate,
379 signature_algorithm,
380 signature,
381 } => {
382 let tbs_certificate = decode_tbs_certificate(certificate.clone())
383 .ok_or(Error::<T>::InvalidCertificate)?;
384 let req = SignatureVerificationRequest {
385 public_key_info: tbs_certificate.subject_public_key_info.clone(),
386 signature_algorithm,
387 data: certificate.0.clone(),
388 signature,
389 };
390 verify_signature(req).ok_or(Error::<T>::InvalidSignature)?;
391
392 ensure!(
393 tbs_certificate.validity.is_valid_at(current_time),
394 Error::<T>::ExpiredCertificate
395 );
396
397 (
398 Certificate::X509(X509Certificate {
399 issuer_id: None,
400 serial: tbs_certificate.serial,
401 subject_common_name: tbs_certificate.subject_common_name,
402 subject_public_key_info: tbs_certificate.subject_public_key_info,
403 validity: tbs_certificate.validity,
404 raw: certificate,
405 issued_serials: BTreeSet::from([tbs_certificate.serial]),
406 nonce: U256::zero(),
407 }),
408 T::Weights::register_issuer_auto_id(),
409 )
410 }
411 RegisterAutoIdX509::Leaf {
412 issuer_id,
413 certificate,
414 signature_algorithm,
415 signature,
416 } => {
417 let mut issuer_auto_id =
418 AutoIds::<T>::get(issuer_id).ok_or(Error::<T>::UnknownIssuer)?;
419 let issuer_public_key_info =
420 issuer_auto_id.certificate.subject_public_key_info();
421
422 ensure!(
423 issuer_auto_id.certificate.is_valid_at(current_time),
424 Error::<T>::ExpiredCertificate
425 );
426
427 let tbs_certificate = decode_tbs_certificate(certificate.clone())
428 .ok_or(Error::<T>::InvalidCertificate)?;
429
430 let req = SignatureVerificationRequest {
431 public_key_info: issuer_public_key_info,
432 signature_algorithm,
433 data: certificate.0.clone(),
434 signature,
435 };
436 verify_signature(req).ok_or(Error::<T>::InvalidSignature)?;
437 ensure!(
438 tbs_certificate.validity.is_valid_at(current_time),
439 Error::<T>::ExpiredCertificate
440 );
441
442 ensure!(
443 !CertificateRevocationList::<T>::get(issuer_id).is_some_and(|serials| {
444 serials.iter().any(|s| {
445 *s == issuer_auto_id.certificate.serial()
446 || *s == tbs_certificate.serial
447 })
448 }),
449 Error::<T>::CertificateRevoked
450 );
451
452 issuer_auto_id
453 .certificate
454 .issue_certificate_serial::<T>(tbs_certificate.serial)?;
455
456 AutoIds::<T>::insert(issuer_id, issuer_auto_id);
457
458 (
459 Certificate::X509(X509Certificate {
460 issuer_id: Some(issuer_id),
461 serial: tbs_certificate.serial,
462 subject_common_name: tbs_certificate.subject_common_name,
463 subject_public_key_info: tbs_certificate.subject_public_key_info,
464 validity: tbs_certificate.validity,
465 raw: certificate,
466 issued_serials: BTreeSet::from([tbs_certificate.serial]),
467 nonce: U256::zero(),
468 }),
469 T::Weights::register_leaf_auto_id(),
470 )
471 }
472 },
473 };
474
475 let auto_id_identifier = certificate.derive_identifier();
476 let auto_id = AutoId { certificate };
477
478 ensure!(
479 !AutoIds::<T>::contains_key(auto_id_identifier),
480 Error::<T>::AutoIdIdentifierAlreadyExists
481 );
482
483 AutoIds::<T>::insert(auto_id_identifier, auto_id);
484
485 Self::deposit_event(Event::<T>::NewAutoIdRegistered(auto_id_identifier));
486 Ok(Some(weight).into())
487 }
488
489 fn do_renew_auto_id_certificate(
490 auto_id_identifier: Identifier,
491 req: RenewAutoId,
492 ) -> DispatchResultWithPostInfo {
493 let current_time = T::Time::now();
494 let auto_id = AutoIds::<T>::get(auto_id_identifier).ok_or(Error::<T>::UnknownAutoId)?;
495 let RenewAutoId::X509(req) = req;
496 let tbs_certificate = decode_tbs_certificate(req.certificate.clone())
497 .ok_or(Error::<T>::InvalidCertificate)?;
498
499 let (issuer_public_key_info, weight) = match req.issuer_id {
500 None => {
501 CertificateRevocationList::<T>::mutate(auto_id_identifier, |serials| {
503 serials
504 .get_or_insert_with(BTreeSet::new)
505 .insert(auto_id.certificate.serial());
506 });
507 (
508 auto_id.certificate.subject_public_key_info(),
509 T::Weights::renew_issuer_auto_id(),
510 )
511 }
512 Some(issuer_id) => {
513 let mut issuer_auto_id =
514 AutoIds::<T>::get(issuer_id).ok_or(Error::<T>::UnknownIssuer)?;
515 let issuer_public_key_info = issuer_auto_id.certificate.subject_public_key_info();
516 ensure!(
517 issuer_auto_id.certificate.is_valid_at(current_time),
518 Error::<T>::ExpiredCertificate
519 );
520 ensure!(
521 !CertificateRevocationList::<T>::get(issuer_id).is_some_and(|serials| {
522 serials.iter().any(|s| {
523 *s == issuer_auto_id.certificate.serial()
524 || *s == tbs_certificate.serial
525 })
526 }),
527 Error::<T>::CertificateRevoked
528 );
529
530 issuer_auto_id
531 .certificate
532 .issue_certificate_serial::<T>(tbs_certificate.serial)?;
533
534 CertificateRevocationList::<T>::mutate(issuer_id, |serials| {
536 serials
537 .get_or_insert_with(BTreeSet::new)
538 .insert(auto_id.certificate.serial());
539 });
540
541 AutoIds::<T>::insert(issuer_id, issuer_auto_id);
542 (issuer_public_key_info, T::Weights::renew_leaf_auto_id())
543 }
544 };
545
546 let signature_req = SignatureVerificationRequest {
547 public_key_info: issuer_public_key_info,
548 signature_algorithm: req.signature_algorithm,
549 data: req.certificate.0.clone(),
550 signature: req.signature,
551 };
552 verify_signature(signature_req).ok_or(Error::<T>::InvalidSignature)?;
553 ensure!(
554 tbs_certificate.validity.is_valid_at(current_time),
555 Error::<T>::ExpiredCertificate
556 );
557
558 ensure!(
559 auto_id.certificate.subject_public_key_info()
560 == tbs_certificate.subject_public_key_info,
561 Error::<T>::PublicKeyMismatch
562 );
563
564 let updated_certificate = Certificate::X509(X509Certificate {
565 issuer_id: req.issuer_id,
566 serial: tbs_certificate.serial,
567 subject_common_name: tbs_certificate.subject_common_name,
568 subject_public_key_info: tbs_certificate.subject_public_key_info,
569 validity: tbs_certificate.validity,
570 raw: req.certificate,
571 issued_serials: auto_id.certificate.issued_serials(),
572 nonce: auto_id.certificate.nonce(),
573 });
574
575 ensure!(
576 auto_id_identifier == updated_certificate.derive_identifier(),
577 Error::<T>::AutoIdIdentifierMismatch
578 );
579
580 let updated_auto_id = AutoId {
581 certificate: updated_certificate,
582 };
583
584 AutoIds::<T>::insert(auto_id_identifier, updated_auto_id);
585
586 Self::deposit_event(Event::<T>::AutoIdRenewed(auto_id_identifier));
587 Ok(Some(weight).into())
588 }
589
590 fn do_verify_signature(
591 auto_id: &AutoId,
592 signing_data: CertificateAction,
593 signature: Signature,
594 ) -> DispatchResult {
595 let Signature {
596 signature_algorithm,
597 value: signature,
598 } = signature;
599 let req = SignatureVerificationRequest {
600 public_key_info: auto_id.certificate.subject_public_key_info(),
601 signature_algorithm,
602 data: signing_data.encode(),
603 signature,
604 };
605
606 verify_signature(req).ok_or(Error::<T>::InvalidSignature)?;
607 Ok(())
608 }
609
610 fn do_revoke_certificate(
611 auto_id_identifier: Identifier,
612 signature: Signature,
613 ) -> DispatchResultWithPostInfo {
614 let auto_id = AutoIds::<T>::get(auto_id_identifier).ok_or(Error::<T>::UnknownAutoId)?;
615
616 let (issuer_id, mut issuer_auto_id, weight) = match auto_id.certificate.issuer_id() {
617 Some(issuer_id) => (
618 issuer_id,
619 AutoIds::<T>::get(issuer_id).ok_or(Error::<T>::UnknownIssuer)?,
620 T::Weights::revoke_leaf_auto_id(),
621 ),
622 None => (
624 auto_id_identifier,
625 auto_id.clone(),
626 T::Weights::revoke_issuer_auto_id(),
627 ),
628 };
629
630 ensure!(
631 !CertificateRevocationList::<T>::get(issuer_id).is_some_and(|serials| {
632 serials.iter().any(|s| {
633 *s == auto_id.certificate.serial() || *s == issuer_auto_id.certificate.serial()
634 })
635 }),
636 Error::<T>::CertificateAlreadyRevoked
637 );
638
639 Self::do_verify_signature(
640 &issuer_auto_id,
641 CertificateAction {
642 id: auto_id_identifier,
643 nonce: issuer_auto_id.certificate.nonce(),
644 action_type: CertificateActionType::RevokeCertificate,
645 },
646 signature,
647 )?;
648
649 CertificateRevocationList::<T>::mutate(issuer_id, |serials| {
650 serials
651 .get_or_insert_with(BTreeSet::new)
652 .insert(auto_id.certificate.serial());
653 });
654
655 issuer_auto_id.certificate.inc_nonce::<T>()?;
656 AutoIds::<T>::insert(issuer_id, issuer_auto_id);
657
658 Self::deposit_event(Event::<T>::CertificateRevoked(auto_id_identifier));
659 Ok(Some(weight).into())
660 }
661
662 fn do_deactivate_auto_id(
663 auto_id_identifier: Identifier,
664 signature: Signature,
665 ) -> DispatchResult {
666 let auto_id = AutoIds::<T>::get(auto_id_identifier).ok_or(Error::<T>::UnknownIssuer)?;
667 Self::do_verify_signature(
668 &auto_id,
669 CertificateAction {
670 id: auto_id_identifier,
671 nonce: auto_id.certificate.nonce(),
672 action_type: CertificateActionType::DeactivateAutoId,
673 },
674 signature,
675 )?;
676
677 AutoIds::<T>::remove(auto_id_identifier);
679
680 Self::deposit_event(Event::<T>::AutoIdDeactivated(auto_id_identifier));
681 Ok(())
682 }
683
684 fn max_register_auto_id_weight() -> Weight {
685 T::Weights::register_issuer_auto_id().max(T::Weights::register_leaf_auto_id())
686 }
687
688 fn max_revoke_auto_id_weight() -> Weight {
689 T::Weights::revoke_issuer_auto_id().max(T::Weights::revoke_leaf_auto_id())
690 }
691
692 fn max_renew_auto_id_weight() -> Weight {
693 T::Weights::renew_issuer_auto_id().max(T::Weights::renew_leaf_auto_id())
694 }
695}