Coverage Report

Created: 2026-08-14 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/reqwest-0.13.4/src/tls.rs
Line
Count
Source
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")]
69
use 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
};
75
use rustls_pki_types::pem::PemObject;
76
#[cfg(feature = "__rustls")]
77
use rustls_pki_types::{ServerName, UnixTime};
78
use std::{
79
    fmt,
80
    io::{BufRead, BufReader},
81
};
82
83
/// Represents a X509 certificate revocation list.
84
#[cfg(feature = "__rustls")]
85
pub struct CertificateRevocationList {
86
    #[cfg(feature = "__rustls")]
87
    inner: rustls_pki_types::CertificateRevocationListDer<'static>,
88
}
89
90
/// Represents a server X509 certificate.
91
#[derive(Clone)]
92
pub 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)]
101
enum 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)]
108
pub struct Identity {
109
    #[cfg_attr(
110
        not(any(feature = "__native-tls", feature = "__rustls")),
111
        allow(unused)
112
    )]
113
    inner: ClientCert,
114
}
115
116
enum 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
128
impl Clone for ClientCert {
129
0
    fn clone(&self) -> Self {
130
0
        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
0
            ClientCert::Pem { key, certs } => ClientCert::Pem {
137
0
                key: key.clone_key(),
138
0
                certs: certs.clone(),
139
0
            },
140
            #[cfg_attr(
141
                any(feature = "__native-tls", feature = "__rustls"),
142
                allow(unreachable_patterns)
143
            )]
144
            _ => unreachable!(),
145
        }
146
0
    }
147
}
148
149
impl 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
0
    pub fn from_der(der: &[u8]) -> crate::Result<Certificate> {
167
0
        Ok(Certificate {
168
0
            #[cfg(feature = "__native-tls")]
169
0
            native: native_tls_crate::Certificate::from_der(der).map_err(crate::error::builder)?,
170
0
            #[cfg(feature = "__rustls")]
171
0
            original: Cert::Der(der.to_owned()),
172
0
        })
173
0
    }
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
0
    pub fn from_pem(pem: &[u8]) -> crate::Result<Certificate> {
192
0
        Ok(Certificate {
193
0
            #[cfg(feature = "__native-tls")]
194
0
            native: native_tls_crate::Certificate::from_pem(pem).map_err(crate::error::builder)?,
195
0
            #[cfg(feature = "__rustls")]
196
0
            original: Cert::Pem(pem.to_owned()),
197
0
        })
198
0
    }
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
0
    pub fn from_pem_bundle(pem_bundle: &[u8]) -> crate::Result<Vec<Certificate>> {
218
0
        let mut reader = BufReader::new(pem_bundle);
219
220
0
        Self::read_pem_certs(&mut reader)?
221
0
            .iter()
222
0
            .map(|cert_vec| Certificate::from_der(cert_vec))
223
0
            .collect::<crate::Result<Vec<Certificate>>>()
224
0
    }
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
0
    pub(crate) fn add_to_rustls(
240
0
        self,
241
0
        root_cert_store: &mut rustls::RootCertStore,
242
0
    ) -> crate::Result<()> {
243
        use std::io::Cursor;
244
245
0
        match self.original {
246
0
            Cert::Der(buf) => root_cert_store
247
0
                .add(buf.into())
248
0
                .map_err(crate::error::builder)?,
249
0
            Cert::Pem(buf) => {
250
0
                let mut reader = Cursor::new(buf);
251
0
                let certs = Self::read_pem_certs(&mut reader)?;
252
0
                for c in certs {
253
0
                    root_cert_store
254
0
                        .add(c.into())
255
0
                        .map_err(crate::error::builder)?;
256
                }
257
            }
258
        }
259
0
        Ok(())
260
0
    }
