1#[cfg(feature = "__rustls")]
48use rustls::{
49 client::danger::HandshakeSignatureValid, client::danger::ServerCertVerified,
50 client::danger::ServerCertVerifier, DigitallySignedStruct, Error as TLSError, SignatureScheme,
51};
52#[cfg(feature = "__rustls")]
53use rustls_pki_types::{ServerName, UnixTime};
54use std::{
55 fmt,
56 io::{BufRead, BufReader},
57};
58
59#[derive(Clone)]
61pub struct Certificate {
62 #[cfg(feature = "default-tls")]
63 native: native_tls_crate::Certificate,
64 #[cfg(feature = "__rustls")]
65 original: Cert,
66}
67
68#[cfg(feature = "__rustls")]
69#[derive(Clone)]
70enum Cert {
71 Der(Vec<u8>),
72 Pem(Vec<u8>),
73}
74
75#[derive(Clone)]
77pub struct Identity {
78 #[cfg_attr(not(any(feature = "native-tls", feature = "__rustls")), allow(unused))]
79 inner: ClientCert,
80}
81
82enum ClientCert {
83 #[cfg(feature = "native-tls")]
84 Pkcs12(native_tls_crate::Identity),
85 #[cfg(feature = "native-tls")]
86 Pkcs8(native_tls_crate::Identity),
87 #[cfg(feature = "__rustls")]
88 Pem {
89 key: rustls_pki_types::PrivateKeyDer<'static>,
90 certs: Vec<rustls_pki_types::CertificateDer<'static>>,
91 },
92}
93
94impl Clone for ClientCert {
95 fn clone(&self) -> Self {
96 match self {
97 #[cfg(feature = "native-tls")]
98 Self::Pkcs8(i) => Self::Pkcs8(i.clone()),
99 #[cfg(feature = "native-tls")]
100 Self::Pkcs12(i) => Self::Pkcs12(i.clone()),
101 #[cfg(feature = "__rustls")]
102 ClientCert::Pem { key, certs } => ClientCert::Pem {
103 key: key.clone_key(),
104 certs: certs.clone(),
105 },
106 #[cfg_attr(
107 any(feature = "native-tls", feature = "__rustls"),
108 allow(unreachable_patterns)
109 )]
110 _ => unreachable!(),
111 }
112 }
113}
114
115impl Certificate {
116 pub fn from_der(der: &[u8]) -> crate::Result<Certificate> {
133 Ok(Certificate {
134 #[cfg(feature = "default-tls")]
135 native: native_tls_crate::Certificate::from_der(der).map_err(crate::error::builder)?,
136 #[cfg(feature = "__rustls")]
137 original: Cert::Der(der.to_owned()),
138 })
139 }
140
141 pub fn from_pem(pem: &[u8]) -> crate::Result<Certificate> {
158 Ok(Certificate {
159 #[cfg(feature = "default-tls")]
160 native: native_tls_crate::Certificate::from_pem(pem).map_err(crate::error::builder)?,
161 #[cfg(feature = "__rustls")]
162 original: Cert::Pem(pem.to_owned()),
163 })
164 }
165
166 pub fn from_pem_bundle(pem_bundle: &[u8]) -> crate::Result<Vec<Certificate>> {
184 let mut reader = BufReader::new(pem_bundle);
185
186 Self::read_pem_certs(&mut reader)?
187 .iter()
188 .map(|cert_vec| Certificate::from_der(&cert_vec))
189 .collect::<crate::Result<Vec<Certificate>>>()
190 }
191
192 #[cfg(feature = "default-tls")]
193 pub(crate) fn add_to_native_tls(self, tls: &mut native_tls_crate::TlsConnectorBuilder) {
194 tls.add_root_certificate(self.native);
195 }
196
197 #[cfg(feature = "__rustls")]
198 pub(crate) fn add_to_rustls(
199 self,
200 root_cert_store: &mut rustls::RootCertStore,
201 ) -> crate::Result<()> {
202 use std::io::Cursor;
203
204 match self.original {
205 Cert::Der(buf) => root_cert_store
206 .add(buf.into())
207 .map_err(crate::error::builder)?,
208 Cert::Pem(buf) => {
209 let mut reader = Cursor::new(buf);
210 let certs = Self::read_pem_certs(&mut reader)?;
211 for c in certs {
212 root_cert_store
213 .add(c.into())
214 .map_err(crate::error::builder)?;
215 }
216 }
217 }
218 Ok(())
219 }
220
221 fn read_pem_certs(reader: &mut impl BufRead) -> crate::Result<Vec<Vec<u8>>> {
222 rustls_pemfile::certs(reader)
223 .map(|result| match result {
224 Ok(cert) => Ok(cert.as_ref().to_vec()),
225 Err(_) => Err(crate::error::builder("invalid certificate encoding")),
226 })
227 .collect()
228 }
229}
230
231impl Identity {
232 #[cfg(feature = "native-tls")]
264 pub fn from_pkcs12_der(der: &[u8], password: &str) -> crate::Result<Identity> {
265 Ok(Identity {
266 inner: ClientCert::Pkcs12(
267 native_tls_crate::Identity::from_pkcs12(der, password)
268 .map_err(crate::error::builder)?,
269 ),
270 })
271 }
272
273 #[cfg(feature = "native-tls")]
298 pub fn from_pkcs8_pem(pem: &[u8], key: &[u8]) -> crate::Result<Identity> {
299 Ok(Identity {
300 inner: ClientCert::Pkcs8(
301 native_tls_crate::Identity::from_pkcs8(pem, key).map_err(crate::error::builder)?,
302 ),
303 })
304 }
305
306 #[cfg(feature = "__rustls")]
332 pub fn from_pem(buf: &[u8]) -> crate::Result<Identity> {
333 use rustls_pemfile::Item;
334 use std::io::Cursor;
335
336 let (key, certs) = {
337 let mut pem = Cursor::new(buf);
338 let mut sk = Vec::<rustls_pki_types::PrivateKeyDer>::new();
339 let mut certs = Vec::<rustls_pki_types::CertificateDer>::new();
340
341 for result in rustls_pemfile::read_all(&mut pem) {
342 match result {
343 Ok(Item::X509Certificate(cert)) => certs.push(cert),
344 Ok(Item::Pkcs1Key(key)) => sk.push(key.into()),
345 Ok(Item::Pkcs8Key(key)) => sk.push(key.into()),
346 Ok(Item::Sec1Key(key)) => sk.push(key.into()),
347 Ok(_) => {
348 return Err(crate::error::builder(TLSError::General(String::from(
349 "No valid certificate was found",
350 ))))
351 }
352 Err(_) => {
353 return Err(crate::error::builder(TLSError::General(String::from(
354 "Invalid identity PEM file",
355 ))))
356 }
357 }
358 }
359
360 if let (Some(sk), false) = (sk.pop(), certs.is_empty()) {
361 (sk, certs)
362 } else {
363 return Err(crate::error::builder(TLSError::General(String::from(
364 "private key or certificate not found",
365 ))));
366 }
367 };
368
369 Ok(Identity {
370 inner: ClientCert::Pem { key, certs },
371 })
372 }
373
374 #[cfg(feature = "native-tls")]
375 pub(crate) fn add_to_native_tls(
376 self,
377 tls: &mut native_tls_crate::TlsConnectorBuilder,
378 ) -> crate::Result<()> {
379 match self.inner {
380 ClientCert::Pkcs12(id) | ClientCert::Pkcs8(id) => {
381 tls.identity(id);
382 Ok(())
383 }
384 #[cfg(feature = "__rustls")]
385 ClientCert::Pem { .. } => Err(crate::error::builder("incompatible TLS identity type")),
386 }
387 }
388
389 #[cfg(feature = "__rustls")]
390 pub(crate) fn add_to_rustls(
391 self,
392 config_builder: rustls::ConfigBuilder<
393 rustls::ClientConfig,
394 rustls::client::WantsClientCert,
396 >,
397 ) -> crate::Result<rustls::ClientConfig> {
398 match self.inner {
399 ClientCert::Pem { key, certs } => config_builder
400 .with_client_auth_cert(certs, key)
401 .map_err(crate::error::builder),
402 #[cfg(feature = "native-tls")]
403 ClientCert::Pkcs12(..) | ClientCert::Pkcs8(..) => {
404 Err(crate::error::builder("incompatible TLS identity type"))
405 }
406 }
407 }
408}
409
410impl fmt::Debug for Certificate {
411 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
412 f.debug_struct("Certificate").finish()
413 }
414}
415
416impl fmt::Debug for Identity {
417 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
418 f.debug_struct("Identity").finish()
419 }
420}
421
422#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
424pub struct Version(InnerVersion);
425
426#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
427#[non_exhaustive]
428enum InnerVersion {
429 Tls1_0,
430 Tls1_1,
431 Tls1_2,
432 Tls1_3,
433}
434
435impl Version {
438 pub const TLS_1_0: Version = Version(InnerVersion::Tls1_0);
440 pub const TLS_1_1: Version = Version(InnerVersion::Tls1_1);
442 pub const TLS_1_2: Version = Version(InnerVersion::Tls1_2);
444 pub const TLS_1_3: Version = Version(InnerVersion::Tls1_3);
446
447 #[cfg(feature = "default-tls")]
448 pub(crate) fn to_native_tls(self) -> Option<native_tls_crate::Protocol> {
449 match self.0 {
450 InnerVersion::Tls1_0 => Some(native_tls_crate::Protocol::Tlsv10),
451 InnerVersion::Tls1_1 => Some(native_tls_crate::Protocol::Tlsv11),
452 InnerVersion::Tls1_2 => Some(native_tls_crate::Protocol::Tlsv12),
453 InnerVersion::Tls1_3 => None,
454 }
455 }
456
457 #[cfg(feature = "__rustls")]
458 pub(crate) fn from_rustls(version: rustls::ProtocolVersion) -> Option<Self> {
459 match version {
460 rustls::ProtocolVersion::SSLv2 => None,
461 rustls::ProtocolVersion::SSLv3 => None,
462 rustls::ProtocolVersion::TLSv1_0 => Some(Self(InnerVersion::Tls1_0)),
463 rustls::ProtocolVersion::TLSv1_1 => Some(Self(InnerVersion::Tls1_1)),
464 rustls::ProtocolVersion::TLSv1_2 => Some(Self(InnerVersion::Tls1_2)),
465 rustls::ProtocolVersion::TLSv1_3 => Some(Self(InnerVersion::Tls1_3)),
466 _ => None,
467 }
468 }
469}
470
471pub(crate) enum TlsBackend {
472 #[allow(dead_code)]
474 #[cfg(feature = "default-tls")]
475 Default,
476 #[cfg(feature = "native-tls")]
477 BuiltNativeTls(native_tls_crate::TlsConnector),
478 #[cfg(feature = "__rustls")]
479 Rustls,
480 #[cfg(feature = "__rustls")]
481 BuiltRustls(rustls::ClientConfig),
482 #[cfg(any(feature = "native-tls", feature = "__rustls",))]
483 UnknownPreconfigured,
484}
485
486impl fmt::Debug for TlsBackend {
487 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
488 match self {
489 #[cfg(feature = "default-tls")]
490 TlsBackend::Default => write!(f, "Default"),
491 #[cfg(feature = "native-tls")]
492 TlsBackend::BuiltNativeTls(_) => write!(f, "BuiltNativeTls"),
493 #[cfg(feature = "__rustls")]
494 TlsBackend::Rustls => write!(f, "Rustls"),
495 #[cfg(feature = "__rustls")]
496 TlsBackend::BuiltRustls(_) => write!(f, "BuiltRustls"),
497 #[cfg(any(feature = "native-tls", feature = "__rustls",))]
498 TlsBackend::UnknownPreconfigured => write!(f, "UnknownPreconfigured"),
499 }
500 }
501}
502
503impl Default for TlsBackend {
504 fn default() -> TlsBackend {
505 #[cfg(all(feature = "default-tls", not(feature = "http3")))]
506 {
507 TlsBackend::Default
508 }
509
510 #[cfg(any(
511 all(feature = "__rustls", not(feature = "default-tls")),
512 feature = "http3"
513 ))]
514 {
515 TlsBackend::Rustls
516 }
517 }
518}
519
520#[cfg(feature = "__rustls")]
521#[derive(Debug)]
522pub(crate) struct NoVerifier;
523
524#[cfg(feature = "__rustls")]
525impl ServerCertVerifier for NoVerifier {
526 fn verify_server_cert(
527 &self,
528 _end_entity: &rustls_pki_types::CertificateDer,
529 _intermediates: &[rustls_pki_types::CertificateDer],
530 _server_name: &ServerName,
531 _ocsp_response: &[u8],
532 _now: UnixTime,
533 ) -> Result<ServerCertVerified, TLSError> {
534 Ok(ServerCertVerified::assertion())
535 }
536
537 fn verify_tls12_signature(
538 &self,
539 _message: &[u8],
540 _cert: &rustls_pki_types::CertificateDer,
541 _dss: &DigitallySignedStruct,
542 ) -> Result<HandshakeSignatureValid, TLSError> {
543 Ok(HandshakeSignatureValid::assertion())
544 }
545
546 fn verify_tls13_signature(
547 &self,
548 _message: &[u8],
549 _cert: &rustls_pki_types::CertificateDer,
550 _dss: &DigitallySignedStruct,
551 ) -> Result<HandshakeSignatureValid, TLSError> {
552 Ok(HandshakeSignatureValid::assertion())
553 }
554
555 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
556 vec![
557 SignatureScheme::RSA_PKCS1_SHA1,
558 SignatureScheme::ECDSA_SHA1_Legacy,
559 SignatureScheme::RSA_PKCS1_SHA256,
560 SignatureScheme::ECDSA_NISTP256_SHA256,
561 SignatureScheme::RSA_PKCS1_SHA384,
562 SignatureScheme::ECDSA_NISTP384_SHA384,
563 SignatureScheme::RSA_PKCS1_SHA512,
564 SignatureScheme::ECDSA_NISTP521_SHA512,
565 SignatureScheme::RSA_PSS_SHA256,
566 SignatureScheme::RSA_PSS_SHA384,
567 SignatureScheme::RSA_PSS_SHA512,
568 SignatureScheme::ED25519,
569 SignatureScheme::ED448,
570 ]
571 }
572}
573
574#[derive(Clone)]
577pub struct TlsInfo {
578 pub(crate) peer_certificate: Option<Vec<u8>>,
579}
580
581impl TlsInfo {
582 pub fn peer_certificate(&self) -> Option<&[u8]> {
584 self.peer_certificate.as_ref().map(|der| &der[..])
585 }
586}
587
588impl std::fmt::Debug for TlsInfo {
589 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
590 f.debug_struct("TlsInfo").finish()
591 }
592}
593
594#[cfg(test)]
595mod tests {
596 use super::*;
597
598 #[cfg(feature = "default-tls")]
599 #[test]
600 fn certificate_from_der_invalid() {
601 Certificate::from_der(b"not der").unwrap_err();
602 }
603
604 #[cfg(feature = "default-tls")]
605 #[test]
606 fn certificate_from_pem_invalid() {
607 Certificate::from_pem(b"not pem").unwrap_err();
608 }
609
610 #[cfg(feature = "native-tls")]
611 #[test]
612 fn identity_from_pkcs12_der_invalid() {
613 Identity::from_pkcs12_der(b"not der", "nope").unwrap_err();
614 }
615
616 #[cfg(feature = "native-tls")]
617 #[test]
618 fn identity_from_pkcs8_pem_invalid() {
619 Identity::from_pkcs8_pem(b"not pem", b"not key").unwrap_err();
620 }
621
622 #[cfg(feature = "__rustls")]
623 #[test]
624 fn identity_from_pem_invalid() {
625 Identity::from_pem(b"not pem").unwrap_err();
626 }
627
628 #[cfg(feature = "__rustls")]
629 #[test]
630 fn identity_from_pem_pkcs1_key() {
631 let pem = b"-----BEGIN CERTIFICATE-----\n\
632 -----END CERTIFICATE-----\n\
633 -----BEGIN RSA PRIVATE KEY-----\n\
634 -----END RSA PRIVATE KEY-----\n";
635
636 Identity::from_pem(pem).unwrap();
637 }
638
639 #[test]
640 fn certificates_from_pem_bundle() {
641 const PEM_BUNDLE: &[u8] = b"
642 -----BEGIN CERTIFICATE-----
643 MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5
644 MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
645 Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
646 A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
647 Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl
648 ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j
649 QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr
650 ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr
651 BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM
652 YyRIHN8wfdVoOw==
653 -----END CERTIFICATE-----
654
655 -----BEGIN CERTIFICATE-----
656 MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5
657 MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
658 Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
659 A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
660 Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi
661 9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk
662 M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB
663 /zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB
664 MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw
665 CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW
666 1KyLa2tJElMzrdfkviT8tQp21KW8EA==
667 -----END CERTIFICATE-----
668 ";
669
670 assert!(Certificate::from_pem_bundle(PEM_BUNDLE).is_ok())
671 }
672}