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