261
262
0
    fn read_pem_certs(reader: &mut impl BufRead) -> crate::Result<Vec<Vec<u8>>> {
263
0
        rustls_pki_types::CertificateDer::pem_reader_iter(reader)
264
0
            .map(|result| match result {
265
0
                Ok(cert) => Ok(cert.as_ref().to_vec()),
266
0
                Err(_) => Err(crate::error::builder("invalid certificate encoding")),
267
0
            })
Unexecuted instantiation: <reqwest::tls::Certificate>::read_pem_certs::<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>::{closure#0}
Unexecuted instantiation: <reqwest::tls::Certificate>::read_pem_certs::<std::io::buffered::bufreader::BufReader<&[u8]>>::{closure#0}
268
0
            .collect()
269
0
    }
Unexecuted instantiation: <reqwest::tls::Certificate>::read_pem_certs::<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>
Unexecuted instantiation: <reqwest::tls::Certificate>::read_pem_certs::<std::io::buffered::bufreader::BufReader<&[u8]>>
270
}
271
272
impl 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
0
    pub fn from_pem(buf: &[u8]) -> crate::Result<Identity> {
374
        use rustls_pki_types::{pem::SectionKind, PrivateKeyDer};
375
        use std::io::Cursor;
376
377
0
        let (key, certs) = {
378
0
            let mut pem = Cursor::new(buf);
379
0
            let mut sk = Vec::<rustls_pki_types::PrivateKeyDer>::new();
380
0
            let mut certs = Vec::<rustls_pki_types::CertificateDer>::new();
381
382
0
            while let Some((kind, data)) =
383
0
                rustls_pki_types::pem::from_buf(&mut pem).map_err(|_| {
384
0
                    crate::error::builder(TLSError::General(String::from(
385
0
                        "Invalid identity PEM file",
386
0
                    )))
387
0
                })?
388
            {
389
0
                match kind {
390
0
                    SectionKind::Certificate => certs.push(data.into()),
391
0
                    SectionKind::PrivateKey => sk.push(PrivateKeyDer::Pkcs8(data.into())),
392
0
                    SectionKind::RsaPrivateKey => sk.push(PrivateKeyDer::Pkcs1(data.into())),
393
0
                    SectionKind::EcPrivateKey => sk.push(PrivateKeyDer::Sec1(data.into())),
394
                    _ => {
395
0
                        return Err(crate::error::builder(TLSError::General(String::from(
396
0
                            "No valid certificate was found",
397
0
                        ))))
398
                    }
399
                }
400
            }
401
402
0
            if let (Some(sk), false) = (sk.pop(), certs.is_empty()) {
403
0
                (sk, certs)
404
            } else {
405
0
                return Err(crate::error::builder(TLSError::General(String::from(
406
0
                    "private key or certificate not found",
407
0
                ))));
408
            }
409
        };
410
411
0
        Ok(Identity {
412
0
            inner: ClientCert::Pem { key, certs },
413
0
        })
414
0
    }
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
0
    pub(crate) fn add_to_rustls(
433
0
        self,
434
0
        config_builder: rustls::ConfigBuilder<
435
0
            rustls::ClientConfig,
436
0
            // Not sure here
437
0
            rustls::client::WantsClientCert,
438
0
        >,
439
0
    ) -> crate::Result<rustls::ClientConfig> {
440
0
        match self.inner {
441
0
            ClientCert::Pem { key, certs } => config_builder
442
0
                .with_client_auth_cert(certs, key)
443
0
                .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
0
    }
450
}
451
452
#[cfg(feature = "__rustls")]
453
impl 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
0
    pub fn from_pem(pem: &[u8]) -> crate::Result<CertificateRevocationList> {
476
        Ok(CertificateRevocationList {
477
            #[cfg(feature = "__rustls")]
478
0
            inner: rustls_pki_types::CertificateRevocationListDer::from_pem_slice(pem)
479
0
                .map_err(|_| crate::error::builder("invalid crl encoding"))?,
480
        })
481
0
    }
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
0
    pub fn from_pem_bundle(pem_bundle: &[u8]) -> crate::Result<Vec<CertificateRevocationList>> {
506
0
        rustls_pki_types::CertificateRevocationListDer::pem_slice_iter(pem_bundle)
507
0
            .map(|result| match result {
508
0
                Ok(crl) => Ok(CertificateRevocationList { inner: crl }),
509
0
                Err(_) => Err(crate::error::builder("invalid crl encoding")),
510
0
            })
511
0
            .collect::<crate::Result<Vec<CertificateRevocationList>>>()
512
0
    }
513
514
    #[cfg(feature = "__rustls")]
515
0
    pub(crate) fn as_rustls_crl<'a>(&self) -> rustls_pki_types::CertificateRevocationListDer<'a> {
516
0
        self.inner.clone()
517
0
    }
518
}
519
520
impl fmt::Debug for Certificate {
521
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
522
0
        f.debug_struct("Certificate").finish()
523
0
    }
524
}
525
526
impl fmt::Debug for Identity {
527
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
528
0
        f.debug_struct("Identity").finish()
529
0
    }
530
}
531
532
#[cfg(feature = "__rustls")]
533
impl fmt::Debug for CertificateRevocationList {
534
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
535
0
        f.debug_struct("CertificateRevocationList").finish()
536
0
    }
