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