rustls/webpki/
server_verifier.rs

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