Skip to main content

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 `rustls`, 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 `native-tls` (or another) by configuration.
18//!
19//! <div class="warning">This feature is enabled by default, and takes
20//! precedence if any other crate enables it. This is true even if you declare
21//! `features = []`. You must set `default-features = false` instead.</div>
22//!
23//! Since Cargo features are additive, other crates in your dependency tree can
24//! cause the default backend to be enabled. If you wish to ensure your
25//! `Client` uses a specific backend, call the appropriate builder methods
26//! (such as [`tls_backend_rustls()`][]).
27//!
28//! [`tls_backend_rustls()`]: crate::ClientBuilder::tls_backend_rustls()
29//!
30//! ## native-tls
31//!
32//! This backend uses the [native-tls][] crate. That will try to use the system
33//! TLS on Windows and Mac, and OpenSSL on Linux targets.
34//!
35//! Enabling the feature explicitly allows for `native-tls`-specific
36//! configuration options.
37//!
38//! [native-tls]: https://crates.io/crates/native-tls
39//!
40//! ## rustls
41//!
42//! This backend uses the [rustls][] crate, a TLS library written in Rust.
43//!
44//! [rustls]: https://crates.io/crates/rustls
45//!
46//! ## rustls-no-provider
47//!
48//! Like `rustls`, but without a built-in crypto provider. This is useful when
49//! you want to supply your own [rustls CryptoProvider][], for example to use
50//! [ring][] instead of the default `aws-lc-rs`.
51//!
52//! **You must install a crypto provider before building a `Client`.** If none
53//! is installed the client will panic at construction time. Install one via
54//! [`CryptoProvider::install_default`][]:
55//!
56//! ```rust,ignore
57//! rustls::crypto::ring::default_provider()
58//!     .install_default()
59//!     .expect("Failed to install rustls crypto provider");
60//!
61//! let client = reqwest::Client::new();
62//! ```
63//!
64//! [rustls CryptoProvider]: https://docs.rs/rustls/latest/rustls/crypto/struct.CryptoProvider.html
65//! [ring]: https://crates.io/crates/ring
66//! [`CryptoProvider::install_default`]: https://docs.rs/rustls/latest/rustls/crypto/struct.CryptoProvider.html#method.install_default
67
68#[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/// Represents a X509 certificate revocation list.
84#[cfg(feature = "__rustls")]
85pub struct CertificateRevocationList {
86    #[cfg(feature = "__rustls")]
87    inner: rustls_pki_types::CertificateRevocationListDer<'static>,
88}
89
90/// Represents a server X509 certificate.
91#[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/// Represents a private key and X509 cert as a client certificate.
107#[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    /// Create a `Certificate` from a binary DER encoded certificate
151    ///
152    /// # Examples
153    ///
154    /// ```
155    /// # use std::fs::File;
156    /// # use std::io::Read;
157    /// # fn cert() -> Result<(), Box<dyn std::error::Error>> {
158    /// let mut buf = Vec::new();
159    /// File::open("my_cert.der")?
160    ///     .read_to_end(&mut buf)?;
161    /// let cert = reqwest::Certificate::from_der(&buf)?;
162    /// # drop(cert);
163    /// # Ok(())
164    /// # }
165    /// ```
166    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    /// Create a `Certificate` from a PEM encoded certificate
176    ///
177    /// # Examples
178    ///
179    /// ```
180    /// # use std::fs::File;
181    /// # use std::io::Read;
182    /// # fn cert() -> Result<(), Box<dyn std::error::Error>> {
183    /// let mut buf = Vec::new();
184    /// File::open("my_cert.pem")?
185    ///     .read_to_end(&mut buf)?;
186    /// let cert = reqwest::Certificate::from_pem(&buf)?;
187    /// # drop(cert);
188    /// # Ok(())
189    /// # }
190    /// ```
191    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    /// Create a collection of `Certificate`s from a PEM encoded certificate bundle.
201    /// Example byte sources may be `.crt`, `.cer` or `.pem` files.
202    ///
203    /// # Examples
204    ///
205    /// ```
206    /// # use std::fs::File;
207    /// # use std::io::Read;
208    /// # fn cert() -> Result<(), Box<dyn std::error::Error>> {
209    /// let mut buf = Vec::new();
210    /// File::open("ca-bundle.crt")?
211    ///     .read_to_end(&mut buf)?;
212    /// let certs = reqwest::Certificate::from_pem_bundle(&buf)?;
213    /// # drop(certs);
214    /// # Ok(())
215    /// # }
216    /// ```
217    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    /*
227    #[cfg(feature = "rustls")]
228    pub fn from_trust_anchor() -> Self {
229
230    }
231    */
232
233    #[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    /// Parses a DER-formatted PKCS #12 archive, using the specified password to decrypt the key.
274    ///
275    /// The archive should contain a leaf certificate and its private key, as well any intermediate
276    /// certificates that allow clients to build a chain to a trusted root.
277    /// The chain certificates should be in order from the leaf certificate towards the root.
278    ///
279    /// PKCS #12 archives typically have the file extension `.p12` or `.pfx`, and can be created
280    /// with the OpenSSL `pkcs12` tool:
281    ///
282    /// ```bash
283    /// openssl pkcs12 -export -out identity.pfx -inkey key.pem -in cert.pem -certfile chain_certs.pem
284    /// ```
285    ///
286    /// # Examples
287    ///
288    /// ```
289    /// # use std::fs::File;
290    /// # use std::io::Read;
291    /// # fn pkcs12() -> Result<(), Box<dyn std::error::Error>> {
292    /// let mut buf = Vec::new();
293    /// File::open("my-ident.pfx")?
294    ///     .read_to_end(&mut buf)?;
295    /// let pkcs12 = reqwest::Identity::from_pkcs12_der(&buf, "my-privkey-password")?;
296    /// # drop(pkcs12);
297    /// # Ok(())
298    /// # }
299    /// ```
300    ///
301    /// # Optional
302    ///
303    /// This requires the `native-tls` Cargo feature enabled.
304    #[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    /// Parses a chain of PEM encoded X509 certificates, with the leaf certificate first.
315    /// `key` is a PEM encoded PKCS #8 formatted private key for the leaf certificate.
316    ///
317    /// The certificate chain should contain any intermediate certificates that should be sent to
318    /// clients to allow them to build a chain to a trusted root.
319    ///
320    /// A certificate chain here means a series of PEM encoded certificates concatenated together.
321    ///
322    /// # Examples
323    ///
324    /// ```
325    /// # use std::fs;
326    /// # fn pkcs8() -> Result<(), Box<dyn std::error::Error>> {
327    /// let cert = fs::read("client.pem")?;
328    /// let key = fs::read("key.pem")?;
329    /// let pkcs8 = reqwest::Identity::from_pkcs8_pem(&cert, &key)?;
330    /// # drop(pkcs8);
331    /// # Ok(())
332    /// # }
333    /// ```
334    ///
335    /// # Optional
336    ///
337    /// This requires the `native-tls` Cargo feature enabled.
338    #[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    /// Parses PEM encoded private key and certificate.
348    ///
349    /// The input should contain a PEM encoded private key
350    /// and at least one PEM encoded certificate.
351    ///
352    /// Note: The private key must be in RSA, SEC1 Elliptic Curve or PKCS#8 format.
353    ///
354    /// # Examples
355    ///
356    /// ```
357    /// # use std::fs::File;
358    /// # use std::io::Read;
359    /// # fn pem() -> Result<(), Box<dyn std::error::Error>> {
360    /// let mut buf = Vec::new();
361    /// File::open("my-ident.pem")?
362    ///     .read_to_end(&mut buf)?;
363    /// let id = reqwest::Identity::from_pem(&buf)?;
364    /// # drop(id);
365    /// # Ok(())
366    /// # }
367    /// ```
368    ///
369    /// # Optional
370    ///
371    /// This requires the `rustls(-...)` Cargo feature enabled.
372    #[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            // Not sure here
437            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    /// Parses a PEM encoded CRL.
455    ///
456    /// # Examples
457    ///
458    /// ```
459    /// # use std::fs::File;
460    /// # use std::io::Read;
461    /// # fn crl() -> Result<(), Box<dyn std::error::Error>> {
462    /// let mut buf = Vec::new();
463    /// File::open("my_crl.pem")?
464    ///     .read_to_end(&mut buf)?;
465    /// let crl = reqwest::tls::CertificateRevocationList::from_pem(&buf)?;
466    /// # drop(crl);
467    /// # Ok(())
468    /// # }
469    /// ```
470    ///
471    /// # Optional
472    ///
473    /// This requires the `rustls(-...)` Cargo feature enabled.
474    #[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    /// Creates a collection of `CertificateRevocationList`s from a PEM encoded CRL bundle.
484    /// Example byte sources may be `.crl` or `.pem` files.
485    ///
486    /// # Examples
487    ///
488    /// ```
489    /// # use std::fs::File;
490    /// # use std::io::Read;
491    /// # fn crls() -> Result<(), Box<dyn std::error::Error>> {
492    /// let mut buf = Vec::new();
493    /// File::open("crl-bundle.crl")?
494    ///     .read_to_end(&mut buf)?;
495    /// let crls = reqwest::tls::CertificateRevocationList::from_pem_bundle(&buf)?;
496    /// # drop(crls);
497    /// # Ok(())
498    /// # }
499    /// ```
500    ///
501    /// # Optional
502    ///
503    /// This requires the `rustls(-...)` Cargo feature enabled.
504    #[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/// A TLS protocol version.
540#[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
552// These could perhaps be From/TryFrom implementations, but those would be
553// part of the public API so let's be careful
554impl Version {
555    /// Version 1.0 of the TLS protocol.
556    pub const TLS_1_0: Version = Version(InnerVersion::Tls1_0);
557    /// Version 1.1 of the TLS protocol.
558    pub const TLS_1_1: Version = Version(InnerVersion::Tls1_1);
559    /// Version 1.2 of the TLS protocol.
560    pub const TLS_1_2: Version = Version(InnerVersion::Tls1_2);
561    /// Version 1.3 of the TLS protocol.
562    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    // This is the default and HTTP/3 feature does not use it so suppress it.
590    #[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/// Hyper extension carrying extra TLS layer information.
788/// Made available to clients on responses when `tls_info` is set.
789#[derive(Clone)]
790pub struct TlsInfo {
791    pub(crate) peer_certificate: Option<Vec<u8>>,
792}
793
794impl TlsInfo {
795    /// Get the DER encoded leaf certificate of the peer.
796    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}