Skip to main content

pallet_auto_id/
lib.rs

1// Copyright (C) 2023 Subspace Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// 	http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16//! Pallet AutoID
17
18#![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
47/// Unique AutoId identifier.
48pub type Identifier = H256;
49
50/// Serial issued by the subject.
51pub type Serial = U256;
52
53/// X509 certificate.
54#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
55pub struct X509Certificate {
56    /// Issuer identifier of this certificate.
57    pub issuer_id: Option<Identifier>,
58    /// Serial number for this certificate
59    pub serial: U256,
60    /// Subject common name of the certificate.
61    pub subject_common_name: Vec<u8>,
62    /// Der encoded certificate's subject's public key info.
63    pub subject_public_key_info: DerVec,
64    /// Validity of the certificate
65    pub validity: Validity,
66    /// Der encoded full X509 certificate.
67    pub raw: DerVec,
68    /// A list of all certificate serials issues by the subject.
69    /// Serial of root certificate is included as well.
70    pub issued_serials: BTreeSet<Serial>,
71    /// Certificate action nonce.
72    pub nonce: U256,
73}
74
75/// Certificate associated with AutoId.
76#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
77pub enum Certificate {
78    X509(X509Certificate),
79}
80
81impl Certificate {
82    /// Returns the subject distinguished name.
83    #[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    /// Returns the subject public key info.
91    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    /// Checks if the certificate is valid at this time.
129    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    /// Deterministically derives an identifier from the certificate.
136    ///
137    /// The identifier is derived by hashing the subject common name of the certificate.
138    /// If the certificate is a leaf certificate, the issuer identifier is combined with the subject common name.
139    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                    // Root certificate
150                    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/// A representation of AutoId
176#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
177pub struct AutoId {
178    /// Certificate associated with this AutoId.
179    pub certificate: Certificate,
180}
181
182/// Type holds X509 certificate details used to register an AutoId.
183#[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/// Request to renew AutoId.
199#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, DecodeWithMemTracking)]
200pub enum RenewAutoId {
201    X509(RenewX509Certificate),
202}
203
204/// Type holds X509 certificate details used to renew.
205#[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/// Signature holds algorithm used and the signature value.
214#[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/// Request to register a new AutoId.
221#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone, DecodeWithMemTracking)]
222pub enum RegisterAutoId {
223    X509(RegisterAutoIdX509),
224}
225
226/// Specific action type taken by the subject of the Certificate.
227#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
228pub enum CertificateActionType {
229    RevokeCertificate,
230    DeactivateAutoId,
231}
232
233/// Signing data used to verify the certificate action.
234#[derive(Debug, Decode, Encode, TypeInfo, PartialEq, Eq, Clone)]
235pub struct CertificateAction {
236    /// On which AutoId the action is taken.
237    pub id: Identifier,
238    /// Current nonce of the certificate.
239    pub nonce: U256,
240    /// Type of action taken.
241    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    /// Stores the auto id identifier against an AutoId.
264    #[pallet::storage]
265    pub(super) type AutoIds<T> = StorageMap<_, Identity, Identifier, AutoId, OptionQuery>;
266
267    /// Stores list of revoked certificates.
268    ///
269    /// It maps the issuer's identifier to the list of revoked serial numbers of certificates. Before accepting
270    /// the certificate, external entities should check if the certificate or its issuer has been revoked.
271    #[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        /// Issuer auto id does not exist.
278        UnknownIssuer,
279        /// Unknown AutoId identifier.
280        UnknownAutoId,
281        /// Certificate is invalid,
282        InvalidCertificate,
283        /// Invalid signature.
284        InvalidSignature,
285        /// Certificate serial already issued.
286        CertificateSerialAlreadyIssued,
287        /// Certificate expired.
288        ExpiredCertificate,
289        /// Certificate revoked.
290        CertificateRevoked,
291        /// Certificate already revoked.
292        CertificateAlreadyRevoked,
293        /// Nonce overflow.
294        NonceOverflow,
295        /// Identifier already exists.
296        AutoIdIdentifierAlreadyExists,
297        /// Identifier mismatch.
298        AutoIdIdentifierMismatch,
299        /// Public key mismatch.
300        PublicKeyMismatch,
301    }
302
303    #[pallet::event]
304    #[pallet::generate_deposit(pub (super) fn deposit_event)]
305    pub enum Event<T: Config> {
306        /// Emits when a new AutoId is registered.
307        NewAutoIdRegistered(Identifier),
308        /// Emits when a Certificate associated with AutoId is revoked.
309        CertificateRevoked(Identifier),
310        /// Emits when an AutoId is deactivated.
311        AutoIdDeactivated(Identifier),
312        /// Emits when an AutoId is renewed.
313        AutoIdRenewed(Identifier),
314    }
315
316    #[pallet::call]
317    impl<T: Config> Pallet<T> {
318        /// Registers a new AutoId after validating the provided certificate.
319        #[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        /// Revokes a certificate associated with given AutoId.
330        ///
331        /// The signature is verified against the issuer's public key.
332        #[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        /// Deactivates a given AutoId.
344        #[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        /// Renews a given AutoId.
357        #[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                // revoke old certificate serial
500                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                // revoke old certificate serial
533                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            // self revoke
621            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        // TODO: remove all the AutoIds registered using leaf certificates if this is the issuer.
676        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}