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