99pub mod certificate;
1010pub mod ops;
1111pub mod policy;
12+ pub mod revocation;
1213pub mod trust_store;
1314pub mod types;
1415
@@ -30,6 +31,7 @@ use cryptography_x509::oid::{
3031use crate :: certificate:: cert_is_self_issued;
3132use crate :: ops:: { CryptoOps , VerificationCertificate } ;
3233use crate :: policy:: Policy ;
34+ use crate :: revocation:: CrlRevocationChecker ;
3335use crate :: trust_store:: Store ;
3436use crate :: types:: {
3537 DNSConstraint , DNSPattern , IPAddress , IPConstraint , RFC822Constraint , RFC822Name ,
@@ -44,6 +46,7 @@ pub enum ValidationErrorKind<'chain, B: CryptoOps> {
4446 reason : & ' static str ,
4547 } ,
4648 FatalError ( & ' static str ) ,
49+ RevocationNotDetermined ( String ) ,
4750 Other ( String ) ,
4851}
4952
@@ -95,6 +98,9 @@ impl<B: CryptoOps> Display for ValidationError<'_, B> {
9598 write ! ( f, "invalid extension: {oid}: {reason}" )
9699 }
97100 ValidationErrorKind :: FatalError ( err) => write ! ( f, "fatal error: {err}" ) ,
101+ ValidationErrorKind :: RevocationNotDetermined ( reason) => {
102+ write ! ( f, "unable to determine revocation status: {reason}" )
103+ }
98104 ValidationErrorKind :: Other ( err) => write ! ( f, "{err}" ) ,
99105 }
100106 }
@@ -306,9 +312,10 @@ pub fn verify<'chain, B: CryptoOps>(
306312 leaf : & VerificationCertificate < ' chain , B > ,
307313 intermediates : & [ VerificationCertificate < ' chain , B > ] ,
308314 policy : & Policy < ' _ , B > ,
315+ revocation_checker : Option < & ' _ CrlRevocationChecker < ' _ > > ,
309316 store : & Store < ' chain , B > ,
310317) -> ValidationResult < ' chain , Chain < ' chain , B > , B > {
311- let builder = ChainBuilder :: new ( intermediates, policy, store) ;
318+ let builder = ChainBuilder :: new ( intermediates, policy, revocation_checker , store) ;
312319
313320 let mut budget = Budget :: new ( ) ;
314321 builder. build_chain ( leaf, & mut budget)
@@ -317,6 +324,7 @@ pub fn verify<'chain, B: CryptoOps>(
317324struct ChainBuilder < ' a , ' chain , B : CryptoOps > {
318325 intermediates : & ' a [ VerificationCertificate < ' chain , B > ] ,
319326 policy : & ' a Policy < ' a , B > ,
327+ revocation_checker : Option < & ' a CrlRevocationChecker < ' a > > ,
320328 store : & ' a Store < ' chain , B > ,
321329}
322330
@@ -353,11 +361,13 @@ impl<'a, 'chain, B: CryptoOps> ChainBuilder<'a, 'chain, B> {
353361 fn new (
354362 intermediates : & ' a [ VerificationCertificate < ' chain , B > ] ,
355363 policy : & ' a Policy < ' a , B > ,
364+ revocation_checker : Option < & ' a CrlRevocationChecker < ' a > > ,
356365 store : & ' a Store < ' chain , B > ,
357366 ) -> Self {
358367 Self {
359368 intermediates,
360369 policy,
370+ revocation_checker,
361371 store,
362372 }
363373 }
@@ -464,6 +474,14 @@ impl<'a, 'chain, B: CryptoOps> ChainBuilder<'a, 'chain, B> {
464474 return Ok ( vec ! [ working_cert. clone( ) ] ) ;
465475 }
466476
477+ if let Some ( revocation_checker) = self . revocation_checker {
478+ if revocation_checker. is_revoked ( working_cert, self . policy ) ? {
479+ return Err ( ValidationError :: new ( ValidationErrorKind :: Other (
480+ "certificate revoked" . to_string ( ) ,
481+ ) ) ) ;
482+ }
483+ }
484+
467485 // Check that our current depth does not exceed our policy-configured
468486 // max depth. We do this after the root set check, since the depth
469487 // only measures the intermediate chain's length, not the root or leaf.
@@ -599,7 +617,8 @@ mod tests {
599617 use cryptography_x509:: certificate:: Certificate ;
600618 use cryptography_x509:: oid:: SUBJECT_ALTERNATIVE_NAME_OID ;
601619
602- use crate :: certificate:: tests:: PublicKeyErrorOps ;
620+ use crate :: certificate:: tests:: { crl_pem, PublicKeyErrorOps } ;
621+ use crate :: ops:: tests:: { crl, NullOps } ;
603622 use crate :: ops:: { CryptoOps , VerificationCertificate } ;
604623 use crate :: policy:: { Policy , PolicyDefinition , Subject } ;
605624 use crate :: trust_store:: Store ;
@@ -622,43 +641,27 @@ mod tests {
622641 "invalid extension: 2.5.29.17: duplicate extension"
623642 ) ;
624643
644+ let err = ValidationError :: < PublicKeyErrorOps > :: new (
645+ ValidationErrorKind :: RevocationNotDetermined ( "oops" . to_owned ( ) ) ,
646+ ) ;
647+ assert_eq ! (
648+ err. to_string( ) ,
649+ "unable to determine revocation status: oops"
650+ ) ;
651+
625652 let err =
626653 ValidationError :: < PublicKeyErrorOps > :: new ( ValidationErrorKind :: FatalError ( "oops" ) ) ;
627654 assert_eq ! ( err. to_string( ) , "fatal error: oops" ) ;
628655 }
629656
630- /// A `CryptoOps` whose public key extraction and signature verification
631- /// always succeed, so that `valid_issuer` can be driven to completion
632- /// without real cryptographic material.
633- struct NullOps ;
634-
635- impl CryptoOps for NullOps {
636- type Key = ( ) ;
637- type Err = ( ) ;
638- type CertificateExtra = ( ) ;
639- type PolicyExtra = ( ) ;
640-
641- fn public_key ( & self , _cert : & Certificate < ' _ > ) -> Result < Self :: Key , Self :: Err > {
642- Ok ( ( ) )
643- }
644-
645- fn verify_signed_by (
646- & self ,
647- _cert : & Certificate < ' _ > ,
648- _key : & Self :: Key ,
649- ) -> Result < ( ) , Self :: Err > {
650- Ok ( ( ) )
651- }
652-
653- fn clone_public_key ( _key : & Self :: Key ) -> Self :: Key { }
654-
655- fn clone_extra ( _extra : & Self :: CertificateExtra ) -> Self :: CertificateExtra { }
656- }
657-
658657 #[ test]
659658 fn test_clone ( ) {
660659 assert_eq ! ( NullOps :: clone_public_key( & ( ) ) , ( ) ) ;
661660 assert_eq ! ( NullOps :: clone_extra( & ( ) ) , ( ) ) ;
661+
662+ let crl_pem = crl_pem ( ) ;
663+ let crl = crl ( & crl_pem) ;
664+ assert ! ( NullOps . verify_crl_signed_by( & crl, & ( ) ) . is_ok( ) ) ;
662665 }
663666
664667 // A self-issued ("looping") CA certificate that is its own issuer.
@@ -706,7 +709,7 @@ qolIOwIgCaIgj9ipK0Q0p+45UJiq+L/ncrxsweJkFq/UYubzhX0=
706709 PolicyDefinition :: server ( NullOps , subject, time, Some ( u8:: MAX ) , None , None ) . unwrap ( ) ;
707710 let policy = Policy :: new ( & policy_def, ( ) ) ;
708711
709- let builder = ChainBuilder :: new ( & intermediates, & policy, & store) ;
712+ let builder = ChainBuilder :: new ( & intermediates, & policy, None , & store) ;
710713 let mut budget = Budget {
711714 name_constraint_checks : usize:: MAX ,
712715 signature_checks : usize:: MAX ,
0 commit comments