1#[cfg(feature = "__rustls")]
48use rustls::{
49 client::danger::HandshakeSignatureValid, client::danger::ServerCertVerified,
50 client::danger::ServerCertVerifier, crypto::WebPkiSupportedAlgorithms,
51 server::ParsedCertificate, DigitallySignedStruct, Error as TLSError, RootCertStore,
52 SignatureScheme,
53};
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 = "default-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(not(any(feature = "native-tls", feature = "__rustls")), allow(unused))]
88 inner: ClientCert,
89}
90
91enum ClientCert {
92 #[cfg(feature = "native-tls")]
93 Pkcs12(native_tls_crate::Identity),
94 #[cfg(feature = "native-tls")]
95 Pkcs8(native_tls_crate::Identity),
96 #[cfg(feature = "__rustls")]
97 Pem {
98 key: rustls_pki_types::PrivateKeyDer<'static>,
99 certs: Vec<rustls_pki_types::CertificateDer<'static>>,
100 },
101}
102
103impl Clone for ClientCert {
104 fn clone(&self) -> Self {
105 match self {
106 #[cfg(feature = "native-tls")]
107 Self::Pkcs8(i) => Self::Pkcs8(i.clone()),
108 #[cfg(feature = "native-tls")]
109 Self::Pkcs12(i) => Self::Pkcs12(i.clone()),
110 #[cfg(feature = "__rustls")]
111 ClientCert::Pem { key, certs } => ClientCert::Pem {
112 key: key.clone_key(),
113 certs: certs.clone(),
114 },
115 #[cfg_attr(
116 any(feature = "native-tls", feature = "__rustls"),
117 allow(unreachable_patterns)
118 )]
119 _ => unreachable!(),
120 }
121 }
122}
123
124impl Certificate {
125 pub fn from_der(der: &[u8]) -> crate::Result<Certificate> {
142 Ok(Certificate {
143 #[cfg(feature = "default-tls")]
144 native: native_tls_crate::Certificate::from_der(der).map_err(crate::error::builder)?,
145 #[cfg(feature = "__rustls")]
146 original: Cert::Der(der.to_owned()),
147 })
148 }
149
150 pub fn from_pem(pem: &[u8]) -> crate::Result<Certificate> {
167 Ok(Certificate {
168 #[cfg(feature = "default-tls")]
169 native: native_tls_crate::Certificate::from_pem(pem).map_err(crate::error::builder)?,
170 #[cfg(feature = "__rustls")]
171 original: Cert::Pem(pem.to_owned()),
172 })
173 }
174
175 pub fn from_pem_bundle(pem_bundle: &[u8]) -> crate::Result<Vec<Certificate>> {
193 let mut reader = BufReader::new(pem_bundle);
194
195 Self::read_pem_certs(&mut reader)?
196 .iter()
197 .map(|cert_vec| Certificate::from_der(&cert_vec))
198 .collect::<crate::Result<Vec<Certificate>>>()
199 }
200
201 #[cfg(feature = "default-tls")]
202 pub(crate) fn add_to_native_tls(self, tls: &mut native_tls_crate::TlsConnectorBuilder) {
203 tls.add_root_certificate(self.native);
204 }
205
206 #[cfg(feature = "__rustls")]
207 pub(crate) fn add_to_rustls(
208 self,
209 root_cert_store: &mut rustls::RootCertStore,
210 ) -> crate::Result<()> {
211 use std::io::Cursor;
212
213 match self.original {
214 Cert::Der(buf) => root_cert_store
215 .add(buf.into())
216 .map_err(crate::error::builder)?,
217 Cert::Pem(buf) => {
218 let mut reader = Cursor::new(buf);
219 let certs = Self::read_pem_certs(&mut reader)?;
220 for c in certs {
221 root_cert_store
222 .add(c.into())
223 .map_err(crate::error::builder)?;
224 }
225 }
226 }
227 Ok(())
228 }
229
230 fn read_pem_certs(reader: &mut impl BufRead) -> crate::Result<Vec<Vec<u8>>> {
231 rustls_pemfile::certs(reader)
232 .map(|result| match result {
233 Ok(cert) => Ok(cert.as_ref().to_vec()),
234 Err(_) => Err(crate::error::builder("invalid certificate encoding")),
235 })
236 .collect()
237 }
238}
239
240impl Identity {
241 #[cfg(feature = "native-tls")]
273 pub fn from_pkcs12_der(der: &[u8], password: &str) -> crate::Result<Identity> {
274 Ok(Identity {
275 inner: ClientCert::Pkcs12(
276 native_tls_crate::Identity::from_pkcs12(der, password)
277 .map_err(crate::error::builder)?,
278 ),
279 })
280 }
281
282 #[cfg(feature = "native-tls")]
307 pub fn from_pkcs8_pem(pem: &[u8], key: &[u8]) -> crate::Result<Identity> {
308 Ok(Identity {
309 inner: ClientCert::Pkcs8(
310 native_tls_crate::Identity::from_pkcs8(pem, key).map_err(crate::error::builder)?,
311 ),
312 })
313 }
314
315 #[cfg(feature = "__rustls")]
341 pub fn from_pem(buf: &[u8]) -> crate::Result<Identity> {
342 use rustls_pemfile::Item;
343 use std::io::Cursor;
344
345 let (key, certs) = {
346 let mut pem = Cursor::new(buf);
347 let mut sk = Vec::<rustls_pki_types::PrivateKeyDer>::new();
348 let mut certs = Vec::<rustls_pki_types::CertificateDer>::new();
349
350 for result in rustls_pemfile::read_all(&mut pem) {
351 match result {
352 Ok(Item::X509Certificate(cert)) => certs.push(cert),
353 Ok(Item::Pkcs1Key(key)) => sk.push(key.into()),
354 Ok(Item::Pkcs8Key(key)) => sk.push(key.into()),
355 Ok(Item::Sec1Key(key)) => sk.push(key.into()),
356 Ok(_) => {
357 return Err(crate::error::builder(TLSError::General(String::from(
358 "No valid certificate was found",
359 ))))
360 }
361 Err(_) => {
362 return Err(crate::error::builder(TLSError::General(String::from(
363 "Invalid identity PEM file",
364 ))))
365 }
366 }
367 }
368
369 if let (Some(sk), false) = (sk.pop(), certs.is_empty()) {
370 (sk, certs)
371 } else {
372 return Err(crate::error::builder(TLSError::General(String::from(
373 "private key or certificate not found",
374 ))));
375 }
376 };
377
378 Ok(Identity {
379 inner: ClientCert::Pem { key, certs },
380 })
381 }
382
383 #[cfg(feature = "native-tls")]
384 pub(crate) fn add_to_native_tls(
385 self,
386 tls: &mut native_tls_crate::TlsConnectorBuilder,
387 ) -> crate::Result<()> {
388 match self.inner {
389 ClientCert::Pkcs12(id) | ClientCert::Pkcs8(id) => {
390 tls.identity(id);
391 Ok(())
392 }
393 #[cfg(feature = "__rustls")]
394 ClientCert::Pem { .. } => Err(crate::error::builder("incompatible TLS identity type")),
395 }
396 }
397
398 #[cfg(feature = "__rustls")]
399 pub(crate) fn add_to_rustls(
400 self,
401 config_builder: rustls::ConfigBuilder<
402 rustls::ClientConfig,
403 rustls::client::WantsClientCert,
405 >,
406 ) -> crate::Result<rustls::ClientConfig> {
407 match self.inner {
408 ClientCert::Pem { key, certs } => config_builder
409 .with_client_auth_cert(certs, key)
410 .map_err(crate::error::builder),
411 #[cfg(feature = "native-tls")]
412 ClientCert::Pkcs12(..) | ClientCert::Pkcs8(..) => {
413 Err(crate::error::builder("incompatible TLS identity type"))
414 }
415 }
416 }
417}
418
419#[cfg(feature = "__rustls")]
420impl CertificateRevocationList {
421 #[cfg(feature = "__rustls")]
442 pub fn from_pem(pem: &[u8]) -> crate::Result<CertificateRevocationList> {
443 Ok(CertificateRevocationList {
444 #[cfg(feature = "__rustls")]
445 inner: rustls_pki_types::CertificateRevocationListDer::from(pem.to_vec()),
446 })
447 }
448
449 #[cfg(feature = "__rustls")]
471 pub fn from_pem_bundle(pem_bundle: &[u8]) -> crate::Result<Vec<CertificateRevocationList>> {
472 let mut reader = BufReader::new(pem_bundle);
473
474 rustls_pemfile::crls(&mut reader)
475 .map(|result| match result {
476 Ok(crl) => Ok(CertificateRevocationList { inner: crl }),
477 Err(_) => Err(crate::error::builder("invalid crl encoding")),
478 })
479 .collect::<crate::Result<Vec<CertificateRevocationList>>>()
480 }
481
482 #[cfg(feature = "__rustls")]
483 pub(crate) fn as_rustls_crl<'a>(&self) -> rustls_pki_types::CertificateRevocationListDer<'a> {
484 self.inner.clone()
485 }
486}
487
488impl fmt::Debug for Certificate {
489 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
490 f.debug_struct("Certificate").finish()
491 }
492}
493
494impl fmt::Debug for Identity {
495 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
496 f.debug_struct("Identity").finish()
497 }
498}
499
500#[cfg(feature = "__rustls")]
501impl fmt::Debug for CertificateRevocationList {
502 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
503 f.debug_struct("CertificateRevocationList").finish()
504 }
505}
506
507#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
509pub struct Version(InnerVersion);
510
511#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
512#[non_exhaustive]
513enum InnerVersion {
514 Tls1_0,
515 Tls1_1,
516 Tls1_2,
517 Tls1_3,
518}
519
520impl Version {
523 pub const TLS_1_0: Version = Version(InnerVersion::Tls1_0);
525 pub const TLS_1_1: Version = Version(InnerVersion::Tls1_1);
527 pub const TLS_1_2: Version = Version(InnerVersion::Tls1_2);
529 pub const TLS_1_3: Version = Version(InnerVersion::Tls1_3);
531
532 #[cfg(feature = "default-tls")]
533 pub(crate) fn to_native_tls(self) -> Option<native_tls_crate::Protocol> {
534 match self.0 {
535 InnerVersion::Tls1_0 => Some(native_tls_crate::Protocol::Tlsv10),
536 InnerVersion::Tls1_1 => Some(native_tls_crate::Protocol::Tlsv11),
537 InnerVersion::Tls1_2 => Some(native_tls_crate::Protocol::Tlsv12),
538 InnerVersion::Tls1_3 => None,
539 }
540 }
541
542 #[cfg(feature = "__rustls")]
543 pub(crate) fn from_rustls(version: rustls::ProtocolVersion) -> Option<Self> {
544 match version {
545 rustls::ProtocolVersion::SSLv2 => None,
546 rustls::ProtocolVersion::SSLv3 => None,
547 rustls::ProtocolVersion::TLSv1_0 => Some(Self(InnerVersion::Tls1_0)),
548 rustls::ProtocolVersion::TLSv1_1 => Some(Self(InnerVersion::Tls1_1)),
549 rustls::ProtocolVersion::TLSv1_2 => Some(Self(InnerVersion::Tls1_2)),
550 rustls::ProtocolVersion::TLSv1_3 => Some(Self(InnerVersion::Tls1_3)),
551 _ => None,
552 }
553 }
554}
555
556pub(crate) enum TlsBackend {
557 #[allow(dead_code)]
559 #[cfg(feature = "default-tls")]
560 Default,
561 #[cfg(feature = "native-tls")]
562 BuiltNativeTls(native_tls_crate::TlsConnector),
563 #[cfg(feature = "__rustls")]
564 Rustls,
565 #[cfg(feature = "__rustls")]
566 BuiltRustls(rustls::ClientConfig),
567 #[cfg(any(feature = "native-tls", feature = "__rustls",))]
568 UnknownPreconfigured,
569}
570
571impl fmt::Debug for TlsBackend {
572 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
573 match self {
574 #[cfg(feature = "default-tls")]
575 TlsBackend::Default => write!(f, "Default"),
576 #[cfg(feature = "native-tls")]
577 TlsBackend::BuiltNativeTls(_) => write!(f, "BuiltNativeTls"),
578 #[cfg(feature = "__rustls")]
579 TlsBackend::Rustls => write!(f, "Rustls"),
580 #[cfg(feature = "__rustls")]
581 TlsBackend::BuiltRustls(_) => write!(f, "BuiltRustls"),
582 #[cfg(any(feature = "native-tls", feature = "__rustls",))]
583 TlsBackend::UnknownPreconfigured => write!(f, "UnknownPreconfigured"),
584 }
585 }
586}
587
588impl Default for TlsBackend {
589 fn default() -> TlsBackend {
590 #[cfg(all(feature = "default-tls", not(feature = "http3")))]
591 {
592 TlsBackend::Default
593 }
594
595 #[cfg(any(
596 all(feature = "__rustls", not(feature = "default-tls")),
597 feature = "http3"
598 ))]
599 {
600 TlsBackend::Rustls
601 }
602 }
603}
604
605#[cfg(feature = "__rustls")]
606#[derive(Debug)]
607pub(crate) struct NoVerifier;
608
609#[cfg(feature = "__rustls")]
610impl ServerCertVerifier for NoVerifier {
611 fn verify_server_cert(
612 &self,
613 _end_entity: &rustls_pki_types::CertificateDer,
614 _intermediates: &[rustls_pki_types::CertificateDer],
615 _server_name: &ServerName,
616 _ocsp_response: &[u8],
617 _now: UnixTime,
618 ) -> Result<ServerCertVerified, TLSError> {
619 Ok(ServerCertVerified::assertion())
620 }
621
622 fn verify_tls12_signature(
623 &self,
624 _message: &[u8],
625 _cert: &rustls_pki_types::CertificateDer,
626 _dss: &DigitallySignedStruct,
627 ) -> Result<HandshakeSignatureValid, TLSError> {
628 Ok(HandshakeSignatureValid::assertion())
629 }
630
631 fn verify_tls13_signature(
632 &self,
633 _message: &[u8],
634 _cert: &rustls_pki_types::CertificateDer,
635 _dss: &DigitallySignedStruct,
636 ) -> Result<HandshakeSignatureValid, TLSError> {
637 Ok(HandshakeSignatureValid::assertion())
638 }
639
640 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
641 vec![
642 SignatureScheme::RSA_PKCS1_SHA1,
643 SignatureScheme::ECDSA_SHA1_Legacy,
644 SignatureScheme::RSA_PKCS1_SHA256,
645 SignatureScheme::ECDSA_NISTP256_SHA256,
646 SignatureScheme::RSA_PKCS1_SHA384,
647 SignatureScheme::ECDSA_NISTP384_SHA384,
648 SignatureScheme::RSA_PKCS1_SHA512,
649 SignatureScheme::ECDSA_NISTP521_SHA512,
650 SignatureScheme::RSA_PSS_SHA256,
651 SignatureScheme::RSA_PSS_SHA384,
652 SignatureScheme::RSA_PSS_SHA512,
653 SignatureScheme::ED25519,
654 SignatureScheme::ED448,
655 ]
656 }
657}
658
659#[cfg(feature = "__rustls")]
660#[derive(Debug)]
661pub(crate) struct IgnoreHostname {
662 roots: RootCertStore,
663 signature_algorithms: WebPkiSupportedAlgorithms,
664}
665
666#[cfg(feature = "__rustls")]
667impl IgnoreHostname {
668 pub(crate) fn new(
669 roots: RootCertStore,
670 signature_algorithms: WebPkiSupportedAlgorithms,
671 ) -> Self {
672 Self {
673 roots,
674 signature_algorithms,
675 }
676 }
677}
678
679#[cfg(feature = "__rustls")]
680impl ServerCertVerifier for IgnoreHostname {
681 fn verify_server_cert(
682 &self,
683 end_entity: &rustls_pki_types::CertificateDer<'_>,
684 intermediates: &[rustls_pki_types::CertificateDer<'_>],
685 _server_name: &ServerName<'_>,
686 _ocsp_response: &[u8],
687 now: UnixTime,
688 ) -> Result<ServerCertVerified, TLSError> {
689 let cert = ParsedCertificate::try_from(end_entity)?;
690
691 rustls::client::verify_server_cert_signed_by_trust_anchor(
692 &cert,
693 &self.roots,
694 intermediates,
695 now,
696 self.signature_algorithms.all,
697 )?;
698 Ok(ServerCertVerified::assertion())
699 }
700
701 fn verify_tls12_signature(
702 &self,
703 message: &[u8],
704 cert: &rustls_pki_types::CertificateDer<'_>,
705 dss: &DigitallySignedStruct,
706 ) -> Result<HandshakeSignatureValid, TLSError> {
707 rustls::crypto::verify_tls12_signature(message, cert, dss, &self.signature_algorithms)
708 }
709
710 fn verify_tls13_signature(
711 &self,
712 message: &[u8],
713 cert: &rustls_pki_types::CertificateDer<'_>,
714 dss: &DigitallySignedStruct,
715 ) -> Result<HandshakeSignatureValid, TLSError> {
716 rustls::crypto::verify_tls13_signature(message, cert, dss, &self.signature_algorithms)
717 }
718
719 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
720 self.signature_algorithms.supported_schemes()
721 }
722}
723
724#[derive(Clone)]
727pub struct TlsInfo {
728 pub(crate) peer_certificate: Option<Vec<u8>>,
729}
730
731impl TlsInfo {
732 pub fn peer_certificate(&self) -> Option<&[u8]> {
734 self.peer_certificate.as_ref().map(|der| &der[..])
735 }
736}
737
738impl std::fmt::Debug for TlsInfo {
739 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
740 f.debug_struct("TlsInfo").finish()
741 }
742}
743
744#[cfg(test)]
745mod tests {
746 use super::*;
747
748 #[cfg(feature = "default-tls")]
749 #[test]
750 fn certificate_from_der_invalid() {
751 Certificate::from_der(b"not der").unwrap_err();
752 }
753
754 #[cfg(feature = "default-tls")]
755 #[test]
756 fn certificate_from_pem_invalid() {
757 Certificate::from_pem(b"not pem").unwrap_err();
758 }
759
760 #[cfg(feature = "native-tls")]
761 #[test]
762 fn identity_from_pkcs12_der_invalid() {
763 Identity::from_pkcs12_der(b"not der", "nope").unwrap_err();
764 }
765
766 #[cfg(feature = "native-tls")]
767 #[test]
768 fn identity_from_pkcs8_pem_invalid() {
769 Identity::from_pkcs8_pem(b"not pem", b"not key").unwrap_err();
770 }
771
772 #[cfg(feature = "__rustls")]
773 #[test]
774 fn identity_from_pem_invalid() {
775 Identity::from_pem(b"not pem").unwrap_err();
776 }
777
778 #[cfg(feature = "__rustls")]
779 #[test]
780 fn identity_from_pem_pkcs1_key() {
781 let pem = b"-----BEGIN CERTIFICATE-----\n\
782 -----END CERTIFICATE-----\n\
783 -----BEGIN RSA PRIVATE KEY-----\n\
784 -----END RSA PRIVATE KEY-----\n";
785
786 Identity::from_pem(pem).unwrap();
787 }
788
789 #[test]
790 fn certificates_from_pem_bundle() {
791 const PEM_BUNDLE: &[u8] = b"
792 -----BEGIN CERTIFICATE-----
793 MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5
794 MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
795 Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
796 A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
797 Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl
798 ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j
799 QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr
800 ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr
801 BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM
802 YyRIHN8wfdVoOw==
803 -----END CERTIFICATE-----
804
805 -----BEGIN CERTIFICATE-----
806 MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5
807 MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
808 Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
809 A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
810 Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi
811 9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk
812 M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB
813 /zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB
814 MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw
815 CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW
816 1KyLa2tJElMzrdfkviT8tQp21KW8EA==
817 -----END CERTIFICATE-----
818 ";
819
820 assert!(Certificate::from_pem_bundle(PEM_BUNDLE).is_ok())
821 }
822
823 #[cfg(feature = "__rustls")]
824 #[test]
825 fn crl_from_pem() {
826 let pem = b"-----BEGIN X509 CRL-----\n-----END X509 CRL-----\n";
827
828 CertificateRevocationList::from_pem(pem).unwrap();
829 }
830
831 #[cfg(feature = "__rustls")]
832 #[test]
833 fn crl_from_pem_bundle() {
834 let pem_bundle = std::fs::read("tests/support/crl.pem").unwrap();
835
836 let result = CertificateRevocationList::from_pem_bundle(&pem_bundle);
837
838 assert!(result.is_ok());
839 let result = result.unwrap();
840 assert_eq!(result.len(), 1);
841 }
842}