1use alloc::vec::Vec;
2
3use pki_types::{CertificateDer, CertificateRevocationListDer, ServerName, UnixTime};
4use webpki::{CertRevocationList, ExpirationPolicy, RevocationCheckDepth, UnknownStatusPolicy};
5
6use crate::crypto::{CryptoProvider, WebPkiSupportedAlgorithms};
7use crate::sync::Arc;
8use crate::verify::{
9 DigitallySignedStruct, HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier,
10};
11use crate::webpki::verify::{
12 ParsedCertificate, verify_server_cert_signed_by_trust_anchor_impl, verify_tls12_signature,
13 verify_tls13_signature,
14};
15use crate::webpki::{VerifierBuilderError, parse_crls, verify_server_name};
16#[cfg(doc)]
17use crate::{ConfigBuilder, ServerConfig, crypto};
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 revocation_expiration_policy: ExpirationPolicy,
30 supported_algs: WebPkiSupportedAlgorithms,
31}
32
33impl ServerCertVerifierBuilder {
34 pub(crate) fn new(
35 roots: Arc<RootCertStore>,
36 supported_algs: WebPkiSupportedAlgorithms,
37 ) -> Self {
38 Self {
39 roots,
40 crls: Vec::new(),
41 revocation_check_depth: RevocationCheckDepth::Chain,
42 unknown_revocation_policy: UnknownStatusPolicy::Deny,
43 revocation_expiration_policy: ExpirationPolicy::Ignore,
44 supported_algs,
45 }
46 }
47
48 pub fn with_crls(
52 mut self,
53 crls: impl IntoIterator<Item = CertificateRevocationListDer<'static>>,
54 ) -> Self {
55 self.crls.extend(crls);
56 self
57 }
58
59 pub fn only_check_end_entity_revocation(mut self) -> Self {
69 self.revocation_check_depth = RevocationCheckDepth::EndEntity;
70 self
71 }
72
73 pub fn allow_unknown_revocation_status(mut self) -> Self {
82 self.unknown_revocation_policy = UnknownStatusPolicy::Allow;
83 self
84 }
85
86 pub fn enforce_revocation_expiration(mut self) -> Self {
95 self.revocation_expiration_policy = ExpirationPolicy::Enforce;
96 self
97 }
98
99 pub fn build(self) -> Result<Arc<WebPkiServerVerifier>, VerifierBuilderError> {
114 if self.roots.is_empty() {
115 return Err(VerifierBuilderError::NoRootAnchors);
116 }
117
118 Ok(WebPkiServerVerifier::new(
119 self.roots,
120 parse_crls(self.crls)?,
121 self.revocation_check_depth,
122 self.unknown_revocation_policy,
123 self.revocation_expiration_policy,
124 self.supported_algs,
125 )
126 .into())
127 }
128}
129
130#[allow(unreachable_pub)]
132#[derive(Debug)]
133pub struct WebPkiServerVerifier {
134 roots: Arc<RootCertStore>,
135 crls: Vec<CertRevocationList<'static>>,
136 revocation_check_depth: RevocationCheckDepth,
137 unknown_revocation_policy: UnknownStatusPolicy,
138 revocation_expiration_policy: ExpirationPolicy,
139 supported: WebPkiSupportedAlgorithms,
140}
141
142#[allow(unreachable_pub)]
143impl WebPkiServerVerifier {
144 pub fn builder(roots: Arc<RootCertStore>) -> ServerCertVerifierBuilder {
153 Self::builder_with_provider(
154 roots,
155 CryptoProvider::get_default_or_install_from_crate_features().clone(),
156 )
157 }
158
159 pub fn builder_with_provider(
168 roots: Arc<RootCertStore>,
169 provider: Arc<CryptoProvider>,
170 ) -> ServerCertVerifierBuilder {
171 ServerCertVerifierBuilder::new(roots, provider.signature_verification_algorithms)
172 }
173
174 pub(crate) fn new_without_revocation(
177 roots: impl Into<Arc<RootCertStore>>,
178 supported_algs: WebPkiSupportedAlgorithms,
179 ) -> Self {
180 Self::new(
181 roots,
182 Vec::default(),
183 RevocationCheckDepth::Chain,
184 UnknownStatusPolicy::Allow,
185 ExpirationPolicy::Ignore,
186 supported_algs,
187 )
188 }
189
190 pub(crate) fn new(
202 roots: impl Into<Arc<RootCertStore>>,
203 crls: Vec<CertRevocationList<'static>>,
204 revocation_check_depth: RevocationCheckDepth,
205 unknown_revocation_policy: UnknownStatusPolicy,
206 revocation_expiration_policy: ExpirationPolicy,
207 supported: WebPkiSupportedAlgorithms,
208 ) -> Self {
209 Self {
210 roots: roots.into(),
211 crls,
212 revocation_check_depth,
213 unknown_revocation_policy,
214 revocation_expiration_policy,
215 supported,
216 }
217 }
218}
219
220impl ServerCertVerifier for WebPkiServerVerifier {
221 fn verify_server_cert(
232 &self,
233 end_entity: &CertificateDer<'_>,
234 intermediates: &[CertificateDer<'_>],
235 server_name: &ServerName<'_>,
236 _ocsp_response: &[u8],
237 now: UnixTime,
238 ) -> Result<ServerCertVerified, Error> {
239 let cert = ParsedCertificate::try_from(end_entity)?;
240
241 let crl_refs = self.crls.iter().collect::<Vec<_>>();
242
243 let revocation = if self.crls.is_empty() {
244 None
245 } else {
246 Some(
249 webpki::RevocationOptionsBuilder::new(crl_refs.as_slice())
250 .unwrap()
253 .with_depth(self.revocation_check_depth)
254 .with_status_policy(self.unknown_revocation_policy)
255 .with_expiration_policy(self.revocation_expiration_policy)
256 .build(),
257 )
258 };
259
260 verify_server_cert_signed_by_trust_anchor_impl(
263 &cert,
264 &self.roots,
265 intermediates,
266 revocation,
267 now,
268 self.supported.all,
269 )?;
270
271 verify_server_name(&cert, server_name)?;
272 Ok(ServerCertVerified::assertion())
273 }
274
275 fn verify_tls12_signature(
276 &self,
277 message: &[u8],
278 cert: &CertificateDer<'_>,
279 dss: &DigitallySignedStruct,
280 ) -> Result<HandshakeSignatureValid, Error> {
281 verify_tls12_signature(message, cert, dss, &self.supported)
282 }
283
284 fn verify_tls13_signature(
285 &self,
286 message: &[u8],
287 cert: &CertificateDer<'_>,
288 dss: &DigitallySignedStruct,
289 ) -> Result<HandshakeSignatureValid, Error> {
290 verify_tls13_signature(message, cert, dss, &self.supported)
291 }
292
293 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
294 self.supported.supported_schemes()
295 }
296
297 fn request_ocsp_response(&self) -> bool {
298 false
299 }
300}
301
302#[cfg(test)]
303#[macro_rules_attribute::apply(test_for_each_provider)]
304mod tests {
305 use std::prelude::v1::*;
306 use std::{println, vec};
307
308 use pki_types::pem::PemObject;
309 use pki_types::{CertificateDer, CertificateRevocationListDer};
310
311 use super::{VerifierBuilderError, WebPkiServerVerifier, provider};
312 use crate::RootCertStore;
313 use crate::sync::Arc;
314
315 fn load_crls(crls_der: &[&[u8]]) -> Vec<CertificateRevocationListDer<'static>> {
316 crls_der
317 .iter()
318 .map(|pem_bytes| CertificateRevocationListDer::from_pem_slice(pem_bytes).unwrap())
319 .collect()
320 }
321
322 fn test_crls() -> Vec<CertificateRevocationListDer<'static>> {
323 load_crls(&[
324 include_bytes!("../../../test-ca/ecdsa-p256/client.revoked.crl.pem").as_slice(),
325 include_bytes!("../../../test-ca/rsa-2048/client.revoked.crl.pem").as_slice(),
326 ])
327 }
328
329 fn load_roots(roots_der: &[&[u8]]) -> Arc<RootCertStore> {
330 let mut roots = RootCertStore::empty();
331 roots_der.iter().for_each(|der| {
332 roots
333 .add(CertificateDer::from(der.to_vec()))
334 .unwrap()
335 });
336 roots.into()
337 }
338
339 fn test_roots() -> Arc<RootCertStore> {
340 load_roots(&[
341 include_bytes!("../../../test-ca/ecdsa-p256/ca.der").as_slice(),
342 include_bytes!("../../../test-ca/rsa-2048/ca.der").as_slice(),
343 ])
344 }
345
346 #[test]
347 fn test_with_invalid_crls() {
348 let result = WebPkiServerVerifier::builder_with_provider(
350 test_roots(),
351 provider::default_provider().into(),
352 )
353 .with_crls(vec![CertificateRevocationListDer::from(vec![0xFF])])
354 .build();
355 assert!(matches!(result, Err(VerifierBuilderError::InvalidCrl(_))));
356 }
357
358 #[test]
359 fn test_with_crls_multiple_calls() {
360 let initial_crls = test_crls();
362 let extra_crls =
363 load_crls(&[
364 include_bytes!("../../../test-ca/eddsa/client.revoked.crl.pem").as_slice(),
365 ]);
366
367 let builder = WebPkiServerVerifier::builder_with_provider(
368 test_roots(),
369 provider::default_provider().into(),
370 )
371 .with_crls(initial_crls.clone())
372 .with_crls(extra_crls.clone());
373
374 assert_eq!(builder.crls.len(), initial_crls.len() + extra_crls.len());
376 println!("{builder:?}");
378 builder.build().unwrap();
379 }
380
381 #[test]
382 fn test_builder_no_roots() {
383 let result = WebPkiServerVerifier::builder_with_provider(
385 RootCertStore::empty().into(),
386 provider::default_provider().into(),
387 )
388 .build();
389 assert!(matches!(result, Err(VerifierBuilderError::NoRootAnchors)));
390 }
391
392 #[test]
393 fn test_server_verifier_ee_only() {
394 let builder = WebPkiServerVerifier::builder_with_provider(
396 test_roots(),
397 provider::default_provider().into(),
398 )
399 .only_check_end_entity_revocation();
400 println!("{builder:?}");
402 builder.build().unwrap();
403 }
404
405 #[test]
406 fn test_server_verifier_allow_unknown() {
407 let builder = WebPkiServerVerifier::builder_with_provider(
410 test_roots(),
411 provider::default_provider().into(),
412 )
413 .allow_unknown_revocation_status();
414 println!("{builder:?}");
416 builder.build().unwrap();
417 }
418
419 #[test]
420 fn test_server_verifier_allow_unknown_ee_only() {
421 let builder = WebPkiServerVerifier::builder_with_provider(
424 test_roots(),
425 provider::default_provider().into(),
426 )
427 .allow_unknown_revocation_status()
428 .only_check_end_entity_revocation();
429 println!("{builder:?}");
431 builder.build().unwrap();
432 }
433
434 #[test]
435 fn test_server_verifier_enforce_expiration() {
436 let builder = WebPkiServerVerifier::builder_with_provider(
439 test_roots(),
440 provider::default_provider().into(),
441 )
442 .enforce_revocation_expiration();
443 println!("{builder:?}");
445 builder.build().unwrap();
446 }
447}