rustls_platform_verifier/verification/
mod.rs

1use rustls::crypto::CryptoProvider;
2use std::sync::Arc;
3
4#[cfg(all(
5    any(unix, target_arch = "wasm32"),
6    not(target_os = "android"),
7    not(target_vendor = "apple"),
8))]
9mod others;
10
11#[cfg(all(
12    any(unix, target_arch = "wasm32"),
13    not(target_os = "android"),
14    not(target_vendor = "apple"),
15))]
16pub use others::Verifier;
17
18#[cfg(target_vendor = "apple")]
19mod apple;
20
21#[cfg(target_vendor = "apple")]
22pub use apple::Verifier;
23
24#[cfg(target_os = "android")]
25pub(crate) mod android;
26
27#[cfg(target_os = "android")]
28pub use android::Verifier;
29
30#[cfg(windows)]
31mod windows;
32
33#[cfg(windows)]
34pub use windows::Verifier;
35
36/// An EKU was invalid for the use case of verifying a server certificate.
37///
38/// This error is used primarily for tests.
39#[cfg_attr(windows, allow(dead_code))] // not used by windows verifier
40#[derive(Debug, PartialEq)]
41pub(crate) struct EkuError;
42
43impl std::fmt::Display for EkuError {
44    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45        f.write_str("certificate had invalid extensions")
46    }
47}
48
49impl std::error::Error for EkuError {}
50
51// Log the certificate we are verifying so that we can try and find what may be wrong with it
52// if we need to debug a user's situation.
53fn log_server_cert(_end_entity: &rustls::pki_types::CertificateDer<'_>) {
54    #[cfg(feature = "cert-logging")]
55    {
56        use base64::Engine;
57        log::debug!(
58            "verifying certificate: {}",
59            base64::engine::general_purpose::STANDARD.encode(_end_entity.as_ref())
60        );
61    }
62}
63
64// Unknown certificate error shorthand. Used when we need to construct an "Other" certificate
65// error with a platform specific error message.
66#[cfg(any(windows, target_vendor = "apple"))]
67fn invalid_certificate(reason: impl Into<String>) -> rustls::Error {
68    rustls::Error::InvalidCertificate(rustls::CertificateError::Other(rustls::OtherError(
69        Arc::from(Box::from(reason.into())),
70    )))
71}
72
73/// List of EKUs that one or more of that *must* be in the end-entity certificate.
74///
75/// Legacy server-gated crypto OIDs are assumed to no longer be in use.
76///
77/// Currently supported:
78/// - id-kp-serverAuth
79// TODO: Chromium also allows for `OID_ANY_EKU` on Android.
80#[cfg(target_os = "windows")]
81// XXX: Windows requires that we NUL terminate EKU strings.
82// See https://github.com/rustls/rustls-platform-verifier/issues/126#issuecomment-2306232794.
83const ALLOWED_EKUS: &[windows_sys::core::PCSTR] =
84    &[windows_sys::Win32::Security::Cryptography::szOID_PKIX_KP_SERVER_AUTH];
85#[cfg(target_os = "android")]
86pub const ALLOWED_EKUS: &[&str] = &["1.3.6.1.5.5.7.3.1"];
87
88impl Verifier {
89    /// Chainable setter to configure the [`CryptoProvider`] for this `Verifier`.
90    ///
91    /// This will be used instead of the rustls process-default `CryptoProvider`, even if one has
92    /// been installed.
93    pub fn with_provider(mut self, crypto_provider: Arc<CryptoProvider>) -> Self {
94        self.set_provider(crypto_provider);
95        self
96    }
97
98    /// Configures the [`CryptoProvider`] for this `Verifier`.
99    ///
100    /// This will be used instead of the rustls process-default `CryptoProvider`, even if one has
101    /// been installed.
102    pub fn set_provider(&mut self, crypto_provider: Arc<CryptoProvider>) {
103        self.crypto_provider = crypto_provider.into();
104    }
105
106    fn get_provider(&self) -> &Arc<CryptoProvider> {
107        self.crypto_provider.get_or_init(|| {
108            CryptoProvider::get_default()
109                .expect("rustls default CryptoProvider not set")
110                .clone()
111        })
112    }
113}