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};
54#[cfg(feature = "__rustls")]
55use rustls_pki_types::{ServerName, UnixTime};
56use std::{
57    fmt,
58    io::{BufRead, BufReader},
59};
60
61/// Represents a X509 certificate revocation list.
62#[cfg(feature = "__rustls")]
63pub struct CertificateRevocationList {
64    #[cfg(feature = "__rustls")]
65    inner: rustls_pki_types::CertificateRevocationListDer<'static>,
66}
67
68/// Represents a server X509 certificate.
69#[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/// Represents a private key and X509 cert as a client certificate.
85#[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    /// Create a `Certificate` from a binary DER encoded certificate
126    ///
127    /// # Examples
128    ///
129    /// ```
130    /// # use std::fs::File;
131    /// # use std::io::Read;
132    /// # fn cert() -> Result<(), Box<dyn std::error::Error>> {
133    /// let mut buf = Vec::new();
134    /// File::open("my_cert.der")?
135    ///     .read_to_end(&mut buf)?;
136    /// let cert = reqwest::Certificate::from_der(&buf)?;
137    /// # drop(cert);
138    /// # Ok(())
139    /// # }
140    /// ```
141    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    /// Create a `Certificate` from a PEM 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.pem")?
160    ///     .read_to_end(&mut buf)?;
161    /// let cert = reqwest::Certificate::from_pem(&buf)?;
162    /// # drop(cert);
163    /// # Ok(())
164    /// # }
165    /// ```
166    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    /// Create a collection of `Certificate`s from a PEM encoded certificate bundle.
176    /// Example byte sources may be `.crt`, `.cer` or `.pem` files.
177    ///
178    /// # Examples
179    ///
180    /// ```
181    /// # use std::fs::File;
182    /// # use std::io::Read;
183    /// # fn cert() -> Result<(), Box<dyn std::error::Error>> {
184    /// let mut buf = Vec::new();
185    /// File::open("ca-bundle.crt")?
186    ///     .read_to_end(&mut buf)?;
187    /// let certs = reqwest::Certificate::from_pem_bundle(&buf)?;
188    /// # drop(certs);
189    /// # Ok(())
190    /// # }
191    /// ```
192    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    /// Parses a DER-formatted PKCS #12 archive, using the specified password to decrypt the key.
242    ///
243    /// The archive should contain a leaf certificate and its private key, as well any intermediate
244    /// certificates that allow clients to build a chain to a trusted root.
245    /// The chain certificates should be in order from the leaf certificate towards the root.
246    ///
247    /// PKCS #12 archives typically have the file extension `.p12` or `.pfx`, and can be created
248    /// with the OpenSSL `pkcs12` tool:
249    ///
250    /// ```bash
251    /// openssl pkcs12 -export -out identity.pfx -inkey key.pem -in cert.pem -certfile chain_certs.pem
252    /// ```
253    ///
254    /// # Examples
255    ///
256    /// ```
257    /// # use std::fs::File;
258    /// # use std::io::Read;
259    /// # fn pkcs12() -> Result<(), Box<dyn std::error::Error>> {
260    /// let mut buf = Vec::new();
261    /// File::open("my-ident.pfx")?
262    ///     .read_to_end(&mut buf)?;
263    /// let pkcs12 = reqwest::Identity::from_pkcs12_der(&buf, "my-privkey-password")?;
264    /// # drop(pkcs12);
265    /// # Ok(())
266    /// # }
267    /// ```
268    ///
269    /// # Optional
270    ///
271    /// This requires the `native-tls` Cargo feature enabled.
272    #[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    /// Parses a chain of PEM encoded X509 certificates, with the leaf certificate first.
283    /// `key` is a PEM encoded PKCS #8 formatted private key for the leaf certificate.
284    ///
285    /// The certificate chain should contain any intermediate certificates that should be sent to
286    /// clients to allow them to build a chain to a trusted root.
287    ///
288    /// A certificate chain here means a series of PEM encoded certificates concatenated together.
289    ///
290    /// # Examples
291    ///
292    /// ```
293    /// # use std::fs;
294    /// # fn pkcs8() -> Result<(), Box<dyn std::error::Error>> {
295    /// let cert = fs::read("client.pem")?;
296    /// let key = fs::read("key.pem")?;
297    /// let pkcs8 = reqwest::Identity::from_pkcs8_pem(&cert, &key)?;
298    /// # drop(pkcs8);
299    /// # Ok(())
300    /// # }
301    /// ```
302    ///
303    /// # Optional
304    ///
305    /// This requires the `native-tls` Cargo feature enabled.
306    #[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    /// Parses PEM encoded private key and certificate.
316    ///
317    /// The input should contain a PEM encoded private key
318    /// and at least one PEM encoded certificate.
319    ///
320    /// Note: The private key must be in RSA, SEC1 Elliptic Curve or PKCS#8 format.
321    ///
322    /// # Examples
323    ///
324    /// ```
325    /// # use std::fs::File;
326    /// # use std::io::Read;
327    /// # fn pem() -> Result<(), Box<dyn std::error::Error>> {
328    /// let mut buf = Vec::new();
329    /// File::open("my-ident.pem")?
330    ///     .read_to_end(&mut buf)?;
331    /// let id = reqwest::Identity::from_pem(&buf)?;
332    /// # drop(id);
333    /// # Ok(())
334    /// # }
335    /// ```
336    ///
337    /// # Optional
338    ///
339    /// This requires the `rustls-tls(-...)` Cargo feature enabled.
340    #[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            // Not sure here
404            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    /// Parses a PEM encoded CRL.
422    ///
423    /// # Examples
424    ///
425    /// ```
426    /// # use std::fs::File;
427    /// # use std::io::Read;
428    /// # fn crl() -> Result<(), Box<dyn std::error::Error>> {
429    /// let mut buf = Vec::new();
430    /// File::open("my_crl.pem")?
431    ///     .read_to_end(&mut buf)?;
432    /// let crl = reqwest::tls::CertificateRevocationList::from_pem(&buf)?;
433    /// # drop(crl);
434    /// # Ok(())
435    /// # }
436    /// ```
437    ///
438    /// # Optional
439    ///
440    /// This requires the `rustls-tls(-...)` Cargo feature enabled.
441    #[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    /// Creates a collection of `CertificateRevocationList`s from a PEM encoded CRL bundle.
450    /// Example byte sources may be `.crl` or `.pem` files.
451    ///
452    /// # Examples
453    ///
454    /// ```
455    /// # use std::fs::File;
456    /// # use std::io::Read;
457    /// # fn crls() -> Result<(), Box<dyn std::error::Error>> {
458    /// let mut buf = Vec::new();
459    /// File::open("crl-bundle.crl")?
460    ///     .read_to_end(&mut buf)?;
461    /// let crls = reqwest::tls::CertificateRevocationList::from_pem_bundle(&buf)?;
462    /// # drop(crls);
463    /// # Ok(())
464    /// # }
465    /// ```
466    ///
467    /// # Optional
468    ///
469    /// This requires the `rustls-tls(-...)` Cargo feature enabled.
470    #[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/// 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}