537
}
538
539
/// A TLS protocol version.
540
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
541
pub struct Version(InnerVersion);
542
543
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
544
#[non_exhaustive]
545
enum 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
554
impl 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
0
    pub(crate) fn from_rustls(version: rustls::ProtocolVersion) -> Option<Self> {
576
0
        match version {
577
0
            rustls::ProtocolVersion::SSLv2 => None,
578
0
            rustls::ProtocolVersion::SSLv3 => None,
579
0
            rustls::ProtocolVersion::TLSv1_0 => Some(Self(InnerVersion::Tls1_0)),
580
0
            rustls::ProtocolVersion::TLSv1_1 => Some(Self(InnerVersion::Tls1_1)),
581
0
            rustls::ProtocolVersion::TLSv1_2 => Some(Self(InnerVersion::Tls1_2)),
582
0
            rustls::ProtocolVersion::TLSv1_3 => Some(Self(InnerVersion::Tls1_3)),
583
0
            _ => None,
584
        }
585
0
    }
586
}
587
588
pub(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
603
impl fmt::Debug for TlsBackend {
604
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
605
0
        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
0
            TlsBackend::Rustls => write!(f, "Rustls"),
612
            #[cfg(feature = "__rustls")]
613
0
            TlsBackend::BuiltRustls(_) => write!(f, "BuiltRustls"),
614
            #[cfg(any(feature = "__native-tls", feature = "__rustls",))]
615
0
            TlsBackend::UnknownPreconfigured => write!(f, "UnknownPreconfigured"),
616
        }
617
0
    }
618
}
619
620
#[allow(clippy::derivable_impls)]
621
impl Default for TlsBackend {
622
0
    fn default() -> TlsBackend {
623
        #[cfg(any(
624
            all(feature = "__rustls", not(feature = "__native-tls")),
625
            feature = "http3"
626
        ))]
627
        {
628
0
            TlsBackend::Rustls
629
        }
630
631
        #[cfg(all(feature = "__native-tls", not(feature = "http3")))]
632
        {
633
            TlsBackend::NativeTls
634
        }
635
0
    }
636
}
637
638
#[cfg(feature = "__rustls")]
639
0
pub(crate) fn rustls_store(certs: Vec<Certificate>) -> crate::Result<RootCertStore> {
640
0
    let mut root_cert_store = rustls::RootCertStore::empty();
641
0
    for cert in certs {
642
0
        cert.add_to_rustls(&mut root_cert_store)?;
643
    }
644
0
    Ok(root_cert_store)
645
0
}
646
647
#[cfg(feature = "__rustls")]
648
#[cfg(any(all(unix, not(target_os = "android")), target_os = "windows"))]
649
0
pub(crate) fn rustls_der(
650
0
    certs: Vec<Certificate>,
651
0
) -> crate::Result<Vec<rustls_pki_types::CertificateDer<'static>>> {
652
0
    let mut ders = Vec::with_capacity(certs.len());
653
0
    for cert in certs {
654
0
        match cert.original {
655
0
            Cert::Der(buf) => ders.push(buf.into()),
656
0
            Cert::Pem(buf) => {
657
0
                let mut reader = std::io::Cursor::new(buf);
658
0
                let pems = Certificate::read_pem_certs(&mut reader)?;
659
0
                for c in pems {
660
0
                    ders.push(c.into());
661
0
                }
662
            }
663
        }
664
    }
665
0
    Ok(ders)
