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#[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 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 pub fn only_check_end_entity_revocation(mut self) -> Self {
67 self.revocation_check_depth = RevocationCheckDepth::EndEntity;
68 self
69 }
70
71 pub fn allow_unknown_revocation_status(mut self) -> Self {
80 self.unknown_revocation_policy = UnknownStatusPolicy::Allow;
81 self
82 }
83
84 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#[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 #[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 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 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 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 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 Some(
228 webpki::RevocationOptionsBuilder::new(crl_refs.as_slice())
229 .unwrap()
232 .with_depth(self.revocation_check_depth)
233 .with_status_policy(self.unknown_revocation_policy)
234 .build(),
235 )
236 };
237
238 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 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 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 assert_eq!(builder.crls.len(), initial_crls.len() + extra_crls.len());
355 println!("{:?}", builder);
357 builder.build().unwrap();
358 }
359
360 #[test]
361 fn test_builder_no_roots() {
362 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 let builder = WebPkiServerVerifier::builder_with_provider(
375 test_roots(),
376 test_provider::default_provider().into(),
377 )
378 .only_check_end_entity_revocation();
379 println!("{:?}", builder);
381 builder.build().unwrap();
382 }
383
384 #[test]
385 fn test_server_verifier_allow_unknown() {
386 let builder = WebPkiServerVerifier::builder_with_provider(
389 test_roots(),
390 test_provider::default_provider().into(),
391 )
392 .allow_unknown_revocation_status();
393 println!("{:?}", builder);
395 builder.build().unwrap();
396 }
397
398 #[test]
399 fn test_server_verifier_allow_unknown_ee_only() {
400 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 println!("{:?}", builder);
410 builder.build().unwrap();
411 }
412}