1#[cfg(feature = "__rustls")]
47use rustls::{
48 client::danger::HandshakeSignatureValid, client::danger::ServerCertVerified,
49 client::danger::ServerCertVerifier, crypto::WebPkiSupportedAlgorithms,
50 server::ParsedCertificate, DigitallySignedStruct, Error as TLSError, RootCertStore,
51 SignatureScheme,
52};
53use rustls_pki_types::pem::PemObject;
54#[cfg(feature = "__rustls")]
55use rustls_pki_types::{ServerName, UnixTime};
56use std::{
57 fmt,
58 io::{BufRead, BufReader},
59};
60
61#[cfg(feature = "__rustls")]
63pub struct CertificateRevocationList {
64 #[cfg(feature = "__rustls")]
65 inner: rustls_pki_types::CertificateRevocationListDer<'static>,
66}
67
68#[derive(Clone)]
70pub struct Certificate {
71 #[cfg(feature = "__native-tls")]
72 native: native_tls_crate::Certificate,
73 #[cfg(feature = "__rustls")]
74 original: Cert,
75}
76
77#[cfg(feature = "__rustls")]
78#[derive(Clone)]
79enum Cert {
80 Der(Vec<u8>),
81 Pem(Vec<u8>),
82}
83
84#[derive(Clone)]
86pub struct Identity {
87 #[cfg_attr(
88 not(any(feature = "__native-tls", feature = "__rustls")),
89 allow(unused)
90 )]
91 inner: ClientCert,
92}
93
94enum ClientCert {
95 #[cfg(feature = "__native-tls")]
96 Pkcs12(native_tls_crate::Identity),
97 #[cfg(feature = "__native-tls")]
98 Pkcs8(native_tls_crate::Identity),
99 #[cfg(feature = "__rustls")]
100 Pem {
101 key: rustls_pki_types::PrivateKeyDer<'static>,
102 certs: Vec<rustls_pki_types::CertificateDer<'static>>,
103 },
104}
105
106impl Clone for ClientCert {
107 fn clone(&self) -> Self {
108 match self {
109 #[cfg(feature = "__native-tls")]
110 Self::Pkcs8(i) => Self::Pkcs8(i.clone()),
111 #[cfg(feature = "__native-tls")]
112 Self::Pkcs12(i) => Self::Pkcs12(i.clone()),
113 #[cfg(feature = "__rustls")]
114 ClientCert::Pem { key, certs } => ClientCert::Pem {
115 key: key.clone_key(),
116 certs: certs.clone(),
117 },
118 #[cfg_attr(
119 any(feature = "__native-tls", feature = "__rustls"),
120 allow(unreachable_patterns)
121 )]
122 _ => unreachable!(),
123 }
124 }
125}
126
127impl Certificate {
128 pub fn from_der(der: &[u8]) -> crate::Result<Certificate> {
145 Ok(Certificate {
146 #[cfg(feature = "__native-tls")]
147 native: native_tls_crate::Certificate::from_der(der).map_err(crate::error::builder)?,
148 #[cfg(feature = "__rustls")]
149 original: Cert::Der(der.to_owned()),
150 })
151 }
152
153 pub fn from_pem(pem: &[u8]) -> crate::Result<Certificate> {
170 Ok(Certificate {
171 #[cfg(feature = "__native-tls")]
172 native: native_tls_crate::Certificate::from_pem(pem).map_err(crate::error::builder)?,
173 #[cfg(feature = "__rustls")]
174 original: Cert::Pem(pem.to_owned()),
175 })
176 }
177
178 pub fn from_pem_bundle(pem_bundle: &[u8]) -> crate::Result<Vec<Certificate>> {
196 let mut reader = BufReader::new(pem_bundle);
197
198 Self::read_pem_certs(&mut reader)?
199 .iter()
200 .map(|cert_vec| Certificate::from_der(cert_vec))
201 .collect::<crate::Result<Vec<Certificate>>>()
202 }
203
204 #[cfg(feature = "__native-tls")]
212 pub(crate) fn add_to_native_tls(self, tls: &mut native_tls_crate::TlsConnectorBuilder) {
213 tls.add_root_certificate(self.native);
214 }
215
216 #[cfg(feature = "__rustls")]
217 pub(crate) fn add_to_rustls(
218 self,
219 root_cert_store: &mut rustls::RootCertStore,
220 ) -> crate::Result<()> {
221 use std::io::Cursor;
222
223 match self.original {
224 Cert::Der(buf) => root_cert_store
225 .add(buf.into())
226 .map_err(crate::error::builder)?,
227 Cert::Pem(buf) => {
228 let mut reader = Cursor::new(buf);
229 let certs = Self::read_pem_certs(&mut reader)?;
230 for c in certs {
231 root_cert_store
232 .add(c.into())
233 .map_err(crate::error::builder)?;
234 }
235 }
236 }
237 Ok(())
238 }
239
240 fn read_pem_certs(reader: &mut impl BufRead) -> crate::Result<Vec<Vec<u8>>> {
241 rustls_pki_types::CertificateDer::pem_reader_iter(reader)
242 .map(|result| match result {
243 Ok(cert) => Ok(cert.as_ref().to_vec()),
244 Err(_) => Err(crate::error::builder("invalid certificate encoding")),
245 })
246 .collect()
247 }
248}
249
250impl Identity {
251 #[cfg(feature = "__native-tls")]
283 pub fn from_pkcs12_der(der: &[u8], password: &str) -> crate::Result<Identity> {
284 Ok(Identity {
285 inner: ClientCert::Pkcs12(
286 native_tls_crate::Identity::from_pkcs12(der, password)
287 .map_err(crate::error::builder)?,
288 ),
289 })
290 }
291
292 #[cfg(feature = "__native-tls")]
317 pub fn from_pkcs8_pem(pem: &[u8], key: &[u8]) -> crate::Result<Identity> {
318 Ok(Identity {
319 inner: ClientCert::Pkcs8(
320 native_tls_crate::Identity::from_pkcs8(pem, key).map_err(crate::error::builder)?,
321 ),
322 })
323 }
324
325 #[cfg(feature = "__rustls")]
351 pub fn from_pem(buf: &[u8]) -> crate::Result<Identity> {
352 use rustls_pki_types::{pem::SectionKind, PrivateKeyDer};
353 use std::io::Cursor;
354
355 let (key, certs) = {
356 let mut pem = Cursor::new(buf);
357 let mut sk = Vec::<rustls_pki_types::PrivateKeyDer>::new();
358 let mut certs = Vec::<rustls_pki_types::CertificateDer>::new();
359
360 while let Some((kind, data)) =
361 rustls_pki_types::pem::from_buf(&mut pem).map_err(|_| {
362 crate::error::builder(TLSError::General(String::from(
363 "Invalid identity PEM file",
364 )))
365 })?
366 {
367 match kind {
368 SectionKind::Certificate => certs.push(data.into()),
369 SectionKind::PrivateKey => sk.push(PrivateKeyDer::Pkcs8(data.into())),
370 SectionKind::RsaPrivateKey => sk.push(PrivateKeyDer::Pkcs1(data.into())),
371 SectionKind::EcPrivateKey => sk.push(PrivateKeyDer::Sec1(data.into())),
372 _ => {
373 return Err(crate::error::builder(TLSError::General(String::from(
374 "No valid certificate was found",
375 ))))
376 }
377 }
378 }
379
380 if let (Some(sk), false) = (sk.pop(), certs.is_empty()) {
381 (sk, certs)
382 } else {
383 return Err(crate::error::builder(TLSError::General(String::from(
384 "private key or certificate not found",
385 ))));
386 }
387 };
388
389 Ok(Identity {
390 inner: ClientCert::Pem { key, certs },
391 })
392 }
393
394 #[cfg(feature = "__native-tls")]
395 pub(crate) fn add_to_native_tls(
396 self,
397 tls: &mut native_tls_crate::TlsConnectorBuilder,
398 ) -> crate::Result<()> {
399 match self.inner {
400 ClientCert::Pkcs12(id) | ClientCert::Pkcs8(id) => {
401 tls.identity(id);
402 Ok(())
403 }
404 #[cfg(feature = "__rustls")]
405 ClientCert::Pem { .. } => Err(crate::error::builder("incompatible TLS identity type")),
406 }
407 }
408
409 #[cfg(feature = "__rustls")]
410 pub(crate) fn add_to_rustls(
411 self,
412 config_builder: rustls::ConfigBuilder<
413 rustls::ClientConfig,
414 rustls::client::WantsClientCert,
416 >,
417 ) -> crate::Result<rustls::ClientConfig> {
418 match self.inner {
419 ClientCert::Pem { key, certs } => config_builder
420 .with_client_auth_cert(certs, key)
421 .map_err(crate::error::builder),
422 #[cfg(feature = "__native-tls")]
423 ClientCert::Pkcs12(..) | ClientCert::Pkcs8(..) => {
424 Err(crate::error::builder("incompatible TLS identity type"))
425 }
426 }
427 }
428}
429
430#[cfg(feature = "__rustls")]
431impl CertificateRevocationList {
432 #[cfg(feature = "__rustls")]
453 pub fn from_pem(pem: &[u8]) -> crate::Result<CertificateRevocationList> {
454 Ok(CertificateRevocationList {
455 #[cfg(feature = "__rustls")]
456 inner: rustls_pki_types::CertificateRevocationListDer::from(pem.to_vec()),
457 })
458 }
459
460 #[cfg(feature = "__rustls")]
482 pub fn from_pem_bundle(pem_bundle: &[u8]) -> crate::Result<Vec<CertificateRevocationList>> {
483 rustls_pki_types::CertificateRevocationListDer::pem_slice_iter(pem_bundle)
484 .map(|result| match result {
485 Ok(crl) => Ok(CertificateRevocationList { inner: crl }),
486 Err(_) => Err(crate::error::builder("invalid crl encoding")),
487 })
488 .collect::<crate::Result<Vec<CertificateRevocationList>>>()
489 }
490
491 #[cfg(feature = "__rustls")]
492 pub(crate) fn as_rustls_crl<'a>(&self) -> rustls_pki_types::CertificateRevocationListDer<'a> {
493 self.inner.clone()
494 }
495}
496
497impl fmt::Debug for Certificate {
498 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
499 f.debug_struct("Certificate").finish()
500 }
501}
502
503impl fmt::Debug for Identity {
504 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
505 f.debug_struct("Identity").finish()
506 }
507}
508
509#[cfg(feature = "__rustls")]
510impl fmt::Debug for CertificateRevocationList {
511 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
512 f.debug_struct("CertificateRevocationList").finish()
513 }
514}
515
516#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
518pub struct Version(InnerVersion);
519
520#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
521#[non_exhaustive]
522enum InnerVersion {
523 Tls1_0,
524 Tls1_1,
525 Tls1_2,
526 Tls1_3,
527}
528
529impl Version {
532 pub const TLS_1_0: Version = Version(InnerVersion::Tls1_0);
534 pub const TLS_1_1: Version = Version(InnerVersion::Tls1_1);
536 pub const TLS_1_2: Version = Version(InnerVersion::Tls1_2);
538 pub const TLS_1_3: Version = Version(InnerVersion::Tls1_3);
540
541 #[cfg(feature = "__native-tls")]
542 pub(crate) fn to_native_tls(self) -> Option<native_tls_crate::Protocol> {
543 match self.0 {
544 InnerVersion::Tls1_0 => Some(native_tls_crate::Protocol::Tlsv10),
545 InnerVersion::Tls1_1 => Some(native_tls_crate::Protocol::Tlsv11),
546 InnerVersion::Tls1_2 => Some(native_tls_crate::Protocol::Tlsv12),
547 InnerVersion::Tls1_3 => None,
548 }
549 }
550
551 #[cfg(feature = "__rustls")]
552 pub(crate) fn from_rustls(version: rustls::ProtocolVersion) -> Option<Self> {
553 match version {
554 rustls::ProtocolVersion::SSLv2 => None,
555 rustls::ProtocolVersion::SSLv3 => None,
556 rustls::ProtocolVersion::TLSv1_0 => Some(Self(InnerVersion::Tls1_0)),
557 rustls::ProtocolVersion::TLSv1_1 => Some(Self(InnerVersion::Tls1_1)),
558 rustls::ProtocolVersion::TLSv1_2 => Some(Self(InnerVersion::Tls1_2)),
559 rustls::ProtocolVersion::TLSv1_3 => Some(Self(InnerVersion::Tls1_3)),
560 _ => None,
561 }
562 }
563}
564
565pub(crate) enum TlsBackend {
566 #[allow(dead_code)]
568 #[cfg(feature = "__native-tls")]
569 NativeTls,
570 #[cfg(feature = "__native-tls")]
571 BuiltNativeTls(native_tls_crate::TlsConnector),
572 #[cfg(feature = "__rustls")]
573 Rustls,
574 #[cfg(feature = "__rustls")]
575 BuiltRustls(Box<rustls::ClientConfig>),
576 #[cfg(any(feature = "__native-tls", feature = "__rustls",))]
577 UnknownPreconfigured,
578}
579
580impl fmt::Debug for TlsBackend {
581 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
582 match self {
583 #[cfg(feature = "__native-tls")]
584 TlsBackend::NativeTls => write!(f, "NativeTls"),
585 #[cfg(feature = "__native-tls")]
586 TlsBackend::BuiltNativeTls(_) => write!(f, "BuiltNativeTls"),
587 #[cfg(feature = "__rustls")]
588 TlsBackend::Rustls => write!(f, "Rustls"),
589 #[cfg(feature = "__rustls")]
590 TlsBackend::BuiltRustls(_) => write!(f, "BuiltRustls"),
591 #[cfg(any(feature = "__native-tls", feature = "__rustls",))]
592 TlsBackend::UnknownPreconfigured => write!(f, "UnknownPreconfigured"),
593 }
594 }
595}
596
597#[allow(clippy::derivable_impls)]
598impl Default for TlsBackend {
599 fn default() -> TlsBackend {
600 #[cfg(any(
601 all(feature = "__rustls", not(feature = "__native-tls")),
602 feature = "http3"
603 ))]
604 {
605 TlsBackend::Rustls
606 }
607
608 #[cfg(all(feature = "__native-tls", not(feature = "http3")))]
609 {
610 TlsBackend::NativeTls
611 }
612 }
613}
614
615#[cfg(feature = "__rustls")]
616pub(crate) fn rustls_store(certs: Vec<Certificate>) -> crate::Result<RootCertStore> {
617 let mut root_cert_store = rustls::RootCertStore::empty();
618 for cert in certs {
619 cert.add_to_rustls(&mut root_cert_store)?;
620 }
621 Ok(root_cert_store)
622}
623
624#[cfg(feature = "__rustls")]
626pub fn default_root_store() -> &'static rustls::RootCertStore {
627 static DEFAULT_ROOTS: std::sync::OnceLock<rustls::RootCertStore> = std::sync::OnceLock::new();
628 DEFAULT_ROOTS.get_or_init(|| {
629 let mut roots = rustls::RootCertStore::empty();
630 roots.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
631 let native = rustls_native_certs::load_native_certs();
632 for err in &native.errors {
633 log::warn!("failed to load native root certificate: {err}");
634 }
635 if !native.certs.is_empty() {
636 roots.add_parsable_certificates(native.certs);
637 }
638 roots
639 })
640}
641
642#[cfg(feature = "__rustls")]
644pub fn merged_root_store(certs: Vec<Certificate>) -> crate::Result<RootCertStore> {
645 let mut store = default_root_store().clone();
646 for cert in certs {
647 cert.add_to_rustls(&mut store)?;
648 }
649 Ok(store)
650}
651
652#[cfg(feature = "__rustls")]
653#[derive(Debug)]
654pub(crate) struct NoVerifier;
655
656#[cfg(feature = "__rustls")]
657impl ServerCertVerifier for NoVerifier {
658 fn verify_server_cert(
659 &self,
660 _end_entity: &rustls_pki_types::CertificateDer,
661 _intermediates: &[rustls_pki_types::CertificateDer],
662 _server_name: &ServerName,
663 _ocsp_response: &[u8],
664 _now: UnixTime,
665 ) -> Result<ServerCertVerified, TLSError> {
666 Ok(ServerCertVerified::assertion())
667 }
668
669 fn verify_tls12_signature(
670 &self,
671 _message: &[u8],
672 _cert: &rustls_pki_types::CertificateDer,
673 _dss: &DigitallySignedStruct,
674 ) -> Result<HandshakeSignatureValid, TLSError> {
675 Ok(HandshakeSignatureValid::assertion())
676 }
677
678 fn verify_tls13_signature(
679 &self,
680 _message: &[u8],
681 _cert: &rustls_pki_types::CertificateDer,
682 _dss: &DigitallySignedStruct,
683 ) -> Result<HandshakeSignatureValid, TLSError> {
684 Ok(HandshakeSignatureValid::assertion())
685 }
686
687 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
688 vec![
689 SignatureScheme::RSA_PKCS1_SHA1,
690 SignatureScheme::ECDSA_SHA1_Legacy,
691 SignatureScheme::RSA_PKCS1_SHA256,
692 SignatureScheme::ECDSA_NISTP256_SHA256,
693 SignatureScheme::RSA_PKCS1_SHA384,
694 SignatureScheme::ECDSA_NISTP384_SHA384,
695 SignatureScheme::RSA_PKCS1_SHA512,
696 SignatureScheme::ECDSA_NISTP521_SHA512,
697 SignatureScheme::RSA_PSS_SHA256,
698 SignatureScheme::RSA_PSS_SHA384,
699 SignatureScheme::RSA_PSS_SHA512,
700 SignatureScheme::ED25519,
701 SignatureScheme::ED448,
702 ]
703 }
704}
705
706#[cfg(feature = "__rustls")]
707#[derive(Debug)]
708pub(crate) struct IgnoreHostname {
709 roots: RootCertStore,
710 signature_algorithms: WebPkiSupportedAlgorithms,
711}
712
713#[cfg(feature = "__rustls")]
714impl IgnoreHostname {
715 pub(crate) fn new(
716 roots: RootCertStore,
717 signature_algorithms: WebPkiSupportedAlgorithms,
718 ) -> Self {
719 Self {
720 roots,
721 signature_algorithms,
722 }
723 }
724}
725
726#[cfg(feature = "__rustls")]
727impl ServerCertVerifier for IgnoreHostname {
728 fn verify_server_cert(
729 &self,
730 end_entity: &rustls_pki_types::CertificateDer<'_>,
731 intermediates: &[rustls_pki_types::CertificateDer<'_>],
732 _server_name: &ServerName<'_>,
733 _ocsp_response: &[u8],
734 now: UnixTime,
735 ) -> Result<ServerCertVerified, TLSError> {
736 let cert = ParsedCertificate::try_from(end_entity)?;
737
738 rustls::client::verify_server_cert_signed_by_trust_anchor(
739 &cert,
740 &self.roots,
741 intermediates,
742 now,
743 self.signature_algorithms.all,
744 )?;
745 Ok(ServerCertVerified::assertion())
746 }
747
748 fn verify_tls12_signature(
749 &self,
750 message: &[u8],
751 cert: &rustls_pki_types::CertificateDer<'_>,
752 dss: &DigitallySignedStruct,
753 ) -> Result<HandshakeSignatureValid, TLSError> {
754 rustls::crypto::verify_tls12_signature(message, cert, dss, &self.signature_algorithms)
755 }
756
757 fn verify_tls13_signature(
758 &self,
759 message: &[u8],
760 cert: &rustls_pki_types::CertificateDer<'_>,
761 dss: &DigitallySignedStruct,
762 ) -> Result<HandshakeSignatureValid, TLSError> {
763 rustls::crypto::verify_tls13_signature(message, cert, dss, &self.signature_algorithms)
764 }
765
766 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
767 self.signature_algorithms.supported_schemes()
768 }
769}
770
771#[derive(Clone)]
774pub struct TlsInfo {
775 pub(crate) peer_certificate: Option<Vec<u8>>,
776}
777
778impl TlsInfo {
779 pub fn peer_certificate(&self) -> Option<&[u8]> {
781 self.peer_certificate.as_ref().map(|der| &der[..])
782 }
783}
784
785impl std::fmt::Debug for TlsInfo {
786 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
787 f.debug_struct("TlsInfo").finish()
788 }
789}
790
791#[cfg(test)]
792mod tests {
793 use super::*;
794
795 #[cfg(feature = "__native-tls")]
796 #[test]
797 fn certificate_from_der_invalid() {
798 Certificate::from_der(b"not der").unwrap_err();
799 }
800
801 #[cfg(feature = "__native-tls")]
802 #[test]
803 fn certificate_from_pem_invalid() {
804 Certificate::from_pem(b"not pem").unwrap_err();
805 }
806
807 #[cfg(feature = "__native-tls")]
808 #[test]
809 fn identity_from_pkcs12_der_invalid() {
810 Identity::from_pkcs12_der(b"not der", "nope").unwrap_err();
811 }
812
813 #[cfg(feature = "__native-tls")]
814 #[test]
815 fn identity_from_pkcs8_pem_invalid() {
816 Identity::from_pkcs8_pem(b"not pem", b"not key").unwrap_err();
817 }
818
819 #[cfg(feature = "__rustls")]
820 #[test]
821 fn identity_from_pem_invalid() {
822 Identity::from_pem(b"not pem").unwrap_err();
823 }
824
825 #[cfg(feature = "__rustls")]
826 #[test]
827 fn identity_from_pem_pkcs1_key() {
828 let pem = b"-----BEGIN CERTIFICATE-----\n\
829 -----END CERTIFICATE-----\n\
830 -----BEGIN RSA PRIVATE KEY-----\n\
831 -----END RSA PRIVATE KEY-----\n";
832
833 Identity::from_pem(pem).unwrap();
834 }
835
836 #[test]
837 fn certificates_from_pem_bundle() {
838 const PEM_BUNDLE: &[u8] = b"
839 -----BEGIN CERTIFICATE-----
840 MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5
841 MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
842 Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
843 A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
844 Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl
845 ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j
846 QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr
847 ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr
848 BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM
849 YyRIHN8wfdVoOw==
850 -----END CERTIFICATE-----
851
852 -----BEGIN CERTIFICATE-----
853 MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5
854 MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
855 Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
856 A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
857 Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi
858 9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk
859 M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB
860 /zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB
861 MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw
862 CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW
863 1KyLa2tJElMzrdfkviT8tQp21KW8EA==
864 -----END CERTIFICATE-----
865 ";
866
867 assert!(Certificate::from_pem_bundle(PEM_BUNDLE).is_ok())
868 }
869
870 #[cfg(feature = "__rustls")]
871 #[test]
872 fn crl_from_pem() {
873 let pem = b"-----BEGIN X509 CRL-----\n-----END X509 CRL-----\n";
874
875 CertificateRevocationList::from_pem(pem).unwrap();
876 }
877
878 #[cfg(feature = "__rustls")]
879 #[test]
880 fn crl_from_pem_bundle() {
881 let pem_bundle = std::fs::read("tests/support/crl.pem").unwrap();
882
883 let result = CertificateRevocationList::from_pem_bundle(&pem_bundle);
884
885 assert!(result.is_ok());
886 let result = result.unwrap();
887 assert_eq!(result.len(), 1);
888 }
889}