rustls_platform_verifier/verification/
others.rs1use super::log_server_cert;
2use once_cell::sync::OnceCell;
3use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};
4use rustls::client::WebPkiServerVerifier;
5use rustls::pki_types;
6use rustls::{
7 crypto::CryptoProvider, CertificateError, DigitallySignedStruct, Error as TlsError, OtherError,
8 SignatureScheme,
9};
10use std::fmt::Debug;
11use std::sync::{Arc, Mutex};
12
13#[derive(Debug)]
15pub struct Verifier {
16 inner: OnceCell<Arc<WebPkiServerVerifier>>,
24
25 extra_roots: Mutex<Vec<pki_types::TrustAnchor<'static>>>,
28
29 #[cfg(any(test, feature = "ffi-testing", feature = "dbg"))]
31 test_only_root_ca_override: Option<Vec<u8>>,
32
33 pub(super) crypto_provider: OnceCell<Arc<CryptoProvider>>,
34}
35
36impl Verifier {
37 pub fn new() -> Self {
44 Self {
45 inner: OnceCell::new(),
46 extra_roots: Vec::new().into(),
47 #[cfg(any(test, feature = "ffi-testing", feature = "dbg"))]
48 test_only_root_ca_override: None,
49 crypto_provider: OnceCell::new(),
50 }
51 }
52
53 pub fn new_with_extra_roots(
57 roots: impl IntoIterator<Item = pki_types::TrustAnchor<'static>>,
58 ) -> Self {
59 Self {
60 inner: OnceCell::new(),
61 extra_roots: roots.into_iter().collect::<Vec<_>>().into(),
62 #[cfg(any(test, feature = "ffi-testing", feature = "dbg"))]
63 test_only_root_ca_override: None,
64 crypto_provider: OnceCell::new(),
65 }
66 }
67
68 #[cfg(any(test, feature = "ffi-testing", feature = "dbg"))]
70 pub(crate) fn new_with_fake_root(root: &[u8]) -> Self {
71 Self {
72 inner: OnceCell::new(),
73 extra_roots: Vec::new().into(),
74 test_only_root_ca_override: Some(root.into()),
75 crypto_provider: OnceCell::new(),
76 }
77 }
78
79 fn get_or_init_verifier(&self) -> Result<&Arc<WebPkiServerVerifier>, TlsError> {
80 self.inner.get_or_try_init(|| self.init_verifier())
81 }
82
83 fn init_verifier(&self) -> Result<Arc<WebPkiServerVerifier>, TlsError> {
85 let mut root_store = rustls::RootCertStore::empty();
86
87 #[cfg(any(test, feature = "ffi-testing", feature = "dbg"))]
89 {
90 if let Some(test_root) = &self.test_only_root_ca_override {
91 let (added, ignored) =
92 root_store.add_parsable_certificates([pki_types::CertificateDer::from(
93 test_root.as_ref(),
94 )]);
95 if (added != 1) || (ignored != 0) {
96 panic!("Failed to insert fake, test-only root trust anchor");
97 }
98 return Ok(WebPkiServerVerifier::builder_with_provider(
99 root_store.into(),
100 Arc::clone(self.get_provider()),
101 )
102 .build()
103 .unwrap());
104 }
105 }
106
107 let mut extra_roots = self.extra_roots.try_lock().unwrap();
110 if !extra_roots.is_empty() {
111 let count = extra_roots.len();
112 root_store.extend(extra_roots.drain(..));
113 log::debug!(
114 "Loaded {count} extra CA certificates in addition to possible system roots",
115 );
116 }
117
118 #[cfg(all(
119 unix,
120 not(target_os = "android"),
121 not(target_os = "macos"),
122 not(target_os = "ios"),
123 not(target_os = "tvos"),
124 not(target_arch = "wasm32"),
125 ))]
126 match rustls_native_certs::load_native_certs() {
127 Ok(certs) => {
128 let (added, ignored) = root_store.add_parsable_certificates(certs);
129
130 if ignored != 0 {
131 log::warn!("Some CA root certificates were ignored due to errors");
132 }
133
134 if root_store.is_empty() {
135 log::error!("No CA certificates were loaded from the system");
136 } else {
137 log::debug!("Loaded {added} CA certificates from the system");
138 }
139 }
140 Err(err) => {
141 const MSG: &str = "failed to load system root certificates: ";
144
145 if root_store.is_empty() {
148 return Err(rustls::Error::General(format!("{MSG}{err}")));
149 } else {
150 log::error!("{MSG}{err}");
151 }
152 }
153 };
154
155 #[cfg(target_arch = "wasm32")]
156 {
157 root_store.add_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.iter().map(|root| {
158 rustls::OwnedTrustAnchor::from_subject_spki_name_constraints(
159 root.subject,
160 root.spki,
161 root.name_constraints,
162 )
163 }));
164 };
165
166 WebPkiServerVerifier::builder_with_provider(
167 root_store.into(),
168 Arc::clone(self.get_provider()),
169 )
170 .build()
171 .map_err(|e| TlsError::Other(OtherError(Arc::new(e))))
172 }
173}
174
175impl ServerCertVerifier for Verifier {
176 fn verify_server_cert(
177 &self,
178 end_entity: &pki_types::CertificateDer<'_>,
179 intermediates: &[pki_types::CertificateDer<'_>],
180 server_name: &pki_types::ServerName,
181 ocsp_response: &[u8],
182 now: pki_types::UnixTime,
183 ) -> Result<ServerCertVerified, TlsError> {
184 log_server_cert(end_entity);
185
186 self.get_or_init_verifier()?
187 .verify_server_cert(end_entity, intermediates, server_name, ocsp_response, now)
188 .map_err(map_webpki_errors)
189 .map_err(|e| {
192 log::error!("failed to verify TLS certificate: {}", e);
193 e
194 })
195 }
196
197 fn verify_tls12_signature(
198 &self,
199 message: &[u8],
200 cert: &pki_types::CertificateDer<'_>,
201 dss: &DigitallySignedStruct,
202 ) -> Result<HandshakeSignatureValid, TlsError> {
203 self.get_or_init_verifier()?
204 .verify_tls12_signature(message, cert, dss)
205 }
206
207 fn verify_tls13_signature(
208 &self,
209 message: &[u8],
210 cert: &pki_types::CertificateDer<'_>,
211 dss: &DigitallySignedStruct,
212 ) -> Result<HandshakeSignatureValid, TlsError> {
213 self.get_or_init_verifier()?
214 .verify_tls13_signature(message, cert, dss)
215 }
216
217 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
218 match self.get_or_init_verifier() {
219 Ok(v) => v.supported_verify_schemes(),
220 Err(_) => Vec::default(),
221 }
222 }
223}
224
225impl Default for Verifier {
226 fn default() -> Self {
227 Self::new()
228 }
229}
230
231fn map_webpki_errors(err: TlsError) -> TlsError {
232 if let TlsError::InvalidCertificate(CertificateError::Other(other_err)) = &err {
233 if let Some(webpki::Error::RequiredEkuNotFound) =
234 other_err.0.downcast_ref::<webpki::Error>()
235 {
236 return TlsError::InvalidCertificate(CertificateError::Other(OtherError(Arc::new(
237 super::EkuError,
238 ))));
239 }
240 }
241
242 err
243}