@@ -13,9 +13,13 @@ use spki::{
1313use crate :: {
1414 AlgorithmIdentifier , SubjectPublicKeyInfo ,
1515 certificate:: { Certificate , TbsCertificate , Version } ,
16- ext:: { AsExtension , Extensions } ,
16+ crl:: { CertificateList , RevokedCert , TbsCertList } ,
17+ ext:: {
18+ AsExtension , Extensions ,
19+ pkix:: { AuthorityKeyIdentifier , CrlNumber , SubjectKeyIdentifier } ,
20+ } ,
1721 serial_number:: SerialNumber ,
18- time:: Validity ,
22+ time:: { Time , Validity } ,
1923} ;
2024
2125pub mod profile;
@@ -564,3 +568,119 @@ where
564568 <T as Builder >:: finalize ( self , signer)
565569 }
566570}
571+
572+ /// X.509 CRL builder
573+ pub struct CrlBuilder {
574+ tbs : TbsCertList ,
575+ }
576+
577+ impl CrlBuilder {
578+ /// Create a `CrlBuilder` with the given issuer and the given monotonic [`CrlNumber`]
579+ #[ cfg( feature = "std" ) ]
580+ pub fn new ( issuer : & Certificate , crl_number : CrlNumber ) -> der:: Result < Self > {
581+ let this_update = Time :: now ( ) ?;
582+ Self :: new_with_this_update ( issuer, crl_number, this_update)
583+ }
584+
585+ /// Create a `CrlBuilder` with the given issuer, a given monotonic [`CrlNumber`], and valid
586+ /// from the given `this_update` start validity date.
587+ pub fn new_with_this_update (
588+ issuer : & Certificate ,
589+ crl_number : CrlNumber ,
590+ this_update : Time ,
591+ ) -> der:: Result < Self > {
592+ // Replaced later when the finalize is called
593+ let signature_alg = AlgorithmIdentifier {
594+ oid : NULL_OID ,
595+ parameters : None ,
596+ } ;
597+
598+ let issuer_name = issuer. tbs_certificate . subject ( ) . clone ( ) ;
599+
600+ let mut crl_extensions = Extensions :: new ( ) ;
601+ crl_extensions. push ( crl_number. to_extension ( & issuer_name, & crl_extensions) ?) ;
602+ let aki = match issuer
603+ . tbs_certificate
604+ . get_extension :: < AuthorityKeyIdentifier > ( ) ?
605+ {
606+ Some ( ( _, aki) ) => aki,
607+ None => {
608+ let ski = SubjectKeyIdentifier :: try_from (
609+ issuer
610+ . tbs_certificate
611+ . subject_public_key_info ( )
612+ . owned_to_ref ( ) ,
613+ ) ?;
614+ AuthorityKeyIdentifier {
615+ // KeyIdentifier must be the same as subjectKeyIdentifier
616+ key_identifier : Some ( ski. 0 . clone ( ) ) ,
617+ // other fields must not be present.
618+ ..Default :: default ( )
619+ }
620+ }
621+ } ;
622+ crl_extensions. push ( aki. to_extension ( & issuer_name, & crl_extensions) ?) ;
623+
624+ let tbs = TbsCertList {
625+ version : Version :: V2 ,
626+ signature : signature_alg,
627+ issuer : issuer_name,
628+ this_update,
629+ next_update : None ,
630+ revoked_certificates : None ,
631+ crl_extensions : Some ( crl_extensions) ,
632+ } ;
633+
634+ Ok ( Self { tbs } )
635+ }
636+
637+ /// Make the CRL valid until the given `next_update`
638+ pub fn with_next_update ( mut self , next_update : Option < Time > ) -> Self {
639+ self . tbs . next_update = next_update;
640+ self
641+ }
642+
643+ /// Add certificates to the revocation list
644+ pub fn with_certificates < I > ( mut self , revoked : I ) -> Self
645+ where
646+ I : Iterator < Item = RevokedCert > ,
647+ {
648+ let certificates = self
649+ . tbs
650+ . revoked_certificates
651+ . get_or_insert_with ( vec:: Vec :: new) ;
652+
653+ let mut revoked: vec:: Vec < RevokedCert > = revoked. collect ( ) ;
654+ certificates. append ( & mut revoked) ;
655+
656+ self
657+ }
658+ }
659+
660+ impl Builder for CrlBuilder {
661+ type Output = CertificateList ;
662+
663+ fn finalize < S > ( & mut self , cert_signer : & S ) -> Result < vec:: Vec < u8 > >
664+ where
665+ S : Keypair + DynSignatureAlgorithmIdentifier ,
666+ S :: VerifyingKey : EncodePublicKey ,
667+ {
668+ self . tbs . signature = cert_signer. signature_algorithm_identifier ( ) ?;
669+
670+ self . tbs . to_der ( ) . map_err ( Error :: from)
671+ }
672+
673+ fn assemble < S > ( self , signature : BitString , _signer : & S ) -> Result < Self :: Output >
674+ where
675+ S : Keypair + DynSignatureAlgorithmIdentifier ,
676+ S :: VerifyingKey : EncodePublicKey ,
677+ {
678+ let signature_algorithm = self . tbs . signature . clone ( ) ;
679+
680+ Ok ( CertificateList {
681+ tbs_cert_list : self . tbs ,
682+ signature_algorithm,
683+ signature,
684+ } )
685+ }
686+ }
0 commit comments