1use alloc::vec::Vec;
2
3use pki_types::{CertificateDer, CertificateRevocationListDer, ServerName, UnixTime};
4use webpki::{CertRevocationList, ExpirationPolicy, RevocationCheckDepth, UnknownStatusPolicy};
5
6use crate::crypto::{CryptoProvider, WebPkiSupportedAlgorithms};
7use crate::log::trace;
8use crate::sync::Arc;
9use crate::verify::{
10 DigitallySignedStruct, HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier,
11};
12use crate::webpki::verify::{
13 ParsedCertificate, verify_server_cert_signed_by_trust_anchor_impl, verify_tls12_signature,
14 verify_tls13_signature,
15};
16use crate::webpki::{VerifierBuilderError, parse_crls, verify_server_name};
17#[cfg(doc)]
18use crate::{ConfigBuilder, ServerConfig, crypto};
19use crate::{Error, RootCertStore, SignatureScheme};
20
21/// A builder for configuring a `webpki` server certificate verifier.
22///
23/// For more information, see the [`WebPkiServerVerifier`] documentation.
24#[derive(Debug, Clone)]
25pub struct ServerCertVerifierBuilder {
26 roots: Arc<RootCertStore>,
27 crls: Vec<CertificateRevocationListDer<'static>>,
28 revocation_check_depth: RevocationCheckDepth,
29 unknown_revocation_policy: UnknownStatusPolicy,
30 revocation_expiration_policy: ExpirationPolicy,
31 supported_algs: WebPkiSupportedAlgorithms,
32}
33
34impl ServerCertVerifierBuilder {
35 pub(crate) fn new(
36 roots: Arc<RootCertStore>,
37 supported_algs: WebPkiSupportedAlgorithms,
38 ) -> Self {
39 Self {
40 roots,
41 crls: Vec::new(),
42 revocation_check_depth: RevocationCheckDepth::Chain,
43 unknown_revocation_policy: UnknownStatusPolicy::Deny,
44 revocation_expiration_policy: ExpirationPolicy::Ignore,
45 supported_algs,
46 }
47 }
48
49 /// Verify the revocation state of presented client certificates against the provided
50 /// certificate revocation lists (CRLs). Calling `with_crls` multiple times appends the
51 /// given CRLs to the existing collection.
52 pub fn with_crls(
53 mut self,
54 crls: impl IntoIterator<Item = CertificateRevocationListDer<'static>>,
55 ) -> Self {
56 self.crls.extend(crls);
57 self
58 }
59
60 /// Only check the end entity certificate revocation status when using CRLs.
61 ///
62 /// If CRLs are provided using [`with_crls`][Self::with_crls] only check the end entity
63 /// certificate's revocation status. Overrides the default behavior of checking revocation
64 /// status for each certificate in the verified chain built to a trust anchor
65 /// (excluding the trust anchor itself).
66 ///
67 /// If no CRLs are provided then this setting has no effect. Neither the end entity certificate
68 /// or any intermediates will have revocation status checked.
69 pub fn only_check_end_entity_revocation(mut self) -> Self {
70 self.revocation_check_depth = RevocationCheckDepth::EndEntity;
71 self
72 }
73
74 /// Allow unknown certificate revocation status when using CRLs.
75 ///
76 /// If CRLs are provided with [`with_crls`][Self::with_crls] and it isn't possible to
77 /// determine the revocation status of a certificate, do not treat it as an error condition.
78 /// Overrides the default behavior where unknown revocation status is considered an error.
79 ///
80 /// If no CRLs are provided then this setting has no effect as revocation status checks
81 /// are not performed.
82 pub fn allow_unknown_revocation_status(mut self) -> Self {
83 self.unknown_revocation_policy = UnknownStatusPolicy::Allow;
84 self
85 }
86
87 /// Enforce the CRL nextUpdate field (i.e. expiration)
88 ///
89 /// If CRLs are provided with [`with_crls`][Self::with_crls] and the verification time is
90 /// beyond the time in the CRL nextUpdate field, it is expired and treated as an error condition.
91 /// Overrides the default behavior where expired CRLs are not treated as an error condition.
92 ///
93 /// If no CRLs are provided then this setting has no effect as revocation status checks
94 /// are not performed.
95 pub fn enforce_revocation_expiration(mut self) -> Self {
96 self.revocation_expiration_policy = ExpirationPolicy::Enforce;
97 self
98 }
99
100 /// Build a server certificate verifier, allowing control over the root certificates to use as
101 /// trust anchors, and to control how server certificate revocation checking is performed.
102 ///
103 /// If `with_signature_verification_algorithms` was not called on the builder, a default set of
104 /// signature verification algorithms is used, controlled by the selected [`crypto::CryptoProvider`].
105 ///
106 /// Once built, the provided `Arc<dyn ServerCertVerifier>` can be used with a Rustls
107 /// [`ServerConfig`] to configure client certificate validation using
108 /// [`with_client_cert_verifier`][ConfigBuilder<ClientConfig, WantsVerifier>::with_client_cert_verifier].
109 ///
110 /// # Errors
111 /// This function will return a [`VerifierBuilderError`] if:
112 /// 1. No trust anchors have been provided.
113 /// 2. DER encoded CRLs have been provided that can not be parsed successfully.
114 pub fn build(self) -> Result<Arc<WebPkiServerVerifier>, VerifierBuilderError> {
115 if self.roots.is_empty() {
116 return Err(VerifierBuilderError::NoRootAnchors);
117 }
118
119 Ok(WebPkiServerVerifier::new(
120 self.roots,
121 parse_crls(self.crls)?,
122 self.revocation_check_depth,
123 self.unknown_revocation_policy,
124 self.revocation_expiration_policy,
125 self.supported_algs,
126 )
127 .into())
128 }
129}
130
131/// Default `ServerCertVerifier`, see the trait impl for more information.
132#[allow(unreachable_pub)]
133#[derive(Debug)]
134pub struct WebPkiServerVerifier {
135 roots: Arc<RootCertStore>,
136 crls: Vec<CertRevocationList<'static>>,
137 revocation_check_depth: RevocationCheckDepth,
138 unknown_revocation_policy: UnknownStatusPolicy,
139 revocation_expiration_policy: ExpirationPolicy,
140 supported: WebPkiSupportedAlgorithms,
141}
142
143#[allow(unreachable_pub)]
144impl WebPkiServerVerifier {
145 /// Create a builder for the `webpki` server certificate verifier configuration using
146 /// the [process-default `CryptoProvider`][CryptoProvider#using-the-per-process-default-cryptoprovider].
147 ///
148 /// Server certificates will be verified using the trust anchors found in the provided `roots`.
149 ///
150 /// Use [`Self::builder_with_provider`] if you wish to specify an explicit provider.
151 ///
152 /// For more information, see the [`ServerCertVerifierBuilder`] documentation.
153 pub fn builder(roots: Arc<RootCertStore>) -> ServerCertVerifierBuilder {
154 Self::builder_with_provider(
155 roots,
156 Arc::clone(CryptoProvider::get_default_or_install_from_crate_features()),
157 )
158 }
159
160 /// Create a builder for the `webpki` server certificate verifier configuration using
161 /// a specified [`CryptoProvider`].
162 ///
163 /// Server certificates will be verified using the trust anchors found in the provided `roots`.
164 ///
165 /// The cryptography used comes from the specified [`CryptoProvider`].
166 ///
167 /// For more information, see the [`ServerCertVerifierBuilder`] documentation.
168 pub fn builder_with_provider(
169 roots: Arc<RootCertStore>,
170 provider: Arc<CryptoProvider>,
171 ) -> ServerCertVerifierBuilder {
172 ServerCertVerifierBuilder::new(roots, provider.signature_verification_algorithms)
173 }
174
175 /// Short-cut for creating a `WebPkiServerVerifier` that does not perform certificate revocation
176 /// checking, avoiding the need to use a builder.
177 pub(crate) fn new_without_revocation(
178 roots: impl Into<Arc<RootCertStore>>,
179 supported_algs: WebPkiSupportedAlgorithms,
180 ) -> Self {
181 Self::new(
182 roots,
183 Vec::default(),
184 RevocationCheckDepth::Chain,
185 UnknownStatusPolicy::Allow,
186 ExpirationPolicy::Ignore,
187 supported_algs,
188 )
189 }
190
191 /// Constructs a new `WebPkiServerVerifier`.
192 ///
193 /// * `roots` is the set of trust anchors to trust for issuing server certs.
194 /// * `crls` are a vec of owned certificate revocation lists (CRLs) to use for
195 /// client certificate validation.
196 /// * `revocation_check_depth` controls which certificates have their revocation status checked
197 /// when `crls` are provided.
198 /// * `unknown_revocation_policy` controls how certificates with an unknown revocation status
199 /// are handled when `crls` are provided.
200 /// * `supported` is the set of supported algorithms that will be used for
201 /// certificate verification and TLS handshake signature verification.
202 pub(crate) fn new(
203 roots: impl Into<Arc<RootCertStore>>,
204 crls: Vec<CertRevocationList<'static>>,
205 revocation_check_depth: RevocationCheckDepth,
206 unknown_revocation_policy: UnknownStatusPolicy,
207 revocation_expiration_policy: ExpirationPolicy,
208 supported: WebPkiSupportedAlgorithms,
209 ) -> Self {
210 Self {
211 roots: roots.into(),
212 crls,
213 revocation_check_depth,
214 unknown_revocation_policy,
215 revocation_expiration_policy,
216 supported,
217 }
218 }
219}
220
221impl ServerCertVerifier for WebPkiServerVerifier {
222 /// Will verify the certificate is valid in the following ways:
223 /// - Signed by a trusted `RootCertStore` CA
224 /// - Not Expired
225 /// - Valid for DNS entry
226 /// - Valid revocation status (if applicable).
227 ///
228 /// Depending on the verifier's configuration revocation status checking may be performed for
229 /// each certificate in the chain to a root CA (excluding the root itself), or only the
230 /// end entity certificate. Similarly, unknown revocation status may be treated as an error
231 /// or allowed based on configuration.
232 fn verify_server_cert(
233 &self,
234 end_entity: &CertificateDer<'_>,
235 intermediates: &[CertificateDer<'_>],
236 server_name: &ServerName<'_>,
237 ocsp_response: &[u8],
238 now: UnixTime,
239 ) -> Result<ServerCertVerified, Error> {
240 let cert = ParsedCertificate::try_from(end_entity)?;
241
242 let crl_refs = self.crls.iter().collect::<Vec<_>>();
243
244 let revocation = if self.crls.is_empty() {
245 None
246 } else {
247 // Note: unwrap here is safe because RevocationOptionsBuilder only errors when given
248 // empty CRLs.
249 Some(
250 webpki::RevocationOptionsBuilder::new(crl_refs.as_slice())
251 // Note: safe to unwrap here - new is only fallible if no CRLs are provided
252 // and we verify this above.
253 .unwrap()
254 .with_depth(self.revocation_check_depth)
255 .with_status_policy(self.unknown_revocation_policy)
256 .with_expiration_policy(self.revocation_expiration_policy)
257 .build(),
258 )
259 };
260
261 // Note: we use the crate-internal `_impl` fn here in order to provide revocation
262 // checking information, if applicable.
263 verify_server_cert_signed_by_trust_anchor_impl(
264 &cert,
265 &self.roots,
266 intermediates,
267 revocation,
268 now,
269 self.supported.all,
270 )?;
271
272 if !ocsp_response.is_empty() {
273 trace!("Unvalidated OCSP response: {:?}", ocsp_response.to_vec());
274 }
275
276 verify_server_name(&cert, server_name)?;
277 Ok(ServerCertVerified::assertion())
278 }
279
280 fn verify_tls12_signature(
281 &self,
282 message: &[u8],
283 cert: &CertificateDer<'_>,
284 dss: &DigitallySignedStruct,
285 ) -> Result<HandshakeSignatureValid, Error> {
286 verify_tls12_signature(message, cert, dss, &self.supported)
287 }
288
289 fn verify_tls13_signature(
290 &self,
291 message: &[u8],
292 cert: &CertificateDer<'_>,
293 dss: &DigitallySignedStruct,
294 ) -> Result<HandshakeSignatureValid, Error> {
295 verify_tls13_signature(message, cert, dss, &self.supported)
296 }
297
298 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
299 self.supported.supported_schemes()
300 }
301}
302
303#[cfg(test)]
304#[macro_rules_attribute::apply(test_for_each_provider)]
305mod tests {
306 use std::prelude::v1::*;
307 use std::{println, vec};
308
309 use pki_types::pem::PemObject;
310 use pki_types::{CertificateDer, CertificateRevocationListDer};
311
312 use super::{VerifierBuilderError, WebPkiServerVerifier, provider};
313 use crate::RootCertStore;
314 use crate::sync::Arc;
315
316 fn load_crls(crls_der: &[&[u8]]) -> Vec<CertificateRevocationListDer<'static>> {
317 crls_der
318 .iter()
319 .map(|pem_bytes| CertificateRevocationListDer::from_pem_slice(pem_bytes).unwrap())
320 .collect()
321 }
322
323 fn test_crls() -> Vec<CertificateRevocationListDer<'static>> {
324 load_crls(&[
325 include_bytes!("../../../test-ca/ecdsa-p256/client.revoked.crl.pem").as_slice(),
326 include_bytes!("../../../test-ca/rsa-2048/client.revoked.crl.pem").as_slice(),
327 ])
328 }
329
330 fn load_roots(roots_der: &[&[u8]]) -> Arc<RootCertStore> {
331 let mut roots = RootCertStore::empty();
332 roots_der.iter().for_each(|der| {
333 roots
334 .add(CertificateDer::from(der.to_vec()))
335 .unwrap()
336 });
337 roots.into()
338 }
339
340 fn test_roots() -> Arc<RootCertStore> {
341 load_roots(&[
342 include_bytes!("../../../test-ca/ecdsa-p256/ca.der").as_slice(),
343 include_bytes!("../../../test-ca/rsa-2048/ca.der").as_slice(),
344 ])
345 }
346
347 #[test]
348 fn test_with_invalid_crls() {
349 // Trying to build a server verifier with invalid CRLs should error at build time.
350 let result = WebPkiServerVerifier::builder_with_provider(
351 test_roots(),
352 provider::default_provider().into(),
353 )
354 .with_crls(vec![CertificateRevocationListDer::from(vec![0xFF])])
355 .build();
356 assert!(matches!(result, Err(VerifierBuilderError::InvalidCrl(_))));
357 }
358
359 #[test]
360 fn test_with_crls_multiple_calls() {
361 // We should be able to call `with_crls` on a server verifier multiple times.
362 let initial_crls = test_crls();
363 let extra_crls =
364 load_crls(&[
365 include_bytes!("../../../test-ca/eddsa/client.revoked.crl.pem").as_slice(),
366 ]);
367
368 let builder = WebPkiServerVerifier::builder_with_provider(
369 test_roots(),
370 provider::default_provider().into(),
371 )
372 .with_crls(initial_crls.clone())
373 .with_crls(extra_crls.clone());
374
375 // There should be the expected number of crls.
376 assert_eq!(builder.crls.len(), initial_crls.len() + extra_crls.len());
377 // The builder should be Debug.
378 println!("{:?}", builder);
379 builder.build().unwrap();
380 }
381
382 #[test]
383 fn test_builder_no_roots() {
384 // Trying to create a server verifier builder with no trust anchors should fail at build time
385 let result = WebPkiServerVerifier::builder_with_provider(
386 RootCertStore::empty().into(),
387 provider::default_provider().into(),
388 )
389 .build();
390 assert!(matches!(result, Err(VerifierBuilderError::NoRootAnchors)));
391 }
392
393 #[test]
394 fn test_server_verifier_ee_only() {
395 // We should be able to build a server cert. verifier that only checks the EE cert.
396 let builder = WebPkiServerVerifier::builder_with_provider(
397 test_roots(),
398 provider::default_provider().into(),
399 )
400 .only_check_end_entity_revocation();
401 // The builder should be Debug.
402 println!("{:?}", builder);
403 builder.build().unwrap();
404 }
405
406 #[test]
407 fn test_server_verifier_allow_unknown() {
408 // We should be able to build a server cert. verifier that allows unknown revocation
409 // status.
410 let builder = WebPkiServerVerifier::builder_with_provider(
411 test_roots(),
412 provider::default_provider().into(),
413 )
414 .allow_unknown_revocation_status();
415 // The builder should be Debug.
416 println!("{:?}", builder);
417 builder.build().unwrap();
418 }
419
420 #[test]
421 fn test_server_verifier_allow_unknown_ee_only() {
422 // We should be able to build a server cert. verifier that allows unknown revocation
423 // status and only checks the EE cert.
424 let builder = WebPkiServerVerifier::builder_with_provider(
425 test_roots(),
426 provider::default_provider().into(),
427 )
428 .allow_unknown_revocation_status()
429 .only_check_end_entity_revocation();
430 // The builder should be Debug.
431 println!("{:?}", builder);
432 builder.build().unwrap();
433 }
434
435 #[test]
436 fn test_server_verifier_enforce_expiration() {
437 // We should be able to build a server cert. verifier that allows unknown revocation
438 // status.
439 let builder = WebPkiServerVerifier::builder_with_provider(
440 test_roots(),
441 provider::default_provider().into(),
442 )
443 .enforce_revocation_expiration();
444 // The builder should be Debug.
445 println!("{:?}", builder);
446 builder.build().unwrap();
447 }
448}
449