@@ -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;
@@ -411,3 +415,119 @@ where
411415 <T as Builder >:: finalize ( self , signer)
412416 }
413417}
418+
419+ /// X.509 CRL builder
420+ pub struct CrlBuilder {
421+ tbs : TbsCertList ,
422+ }
423+
424+ impl CrlBuilder {
425+ /// Create a `CrlBuilder` with the given issuer and the given monotonic [`CrlNumber`]
426+ #[ cfg( feature = "std" ) ]
427+ pub fn new ( issuer : & Certificate , crl_number : CrlNumber ) -> der:: Result < Self > {
428+ let this_update = Time :: now ( ) ?;
429+ Self :: new_with_this_update ( issuer, crl_number, this_update)
430+ }
431+
432+ /// Create a `CrlBuilder` with the given issuer, a given monotonic [`CrlNumber`], and valid
433+ /// from the given `this_update` start validity date.
434+ pub fn new_with_this_update (
435+ issuer : & Certificate ,
436+ crl_number : CrlNumber ,
437+ this_update : Time ,
438+ ) -> der:: Result < Self > {
439+ // Replaced later when the finalize is called
440+ let signature_alg = AlgorithmIdentifier {
441+ oid : NULL_OID ,
442+ parameters : None ,
443+ } ;
444+
445+ let issuer_name = issuer. tbs_certificate . subject ( ) . clone ( ) ;
446+
447+ let mut crl_extensions = Extensions :: new ( ) ;
448+ crl_extensions. push ( crl_number. to_extension ( & issuer_name, & crl_extensions) ?) ;
449+ let aki = match issuer
450+ . tbs_certificate
451+ . get_extension :: < AuthorityKeyIdentifier > ( ) ?
452+ {
453+ Some ( ( _, aki) ) => aki,
454+ None => {
455+ let ski = SubjectKeyIdentifier :: try_from (
456+ issuer
457+ . tbs_certificate
458+ . subject_public_key_info ( )
459+ . owned_to_ref ( ) ,
460+ ) ?;
461+ AuthorityKeyIdentifier {
462+ // KeyIdentifier must be the same as subjectKeyIdentifier
463+ key_identifier : Some ( ski. 0 . clone ( ) ) ,
464+ // other fields must not be present.
465+ ..Default :: default ( )
466+ }
467+ }
468+ } ;
469+ crl_extensions. push ( aki. to_extension ( & issuer_name, & crl_extensions) ?) ;
470+
471+ let tbs = TbsCertList {
472+ version : Version :: V2 ,
473+ signature : signature_alg,
474+ issuer : issuer_name,
475+ this_update,
476+ next_update : None ,
477+ revoked_certificates : None ,
478+ crl_extensions : Some ( crl_extensions) ,
479+ } ;
480+
481+ Ok ( Self { tbs } )
482+ }
483+
484+ /// Make the CRL valid until the given `next_update`
485+ pub fn with_next_update ( mut self , next_update : Option < Time > ) -> Self {
486+ self . tbs . next_update = next_update;
487+ self
488+ }
489+
490+ /// Add certificates to the revocation list
491+ pub fn with_certificates < I > ( mut self , revoked : I ) -> Self
492+ where
493+ I : Iterator < Item = RevokedCert > ,
494+ {
495+ let certificates = self
496+ . tbs
497+ . revoked_certificates
498+ . get_or_insert_with ( vec:: Vec :: new) ;
499+
500+ let mut revoked: vec:: Vec < RevokedCert > = revoked. collect ( ) ;
501+ certificates. append ( & mut revoked) ;
502+
503+ self
504+ }
505+ }
506+
507+ impl Builder for CrlBuilder {
508+ type Output = CertificateList ;
509+
510+ fn finalize < S > ( & mut self , cert_signer : & S ) -> Result < vec:: Vec < u8 > >
511+ where
512+ S : Keypair + DynSignatureAlgorithmIdentifier ,
513+ S :: VerifyingKey : EncodePublicKey ,
514+ {
515+ self . tbs . signature = cert_signer. signature_algorithm_identifier ( ) ?;
516+
517+ self . tbs . to_der ( ) . map_err ( Error :: from)
518+ }
519+
520+ fn assemble < S > ( self , signature : BitString , _signer : & S ) -> Result < Self :: Output >
521+ where
522+ S : Keypair + DynSignatureAlgorithmIdentifier ,
523+ S :: VerifyingKey : EncodePublicKey ,
524+ {
525+ let signature_algorithm = self . tbs . signature . clone ( ) ;
526+
527+ Ok ( CertificateList {
528+ tbs_cert_list : self . tbs ,
529+ signature_algorithm,
530+ signature,
531+ } )
532+ }
533+ }
0 commit comments