1#[cfg(feature = "__rustls")]
69use rustls::{
70 client::danger::HandshakeSignatureValid, client::danger::ServerCertVerified,
71 client::danger::ServerCertVerifier, crypto::WebPkiSupportedAlgorithms,
72 server::ParsedCertificate, DigitallySignedStruct, Error as TLSError, RootCertStore,
73 SignatureScheme,
74};
75use rustls_pki_types::pem::PemObject;
76#[cfg(feature = "__rustls")]
77use rustls_pki_types::{ServerName, UnixTime};
78use std::{
79 fmt,
80 io::{BufRead, BufReader},
81};
82
83#[cfg(feature = "__rustls")]
85pub struct CertificateRevocationList {
86 #[cfg(feature = "__rustls")]
87 inner: rustls_pki_types::CertificateRevocationListDer<'static>,
88}
89
90#[derive(Clone)]
92pub struct Certificate {
93 #[cfg(feature = "__native-tls")]
94 native: native_tls_crate::Certificate,
95 #[cfg(feature = "__rustls")]
96 original: Cert,
97}
98
99#[cfg(feature = "__rustls")]
100#[derive(Clone)]
101enum Cert {
102 Der(Vec<u8>),
103 Pem(Vec<u8>),
104}
105
106#[derive(Clone)]
108pub struct Identity {
109 #[cfg_attr(
110 not(any(feature = "__native-tls", feature = "__rustls")),
111 allow(unused)
112 )]
113 inner: ClientCert,
114}
115
116enum ClientCert {
117 #[cfg(feature = "__native-tls")]
118 Pkcs12(native_tls_crate::Identity),
119 #[cfg(feature = "__native-tls")]
120 Pkcs8(native_tls_crate::Identity),
121 #[cfg(feature = "__rustls")]
122 Pem {
123 key: rustls_pki_types::PrivateKeyDer<'static>,
124 certs: Vec<rustls_pki_types::CertificateDer<'static>>,
125 },
126}
127
128impl Clone for ClientCert {
129 fn clone(&self) -> Self {
130 match self {
131 #[cfg(feature = "__native-tls")]
132 Self::Pkcs8(i) => Self::Pkcs8(i.clone()),
133 #[cfg(feature = "__native-tls")]
134 Self::Pkcs12(i) => Self::Pkcs12(i.clone()),
135 #[cfg(feature = "__rustls")]
136 ClientCert::Pem { key, certs } => ClientCert::Pem {
137 key: key.clone_key(),
138 certs: certs.clone(),
139 },
140 #[cfg_attr(
141 any(feature = "__native-tls", feature = "__rustls"),
142 allow(unreachable_patterns)
143 )]
144 _ => unreachable!(),
145 }
146 }
147}
148
149impl Certificate {
150 pub fn from_der(der: &[u8]) -> crate::Result<Certificate> {
167 Ok(Certificate {
168 #[cfg(feature = "__native-tls")]
169 native: native_tls_crate::Certificate::from_der(der).map_err(crate::error::builder)?,
170 #[cfg(feature = "__rustls")]
171 original: Cert::Der(der.to_owned()),
172 })
173 }
174
175 pub fn from_pem(pem: &[u8]) -> crate::Result<Certificate> {
192 Ok(Certificate {
193 #[cfg(feature = "__native-tls")]
194 native: native_tls_crate::Certificate::from_pem(pem).map_err(crate::error::builder)?,
195 #[cfg(feature = "__rustls")]
196 original: Cert::Pem(pem.to_owned()),
197 })
198 }
199
200 pub fn from_pem_bundle(pem_bundle: &[u8]) -> crate::Result<Vec<Certificate>> {
218 let mut reader = BufReader::new(pem_bundle);
219
220 Self::read_pem_certs(&mut reader)?
221 .iter()
222 .map(|cert_vec| Certificate::from_der(cert_vec))
223 .collect::<crate::Result<Vec<Certificate>>>()
224 }
225
226 #[cfg(feature = "__native-tls")]
234 pub(crate) fn add_to_native_tls(self, tls: &mut native_tls_crate::TlsConnectorBuilder) {
235 tls.add_root_certificate(self.native);
236 }
237
238 #[cfg(feature = "__rustls")]
239 pub(crate) fn add_to_rustls(
240 self,
241 root_cert_store: &mut rustls::RootCertStore,
242 ) -> crate::Result<()> {
243 use std::io::Cursor;
244
245 match self.original {
246 Cert::Der(buf) => root_cert_store
247 .add(buf.into())
248 .map_err(crate::error::builder)?,
249 Cert::Pem(buf) => {
250 let mut reader = Cursor::new(buf);
251 let certs = Self::read_pem_certs(&mut reader)?;
252 for c in certs {
253 root_cert_store
254 .add(c.into())
255 .map_err(crate::error::builder)?;
256 }
257 }
258 }
259 Ok(())
260 }
261
262 fn read_pem_certs(reader: &mut impl BufRead) -> crate::Result<Vec<Vec<u8>>> {
263 rustls_pki_types::CertificateDer::pem_reader_iter(reader)
264 .map(|result| match result {
265 Ok(cert) => Ok(cert.as_ref().to_vec()),
266 Err(_) => Err(crate::error::builder("invalid certificate encoding")),
267 })
268 .collect()
269 }
270}
271
272impl Identity {
273 #[cfg(feature = "__native-tls")]
305 pub fn from_pkcs12_der(der: &[u8], password: &str) -> crate::Result<Identity> {
306 Ok(Identity {
307 inner: ClientCert::Pkcs12(
308 native_tls_crate::Identity::from_pkcs12(der, password)
309 .map_err(crate::error::builder)?,
310 ),
311 })
312 }
313
314 #[cfg(feature = "__native-tls")]
339 pub fn from_pkcs8_pem(pem: &[u8], key: &[u8]) -> crate::Result<Identity> {
340 Ok(Identity {
341 inner: ClientCert::Pkcs8(
342 native_tls_crate::Identity::from_pkcs8(pem, key).map_err(crate::error::builder)?,
343 ),
344 })
345 }
346
347 #[cfg(feature = "__rustls")]
373 pub fn from_pem(buf: &[u8]) -> crate::Result<Identity> {
374 use rustls_pki_types::{pem::SectionKind, PrivateKeyDer};
375 use std::io::Cursor;
376
377 let (key, certs) = {
378 let mut pem = Cursor::new(buf);
379 let mut sk = Vec::<rustls_pki_types::PrivateKeyDer>::new();
380 let mut certs = Vec::<rustls_pki_types::CertificateDer>::new();
381
382 while let Some((kind, data)) =
383 rustls_pki_types::pem::from_buf(&mut pem).map_err(|_| {
384 crate::error::builder(TLSError::General(String::from(
385 "Invalid identity PEM file",
386 )))
387 })?
388 {
389 match kind {
390 SectionKind::Certificate => certs.push(data.into()),
391 SectionKind::PrivateKey => sk.push(PrivateKeyDer::Pkcs8(data.into())),
392 SectionKind::RsaPrivateKey => sk.push(PrivateKeyDer::Pkcs1(data.into())),
393 SectionKind::EcPrivateKey => sk.push(PrivateKeyDer::Sec1(data.into())),
394 _ => {
395 return Err(crate::error::builder(TLSError::General(String::from(
396 "No valid certificate was found",
397 ))))
398 }
399 }
400 }
401
402 if let (Some(sk), false) = (sk.pop(), certs.is_empty()) {
403 (sk, certs)
404 } else {
405 return Err(crate::error::builder(TLSError::General(String::from(
406 "private key or certificate not found",
407 ))));
408 }
409 };
410
411 Ok(Identity {
412 inner: ClientCert::Pem { key, certs },
413 })
414 }
415
416 #[cfg(feature = "__native-tls")]
417 pub(crate) fn add_to_native_tls(
418 self,
419 tls: &mut native_tls_crate::TlsConnectorBuilder,
420 ) -> crate::Result<()> {
421 match self.inner {
422 ClientCert::Pkcs12(id) | ClientCert::Pkcs8(id) => {
423 tls.identity(id);
424 Ok(())
425 }
426 #[cfg(feature = "__rustls")]
427 ClientCert::Pem { .. } => Err(crate::error::builder("incompatible TLS identity type")),
428 }
429 }
430
431 #[cfg(feature = "__rustls")]
432 pub(crate) fn add_to_rustls(
433 self,
434 config_builder: rustls::ConfigBuilder<
435 rustls::ClientConfig,
436 rustls::client::WantsClientCert,
438 >,
439 ) -> crate::Result<rustls::ClientConfig> {
440 match self.inner {
441 ClientCert::Pem { key, certs } => config_builder
442 .with_client_auth_cert(certs, key)
443 .map_err(crate::error::builder),
444 #[cfg(feature = "__native-tls")]
445 ClientCert::Pkcs12(..) | ClientCert::Pkcs8(..) => {
446 Err(crate::error::builder("incompatible TLS identity type"))
447 }
448 }
449 }
450}
451
452#[cfg(feature = "__rustls")]
453impl CertificateRevocationList {
454 #[cfg(feature = "__rustls")]
475 pub fn from_pem(pem: &[u8]) -> crate::Result<CertificateRevocationList> {
476 Ok(CertificateRevocationList {
477 #[cfg(feature = "__rustls")]
478 inner: rustls_pki_types::CertificateRevocationListDer::from_pem_slice(pem)
479 .map_err(|_| crate::error::builder("invalid crl encoding"))?,
480 })
481 }
482
483 #[cfg(feature = "__rustls")]
505 pub fn from_pem_bundle(pem_bundle: &[u8]) -> crate::Result<Vec<CertificateRevocationList>> {
506 rustls_pki_types::CertificateRevocationListDer::pem_slice_iter(pem_bundle)
507 .map(|result| match result {
508 Ok(crl) => Ok(CertificateRevocationList { inner: crl }),
509 Err(_) => Err(crate::error::builder("invalid crl encoding")),
510 })
511 .collect::<crate::Result<Vec<CertificateRevocationList>>>()
512 }
513
514 #[cfg(feature = "__rustls")]
515 pub(crate) fn as_rustls_crl<'a>(&self) -> rustls_pki_types::CertificateRevocationListDer<'a> {
516 self.inner.clone()
517 }
518}
519
520impl fmt::Debug for Certificate {
521 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
522 f.debug_struct("Certificate").finish()
523 }
524}
525
526impl fmt::Debug for Identity {
527 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
528 f.debug_struct("Identity").finish()
529 }
530}
531
532#[cfg(feature = "__rustls")]
533impl fmt::Debug for CertificateRevocationList {
534 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
535 f.debug_struct("CertificateRevocationList").finish()
536 }
537}
538
539#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
541pub struct Version(InnerVersion);
542
543#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
544#[non_exhaustive]
545enum InnerVersion {
546 Tls1_0,
547 Tls1_1,
548 Tls1_2,
549 Tls1_3,
550}
551
552impl Version {
555 pub const TLS_1_0: Version = Version(InnerVersion::Tls1_0);
557 pub const TLS_1_1: Version = Version(InnerVersion::Tls1_1);
559 pub const TLS_1_2: Version = Version(InnerVersion::Tls1_2);
561 pub const TLS_1_3: Version = Version(InnerVersion::Tls1_3);
563
564 #[cfg(feature = "__native-tls")]
565 pub(crate) fn to_native_tls(self) -> Option<native_tls_crate::Protocol> {
566 match self.0 {
567 InnerVersion::Tls1_0 => Some(native_tls_crate::Protocol::Tlsv10),
568 InnerVersion::Tls1_1 => Some(native_tls_crate::Protocol::Tlsv11),
569 InnerVersion::Tls1_2 => Some(native_tls_crate::Protocol::Tlsv12),
570 InnerVersion::Tls1_3 => Some(native_tls_crate::Protocol::Tlsv13),
571 }
572 }
573
574 #[cfg(feature = "__rustls")]
575 pub(crate) fn from_rustls(version: rustls::ProtocolVersion) -> Option<Self> {
576 match version {
577 rustls::ProtocolVersion::SSLv2 => None,
578 rustls::ProtocolVersion::SSLv3 => None,
579 rustls::ProtocolVersion::TLSv1_0 => Some(Self(InnerVersion::Tls1_0)),
580 rustls::ProtocolVersion::TLSv1_1 => Some(Self(InnerVersion::Tls1_1)),
581 rustls::ProtocolVersion::TLSv1_2 => Some(Self(InnerVersion::Tls1_2)),
582 rustls::ProtocolVersion::TLSv1_3 => Some(Self(InnerVersion::Tls1_3)),
583 _ => None,
584 }
585 }
586}
587
588pub(crate) enum TlsBackend {
589 #[allow(dead_code)]
591 #[cfg(feature = "__native-tls")]
592 NativeTls,
593 #[cfg(feature = "__native-tls")]
594 BuiltNativeTls(native_tls_crate::TlsConnector),
595 #[cfg(feature = "__rustls")]
596 Rustls,
597 #[cfg(feature = "__rustls")]
598 BuiltRustls(rustls::ClientConfig),
599 #[cfg(any(feature = "__native-tls", feature = "__rustls",))]
600 UnknownPreconfigured,
601}
602
603impl fmt::Debug for TlsBackend {
604 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
605 match self {
606 #[cfg(feature = "__native-tls")]
607 TlsBackend::NativeTls => write!(f, "NativeTls"),
608 #[cfg(feature = "__native-tls")]
609 TlsBackend::BuiltNativeTls(_) => write!(f, "BuiltNativeTls"),
610 #[cfg(feature = "__rustls")]
611 TlsBackend::Rustls => write!(f, "Rustls"),
612 #[cfg(feature = "__rustls")]
613 TlsBackend::BuiltRustls(_) => write!(f, "BuiltRustls"),
614 #[cfg(any(feature = "__native-tls", feature = "__rustls",))]
615 TlsBackend::UnknownPreconfigured => write!(f, "UnknownPreconfigured"),
616 }
617 }
618}
619
620#[allow(clippy::derivable_impls)]
621impl Default for TlsBackend {
622 fn default() -> TlsBackend {
623 #[cfg(any(
624 all(feature = "__rustls", not(feature = "__native-tls")),
625 feature = "http3"
626 ))]
627 {
628 TlsBackend::Rustls
629 }
630
631 #[cfg(all(feature = "__native-tls", not(feature = "http3")))]
632 {
633 TlsBackend::NativeTls
634 }
635 }
636}
637
638#[cfg(feature = "__rustls")]
639pub(crate) fn rustls_store(certs: Vec<Certificate>) -> crate::Result<RootCertStore> {
640 let mut root_cert_store = rustls::RootCertStore::empty();
641 for cert in certs {
642 cert.add_to_rustls(&mut root_cert_store)?;
643 }
644 Ok(root_cert_store)
645}
646
647#[cfg(feature = "__rustls")]
648#[cfg(any(all(unix, not(target_os = "android")), target_os = "windows"))]
649pub(crate) fn rustls_der(
650 certs: Vec<Certificate>,
651) -> crate::Result<Vec<rustls_pki_types::CertificateDer<'static>>> {
652 let mut ders = Vec::with_capacity(certs.len());
653 for cert in certs {
654 match cert.original {
655 Cert::Der(buf) => ders.push(buf.into()),
656 Cert::Pem(buf) => {
657 let mut reader = std::io::Cursor::new(buf);
658 let pems = Certificate::read_pem_certs(&mut reader)?;
659 for c in pems {
660 ders.push(c.into());
661 }
662 }
663 }
664 }
665 Ok(ders)
666}
667
668#[cfg(feature = "__rustls")]
669#[derive(Debug)]
670pub(crate) struct NoVerifier;
671
672#[cfg(feature = "__rustls")]
673impl ServerCertVerifier for NoVerifier {
674 fn verify_server_cert(
675 &self,
676 _end_entity: &rustls_pki_types::CertificateDer,
677 _intermediates: &[rustls_pki_types::CertificateDer],
678 _server_name: &ServerName,
679 _ocsp_response: &[u8],
680 _now: UnixTime,
681 ) -> Result<ServerCertVerified, TLSError> {
682 Ok(ServerCertVerified::assertion())
683 }
684
685 fn verify_tls12_signature(
686 &self,
687 _message: &[u8],
688 _cert: &rustls_pki_types::CertificateDer,
689 _dss: &DigitallySignedStruct,
690 ) -> Result<HandshakeSignatureValid, TLSError> {
691 Ok(HandshakeSignatureValid::assertion())
692 }
693
694 fn verify_tls13_signature(
695 &self,
696 _message: &[u8],
697 _cert: &rustls_pki_types::CertificateDer,
698 _dss: &DigitallySignedStruct,
699 ) -> Result<HandshakeSignatureValid, TLSError> {
700 Ok(HandshakeSignatureValid::assertion())
701 }
702
703 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
704 vec![
705 SignatureScheme::RSA_PKCS1_SHA1,
706 SignatureScheme::ECDSA_SHA1_Legacy,
707 SignatureScheme::RSA_PKCS1_SHA256,
708 SignatureScheme::ECDSA_NISTP256_SHA256,
709 SignatureScheme::RSA_PKCS1_SHA384,
710 SignatureScheme::ECDSA_NISTP384_SHA384,
711 SignatureScheme::RSA_PKCS1_SHA512,
712 SignatureScheme::ECDSA_NISTP521_SHA512,
713 SignatureScheme::RSA_PSS_SHA256,
714 SignatureScheme::RSA_PSS_SHA384,
715 SignatureScheme::RSA_PSS_SHA512,
716 SignatureScheme::ED25519,
717 SignatureScheme::ED448,
718 ]
719 }
720}
721
722#[cfg(feature = "__rustls")]
723#[derive(Debug)]
724pub(crate) struct IgnoreHostname {
725 roots: RootCertStore,
726 signature_algorithms: WebPkiSupportedAlgorithms,
727}
728
729#[cfg(feature = "__rustls")]
730impl IgnoreHostname {
731 pub(crate) fn new(
732 roots: RootCertStore,
733 signature_algorithms: WebPkiSupportedAlgorithms,
734 ) -> Self {
735 Self {
736 roots,
737 signature_algorithms,
738 }
739 }
740}
741
742#[cfg(feature = "__rustls")]
743impl ServerCertVerifier for IgnoreHostname {
744 fn verify_server_cert(
745 &self,
746 end_entity: &rustls_pki_types::CertificateDer<'_>,
747 intermediates: &[rustls_pki_types::CertificateDer<'_>],
748 _server_name: &ServerName<'_>,
749 _ocsp_response: &[u8],
750 now: UnixTime,
751 ) -> Result<ServerCertVerified, TLSError> {
752 let cert = ParsedCertificate::try_from(end_entity)?;
753
754 rustls::client::verify_server_cert_signed_by_trust_anchor(
755 &cert,
756 &self.roots,
757 intermediates,
758 now,
759 self.signature_algorithms.all,
760 )?;
761 Ok(ServerCertVerified::assertion())
762 }
763
764 fn verify_tls12_signature(
765 &self,
766 message: &[u8],
767 cert: &rustls_pki_types::CertificateDer<'_>,
768 dss: &DigitallySignedStruct,
769 ) -> Result<HandshakeSignatureValid, TLSError> {
770 rustls::crypto::verify_tls12_signature(message, cert, dss, &self.signature_algorithms)
771 }
772
773 fn verify_tls13_signature(
774 &self,
775 message: &[u8],
776 cert: &rustls_pki_types::CertificateDer<'_>,
777 dss: &DigitallySignedStruct,
778 ) -> Result<HandshakeSignatureValid, TLSError> {
779 rustls::crypto::verify_tls13_signature(message, cert, dss, &self.signature_algorithms)
780 }
781
782 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
783 self.signature_algorithms.supported_schemes()
784 }
785}
786
787#[derive(Clone)]
790pub struct TlsInfo {
791 pub(crate) peer_certificate: Option<Vec<u8>>,
792}
793
794impl TlsInfo {
795 pub fn peer_certificate(&self) -> Option<&[u8]> {
797 self.peer_certificate.as_ref().map(|der| &der[..])
798 }
799}
800
801impl std::fmt::Debug for TlsInfo {
802 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
803 f.debug_struct("TlsInfo").finish()
804 }
805}
806
807#[cfg(test)]
808mod tests {
809 use super::*;
810
811 #[cfg(feature = "__native-tls")]
812 #[test]
813 fn certificate_from_der_invalid() {
814 Certificate::from_der(b"not der").unwrap_err();
815 }
816
817 #[cfg(feature = "__native-tls")]
818 #[test]
819 fn certificate_from_pem_invalid() {
820 Certificate::from_pem(b"not pem").unwrap_err();
821 }
822
823 #[cfg(feature = "__native-tls")]
824 #[test]
825 fn identity_from_pkcs12_der_invalid() {
826 Identity::from_pkcs12_der(b"not der", "nope").unwrap_err();
827 }
828
829 #[cfg(feature = "__native-tls")]
830 #[test]
831 fn identity_from_pkcs8_pem_invalid() {
832 Identity::from_pkcs8_pem(b"not pem", b"not key").unwrap_err();
833 }
834
835 #[cfg(feature = "__rustls")]
836 #[test]
837 fn identity_from_pem_invalid() {
838 Identity::from_pem(b"not pem").unwrap_err();
839 }
840
841 #[cfg(feature = "__rustls")]
842 #[test]
843 fn identity_from_pem_pkcs1_key() {
844 let pem = b"-----BEGIN CERTIFICATE-----\n\
845 -----END CERTIFICATE-----\n\
846 -----BEGIN RSA PRIVATE KEY-----\n\
847 -----END RSA PRIVATE KEY-----\n";
848
849 Identity::from_pem(pem).unwrap();
850 }
851
852 #[test]
853 fn certificates_from_pem_bundle() {
854 const PEM_BUNDLE: &[u8] = b"
855 -----BEGIN CERTIFICATE-----
856 MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5
857 MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
858 Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
859 A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
860 Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl
861 ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j
862 QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr
863 ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr
864 BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM
865 YyRIHN8wfdVoOw==
866 -----END CERTIFICATE-----
867
868 -----BEGIN CERTIFICATE-----
869 MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5
870 MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
871 Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
872 A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
873 Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi
874 9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk
875 M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB
876 /zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB
877 MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw
878 CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW
879 1KyLa2tJElMzrdfkviT8tQp21KW8EA==
880 -----END CERTIFICATE-----
881 ";
882
883 assert!(Certificate::from_pem_bundle(PEM_BUNDLE).is_ok())
884 }
885
886 #[cfg(feature = "__rustls")]
887 #[test]
888 fn crl_from_pem() {
889 let pem = b"-----BEGIN X509 CRL-----\n-----END X509 CRL-----\n";
890
891 CertificateRevocationList::from_pem(pem).unwrap();
892 }
893
894 #[cfg(feature = "__rustls")]
895 #[test]
896 fn invalid_crl_from_pem() {
897 CertificateRevocationList::from_pem(b"Invalid").unwrap_err();
898 }
899
900 #[cfg(feature = "__rustls")]
901 #[test]
902 fn crl_from_pem_bundle() {
903 let pem_bundle = std::fs::read("tests/support/crl.pem").unwrap();
904
905 let result = CertificateRevocationList::from_pem_bundle(&pem_bundle);
906
907 assert!(result.is_ok());
908 let result = result.unwrap();
909 assert_eq!(result.len(), 1);
910 }
911}