rustls/webpki/
server_verifier.rs

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::prelude::v1::*;
286    use std::sync::Arc;
287    use std::{println, vec};
288
289    use pki_types::{CertificateDer, CertificateRevocationListDer};
290
291    use super::{VerifierBuilderError, WebPkiServerVerifier};
292    use crate::{test_provider, RootCertStore};
293
294    fn load_crls(crls_der: &[&[u8]]) -> Vec<CertificateRevocationListDer<'static>> {
295        crls_der
296            .iter()
297            .map(|pem_bytes| {
298                rustls_pemfile::crls(&mut &pem_bytes[..])
299                    .next()
300                    .unwrap()
301                    .unwrap()
302            })
303            .collect()
304    }
305
306    fn test_crls() -> Vec<CertificateRevocationListDer<'static>> {
307        load_crls(&[
308            include_bytes!("../../../test-ca/ecdsa-p256/client.revoked.crl.pem").as_slice(),
309            include_bytes!("../../../test-ca/rsa/client.revoked.crl.pem").as_slice(),
310        ])
311    }
312
313    fn load_roots(roots_der: &[&[u8]]) -> Arc<RootCertStore> {
314        let mut roots = RootCertStore::empty();
315        roots_der.iter().for_each(|der| {
316            roots
317                .add(CertificateDer::from(der.to_vec()))
318                .unwrap()
319        });
320        roots.into()
321    }
322
323    fn test_roots() -> Arc<RootCertStore> {
324        load_roots(&[
325            include_bytes!("../../../test-ca/ecdsa-p256/ca.der").as_slice(),
326            include_bytes!("../../../test-ca/rsa/ca.der").as_slice(),
327        ])
328    }
329
330    #[test]
331    fn test_with_invalid_crls() {
332        // Trying to build a server verifier with invalid CRLs should error at build time.
333        let result = WebPkiServerVerifier::builder_with_provider(
334            test_roots(),
335            test_provider::default_provider().into(),
336        )
337        .with_crls(vec![CertificateRevocationListDer::from(vec![0xFF])])
338        .build();
339        assert!(matches!(result, Err(VerifierBuilderError::InvalidCrl(_))));
340    }
341
342    #[test]
343    fn test_with_crls_multiple_calls() {
344        // We should be able to call `with_crls` on a server verifier multiple times.
345        let initial_crls = test_crls();
346        let extra_crls =
347            load_crls(&[
348                include_bytes!("../../../test-ca/eddsa/client.revoked.crl.pem").as_slice(),
349            ]);
350
351        let builder = WebPkiServerVerifier::builder_with_provider(
352            test_roots(),
353            test_provider::default_provider().into(),
354        )
355        .with_crls(initial_crls.clone())
356        .with_crls(extra_crls.clone());
357
358        // There should be the expected number of crls.
359        assert_eq!(builder.crls.len(), initial_crls.len() + extra_crls.len());
360        // The builder should be Debug.
361        println!("{:?}", builder);
362        builder.build().unwrap();
363    }
364
365    #[test]
366    fn test_builder_no_roots() {
367        // Trying to create a server verifier builder with no trust anchors should fail at build time
368        let result = WebPkiServerVerifier::builder_with_provider(
369            RootCertStore::empty().into(),
370            test_provider::default_provider().into(),
371        )
372        .build();
373        assert!(matches!(result, Err(VerifierBuilderError::NoRootAnchors)));
374    }
375
376    #[test]
377    fn test_server_verifier_ee_only() {
378        // We should be able to build a server cert. verifier that only checks the EE cert.
379        let builder = WebPkiServerVerifier::builder_with_provider(
380            test_roots(),
381            test_provider::default_provider().into(),
382        )
383        .only_check_end_entity_revocation();
384        // The builder should be Debug.
385        println!("{:?}", builder);
386        builder.build().unwrap();
387    }
388
389    #[test]
390    fn test_server_verifier_allow_unknown() {
391        // We should be able to build a server cert. verifier that allows unknown revocation
392        // status.
393        let builder = WebPkiServerVerifier::builder_with_provider(
394            test_roots(),
395            test_provider::default_provider().into(),
396        )
397        .allow_unknown_revocation_status();
398        // The builder should be Debug.
399        println!("{:?}", builder);
400        builder.build().unwrap();
401    }
402
403    #[test]
404    fn test_server_verifier_allow_unknown_ee_only() {
405        // We should be able to build a server cert. verifier that allows unknown revocation
406        // status and only checks the EE cert.
407        let builder = WebPkiServerVerifier::builder_with_provider(
408            test_roots(),
409            test_provider::default_provider().into(),
410        )
411        .allow_unknown_revocation_status()
412        .only_check_end_entity_revocation();
413        // The builder should be Debug.
414        println!("{:?}", builder);
415        builder.build().unwrap();
416    }
417}