1use std::fmt::{self, Debug};
2#[cfg(feature = "rustls")]
3use std::sync::Arc;
4
5#[cfg(feature = "boring-tls")]
6use boring::{
7 pkey::PKey,
8 ssl::{SslConnector, SslVersion},
9 x509::store::X509StoreBuilder,
10};
11#[cfg(feature = "native-tls")]
12use native_tls::{Protocol, TlsConnector};
13#[cfg(feature = "rustls")]
14use rustls::{
15 client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
16 crypto::{verify_tls12_signature, verify_tls13_signature, CryptoProvider},
17 pki_types::{self, pem::PemObject, CertificateDer, PrivateKeyDer, ServerName, UnixTime},
18 server::ParsedCertificate,
19 ClientConfig, DigitallySignedStruct, Error as TlsError, RootCertStore, SignatureScheme,
20};
21
22#[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
23use crate::transport::smtp::{error, Error};
24
25#[derive(Debug, Copy, Clone)]
27#[non_exhaustive]
28#[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
29pub enum TlsVersion {
30 Tlsv10,
38 Tlsv11,
46 Tlsv12,
52 Tlsv13,
59}
60
61#[derive(Clone)]
67#[allow(missing_copy_implementations)]
68#[cfg_attr(
69 not(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")),
70 deprecated(
71 note = "starting from lettre v0.12 `Tls` won't be available when none of the TLS backends are enabled"
72 )
73)]
74#[cfg_attr(
75 docsrs,
76 doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
77)]
78pub enum Tls {
79 None,
89 #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
99 #[cfg_attr(
100 docsrs,
101 doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
102 )]
103 Opportunistic(TlsParameters),
104 #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
114 #[cfg_attr(
115 docsrs,
116 doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
117 )]
118 Required(TlsParameters),
119 #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
127 #[cfg_attr(
128 docsrs,
129 doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
130 )]
131 Wrapper(TlsParameters),
132}
133
134impl Debug for Tls {
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 match &self {
137 Self::None => f.pad("None"),
138 #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
139 Self::Opportunistic(_) => f.pad("Opportunistic"),
140 #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
141 Self::Required(_) => f.pad("Required"),
142 #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
143 Self::Wrapper(_) => f.pad("Wrapper"),
144 }
145 }
146}
147
148#[allow(missing_copy_implementations)]
150#[derive(Clone, Debug, Default)]
151#[cfg_attr(
152 not(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")),
153 deprecated(
154 note = "starting from lettre v0.12 `CertificateStore` won't be available when none of the TLS backends are enabled"
155 )
156)]
157#[cfg_attr(
158 docsrs,
159 doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
160)]
161pub enum CertificateStore {
162 #[default]
173 Default,
174 #[cfg(all(feature = "rustls", feature = "webpki-roots"))]
178 WebpkiRoots,
179 None,
181}
182
183#[derive(Clone)]
185#[cfg_attr(
186 not(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")),
187 deprecated(
188 note = "starting from lettre v0.12 `TlsParameters` won't be available when none of the TLS backends are enabled"
189 )
190)]
191#[cfg_attr(
192 docsrs,
193 doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
194)]
195pub struct TlsParameters {
196 pub(crate) connector: InnerTlsParameters,
197 pub(super) domain: String,
199}
200
201#[derive(Debug, Clone)]
203#[cfg_attr(
204 not(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")),
205 deprecated(
206 note = "starting from lettre v0.12 `TlsParametersBuilder` won't be available when none of the TLS backends are enabled"
207 )
208)]
209#[cfg_attr(
210 docsrs,
211 doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
212)]
213pub struct TlsParametersBuilder {
214 domain: String,
215 cert_store: CertificateStore,
216 root_certs: Vec<Certificate>,
217 identity: Option<Identity>,
218 accept_invalid_hostnames: bool,
219 accept_invalid_certs: bool,
220 #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
221 min_tls_version: TlsVersion,
222}
223
224impl TlsParametersBuilder {
225 pub fn new(domain: String) -> Self {
227 Self {
228 domain,
229 cert_store: CertificateStore::Default,
230 root_certs: Vec::new(),
231 identity: None,
232 accept_invalid_hostnames: false,
233 accept_invalid_certs: false,
234 #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
235 min_tls_version: TlsVersion::Tlsv12,
236 }
237 }
238
239 pub fn certificate_store(mut self, cert_store: CertificateStore) -> Self {
241 self.cert_store = cert_store;
242 self
243 }
244
245 pub fn add_root_certificate(mut self, cert: Certificate) -> Self {
249 self.root_certs.push(cert);
250 self
251 }
252
253 pub fn identify_with(mut self, identity: Identity) -> Self {
257 self.identity = Some(identity);
258 self
259 }
260
261 #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
275 #[cfg_attr(
276 docsrs,
277 doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
278 )]
279 pub fn dangerous_accept_invalid_hostnames(mut self, accept_invalid_hostnames: bool) -> Self {
280 self.accept_invalid_hostnames = accept_invalid_hostnames;
281 self
282 }
283
284 #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
288 #[cfg_attr(
289 docsrs,
290 doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
291 )]
292 pub fn set_min_tls_version(mut self, min_tls_version: TlsVersion) -> Self {
293 self.min_tls_version = min_tls_version;
294 self
295 }
296
297 pub fn dangerous_accept_invalid_certs(mut self, accept_invalid_certs: bool) -> Self {
314 self.accept_invalid_certs = accept_invalid_certs;
315 self
316 }
317
318 #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
321 #[cfg_attr(
322 docsrs,
323 doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
324 )]
325 pub fn build(self) -> Result<TlsParameters, Error> {
326 #[cfg(feature = "rustls")]
327 return self.build_rustls();
328 #[cfg(all(not(feature = "rustls"), feature = "native-tls"))]
329 return self.build_native();
330 #[cfg(all(not(feature = "rustls"), feature = "boring-tls"))]
331 return self.build_boring();
332 }
333
334 #[cfg(feature = "native-tls")]
336 #[cfg_attr(docsrs, doc(cfg(feature = "native-tls")))]
337 pub fn build_native(self) -> Result<TlsParameters, Error> {
338 let mut tls_builder = TlsConnector::builder();
339
340 match self.cert_store {
341 CertificateStore::Default => {}
342 CertificateStore::None => {
343 tls_builder.disable_built_in_roots(true);
344 }
345 #[allow(unreachable_patterns)]
346 other => {
347 return Err(error::tls(format!(
348 "{other:?} is not supported in native tls"
349 )))
350 }
351 }
352 for cert in self.root_certs {
353 tls_builder.add_root_certificate(cert.native_tls);
354 }
355 tls_builder.danger_accept_invalid_hostnames(self.accept_invalid_hostnames);
356 tls_builder.danger_accept_invalid_certs(self.accept_invalid_certs);
357
358 let min_tls_version = match self.min_tls_version {
359 TlsVersion::Tlsv10 => Protocol::Tlsv10,
360 TlsVersion::Tlsv11 => Protocol::Tlsv11,
361 TlsVersion::Tlsv12 => Protocol::Tlsv12,
362 TlsVersion::Tlsv13 => {
363 return Err(error::tls(
364 "min tls version Tlsv13 not supported in native tls",
365 ))
366 }
367 };
368
369 tls_builder.min_protocol_version(Some(min_tls_version));
370 if let Some(identity) = self.identity {
371 tls_builder.identity(identity.native_tls);
372 }
373
374 let connector = tls_builder.build().map_err(error::tls)?;
375 Ok(TlsParameters {
376 connector: InnerTlsParameters::NativeTls { connector },
377 domain: self.domain,
378 })
379 }
380
381 #[cfg(feature = "boring-tls")]
383 #[cfg_attr(docsrs, doc(cfg(feature = "boring-tls")))]
384 pub fn build_boring(self) -> Result<TlsParameters, Error> {
385 use boring::ssl::{SslMethod, SslVerifyMode};
386
387 let mut tls_builder = SslConnector::builder(SslMethod::tls_client()).map_err(error::tls)?;
388
389 if self.accept_invalid_certs {
390 tls_builder.set_verify(SslVerifyMode::NONE);
391 } else {
392 match self.cert_store {
393 CertificateStore::Default => {}
394 CertificateStore::None => {
395 tls_builder
397 .set_cert_store(X509StoreBuilder::new().map_err(error::tls)?.build());
398 }
399 #[allow(unreachable_patterns)]
400 other => {
401 return Err(error::tls(format!(
402 "{other:?} is not supported in boring tls"
403 )))
404 }
405 }
406
407 let cert_store = tls_builder.cert_store_mut();
408
409 for cert in self.root_certs {
410 cert_store.add_cert(cert.boring_tls).map_err(error::tls)?;
411 }
412 }
413
414 if let Some(identity) = self.identity {
415 tls_builder
416 .set_certificate(identity.boring_tls.0.as_ref())
417 .map_err(error::tls)?;
418 tls_builder
419 .set_private_key(identity.boring_tls.1.as_ref())
420 .map_err(error::tls)?;
421 }
422
423 let min_tls_version = match self.min_tls_version {
424 TlsVersion::Tlsv10 => SslVersion::TLS1,
425 TlsVersion::Tlsv11 => SslVersion::TLS1_1,
426 TlsVersion::Tlsv12 => SslVersion::TLS1_2,
427 TlsVersion::Tlsv13 => SslVersion::TLS1_3,
428 };
429
430 tls_builder
431 .set_min_proto_version(Some(min_tls_version))
432 .map_err(error::tls)?;
433 let connector = tls_builder.build();
434 Ok(TlsParameters {
435 connector: InnerTlsParameters::BoringTls {
436 connector,
437 accept_invalid_hostnames: self.accept_invalid_hostnames,
438 },
439 domain: self.domain,
440 })
441 }
442
443 #[cfg(feature = "rustls")]
445 #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
446 pub fn build_rustls(self) -> Result<TlsParameters, Error> {
447 let just_version3 = &[&rustls::version::TLS13];
448 let supported_versions = match self.min_tls_version {
449 TlsVersion::Tlsv10 => {
450 return Err(error::tls("min tls version Tlsv10 not supported in rustls"))
451 }
452 TlsVersion::Tlsv11 => {
453 return Err(error::tls("min tls version Tlsv11 not supported in rustls"))
454 }
455 TlsVersion::Tlsv12 => rustls::ALL_VERSIONS,
456 TlsVersion::Tlsv13 => just_version3,
457 };
458
459 let crypto_provider = crate::rustls_crypto::crypto_provider();
460 let tls = ClientConfig::builder_with_provider(Arc::clone(&crypto_provider))
461 .with_protocol_versions(supported_versions)
462 .map_err(error::tls)?;
463
464 let mut root_cert_store = RootCertStore::empty();
466
467 #[cfg(all(
468 not(feature = "rustls-platform-verifier"),
469 feature = "rustls-native-certs"
470 ))]
471 fn load_native_roots(store: &mut RootCertStore) {
472 let rustls_native_certs::CertificateResult { certs, errors, .. } =
473 rustls_native_certs::load_native_certs();
474 let errors_len = errors.len();
475
476 let (added, ignored) = store.add_parsable_certificates(certs);
477 #[cfg(feature = "tracing")]
478 tracing::debug!(
479 "loaded platform certs with {errors_len} failing to load, {added} valid and {ignored} ignored (invalid) certs"
480 );
481 #[cfg(not(feature = "tracing"))]
482 let _ = (errors_len, added, ignored);
483 }
484
485 #[cfg(all(feature = "rustls", feature = "webpki-roots"))]
486 fn load_webpki_roots(store: &mut RootCertStore) {
487 store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
488 }
489
490 #[cfg_attr(not(feature = "rustls-platform-verifier"), allow(unused_mut))]
491 let mut extra_roots = None::<Vec<CertificateDer<'static>>>;
492 match self.cert_store {
493 CertificateStore::Default => {
494 #[cfg(feature = "rustls-platform-verifier")]
495 {
496 extra_roots = Some(Vec::new());
497 }
498
499 #[cfg(all(
500 not(feature = "rustls-platform-verifier"),
501 feature = "rustls-native-certs"
502 ))]
503 load_native_roots(&mut root_cert_store);
504
505 #[cfg(all(
506 not(feature = "rustls-platform-verifier"),
507 not(feature = "rustls-native-certs"),
508 feature = "webpki-roots"
509 ))]
510 load_webpki_roots(&mut root_cert_store);
511 }
512 #[cfg(all(feature = "rustls", feature = "webpki-roots"))]
513 CertificateStore::WebpkiRoots => {
514 load_webpki_roots(&mut root_cert_store);
515 }
516 CertificateStore::None => {}
517 }
518 for cert in self.root_certs {
519 for rustls_cert in cert.rustls {
520 #[cfg(feature = "rustls-platform-verifier")]
521 if let Some(extra_roots) = &mut extra_roots {
522 extra_roots.push(rustls_cert.clone());
523 }
524 root_cert_store.add(rustls_cert).map_err(error::tls)?;
525 }
526 }
527
528 let tls = if self.accept_invalid_certs
529 || (extra_roots.is_none() && self.accept_invalid_hostnames)
530 {
531 let verifier = InvalidCertsVerifier {
532 ignore_invalid_hostnames: self.accept_invalid_hostnames,
533 ignore_invalid_certs: self.accept_invalid_certs,
534 roots: root_cert_store,
535 crypto_provider,
536 };
537 tls.dangerous()
538 .with_custom_certificate_verifier(Arc::new(verifier))
539 } else {
540 #[cfg(feature = "rustls-platform-verifier")]
541 if let Some(extra_roots) = extra_roots {
542 tls.dangerous().with_custom_certificate_verifier(Arc::new(
543 rustls_platform_verifier::Verifier::new_with_extra_roots(
544 extra_roots,
545 crypto_provider,
546 )
547 .map_err(error::tls)?,
548 ))
549 } else {
550 tls.with_root_certificates(root_cert_store)
551 }
552
553 #[cfg(not(feature = "rustls-platform-verifier"))]
554 {
555 tls.with_root_certificates(root_cert_store)
556 }
557 };
558
559 let tls = if let Some(identity) = self.identity {
560 let (client_certificates, private_key) = identity.rustls_tls;
561 tls.with_client_auth_cert(client_certificates, private_key)
562 .map_err(error::tls)?
563 } else {
564 tls.with_no_client_auth()
565 };
566
567 Ok(TlsParameters {
568 connector: InnerTlsParameters::Rustls {
569 config: Arc::new(tls),
570 },
571 domain: self.domain,
572 })
573 }
574}
575
576#[derive(Clone)]
577#[allow(clippy::enum_variant_names)]
578pub(crate) enum InnerTlsParameters {
579 #[cfg(feature = "native-tls")]
580 NativeTls { connector: TlsConnector },
581 #[cfg(feature = "rustls")]
582 Rustls { config: Arc<ClientConfig> },
583 #[cfg(feature = "boring-tls")]
584 BoringTls {
585 connector: SslConnector,
586 accept_invalid_hostnames: bool,
587 },
588}
589
590impl TlsParameters {
591 #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
594 #[cfg_attr(
595 docsrs,
596 doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
597 )]
598 pub fn new(domain: String) -> Result<Self, Error> {
599 TlsParametersBuilder::new(domain).build()
600 }
601
602 pub fn builder(domain: String) -> TlsParametersBuilder {
604 TlsParametersBuilder::new(domain)
605 }
606
607 #[cfg(feature = "native-tls")]
609 #[cfg_attr(docsrs, doc(cfg(feature = "native-tls")))]
610 pub fn new_native(domain: String) -> Result<Self, Error> {
611 TlsParametersBuilder::new(domain).build_native()
612 }
613
614 #[cfg(feature = "rustls")]
616 #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
617 pub fn new_rustls(domain: String) -> Result<Self, Error> {
618 TlsParametersBuilder::new(domain).build_rustls()
619 }
620
621 #[cfg(feature = "boring-tls")]
623 #[cfg_attr(docsrs, doc(cfg(feature = "boring-tls")))]
624 pub fn new_boring(domain: String) -> Result<Self, Error> {
625 TlsParametersBuilder::new(domain).build_boring()
626 }
627
628 pub fn domain(&self) -> &str {
629 &self.domain
630 }
631}
632
633#[derive(Clone)]
635#[allow(missing_copy_implementations)]
636#[cfg_attr(
637 not(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")),
638 deprecated(
639 note = "starting from lettre v0.12 `Certificate` won't be available when none of the TLS backends are enabled"
640 )
641)]
642#[cfg_attr(
643 docsrs,
644 doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
645)]
646pub struct Certificate {
647 #[cfg(feature = "native-tls")]
648 native_tls: native_tls::Certificate,
649 #[cfg(feature = "rustls")]
650 rustls: Vec<CertificateDer<'static>>,
651 #[cfg(feature = "boring-tls")]
652 boring_tls: boring::x509::X509,
653}
654
655#[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
656impl Certificate {
657 pub fn from_der(der: Vec<u8>) -> Result<Self, Error> {
659 #[cfg(feature = "native-tls")]
660 let native_tls_cert = native_tls::Certificate::from_der(&der).map_err(error::tls)?;
661
662 #[cfg(feature = "boring-tls")]
663 let boring_tls_cert = boring::x509::X509::from_der(&der).map_err(error::tls)?;
664
665 Ok(Self {
666 #[cfg(feature = "native-tls")]
667 native_tls: native_tls_cert,
668 #[cfg(feature = "rustls")]
669 rustls: vec![der.into()],
670 #[cfg(feature = "boring-tls")]
671 boring_tls: boring_tls_cert,
672 })
673 }
674
675 pub fn from_pem(pem: &[u8]) -> Result<Self, Error> {
677 #[cfg(feature = "native-tls")]
678 let native_tls_cert = native_tls::Certificate::from_pem(pem).map_err(error::tls)?;
679
680 #[cfg(feature = "boring-tls")]
681 let boring_tls_cert = boring::x509::X509::from_pem(pem).map_err(error::tls)?;
682
683 #[cfg(feature = "rustls")]
684 let rustls_cert = {
685 CertificateDer::pem_slice_iter(pem)
686 .collect::<Result<Vec<_>, pki_types::pem::Error>>()
687 .map_err(|_| error::tls("invalid certificates"))?
688 };
689
690 Ok(Self {
691 #[cfg(feature = "native-tls")]
692 native_tls: native_tls_cert,
693 #[cfg(feature = "rustls")]
694 rustls: rustls_cert,
695 #[cfg(feature = "boring-tls")]
696 boring_tls: boring_tls_cert,
697 })
698 }
699}
700
701impl Debug for Certificate {
702 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
703 f.debug_struct("Certificate").finish()
704 }
705}
706
707#[allow(missing_copy_implementations)]
709#[cfg_attr(
710 not(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")),
711 deprecated(
712 note = "starting from lettre v0.12 `Identity` won't be available when none of the TLS backends are enabled"
713 )
714)]
715#[cfg_attr(
716 docsrs,
717 doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
718)]
719pub struct Identity {
720 #[cfg(feature = "native-tls")]
721 native_tls: native_tls::Identity,
722 #[cfg(feature = "rustls")]
723 rustls_tls: (Vec<CertificateDer<'static>>, PrivateKeyDer<'static>),
724 #[cfg(feature = "boring-tls")]
725 boring_tls: (boring::x509::X509, PKey<boring::pkey::Private>),
726}
727
728impl Debug for Identity {
729 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
730 f.debug_struct("Identity").finish()
731 }
732}
733
734impl Clone for Identity {
735 fn clone(&self) -> Self {
736 Identity {
737 #[cfg(feature = "native-tls")]
738 native_tls: self.native_tls.clone(),
739 #[cfg(feature = "rustls")]
740 rustls_tls: (self.rustls_tls.0.clone(), self.rustls_tls.1.clone_key()),
741 #[cfg(feature = "boring-tls")]
742 boring_tls: (self.boring_tls.0.clone(), self.boring_tls.1.clone()),
743 }
744 }
745}
746
747#[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
748impl Identity {
749 pub fn from_pem(pem: &[u8], key: &[u8]) -> Result<Self, Error> {
750 Ok(Self {
751 #[cfg(feature = "native-tls")]
752 native_tls: Identity::from_pem_native_tls(pem, key)?,
753 #[cfg(feature = "rustls")]
754 rustls_tls: Identity::from_pem_rustls_tls(pem, key)?,
755 #[cfg(feature = "boring-tls")]
756 boring_tls: Identity::from_pem_boring_tls(pem, key)?,
757 })
758 }
759
760 #[cfg(feature = "native-tls")]
761 fn from_pem_native_tls(pem: &[u8], key: &[u8]) -> Result<native_tls::Identity, Error> {
762 native_tls::Identity::from_pkcs8(pem, key).map_err(error::tls)
763 }
764
765 #[cfg(feature = "rustls")]
766 fn from_pem_rustls_tls(
767 pem: &[u8],
768 key: &[u8],
769 ) -> Result<(Vec<CertificateDer<'static>>, PrivateKeyDer<'static>), Error> {
770 let key = match PrivateKeyDer::from_pem_slice(key) {
771 Ok(key) => key,
772 Err(pki_types::pem::Error::NoItemsFound) => {
773 return Err(error::tls("no private key found"))
774 }
775 Err(err) => return Err(error::tls(err)),
776 };
777
778 Ok((vec![pem.to_owned().into()], key))
779 }
780
781 #[cfg(feature = "boring-tls")]
782 fn from_pem_boring_tls(
783 pem: &[u8],
784 key: &[u8],
785 ) -> Result<(boring::x509::X509, PKey<boring::pkey::Private>), Error> {
786 let cert = boring::x509::X509::from_pem(pem).map_err(error::tls)?;
787 let key = boring::pkey::PKey::private_key_from_pem(key).map_err(error::tls)?;
788 Ok((cert, key))
789 }
790}
791
792#[cfg(feature = "rustls")]
793#[derive(Debug)]
794struct InvalidCertsVerifier {
795 ignore_invalid_hostnames: bool,
796 ignore_invalid_certs: bool,
797 roots: RootCertStore,
798 crypto_provider: Arc<CryptoProvider>,
799}
800
801#[cfg(feature = "rustls")]
802impl ServerCertVerifier for InvalidCertsVerifier {
803 fn verify_server_cert(
804 &self,
805 end_entity: &CertificateDer<'_>,
806 intermediates: &[CertificateDer<'_>],
807 server_name: &ServerName<'_>,
808 _ocsp_response: &[u8],
809 now: UnixTime,
810 ) -> Result<ServerCertVerified, TlsError> {
811 let cert = ParsedCertificate::try_from(end_entity)?;
812
813 if !self.ignore_invalid_certs {
814 rustls::client::verify_server_cert_signed_by_trust_anchor(
815 &cert,
816 &self.roots,
817 intermediates,
818 now,
819 self.crypto_provider.signature_verification_algorithms.all,
820 )?;
821 }
822
823 if !self.ignore_invalid_hostnames {
824 rustls::client::verify_server_name(&cert, server_name)?;
825 }
826 Ok(ServerCertVerified::assertion())
827 }
828
829 fn verify_tls12_signature(
830 &self,
831 message: &[u8],
832 cert: &CertificateDer<'_>,
833 dss: &DigitallySignedStruct,
834 ) -> Result<HandshakeSignatureValid, TlsError> {
835 verify_tls12_signature(
836 message,
837 cert,
838 dss,
839 &self.crypto_provider.signature_verification_algorithms,
840 )
841 }
842
843 fn verify_tls13_signature(
844 &self,
845 message: &[u8],
846 cert: &CertificateDer<'_>,
847 dss: &DigitallySignedStruct,
848 ) -> Result<HandshakeSignatureValid, TlsError> {
849 verify_tls13_signature(
850 message,
851 cert,
852 dss,
853 &self.crypto_provider.signature_verification_algorithms,
854 )
855 }
856
857 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
858 self.crypto_provider
859 .signature_verification_algorithms
860 .supported_schemes()
861 }
862}