5
5
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
6
*/
7
7
8
+ use std:: sync:: Arc ;
9
+
8
10
use chrono:: NaiveDateTime ;
9
11
use pki_types:: { CertificateDer , UnixTime } ;
10
12
use rustls:: {
@@ -14,19 +16,21 @@ use rustls::{
14
16
15
17
use crate :: {
16
18
mbedtls_err_into_rustls_err, mbedtls_err_into_rustls_err_with_error_msg, rustls_cert_to_mbedtls_cert,
17
- verify_certificates_active, verify_tls_signature,
19
+ verify_certificates_active, verify_tls_signature, CertActiveCheck ,
18
20
} ;
19
21
20
- /// A `rustls` `ClientCertVerifier` implemented using the PKI functionality of
22
+ /// A [ `rustls`] [ `ClientCertVerifier`] implemented using the PKI functionality of
21
23
/// `mbedtls`
22
24
#[ derive( Clone ) ]
23
25
pub struct MbedTlsClientCertVerifier {
24
26
trusted_cas : mbedtls:: alloc:: List < mbedtls:: x509:: Certificate > ,
25
- root_subjects : Vec < rustls:: DistinguishedName > ,
27
+ root_subjects : Vec < DistinguishedName > ,
28
+ verify_callback : Option < Arc < dyn mbedtls:: x509:: VerifyCallback + ' static > > ,
29
+ cert_active_check : CertActiveCheck ,
26
30
}
27
31
28
32
impl MbedTlsClientCertVerifier {
29
- /// Constructs a new `MbedTlsClientCertVerifier` object given the provided trusted certificate authority
33
+ /// Constructs a new [ `MbedTlsClientCertVerifier`] object given the provided trusted certificate authority
30
34
/// certificates.
31
35
///
32
36
/// Returns an error if any of the certificates are invalid.
@@ -40,7 +44,7 @@ impl MbedTlsClientCertVerifier {
40
44
Self :: new_from_mbedtls_trusted_cas ( trusted_cas)
41
45
}
42
46
43
- /// Constructs a new `MbedTlsClientCertVerifier` object given the provided trusted certificate authority
47
+ /// Constructs a new [ `MbedTlsClientCertVerifier`] object given the provided trusted certificate authority
44
48
/// certificates.
45
49
pub fn new_from_mbedtls_trusted_cas (
46
50
trusted_cas : mbedtls:: alloc:: List < mbedtls:: x509:: Certificate > ,
@@ -49,7 +53,12 @@ impl MbedTlsClientCertVerifier {
49
53
for ca in trusted_cas. iter ( ) {
50
54
root_subjects. push ( DistinguishedName :: from ( ca. subject_raw ( ) ?) ) ;
51
55
}
52
- Ok ( Self { trusted_cas, root_subjects } )
56
+ Ok ( Self {
57
+ trusted_cas,
58
+ root_subjects,
59
+ verify_callback : None ,
60
+ cert_active_check : CertActiveCheck :: default ( ) ,
61
+ } )
53
62
}
54
63
55
64
/// The certificate authority certificates used to construct this object
@@ -62,6 +71,28 @@ impl MbedTlsClientCertVerifier {
62
71
pub fn root_subjects ( & self ) -> & [ DistinguishedName ] {
63
72
self . root_subjects . as_ref ( )
64
73
}
74
+
75
+ /// Retrieves the verification callback function set for the certificate verification process.
76
+ pub fn verify_callback ( & self ) -> Option < Arc < dyn mbedtls:: x509:: VerifyCallback + ' static > > {
77
+ self . verify_callback . clone ( )
78
+ }
79
+
80
+ /// Sets the verification callback for mbedtls certificate verification process,
81
+ ///
82
+ /// This callback function allows you to add logic at end of mbedtls verification before returning.
83
+ pub fn set_verify_callback ( & mut self , callback : Option < Arc < dyn mbedtls:: x509:: VerifyCallback + ' static > > ) {
84
+ self . verify_callback = callback;
85
+ }
86
+
87
+ /// Getter for [`CertActiveCheck`]
88
+ pub fn cert_active_check ( & self ) -> & CertActiveCheck {
89
+ & self . cert_active_check
90
+ }
91
+
92
+ /// Setter for [`CertActiveCheck`]
93
+ pub fn set_cert_active_check ( & mut self , check : CertActiveCheck ) {
94
+ self . cert_active_check = check;
95
+ }
65
96
}
66
97
67
98
impl ClientCertVerifier for MbedTlsClientCertVerifier {
@@ -74,7 +105,7 @@ impl ClientCertVerifier for MbedTlsClientCertVerifier {
74
105
end_entity : & CertificateDer ,
75
106
intermediates : & [ CertificateDer ] ,
76
107
now : UnixTime ,
77
- ) -> Result < rustls :: server :: danger :: ClientCertVerified , rustls:: Error > {
108
+ ) -> Result < ClientCertVerified , rustls:: Error > {
78
109
let now = NaiveDateTime :: from_timestamp_opt (
79
110
now. as_secs ( )
80
111
. try_into ( )
@@ -92,11 +123,25 @@ impl ClientCertVerifier for MbedTlsClientCertVerifier {
92
123
. into_iter ( )
93
124
. collect ( ) ;
94
125
95
- verify_certificates_active ( chain. iter ( ) . map ( |c| & * * c) , now) ?;
126
+ verify_certificates_active ( chain. iter ( ) . map ( |c| & * * c) , now, & self . cert_active_check ) ?;
96
127
97
128
let mut error_msg = String :: default ( ) ;
98
- mbedtls:: x509:: Certificate :: verify ( & chain, & self . trusted_cas , None , Some ( & mut error_msg) )
99
- . map_err ( |e| mbedtls_err_into_rustls_err_with_error_msg ( e, & error_msg) ) ?;
129
+ match & self . verify_callback {
130
+ Some ( callback) => {
131
+ let callback = Arc :: clone ( callback) ;
132
+ mbedtls:: x509:: Certificate :: verify_with_callback (
133
+ & chain,
134
+ & self . trusted_cas ,
135
+ None ,
136
+ Some ( & mut error_msg) ,
137
+ move |cert : & mbedtls:: x509:: Certificate , depth : i32 , flags : & mut mbedtls:: x509:: VerifyError | {
138
+ callback ( cert, depth, flags)
139
+ } ,
140
+ )
141
+ }
142
+ None => mbedtls:: x509:: Certificate :: verify ( & chain, & self . trusted_cas , None , Some ( & mut error_msg) ) ,
143
+ }
144
+ . map_err ( |e| mbedtls_err_into_rustls_err_with_error_msg ( e, & error_msg) ) ?;
100
145
101
146
Ok ( ClientCertVerified :: assertion ( ) )
102
147
}
@@ -272,4 +317,74 @@ mod tests {
272
317
rustls:: Error :: InvalidCertificate ( CertificateError :: Expired )
273
318
) ;
274
319
}
320
+
321
+ #[ test]
322
+ fn client_cert_verifier_active_check ( ) {
323
+ let cert_chain = get_chain ( include_bytes ! ( "../test-data/rsa/client.fullchain" ) ) ;
324
+ let trusted_cas = [ CertificateDer :: from ( include_bytes ! ( "../test-data/rsa/ca.der" ) . to_vec ( ) ) ] ;
325
+
326
+ let mut verifier = MbedTlsClientCertVerifier :: new ( trusted_cas. iter ( ) ) . unwrap ( ) ;
327
+ let now = SystemTime :: from ( DateTime :: parse_from_rfc3339 ( "2052-11-26T12:00:00+00:00" ) . unwrap ( ) ) ;
328
+ let now = UnixTime :: since_unix_epoch (
329
+ now. duration_since ( SystemTime :: UNIX_EPOCH )
330
+ . unwrap ( ) ,
331
+ ) ;
332
+
333
+ assert_eq ! (
334
+ verifier
335
+ . verify_client_cert( & cert_chain[ 0 ] , & cert_chain[ 1 ..] , now)
336
+ . unwrap_err( ) ,
337
+ rustls:: Error :: InvalidCertificate ( CertificateError :: Expired )
338
+ ) ;
339
+ verifier. set_cert_active_check ( crate :: CertActiveCheck { ignore_expired : true , ignore_not_active_yet : false } ) ;
340
+
341
+ assert ! ( verifier
342
+ . verify_client_cert( & cert_chain[ 0 ] , & cert_chain[ 1 ..] , now)
343
+ . is_ok( ) ) ;
344
+
345
+ let now = SystemTime :: from ( DateTime :: parse_from_rfc3339 ( "2002-11-26T12:00:00+00:00" ) . unwrap ( ) ) ;
346
+ let now = UnixTime :: since_unix_epoch (
347
+ now. duration_since ( SystemTime :: UNIX_EPOCH )
348
+ . unwrap ( ) ,
349
+ ) ;
350
+ assert_eq ! (
351
+ verifier
352
+ . verify_client_cert( & cert_chain[ 0 ] , & cert_chain[ 1 ..] , now)
353
+ . unwrap_err( ) ,
354
+ rustls:: Error :: InvalidCertificate ( CertificateError :: NotValidYet )
355
+ ) ;
356
+ verifier. set_cert_active_check ( crate :: CertActiveCheck { ignore_expired : false , ignore_not_active_yet : true } ) ;
357
+
358
+ assert ! ( verifier
359
+ . verify_client_cert( & cert_chain[ 0 ] , & cert_chain[ 1 ..] , now)
360
+ . is_ok( ) ) ;
361
+ }
362
+
363
+ #[ test]
364
+ fn client_cert_verifier_callback ( ) {
365
+ let mut cert_chain = get_chain ( include_bytes ! ( "../test-data/rsa/client.fullchain" ) ) ;
366
+ cert_chain. remove ( 1 ) ;
367
+ let trusted_cas = [ CertificateDer :: from ( include_bytes ! ( "../test-data/rsa/ca.der" ) . to_vec ( ) ) ] ;
368
+
369
+ let mut verifier = MbedTlsClientCertVerifier :: new ( trusted_cas. iter ( ) ) . unwrap ( ) ;
370
+ assert ! ( verifier. verify_callback( ) . is_none( ) ) ;
371
+ let now = SystemTime :: from ( DateTime :: parse_from_rfc3339 ( "2023-11-26T12:00:00+00:00" ) . unwrap ( ) ) ;
372
+ let now = UnixTime :: since_unix_epoch (
373
+ now. duration_since ( SystemTime :: UNIX_EPOCH )
374
+ . unwrap ( ) ,
375
+ ) ;
376
+
377
+ let verify_res = verifier. verify_client_cert ( & cert_chain[ 0 ] , & cert_chain[ 1 ..] , now) ;
378
+ assert ! ( matches!( verify_res, Err ( rustls:: Error :: InvalidCertificate ( _) ) ) ) ;
379
+
380
+ verifier. set_verify_callback ( Some ( Arc :: new (
381
+ move |_cert : & mbedtls:: x509:: Certificate , _depth : i32 , flags : & mut mbedtls:: x509:: VerifyError | {
382
+ flags. remove ( mbedtls:: x509:: VerifyError :: CERT_NOT_TRUSTED ) ;
383
+ Ok ( ( ) )
384
+ } ,
385
+ ) ) ) ;
386
+ assert ! ( verifier. verify_callback( ) . is_some( ) ) ;
387
+ let verify_res = verifier. verify_client_cert ( & cert_chain[ 0 ] , & cert_chain[ 1 ..] , now) ;
388
+ assert ! ( verify_res. is_ok( ) , "{:?}" , verify_res) ;
389
+ }
275
390
}
0 commit comments