rustls/webpki/client_verifier.rs
1use alloc::sync::Arc;
2use alloc::vec::Vec;
3
4use pki_types::{CertificateDer, CertificateRevocationListDer, UnixTime};
5use webpki::{CertRevocationList, ExpirationPolicy, RevocationCheckDepth, UnknownStatusPolicy};
6
7use super::{pki_error, VerifierBuilderError};
8#[cfg(doc)]
9use crate::crypto;
10use crate::crypto::{CryptoProvider, WebPkiSupportedAlgorithms};
11#[cfg(doc)]
12use crate::server::ServerConfig;
13use crate::verify::{
14 ClientCertVerified, ClientCertVerifier, DigitallySignedStruct, HandshakeSignatureValid,
15 NoClientAuth,
16};
17use crate::webpki::parse_crls;
18use crate::webpki::verify::{verify_tls12_signature, verify_tls13_signature, ParsedCertificate};
19#[cfg(doc)]
20use crate::ConfigBuilder;
21use crate::{DistinguishedName, Error, RootCertStore, SignatureScheme};
22
23/// A builder for configuring a `webpki` client certificate verifier.
24///
25/// For more information, see the [`WebPkiClientVerifier`] documentation.
26#[derive(Debug, Clone)]
27pub struct ClientCertVerifierBuilder {
28 roots: Arc<RootCertStore>,
29 root_hint_subjects: Vec<DistinguishedName>,
30 crls: Vec<CertificateRevocationListDer<'static>>,
31 revocation_check_depth: RevocationCheckDepth,
32 unknown_revocation_policy: UnknownStatusPolicy,
33 revocation_expiration_policy: ExpirationPolicy,
34 anon_policy: AnonymousClientPolicy,
35 supported_algs: WebPkiSupportedAlgorithms,
36}
37
38impl ClientCertVerifierBuilder {
39 pub(crate) fn new(
40 roots: Arc<RootCertStore>,
41 supported_algs: WebPkiSupportedAlgorithms,
42 ) -> Self {
43 Self {
44 root_hint_subjects: roots.subjects(),
45 roots,
46 crls: Vec::new(),
47 anon_policy: AnonymousClientPolicy::Deny,
48 revocation_check_depth: RevocationCheckDepth::Chain,
49 unknown_revocation_policy: UnknownStatusPolicy::Deny,
50 revocation_expiration_policy: ExpirationPolicy::Ignore,
51 supported_algs,
52 }
53 }
54
55 /// Clear the list of trust anchor hint subjects.
56 ///
57 /// By default, the client cert verifier will use the subjects provided by the root cert
58 /// store configured for client authentication. Calling this function will remove these
59 /// hint subjects, indicating the client should make a free choice of which certificate
60 /// to send.
61 ///
62 /// See [`ClientCertVerifier::root_hint_subjects`] for more information on
63 /// circumstances where you may want to clear the default hint subjects.
64 pub fn clear_root_hint_subjects(mut self) -> Self {
65 self.root_hint_subjects = Vec::default();
66 self
67 }
68
69 /// Add additional [`DistinguishedName`]s to the list of trust anchor hint subjects.
70 ///
71 /// By default, the client cert verifier will use the subjects provided by the root cert
72 /// store configured for client authentication. Calling this function will add to these
73 /// existing hint subjects. Calling this function with empty `subjects` will have no
74 /// effect.
75 ///
76 /// See [`ClientCertVerifier::root_hint_subjects`] for more information on
77 /// circumstances where you may want to override the default hint subjects.
78 pub fn add_root_hint_subjects(
79 mut self,
80 subjects: impl IntoIterator<Item = DistinguishedName>,
81 ) -> Self {
82 self.root_hint_subjects.extend(subjects);
83 self
84 }
85
86 /// Verify the revocation state of presented client certificates against the provided
87 /// certificate revocation lists (CRLs). Calling `with_crls` multiple times appends the
88 /// given CRLs to the existing collection.
89 ///
90 /// By default all certificates in the verified chain built from the presented client
91 /// certificate to a trust anchor will have their revocation status checked. Calling
92 /// [`only_check_end_entity_revocation`][Self::only_check_end_entity_revocation] will
93 /// change this behavior to only check the end entity client certificate.
94 ///
95 /// By default if a certificate's revocation status can not be determined using the
96 /// configured CRLs, it will be treated as an error. Calling
97 /// [`allow_unknown_revocation_status`][Self::allow_unknown_revocation_status] will change
98 /// this behavior to allow unknown revocation status.
99 pub fn with_crls(
100 mut self,
101 crls: impl IntoIterator<Item = CertificateRevocationListDer<'static>>,
102 ) -> Self {
103 self.crls.extend(crls);
104 self
105 }
106
107 /// Only check the end entity certificate revocation status when using CRLs.
108 ///
109 /// If CRLs are provided using [`with_crls`][Self::with_crls] only check the end entity
110 /// certificate's revocation status. Overrides the default behavior of checking revocation
111 /// status for each certificate in the verified chain built to a trust anchor
112 /// (excluding the trust anchor itself).
113 ///
114 /// If no CRLs are provided then this setting has no effect. Neither the end entity certificate
115 /// or any intermediates will have revocation status checked.
116 pub fn only_check_end_entity_revocation(mut self) -> Self {
117 self.revocation_check_depth = RevocationCheckDepth::EndEntity;
118 self
119 }
120
121 /// Allow unauthenticated clients to connect.
122 ///
123 /// Clients that offer a client certificate issued by a trusted root, and clients that offer no
124 /// client certificate will be allowed to connect.
125 pub fn allow_unauthenticated(mut self) -> Self {
126 self.anon_policy = AnonymousClientPolicy::Allow;
127 self
128 }
129
130 /// Allow unknown certificate revocation status when using CRLs.
131 ///
132 /// If CRLs are provided with [`with_crls`][Self::with_crls] and it isn't possible to
133 /// determine the revocation status of a certificate, do not treat it as an error condition.
134 /// Overrides the default behavior where unknown revocation status is considered an error.
135 ///
136 /// If no CRLs are provided then this setting has no effect as revocation status checks
137 /// are not performed.
138 pub fn allow_unknown_revocation_status(mut self) -> Self {
139 self.unknown_revocation_policy = UnknownStatusPolicy::Allow;
140 self
141 }
142
143 /// Enforce the CRL nextUpdate field (i.e. expiration)
144 ///
145 /// If CRLs are provided with [`with_crls`][Self::with_crls] and the verification time is
146 /// beyond the time in the CRL nextUpdate field, it is expired and treated as an error condition.
147 /// Overrides the default behavior where expired CRLs are not treated as an error condition.
148 ///
149 /// If no CRLs are provided then this setting has no effect as revocation status checks
150 /// are not performed.
151 pub fn enforce_revocation_expiration(mut self) -> Self {
152 self.revocation_expiration_policy = ExpirationPolicy::Enforce;
153 self
154 }
155
156 /// Build a client certificate verifier. The built verifier will be used for the server to offer
157 /// client certificate authentication, to control how offered client certificates are validated,
158 /// and to determine what to do with anonymous clients that do not respond to the client
159 /// certificate authentication offer with a client certificate.
160 ///
161 /// If `with_signature_verification_algorithms` was not called on the builder, a default set of
162 /// signature verification algorithms is used, controlled by the selected [`CryptoProvider`].
163 ///
164 /// Once built, the provided `Arc<dyn ClientCertVerifier>` can be used with a Rustls
165 /// [`ServerConfig`] to configure client certificate validation using
166 /// [`with_client_cert_verifier`][ConfigBuilder<ClientConfig, WantsVerifier>::with_client_cert_verifier].
167 ///
168 /// # Errors
169 /// This function will return a [`VerifierBuilderError`] if:
170 /// 1. No trust anchors have been provided.
171 /// 2. DER encoded CRLs have been provided that can not be parsed successfully.
172 pub fn build(self) -> Result<Arc<dyn ClientCertVerifier>, VerifierBuilderError> {
173 if self.roots.is_empty() {
174 return Err(VerifierBuilderError::NoRootAnchors);
175 }
176
177 Ok(Arc::new(WebPkiClientVerifier::new(
178 self.roots,
179 self.root_hint_subjects,
180 parse_crls(self.crls)?,
181 self.revocation_check_depth,
182 self.unknown_revocation_policy,
183 self.revocation_expiration_policy,
184 self.anon_policy,
185 self.supported_algs,
186 )))
187 }
188}
189
190/// A client certificate verifier that uses the `webpki` crate[^1] to perform client certificate
191/// validation.
192///
193/// It must be created via the [`WebPkiClientVerifier::builder()`] or
194/// [`WebPkiClientVerifier::builder_with_provider()`] functions.
195///
196/// Once built, the provided `Arc<dyn ClientCertVerifier>` can be used with a Rustls [`ServerConfig`]
197/// to configure client certificate validation using [`with_client_cert_verifier`][ConfigBuilder<ClientConfig, WantsVerifier>::with_client_cert_verifier].
198///
199/// Example:
200///
201/// To require all clients present a client certificate issued by a trusted CA:
202/// ```no_run
203/// # #[cfg(any(feature = "ring", feature = "aws_lc_rs"))] {
204/// # use rustls::RootCertStore;
205/// # use rustls::server::WebPkiClientVerifier;
206/// # let roots = RootCertStore::empty();
207/// let client_verifier = WebPkiClientVerifier::builder(roots.into())
208/// .build()
209/// .unwrap();
210/// # }
211/// ```
212///
213/// Or, to allow clients presenting a client certificate authenticated by a trusted CA, or
214/// anonymous clients that present no client certificate:
215/// ```no_run
216/// # #[cfg(any(feature = "ring", feature = "aws_lc_rs"))] {
217/// # use rustls::RootCertStore;
218/// # use rustls::server::WebPkiClientVerifier;
219/// # let roots = RootCertStore::empty();
220/// let client_verifier = WebPkiClientVerifier::builder(roots.into())
221/// .allow_unauthenticated()
222/// .build()
223/// .unwrap();
224/// # }
225/// ```
226///
227/// If you wish to disable advertising client authentication:
228/// ```no_run
229/// # use rustls::RootCertStore;
230/// # use rustls::server::WebPkiClientVerifier;
231/// # let roots = RootCertStore::empty();
232/// let client_verifier = WebPkiClientVerifier::no_client_auth();
233/// ```
234///
235/// You can also configure the client verifier to check for certificate revocation with
236/// client certificate revocation lists (CRLs):
237/// ```no_run
238/// # #[cfg(any(feature = "ring", feature = "aws_lc_rs"))] {
239/// # use rustls::RootCertStore;
240/// # use rustls::server::{WebPkiClientVerifier};
241/// # let roots = RootCertStore::empty();
242/// # let crls = Vec::new();
243/// let client_verifier = WebPkiClientVerifier::builder(roots.into())
244/// .with_crls(crls)
245/// .build()
246/// .unwrap();
247/// # }
248/// ```
249///
250/// [^1]: <https://github.com/rustls/webpki>
251#[derive(Debug)]
252pub struct WebPkiClientVerifier {
253 roots: Arc<RootCertStore>,
254 root_hint_subjects: Vec<DistinguishedName>,
255 crls: Vec<CertRevocationList<'static>>,
256 revocation_check_depth: RevocationCheckDepth,
257 unknown_revocation_policy: UnknownStatusPolicy,
258 revocation_expiration_policy: ExpirationPolicy,
259 anonymous_policy: AnonymousClientPolicy,
260 supported_algs: WebPkiSupportedAlgorithms,
261}
262
263impl WebPkiClientVerifier {
264 /// Create a builder for the `webpki` client certificate verifier configuration using
265 /// the [process-default `CryptoProvider`][CryptoProvider#using-the-per-process-default-cryptoprovider].
266 ///
267 /// Client certificate authentication will be offered by the server, and client certificates
268 /// will be verified using the trust anchors found in the provided `roots`. If you
269 /// wish to disable client authentication use [`WebPkiClientVerifier::no_client_auth()`] instead.
270 ///
271 /// Use [`Self::builder_with_provider`] if you wish to specify an explicit provider.
272 ///
273 /// For more information, see the [`ClientCertVerifierBuilder`] documentation.
274 pub fn builder(roots: Arc<RootCertStore>) -> ClientCertVerifierBuilder {
275 Self::builder_with_provider(
276 roots,
277 Arc::clone(CryptoProvider::get_default_or_install_from_crate_features()),
278 )
279 }
280
281 /// Create a builder for the `webpki` client certificate verifier configuration using
282 /// a specified [`CryptoProvider`].
283 ///
284 /// Client certificate authentication will be offered by the server, and client certificates
285 /// will be verified using the trust anchors found in the provided `roots`. If you
286 /// wish to disable client authentication use [WebPkiClientVerifier::no_client_auth()] instead.
287 ///
288 /// The cryptography used comes from the specified [`CryptoProvider`].
289 ///
290 /// For more information, see the [`ClientCertVerifierBuilder`] documentation.
291 pub fn builder_with_provider(
292 roots: Arc<RootCertStore>,
293 provider: Arc<CryptoProvider>,
294 ) -> ClientCertVerifierBuilder {
295 ClientCertVerifierBuilder::new(roots, provider.signature_verification_algorithms)
296 }
297
298 /// Create a new `WebPkiClientVerifier` that disables client authentication. The server will
299 /// not offer client authentication and anonymous clients will be accepted.
300 ///
301 /// This is in contrast to using `WebPkiClientVerifier::builder().allow_unauthenticated().build()`,
302 /// which will produce a verifier that will offer client authentication, but not require it.
303 pub fn no_client_auth() -> Arc<dyn ClientCertVerifier> {
304 Arc::new(NoClientAuth {})
305 }
306
307 /// Construct a new `WebpkiClientVerifier`.
308 ///
309 /// * `roots` is a list of trust anchors to use for certificate validation.
310 /// * `root_hint_subjects` is a list of distinguished names to use for hinting acceptable
311 /// certificate authority subjects to a client.
312 /// * `crls` is a `Vec` of owned certificate revocation lists (CRLs) to use for
313 /// client certificate validation.
314 /// * `revocation_check_depth` controls which certificates have their revocation status checked
315 /// when `crls` are provided.
316 /// * `unknown_revocation_policy` controls how certificates with an unknown revocation status
317 /// are handled when `crls` are provided.
318 /// * `anonymous_policy` controls whether client authentication is required, or if anonymous
319 /// clients can connect.
320 /// * `supported_algs` specifies which signature verification algorithms should be used.
321 pub(crate) fn new(
322 roots: Arc<RootCertStore>,
323 root_hint_subjects: Vec<DistinguishedName>,
324 crls: Vec<CertRevocationList<'static>>,
325 revocation_check_depth: RevocationCheckDepth,
326 unknown_revocation_policy: UnknownStatusPolicy,
327 revocation_expiration_policy: ExpirationPolicy,
328 anonymous_policy: AnonymousClientPolicy,
329 supported_algs: WebPkiSupportedAlgorithms,
330 ) -> Self {
331 Self {
332 roots,
333 root_hint_subjects,
334 crls,
335 revocation_check_depth,
336 unknown_revocation_policy,
337 revocation_expiration_policy,
338 anonymous_policy,
339 supported_algs,
340 }
341 }
342}
343
344impl ClientCertVerifier for WebPkiClientVerifier {
345 fn offer_client_auth(&self) -> bool {
346 true
347 }
348
349 fn client_auth_mandatory(&self) -> bool {
350 match self.anonymous_policy {
351 AnonymousClientPolicy::Allow => false,
352 AnonymousClientPolicy::Deny => true,
353 }
354 }
355
356 fn root_hint_subjects(&self) -> &[DistinguishedName] {
357 &self.root_hint_subjects
358 }
359
360 fn verify_client_cert(
361 &self,
362 end_entity: &CertificateDer<'_>,
363 intermediates: &[CertificateDer<'_>],
364 now: UnixTime,
365 ) -> Result<ClientCertVerified, Error> {
366 let cert = ParsedCertificate::try_from(end_entity)?;
367
368 let crl_refs = self.crls.iter().collect::<Vec<_>>();
369
370 let revocation = if self.crls.is_empty() {
371 None
372 } else {
373 Some(
374 webpki::RevocationOptionsBuilder::new(&crl_refs)
375 // Note: safe to unwrap here - new is only fallible if no CRLs are provided
376 // and we verify this above.
377 .unwrap()
378 .with_depth(self.revocation_check_depth)
379 .with_status_policy(self.unknown_revocation_policy)
380 .with_expiration_policy(self.revocation_expiration_policy)
381 .build(),
382 )
383 };
384
385 cert.0
386 .verify_for_usage(
387 self.supported_algs.all,
388 &self.roots.roots,
389 intermediates,
390 now,
391 webpki::KeyUsage::client_auth(),
392 revocation,
393 None,
394 )
395 .map_err(pki_error)
396 .map(|_| ClientCertVerified::assertion())
397 }
398
399 fn verify_tls12_signature(
400 &self,
401 message: &[u8],
402 cert: &CertificateDer<'_>,
403 dss: &DigitallySignedStruct,
404 ) -> Result<HandshakeSignatureValid, Error> {
405 verify_tls12_signature(message, cert, dss, &self.supported_algs)
406 }
407
408 fn verify_tls13_signature(
409 &self,
410 message: &[u8],
411 cert: &CertificateDer<'_>,
412 dss: &DigitallySignedStruct,
413 ) -> Result<HandshakeSignatureValid, Error> {
414 verify_tls13_signature(message, cert, dss, &self.supported_algs)
415 }
416
417 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
418 self.supported_algs.supported_schemes()
419 }
420}
421
422/// Controls how the [WebPkiClientVerifier] handles anonymous clients.
423#[derive(Debug, Clone, Copy, PartialEq, Eq)]
424pub(crate) enum AnonymousClientPolicy {
425 /// Clients that do not present a client certificate are allowed.
426 Allow,
427 /// Clients that do not present a client certificate are denied.
428 Deny,
429}
430
431test_for_each_provider! {
432 use super::WebPkiClientVerifier;
433 use crate::server::VerifierBuilderError;
434 use crate::RootCertStore;
435
436 use pki_types::{CertificateDer, CertificateRevocationListDer};
437
438 use std::prelude::v1::*;
439 use std::sync::Arc;
440 use std::{vec, format, println};
441
442 fn load_crls(crls_der: &[&[u8]]) -> Vec<CertificateRevocationListDer<'static>> {
443 crls_der
444 .iter()
445 .map(|pem_bytes| {
446 rustls_pemfile::crls(&mut &pem_bytes[..])
447 .next()
448 .unwrap()
449 .unwrap()
450 })
451 .collect()
452 }
453
454 fn test_crls() -> Vec<CertificateRevocationListDer<'static>> {
455 load_crls(&[
456 include_bytes!("../../../test-ca/ecdsa-p256/client.revoked.crl.pem").as_slice(),
457 include_bytes!("../../../test-ca/rsa-2048/client.revoked.crl.pem").as_slice(),
458 ])
459 }
460
461 fn load_roots(roots_der: &[&[u8]]) -> Arc<RootCertStore> {
462 let mut roots = RootCertStore::empty();
463 roots_der.iter().for_each(|der| {
464 roots
465 .add(CertificateDer::from(der.to_vec()))
466 .unwrap()
467 });
468 roots.into()
469 }
470
471 fn test_roots() -> Arc<RootCertStore> {
472 load_roots(&[
473 include_bytes!("../../../test-ca/ecdsa-p256/ca.der").as_slice(),
474 include_bytes!("../../../test-ca/rsa-2048/ca.der").as_slice(),
475 ])
476 }
477
478 #[test]
479 fn test_client_verifier_no_auth() {
480 // We should be able to build a verifier that turns off client authentication.
481 WebPkiClientVerifier::no_client_auth();
482 }
483
484 #[test]
485 fn test_client_verifier_required_auth() {
486 // We should be able to build a verifier that requires client authentication, and does
487 // no revocation checking.
488 let builder = WebPkiClientVerifier::builder_with_provider(
489 test_roots(),
490 provider::default_provider().into(),
491 );
492 // The builder should be Debug.
493 println!("{:?}", builder);
494 builder.build().unwrap();
495 }
496
497 #[test]
498 fn test_client_verifier_optional_auth() {
499 // We should be able to build a verifier that allows client authentication, and anonymous
500 // access, and does no revocation checking.
501 let builder = WebPkiClientVerifier::builder_with_provider(
502 test_roots(),
503 provider::default_provider().into(),
504 )
505 .allow_unauthenticated();
506 // The builder should be Debug.
507 println!("{:?}", builder);
508 builder.build().unwrap();
509 }
510
511 #[test]
512 fn test_client_verifier_without_crls_required_auth() {
513 // We should be able to build a verifier that requires client authentication, and does
514 // no revocation checking, that hasn't been configured to determine how to handle
515 // unauthenticated clients yet.
516 let builder = WebPkiClientVerifier::builder_with_provider(
517 test_roots(),
518 provider::default_provider().into(),
519 );
520 // The builder should be Debug.
521 println!("{:?}", builder);
522 builder.build().unwrap();
523 }
524
525 #[test]
526 fn test_client_verifier_without_crls_opptional_auth() {
527 // We should be able to build a verifier that allows client authentication,
528 // and anonymous access, that does no revocation checking.
529 let builder = WebPkiClientVerifier::builder_with_provider(
530 test_roots(),
531 provider::default_provider().into(),
532 )
533 .allow_unauthenticated();
534 // The builder should be Debug.
535 println!("{:?}", builder);
536 builder.build().unwrap();
537 }
538
539 #[test]
540 fn test_with_invalid_crls() {
541 // Trying to build a client verifier with invalid CRLs should error at build time.
542 let result = WebPkiClientVerifier::builder_with_provider(
543 test_roots(),
544 provider::default_provider().into(),
545 )
546 .with_crls(vec![CertificateRevocationListDer::from(vec![0xFF])])
547 .build();
548 assert!(matches!(result, Err(VerifierBuilderError::InvalidCrl(_))));
549 }
550
551 #[test]
552 fn test_with_crls_multiple_calls() {
553 // We should be able to call `with_crls` on a client verifier multiple times.
554 let initial_crls = test_crls();
555 let extra_crls =
556 load_crls(&[
557 include_bytes!("../../../test-ca/eddsa/client.revoked.crl.pem").as_slice(),
558 ]);
559 let builder = WebPkiClientVerifier::builder_with_provider(
560 test_roots(),
561 provider::default_provider().into(),
562 )
563 .with_crls(initial_crls.clone())
564 .with_crls(extra_crls.clone());
565
566 // There should be the expected number of crls.
567 assert_eq!(builder.crls.len(), initial_crls.len() + extra_crls.len());
568 // The builder should be Debug.
569 println!("{:?}", builder);
570 builder.build().unwrap();
571 }
572
573 #[test]
574 fn test_client_verifier_with_crls_required_auth_implicit() {
575 // We should be able to build a verifier that requires client authentication, and that does
576 // revocation checking with CRLs, and that does not allow any anonymous access.
577 let builder = WebPkiClientVerifier::builder_with_provider(
578 test_roots(),
579 provider::default_provider().into(),
580 )
581 .with_crls(test_crls());
582 // The builder should be Debug.
583 println!("{:?}", builder);
584 builder.build().unwrap();
585 }
586
587 #[test]
588 fn test_client_verifier_with_crls_optional_auth() {
589 // We should be able to build a verifier that supports client authentication, that does
590 // revocation checking with CRLs, and that allows anonymous access.
591 let builder = WebPkiClientVerifier::builder_with_provider(
592 test_roots(),
593 provider::default_provider().into(),
594 )
595 .with_crls(test_crls())
596 .allow_unauthenticated();
597 // The builder should be Debug.
598 println!("{:?}", builder);
599 builder.build().unwrap();
600 }
601
602 #[test]
603 fn test_client_verifier_ee_only() {
604 // We should be able to build a client verifier that only checks EE revocation status.
605 let builder = WebPkiClientVerifier::builder_with_provider(
606 test_roots(),
607 provider::default_provider().into(),
608 )
609 .with_crls(test_crls())
610 .only_check_end_entity_revocation();
611 // The builder should be Debug.
612 println!("{:?}", builder);
613 builder.build().unwrap();
614 }
615
616 #[test]
617 fn test_client_verifier_allow_unknown() {
618 // We should be able to build a client verifier that allows unknown revocation status
619 let builder = WebPkiClientVerifier::builder_with_provider(
620 test_roots(),
621 provider::default_provider().into(),
622 )
623 .with_crls(test_crls())
624 .allow_unknown_revocation_status();
625 // The builder should be Debug.
626 println!("{:?}", builder);
627 builder.build().unwrap();
628 }
629
630 #[test]
631 fn test_client_verifier_enforce_expiration() {
632 // We should be able to build a client verifier that allows unknown revocation status
633 let builder = WebPkiClientVerifier::builder_with_provider(
634 test_roots(),
635 provider::default_provider().into(),
636 )
637 .with_crls(test_crls())
638 .enforce_revocation_expiration();
639 // The builder should be Debug.
640 println!("{:?}", builder);
641 builder.build().unwrap();
642 }
643
644 #[test]
645 fn test_builder_no_roots() {
646 // Trying to create a client verifier builder with no trust anchors should fail at build time
647 let result = WebPkiClientVerifier::builder_with_provider(
648 RootCertStore::empty().into(),
649 provider::default_provider().into(),
650 )
651 .build();
652 assert!(matches!(result, Err(VerifierBuilderError::NoRootAnchors)));
653 }
654
655 #[test]
656 fn smoke() {
657 let all = vec![
658 VerifierBuilderError::NoRootAnchors,
659 VerifierBuilderError::InvalidCrl(crate::CertRevocationListError::ParseError),
660 ];
661
662 for err in all {
663 let _ = format!("{:?}", err);
664 let _ = format!("{}", err);
665 }
666 }
667}