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