666
0
}
667
668
#[cfg(feature = "__rustls")]
669
#[derive(Debug)]
670
pub(crate) struct NoVerifier;
671
672
#[cfg(feature = "__rustls")]
673
impl ServerCertVerifier for NoVerifier {
674
0
    fn verify_server_cert(
675
0
        &self,
676
0
        _end_entity: &rustls_pki_types::CertificateDer,
677
0
        _intermediates: &[rustls_pki_types::CertificateDer],
678
0
        _server_name: &ServerName,
679
0
        _ocsp_response: &[u8],
680
0
        _now: UnixTime,
681
0
    ) -> Result<ServerCertVerified, TLSError> {
682
0
        Ok(ServerCertVerified::assertion())
683
0
    }
684
685
0
    fn verify_tls12_signature(
686
0
        &self,
687
0
        _message: &[u8],
688
0
        _cert: &rustls_pki_types::CertificateDer,
689
0
        _dss: &DigitallySignedStruct,
690
0
    ) -> Result<HandshakeSignatureValid, TLSError> {
691
0
        Ok(HandshakeSignatureValid::assertion())
692
0
    }
693
694
0
    fn verify_tls13_signature(
695
0
        &self,
696
0
        _message: &[u8],
697
0
        _cert: &rustls_pki_types::CertificateDer,
698
0
        _dss: &DigitallySignedStruct,
699
0
    ) -> Result<HandshakeSignatureValid, TLSError> {
700
0
        Ok(HandshakeSignatureValid::assertion())
701
0
    }
702
703
0
    fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
704
0
        vec![
705
0
            SignatureScheme::RSA_PKCS1_SHA1,
706
0
            SignatureScheme::ECDSA_SHA1_Legacy,
707
0
            SignatureScheme::RSA_PKCS1_SHA256,
708
0
            SignatureScheme::ECDSA_NISTP256_SHA256,
709
0
            SignatureScheme::RSA_PKCS1_SHA384,
710
0
            SignatureScheme::ECDSA_NISTP384_SHA384,
711
0
            SignatureScheme::RSA_PKCS1_SHA512,
712
0
            SignatureScheme::ECDSA_NISTP521_SHA512,
713
0
            SignatureScheme::RSA_PSS_SHA256,
714
0
            SignatureScheme::RSA_PSS_SHA384,
715
0
            SignatureScheme::RSA_PSS_SHA512,
716
0
            SignatureScheme::ED25519,
717
0
            SignatureScheme::ED448,
718
        ]
719
0
    }
720
}
721
722
#[cfg(feature = "__rustls")]
723
#[derive(Debug)]
724
pub(crate) struct IgnoreHostname {
725
    roots: RootCertStore,
726
    signature_algorithms: WebPkiSupportedAlgorithms,
727
}
728
729
#[cfg(feature = "__rustls")]
730
impl IgnoreHostname {
731
0
    pub(crate) fn new(
732
0
        roots: RootCertStore,
733
0
        signature_algorithms: WebPkiSupportedAlgorithms,
734
0
    ) -> Self {
735
0
        Self {
736
0
            roots,
737
0
            signature_algorithms,
738
0
        }
739
0
    }
740
}
741
742
#[cfg(feature = "__rustls")]
743
impl ServerCertVerifier for IgnoreHostname {
744
0
    fn verify_server_cert(
745
0
        &self,
746
0
        end_entity: &rustls_pki_types::CertificateDer<'_>,
747
0
        intermediates: &[rustls_pki_types::CertificateDer<'_>],
748
0
        _server_name: &ServerName<'_>,
749
0
        _ocsp_response: &[u8],
750
0
        now: UnixTime,
751
0
    ) -> Result<ServerCertVerified, TLSError> {
752
0
        let cert = ParsedCertificate::try_from(end_entity)?;
753
754
0
        rustls::client::verify_server_cert_signed_by_trust_anchor(
755
0
            &cert,
756
0
            &self.roots,
757
0
            intermediates,
758
0
            now,
759
0
            self.signature_algorithms.all,
760
0
        )?;
761
0
        Ok(ServerCertVerified::assertion())
762
0
    }
763
764
0
    fn verify_tls12_signature(
765
0
        &self,
766
0
        message: &[u8],
767
0
        cert: &rustls_pki_types::CertificateDer<'_>,
768
0
        dss: &DigitallySignedStruct,
769
0
    ) -> Result<HandshakeSignatureValid, TLSError> {
770
0
        rustls::crypto::verify_tls12_signature(message, cert, dss, &self.signature_algorithms)
771
0
    }
772
773
0
    fn verify_tls13_signature(
774
0
        &self,
775
0
        message: &[u8],
776
0
        cert: &rustls_pki_types::CertificateDer<'_>,
777
0
        dss: &DigitallySignedStruct,
778
0
    ) -> Result<HandshakeSignatureValid, TLSError> {
779
0
        rustls::crypto::verify_tls13_signature(message, cert, dss, &self.signature_algorithms)
780
0
    }
781
782
0
    fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
783
0
        self.signature_algorithms.supported_schemes()
784
0
    }
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)]
790
pub struct TlsInfo {
791
    pub(crate) peer_certificate: Option<Vec<u8>>,
792
}
793
794
impl TlsInfo {
795
    /// Get the DER encoded leaf certificate of the peer.
796
0
    pub fn peer_certificate(&self) -> Option<&[u8]> {
797
0
        self.peer_certificate.as_ref().map(|der| &der[..])
798
0
    }
799
}
800
801
impl std::fmt::Debug for TlsInfo {
802
0
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
803
0
        f.debug_struct("TlsInfo").finish()
804
0
    }
805
}
806
807
#[cfg(test)]
808
mod 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
}