reqwest/
tls.rs

1//! TLS configuration and types
2//!
3//! A `Client` will use transport layer security (TLS) by default to connect to
4//! HTTPS destinations.
5//!
6//! # Backends
7//!
8//! reqwest supports several TLS backends, enabled with Cargo features.
9//!
10//! ## default-tls
11//!
12//! reqwest will pick a TLS backend by default. This is true when the
13//! `default-tls` feature is enabled.
14//!
15//! While it currently uses `native-tls`, the feature set is designed to only
16//! enable configuration that is shared among available backends. This allows
17//! reqwest to change the default to `rustls` (or another) at some point in the
18//! future.
19//!
20//! <div class="warning">This feature is enabled by default, and takes
21//! precedence if any other crate enables it. This is true even if you declare
22//! `features = []`. You must set `default-features = false` instead.</div>
23//!
24//! Since Cargo features are additive, other crates in your dependency tree can
25//! cause the default backend to be enabled. If you wish to ensure your
26//! `Client` uses a specific backend, call the appropriate builder methods
27//! (such as [`use_rustls_tls()`][]).
28//!
29//! [`use_rustls_tls()`]: crate::ClientBuilder::use_rustls_tls()
30//!
31//! ## native-tls
32//!
33//! This backend uses the [native-tls][] crate. That will try to use the system
34//! TLS on Windows and Mac, and OpenSSL on Linux targets.
35//!
36//! Enabling the feature explicitly allows for `native-tls`-specific
37//! configuration options.
38//!
39//! [native-tls]: https://crates.io/crates/native-tls
40//!
41//! ## rustls-tls
42//!
43//! This backend uses the [rustls][] crate, a TLS library written in Rust.
44//!
45//! [rustls]: https://crates.io/crates/rustls
46
47#[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};
54use rustls_pki_types::pem::PemObject;
55#[cfg(feature = "__rustls")]
56use rustls_pki_types::{ServerName, UnixTime};
57use std::{
58    fmt,
59    io::{BufRead, BufReader},
60};
61
62/// Represents a X509 certificate revocation list.
63#[cfg(feature = "__rustls")]
64pub struct CertificateRevocationList {
65    #[cfg(feature = "__rustls")]
66    inner: rustls_pki_types::CertificateRevocationListDer<'static>,
67}
68
69/// Represents a server X509 certificate.
70#[derive(Clone)]
71pub struct Certificate {
72    #[cfg(feature = "default-tls")]
73    native: native_tls_crate::Certificate,
74    #[cfg(feature = "__rustls")]
75    original: Cert,
76}
77
78#[cfg(feature = "__rustls")]
79#[derive(Clone)]
80enum Cert {
81    Der(Vec<u8>),
82    Pem(Vec<u8>),
83}
84
85/// Represents a private key and X509 cert as a client certificate.
86#[derive(Clone)]
87pub struct Identity {
88    #[cfg_attr(not(any(feature = "native-tls", feature = "__rustls")), allow(unused))]
89    inner: ClientCert,
90}
91
92enum ClientCert {
93    #[cfg(feature = "native-tls")]
94    Pkcs12(native_tls_crate::Identity),
95    #[cfg(feature = "native-tls")]
96    Pkcs8(native_tls_crate::Identity),
97    #[cfg(feature = "__rustls")]
98    Pem {
99        key: rustls_pki_types::PrivateKeyDer<'static>,
100        certs: Vec<rustls_pki_types::CertificateDer<'static>>,
101    },
102}
103
104impl Clone for ClientCert {
105    fn clone(&self) -> Self {
106        match self {
107            #[cfg(feature = "native-tls")]
108            Self::Pkcs8(i) => Self::Pkcs8(i.clone()),
109            #[cfg(feature = "native-tls")]
110            Self::Pkcs12(i) => Self::Pkcs12(i.clone()),
111            #[cfg(feature = "__rustls")]
112            ClientCert::Pem { key, certs } => ClientCert::Pem {
113                key: key.clone_key(),
114                certs: certs.clone(),
115            },
116            #[cfg_attr(
117                any(feature = "native-tls", feature = "__rustls"),
118                allow(unreachable_patterns)
119            )]
120            _ => unreachable!(),
121        }
122    }
123}
124
125impl Certificate {
126    /// Create a `Certificate` from a binary DER encoded certificate
127    ///
128    /// # Examples
129    ///
130    /// ```
131    /// # use std::fs::File;
132    /// # use std::io::Read;
133    /// # fn cert() -> Result<(), Box<dyn std::error::Error>> {
134    /// let mut buf = Vec::new();
135    /// File::open("my_cert.der")?
136    ///     .read_to_end(&mut buf)?;
137    /// let cert = reqwest::Certificate::from_der(&buf)?;
138    /// # drop(cert);
139    /// # Ok(())
140    /// # }
141    /// ```
142    pub fn from_der(der: &[u8]) -> crate::Result<Certificate> {
143        Ok(Certificate {
144            #[cfg(feature = "default-tls")]
145            native: native_tls_crate::Certificate::from_der(der).map_err(crate::error::builder)?,
146            #[cfg(feature = "__rustls")]
147            original: Cert::Der(der.to_owned()),
148        })
149    }
150
151    /// Create a `Certificate` from a PEM encoded certificate
152    ///
153    /// # Examples
154    ///
155    /// ```
156    /// # use std::fs::File;
157    /// # use std::io::Read;
158    /// # fn cert() -> Result<(), Box<dyn std::error::Error>> {
159    /// let mut buf = Vec::new();
160    /// File::open("my_cert.pem")?
161    ///     .read_to_end(&mut buf)?;
162    /// let cert = reqwest::Certificate::from_pem(&buf)?;
163    /// # drop(cert);
164    /// # Ok(())
165    /// # }
166    /// ```
167    pub fn from_pem(pem: &[u8]) -> crate::Result<Certificate> {
168        Ok(Certificate {
169            #[cfg(feature = "default-tls")]
170            native: native_tls_crate::Certificate::from_pem(pem).map_err(crate::error::builder)?,
171            #[cfg(feature = "__rustls")]
172            original: Cert::Pem(pem.to_owned()),
173        })
174    }
175
176    /// Create a collection of `Certificate`s from a PEM encoded certificate bundle.
177    /// Example byte sources may be `.crt`, `.cer` or `.pem` files.
178    ///
179    /// # Examples
180    ///
181    /// ```
182    /// # use std::fs::File;
183    /// # use std::io::Read;
184    /// # fn cert() -> Result<(), Box<dyn std::error::Error>> {
185    /// let mut buf = Vec::new();
186    /// File::open("ca-bundle.crt")?
187    ///     .read_to_end(&mut buf)?;
188    /// let certs = reqwest::Certificate::from_pem_bundle(&buf)?;
189    /// # drop(certs);
190    /// # Ok(())
191    /// # }
192    /// ```
193    pub fn from_pem_bundle(pem_bundle: &[u8]) -> crate::Result<Vec<Certificate>> {
194        let mut reader = BufReader::new(pem_bundle);
195
196        Self::read_pem_certs(&mut reader)?
197            .iter()
198            .map(|cert_vec| Certificate::from_der(cert_vec))
199            .collect::<crate::Result<Vec<Certificate>>>()
200    }
201
202    #[cfg(feature = "default-tls")]
203    pub(crate) fn add_to_native_tls(self, tls: &mut native_tls_crate::TlsConnectorBuilder) {
204        tls.add_root_certificate(self.native);
205    }
206
207    #[cfg(feature = "__rustls")]
208    pub(crate) fn add_to_rustls(
209        self,
210        root_cert_store: &mut rustls::RootCertStore,
211    ) -> crate::Result<()> {
212        use std::io::Cursor;
213
214        match self.original {
215            Cert::Der(buf) => root_cert_store
216                .add(buf.into())
217                .map_err(crate::error::builder)?,
218            Cert::Pem(buf) => {
219                let mut reader = Cursor::new(buf);
220                let certs = Self::read_pem_certs(&mut reader)?;
221                for c in certs {
222                    root_cert_store
223                        .add(c.into())
224                        .map_err(crate::error::builder)?;
225                }
226            }
227        }
228        Ok(())
229    }
230
231    fn read_pem_certs(reader: &mut impl BufRead) -> crate::Result<Vec<Vec<u8>>> {
232        rustls_pki_types::CertificateDer::pem_reader_iter(reader)
233            .map(|result| match result {
234                Ok(cert) => Ok(cert.as_ref().to_vec()),
235                Err(_) => Err(crate::error::builder("invalid certificate encoding")),
236            })
237            .collect()
238    }
239}
240
241impl Identity {
242    /// Parses a DER-formatted PKCS #12 archive, using the specified password to decrypt the key.
243    ///
244    /// The archive should contain a leaf certificate and its private key, as well any intermediate
245    /// certificates that allow clients to build a chain to a trusted root.
246    /// The chain certificates should be in order from the leaf certificate towards the root.
247    ///
248    /// PKCS #12 archives typically have the file extension `.p12` or `.pfx`, and can be created
249    /// with the OpenSSL `pkcs12` tool:
250    ///
251    /// ```bash
252    /// openssl pkcs12 -export -out identity.pfx -inkey key.pem -in cert.pem -certfile chain_certs.pem
253    /// ```
254    ///
255    /// # Examples
256    ///
257    /// ```
258    /// # use std::fs::File;
259    /// # use std::io::Read;
260    /// # fn pkcs12() -> Result<(), Box<dyn std::error::Error>> {
261    /// let mut buf = Vec::new();
262    /// File::open("my-ident.pfx")?
263    ///     .read_to_end(&mut buf)?;
264    /// let pkcs12 = reqwest::Identity::from_pkcs12_der(&buf, "my-privkey-password")?;
265    /// # drop(pkcs12);
266    /// # Ok(())
267    /// # }
268    /// ```
269    ///
270    /// # Optional
271    ///
272    /// This requires the `native-tls` Cargo feature enabled.
273    #[cfg(feature = "native-tls")]
274    pub fn from_pkcs12_der(der: &[u8], password: &str) -> crate::Result<Identity> {
275        Ok(Identity {
276            inner: ClientCert::Pkcs12(
277                native_tls_crate::Identity::from_pkcs12(der, password)
278                    .map_err(crate::error::builder)?,
279            ),
280        })
281    }
282
283    /// Parses a chain of PEM encoded X509 certificates, with the leaf certificate first.
284    /// `key` is a PEM encoded PKCS #8 formatted private key for the leaf certificate.
285    ///
286    /// The certificate chain should contain any intermediate certificates that should be sent to
287    /// clients to allow them to build a chain to a trusted root.
288    ///
289    /// A certificate chain here means a series of PEM encoded certificates concatenated together.
290    ///
291    /// # Examples
292    ///
293    /// ```
294    /// # use std::fs;
295    /// # fn pkcs8() -> Result<(), Box<dyn std::error::Error>> {
296    /// let cert = fs::read("client.pem")?;
297    /// let key = fs::read("key.pem")?;
298    /// let pkcs8 = reqwest::Identity::from_pkcs8_pem(&cert, &key)?;
299    /// # drop(pkcs8);
300    /// # Ok(())
301    /// # }
302    /// ```
303    ///
304    /// # Optional
305    ///
306    /// This requires the `native-tls` Cargo feature enabled.
307    #[cfg(feature = "native-tls")]
308    pub fn from_pkcs8_pem(pem: &[u8], key: &[u8]) -> crate::Result<Identity> {
309        Ok(Identity {
310            inner: ClientCert::Pkcs8(
311                native_tls_crate::Identity::from_pkcs8(pem, key).map_err(crate::error::builder)?,
312            ),
313        })
314    }
315
316    /// Parses PEM encoded private key and certificate.
317    ///
318    /// The input should contain a PEM encoded private key
319    /// and at least one PEM encoded certificate.
320    ///
321    /// Note: The private key must be in RSA, SEC1 Elliptic Curve or PKCS#8 format.
322    ///
323    /// # Examples
324    ///
325    /// ```
326    /// # use std::fs::File;
327    /// # use std::io::Read;
328    /// # fn pem() -> Result<(), Box<dyn std::error::Error>> {
329    /// let mut buf = Vec::new();
330    /// File::open("my-ident.pem")?
331    ///     .read_to_end(&mut buf)?;
332    /// let id = reqwest::Identity::from_pem(&buf)?;
333    /// # drop(id);
334    /// # Ok(())
335    /// # }
336    /// ```
337    ///
338    /// # Optional
339    ///
340    /// This requires the `rustls-tls(-...)` Cargo feature enabled.
341    #[cfg(feature = "__rustls")]
342    pub fn from_pem(buf: &[u8]) -> crate::Result<Identity> {
343        use rustls_pki_types::{pem::SectionKind, PrivateKeyDer};
344        use std::io::Cursor;
345
346        let (key, certs) = {
347            let mut pem = Cursor::new(buf);
348            let mut sk = Vec::<rustls_pki_types::PrivateKeyDer>::new();
349            let mut certs = Vec::<rustls_pki_types::CertificateDer>::new();
350
351            while let Some((kind, data)) =
352                rustls_pki_types::pem::from_buf(&mut pem).map_err(|_| {
353                    crate::error::builder(TLSError::General(String::from(
354                        "Invalid identity PEM file",
355                    )))
356                })?
357            {
358                match kind {
359                    SectionKind::Certificate => certs.push(data.into()),
360                    SectionKind::PrivateKey => sk.push(PrivateKeyDer::Pkcs8(data.into())),
361                    SectionKind::RsaPrivateKey => sk.push(PrivateKeyDer::Pkcs1(data.into())),
362                    SectionKind::EcPrivateKey => sk.push(PrivateKeyDer::Sec1(data.into())),
363                    _ => {
364                        return Err(crate::error::builder(TLSError::General(String::from(
365                            "No valid certificate was found",
366                        ))))
367                    }
368                }
369            }
370
371            if let (Some(sk), false) = (sk.pop(), certs.is_empty()) {
372                (sk, certs)
373            } else {
374                return Err(crate::error::builder(TLSError::General(String::from(
375                    "private key or certificate not found",
376                ))));
377            }
378        };
379
380        Ok(Identity {
381            inner: ClientCert::Pem { key, certs },
382        })
383    }
384
385    #[cfg(feature = "native-tls")]
386    pub(crate) fn add_to_native_tls(
387        self,
388        tls: &mut native_tls_crate::TlsConnectorBuilder,
389    ) -> crate::Result<()> {
390        match self.inner {
391            ClientCert::Pkcs12(id) | ClientCert::Pkcs8(id) => {
392                tls.identity(id);
393                Ok(())
394            }
395            #[cfg(feature = "__rustls")]
396            ClientCert::Pem { .. } => Err(crate::error::builder("incompatible TLS identity type")),
397        }
398    }
399
400    #[cfg(feature = "__rustls")]
401    pub(crate) fn add_to_rustls(
402        self,
403        config_builder: rustls::ConfigBuilder<
404            rustls::ClientConfig,
405            // Not sure here
406            rustls::client::WantsClientCert,
407        >,
408    ) -> crate::Result<rustls::ClientConfig> {
409        match self.inner {
410            ClientCert::Pem { key, certs } => config_builder
411                .with_client_auth_cert(certs, key)
412                .map_err(crate::error::builder),
413            #[cfg(feature = "native-tls")]
414            ClientCert::Pkcs12(..) | ClientCert::Pkcs8(..) => {
415                Err(crate::error::builder("incompatible TLS identity type"))
416            }
417        }
418    }
419}
420
421#[cfg(feature = "__rustls")]
422impl CertificateRevocationList {
423    /// Parses a PEM encoded CRL.
424    ///
425    /// # Examples
426    ///
427    /// ```
428    /// # use std::fs::File;
429    /// # use std::io::Read;
430    /// # fn crl() -> Result<(), Box<dyn std::error::Error>> {
431    /// let mut buf = Vec::new();
432    /// File::open("my_crl.pem")?
433    ///     .read_to_end(&mut buf)?;
434    /// let crl = reqwest::tls::CertificateRevocationList::from_pem(&buf)?;
435    /// # drop(crl);
436    /// # Ok(())
437    /// # }
438    /// ```
439    ///
440    /// # Optional
441    ///
442    /// This requires the `rustls-tls(-...)` Cargo feature enabled.
443    #[cfg(feature = "__rustls")]
444    pub fn from_pem(pem: &[u8]) -> crate::Result<CertificateRevocationList> {
445        Ok(CertificateRevocationList {
446            #[cfg(feature = "__rustls")]
447            inner: rustls_pki_types::CertificateRevocationListDer::from(pem.to_vec()),
448        })
449    }
450
451    /// Creates a collection of `CertificateRevocationList`s from a PEM encoded CRL bundle.
452    /// Example byte sources may be `.crl` or `.pem` files.
453    ///
454    /// # Examples
455    ///
456    /// ```
457    /// # use std::fs::File;
458    /// # use std::io::Read;
459    /// # fn crls() -> Result<(), Box<dyn std::error::Error>> {
460    /// let mut buf = Vec::new();
461    /// File::open("crl-bundle.crl")?
462    ///     .read_to_end(&mut buf)?;
463    /// let crls = reqwest::tls::CertificateRevocationList::from_pem_bundle(&buf)?;
464    /// # drop(crls);
465    /// # Ok(())
466    /// # }
467    /// ```
468    ///
469    /// # Optional
470    ///
471    /// This requires the `rustls-tls(-...)` Cargo feature enabled.
472    #[cfg(feature = "__rustls")]
473    pub fn from_pem_bundle(pem_bundle: &[u8]) -> crate::Result<Vec<CertificateRevocationList>> {
474        rustls_pki_types::CertificateRevocationListDer::pem_slice_iter(pem_bundle)
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/// A TLS protocol version.
508#[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
520// These could perhaps be From/TryFrom implementations, but those would be
521// part of the public API so let's be careful
522impl Version {
523    /// Version 1.0 of the TLS protocol.
524    pub const TLS_1_0: Version = Version(InnerVersion::Tls1_0);
525    /// Version 1.1 of the TLS protocol.
526    pub const TLS_1_1: Version = Version(InnerVersion::Tls1_1);
527    /// Version 1.2 of the TLS protocol.
528    pub const TLS_1_2: Version = Version(InnerVersion::Tls1_2);
529    /// Version 1.3 of the TLS protocol.
530    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    // This is the default and HTTP/3 feature does not use it so suppress it.
558    #[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
588#[allow(clippy::derivable_impls)]
589impl Default for TlsBackend {
590    fn default() -> TlsBackend {
591        #[cfg(all(feature = "default-tls", not(feature = "http3")))]
592        {
593            TlsBackend::Default
594        }
595
596        #[cfg(any(
597            all(feature = "__rustls", not(feature = "default-tls")),
598            feature = "http3"
599        ))]
600        {
601            TlsBackend::Rustls
602        }
603    }
604}
605
606#[cfg(feature = "__rustls")]
607#[derive(Debug)]
608pub(crate) struct NoVerifier;
609
610#[cfg(feature = "__rustls")]
611impl ServerCertVerifier for NoVerifier {
612    fn verify_server_cert(
613        &self,
614        _end_entity: &rustls_pki_types::CertificateDer,
615        _intermediates: &[rustls_pki_types::CertificateDer],
616        _server_name: &ServerName,
617        _ocsp_response: &[u8],
618        _now: UnixTime,
619    ) -> Result<ServerCertVerified, TLSError> {
620        Ok(ServerCertVerified::assertion())
621    }
622
623    fn verify_tls12_signature(
624        &self,
625        _message: &[u8],
626        _cert: &rustls_pki_types::CertificateDer,
627        _dss: &DigitallySignedStruct,
628    ) -> Result<HandshakeSignatureValid, TLSError> {
629        Ok(HandshakeSignatureValid::assertion())
630    }
631
632    fn verify_tls13_signature(
633        &self,
634        _message: &[u8],
635        _cert: &rustls_pki_types::CertificateDer,
636        _dss: &DigitallySignedStruct,
637    ) -> Result<HandshakeSignatureValid, TLSError> {
638        Ok(HandshakeSignatureValid::assertion())
639    }
640
641    fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
642        vec![
643            SignatureScheme::RSA_PKCS1_SHA1,
644            SignatureScheme::ECDSA_SHA1_Legacy,
645            SignatureScheme::RSA_PKCS1_SHA256,
646            SignatureScheme::ECDSA_NISTP256_SHA256,
647            SignatureScheme::RSA_PKCS1_SHA384,
648            SignatureScheme::ECDSA_NISTP384_SHA384,
649            SignatureScheme::RSA_PKCS1_SHA512,
650            SignatureScheme::ECDSA_NISTP521_SHA512,
651            SignatureScheme::RSA_PSS_SHA256,
652            SignatureScheme::RSA_PSS_SHA384,
653            SignatureScheme::RSA_PSS_SHA512,
654            SignatureScheme::ED25519,
655            SignatureScheme::ED448,
656        ]
657    }
658}
659
660#[cfg(feature = "__rustls")]
661#[derive(Debug)]
662pub(crate) struct IgnoreHostname {
663    roots: RootCertStore,
664    signature_algorithms: WebPkiSupportedAlgorithms,
665}
666
667#[cfg(feature = "__rustls")]
668impl IgnoreHostname {
669    pub(crate) fn new(
670        roots: RootCertStore,
671        signature_algorithms: WebPkiSupportedAlgorithms,
672    ) -> Self {
673        Self {
674            roots,
675            signature_algorithms,
676        }
677    }
678}
679
680#[cfg(feature = "__rustls")]
681impl ServerCertVerifier for IgnoreHostname {
682    fn verify_server_cert(
683        &self,
684        end_entity: &rustls_pki_types::CertificateDer<'_>,
685        intermediates: &[rustls_pki_types::CertificateDer<'_>],
686        _server_name: &ServerName<'_>,
687        _ocsp_response: &[u8],
688        now: UnixTime,
689    ) -> Result<ServerCertVerified, TLSError> {
690        let cert = ParsedCertificate::try_from(end_entity)?;
691
692        rustls::client::verify_server_cert_signed_by_trust_anchor(
693            &cert,
694            &self.roots,
695            intermediates,
696            now,
697            self.signature_algorithms.all,
698        )?;
699        Ok(ServerCertVerified::assertion())
700    }
701
702    fn verify_tls12_signature(
703        &self,
704        message: &[u8],
705        cert: &rustls_pki_types::CertificateDer<'_>,
706        dss: &DigitallySignedStruct,
707    ) -> Result<HandshakeSignatureValid, TLSError> {
708        rustls::crypto::verify_tls12_signature(message, cert, dss, &self.signature_algorithms)
709    }
710
711    fn verify_tls13_signature(
712        &self,
713        message: &[u8],
714        cert: &rustls_pki_types::CertificateDer<'_>,
715        dss: &DigitallySignedStruct,
716    ) -> Result<HandshakeSignatureValid, TLSError> {
717        rustls::crypto::verify_tls13_signature(message, cert, dss, &self.signature_algorithms)
718    }
719
720    fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
721        self.signature_algorithms.supported_schemes()
722    }
723}
724
725/// Hyper extension carrying extra TLS layer information.
726/// Made available to clients on responses when `tls_info` is set.
727#[derive(Clone)]
728pub struct TlsInfo {
729    pub(crate) peer_certificate: Option<Vec<u8>>,
730}
731
732impl TlsInfo {
733    /// Get the DER encoded leaf certificate of the peer.
734    pub fn peer_certificate(&self) -> Option<&[u8]> {
735        self.peer_certificate.as_ref().map(|der| &der[..])
736    }
737}
738
739impl std::fmt::Debug for TlsInfo {
740    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
741        f.debug_struct("TlsInfo").finish()
742    }
743}
744
745#[cfg(test)]
746mod tests {
747    use super::*;
748
749    #[cfg(feature = "default-tls")]
750    #[test]
751    fn certificate_from_der_invalid() {
752        Certificate::from_der(b"not der").unwrap_err();
753    }
754
755    #[cfg(feature = "default-tls")]
756    #[test]
757    fn certificate_from_pem_invalid() {
758        Certificate::from_pem(b"not pem").unwrap_err();
759    }
760
761    #[cfg(feature = "native-tls")]
762    #[test]
763    fn identity_from_pkcs12_der_invalid() {
764        Identity::from_pkcs12_der(b"not der", "nope").unwrap_err();
765    }
766
767    #[cfg(feature = "native-tls")]
768    #[test]
769    fn identity_from_pkcs8_pem_invalid() {
770        Identity::from_pkcs8_pem(b"not pem", b"not key").unwrap_err();
771    }
772
773    #[cfg(feature = "__rustls")]
774    #[test]
775    fn identity_from_pem_invalid() {
776        Identity::from_pem(b"not pem").unwrap_err();
777    }
778
779    #[cfg(feature = "__rustls")]
780    #[test]
781    fn identity_from_pem_pkcs1_key() {
782        let pem = b"-----BEGIN CERTIFICATE-----\n\
783            -----END CERTIFICATE-----\n\
784            -----BEGIN RSA PRIVATE KEY-----\n\
785            -----END RSA PRIVATE KEY-----\n";
786
787        Identity::from_pem(pem).unwrap();
788    }
789
790    #[test]
791    fn certificates_from_pem_bundle() {
792        const PEM_BUNDLE: &[u8] = b"
793            -----BEGIN CERTIFICATE-----
794            MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5
795            MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
796            Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
797            A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
798            Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl
799            ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j
800            QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr
801            ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr
802            BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM
803            YyRIHN8wfdVoOw==
804            -----END CERTIFICATE-----
805
806            -----BEGIN CERTIFICATE-----
807            MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5
808            MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
809            Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
810            A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
811            Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi
812            9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk
813            M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB
814            /zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB
815            MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw
816            CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW
817            1KyLa2tJElMzrdfkviT8tQp21KW8EA==
818            -----END CERTIFICATE-----
819        ";
820
821        assert!(Certificate::from_pem_bundle(PEM_BUNDLE).is_ok())
822    }
823
824    #[cfg(feature = "__rustls")]
825    #[test]
826    fn crl_from_pem() {
827        let pem = b"-----BEGIN X509 CRL-----\n-----END X509 CRL-----\n";
828
829        CertificateRevocationList::from_pem(pem).unwrap();
830    }
831
832    #[cfg(feature = "__rustls")]
833    #[test]
834    fn crl_from_pem_bundle() {
835        let pem_bundle = std::fs::read("tests/support/crl.pem").unwrap();
836
837        let result = CertificateRevocationList::from_pem_bundle(&pem_bundle);
838
839        assert!(result.is_ok());
840        let result = result.unwrap();
841        assert_eq!(result.len(), 1);
842    }
843}