Coverage Report

Created: 2026-05-16 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/reqwest-0.13.3/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
#[cfg(feature = "__rustls")]
47
use rustls::{
48
    client::danger::HandshakeSignatureValid, client::danger::ServerCertVerified,
49
    client::danger::ServerCertVerifier, crypto::WebPkiSupportedAlgorithms,
50
    server::ParsedCertificate, DigitallySignedStruct, Error as TLSError, RootCertStore,
51
    SignatureScheme,
52
};
53
use rustls_pki_types::pem::PemObject;
54
#[cfg(feature = "__rustls")]
55
use rustls_pki_types::{ServerName, UnixTime};
56
use std::{
57
    fmt,
58
    io::{BufRead, BufReader},
59
};
60
61
/// Represents a X509 certificate revocation list.
62
#[cfg(feature = "__rustls")]
63
pub struct CertificateRevocationList {
64
    #[cfg(feature = "__rustls")]
65
    inner: rustls_pki_types::CertificateRevocationListDer<'static>,
66
}
67
68
/// Represents a server X509 certificate.
69
#[derive(Clone)]
70
pub struct Certificate {
71
    #[cfg(feature = "__native-tls")]
72
    native: native_tls_crate::Certificate,
73
    #[cfg(feature = "__rustls")]
74
    original: Cert,
75
}
76
77
#[cfg(feature = "__rustls")]
78
#[derive(Clone)]
79
enum 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)]
86
pub struct Identity {
87
    #[cfg_attr(
88
        not(any(feature = "__native-tls", feature = "__rustls")),
89
        allow(unused)
90
    )]
91
    inner: ClientCert,
92
}
93
94
enum ClientCert {
95
    #[cfg(feature = "__native-tls")]
96
    Pkcs12(native_tls_crate::Identity),
97
    #[cfg(feature = "__native-tls")]
98
    Pkcs8(native_tls_crate::Identity),
99
    #[cfg(feature = "__rustls")]
100
    Pem {
101
        key: rustls_pki_types::PrivateKeyDer<'static>,
102
        certs: Vec<rustls_pki_types::CertificateDer<'static>>,
103
    },
104
}
105
106
impl Clone for ClientCert {
107
0
    fn clone(&self) -> Self {
108
0
        match self {
109
            #[cfg(feature = "__native-tls")]
110
            Self::Pkcs8(i) => Self::Pkcs8(i.clone()),
111
            #[cfg(feature = "__native-tls")]
112
            Self::Pkcs12(i) => Self::Pkcs12(i.clone()),
113
            #[cfg(feature = "__rustls")]
114
0
            ClientCert::Pem { key, certs } => ClientCert::Pem {
115
0
                key: key.clone_key(),
116
0
                certs: certs.clone(),
117
0
            },
118
            #[cfg_attr(
119
                any(feature = "__native-tls", feature = "__rustls"),
120
                allow(unreachable_patterns)
121
            )]
122
            _ => unreachable!(),
123
        }
124
0
    }
125
}
126
127
impl Certificate {
128
    /// Create a `Certificate` from a binary DER encoded certificate
129
    ///
130
    /// # Examples
131
    ///
132
    /// ```
133
    /// # use std::fs::File;
134
    /// # use std::io::Read;
135
    /// # fn cert() -> Result<(), Box<dyn std::error::Error>> {
136
    /// let mut buf = Vec::new();
137
    /// File::open("my_cert.der")?
138
    ///     .read_to_end(&mut buf)?;
139
    /// let cert = reqwest::Certificate::from_der(&buf)?;
140
    /// # drop(cert);
141
    /// # Ok(())
142
    /// # }
143
    /// ```
144
0
    pub fn from_der(der: &[u8]) -> crate::Result<Certificate> {
145
0
        Ok(Certificate {
146
0
            #[cfg(feature = "__native-tls")]
147
0
            native: native_tls_crate::Certificate::from_der(der).map_err(crate::error::builder)?,
148
0
            #[cfg(feature = "__rustls")]
149
0
            original: Cert::Der(der.to_owned()),
150
0
        })
151
0
    }
152
153
    /// Create a `Certificate` from a PEM encoded certificate
154
    ///
155
    /// # Examples
156
    ///
157
    /// ```
158
    /// # use std::fs::File;
159
    /// # use std::io::Read;
160
    /// # fn cert() -> Result<(), Box<dyn std::error::Error>> {
161
    /// let mut buf = Vec::new();
162
    /// File::open("my_cert.pem")?
163
    ///     .read_to_end(&mut buf)?;
164
    /// let cert = reqwest::Certificate::from_pem(&buf)?;
165
    /// # drop(cert);
166
    /// # Ok(())
167
    /// # }
168
    /// ```
169
0
    pub fn from_pem(pem: &[u8]) -> crate::Result<Certificate> {
170
0
        Ok(Certificate {
171
0
            #[cfg(feature = "__native-tls")]
172
0
            native: native_tls_crate::Certificate::from_pem(pem).map_err(crate::error::builder)?,
173
0
            #[cfg(feature = "__rustls")]
174
0
            original: Cert::Pem(pem.to_owned()),
175
0
        })
176
0
    }
177
178
    /// Create a collection of `Certificate`s from a PEM encoded certificate bundle.
179
    /// Example byte sources may be `.crt`, `.cer` or `.pem` files.
180
    ///
181
    /// # Examples
182
    ///
183
    /// ```
184
    /// # use std::fs::File;
185
    /// # use std::io::Read;
186
    /// # fn cert() -> Result<(), Box<dyn std::error::Error>> {
187
    /// let mut buf = Vec::new();
188
    /// File::open("ca-bundle.crt")?
189
    ///     .read_to_end(&mut buf)?;
190
    /// let certs = reqwest::Certificate::from_pem_bundle(&buf)?;
191
    /// # drop(certs);
192
    /// # Ok(())
193
    /// # }
194
    /// ```
195
0
    pub fn from_pem_bundle(pem_bundle: &[u8]) -> crate::Result<Vec<Certificate>> {
196
0
        let mut reader = BufReader::new(pem_bundle);
197
198
0
        Self::read_pem_certs(&mut reader)?
199
0
            .iter()
200
0
            .map(|cert_vec| Certificate::from_der(cert_vec))
201
0
            .collect::<crate::Result<Vec<Certificate>>>()
202
0
    }
203
204
    /*
205
    #[cfg(feature = "rustls")]
206
    pub fn from_trust_anchor() -> Self {
207
208
    }
209
    */
210
211
    #[cfg(feature = "__native-tls")]
212
    pub(crate) fn add_to_native_tls(self, tls: &mut native_tls_crate::TlsConnectorBuilder) {
213
        tls.add_root_certificate(self.native);
214
    }
215
216
    #[cfg(feature = "__rustls")]
217
0
    pub(crate) fn add_to_rustls(
218
0
        self,
219
0
        root_cert_store: &mut rustls::RootCertStore,
220
0
    ) -> crate::Result<()> {
221
        use std::io::Cursor;
222
223
0
        match self.original {
224
0
            Cert::Der(buf) => root_cert_store
225
0
                .add(buf.into())
226
0
                .map_err(crate::error::builder)?,
227
0
            Cert::Pem(buf) => {
228
0
                let mut reader = Cursor::new(buf);
229
0
                let certs = Self::read_pem_certs(&mut reader)?;
230
0
                for c in certs {
231
0
                    root_cert_store
232
0
                        .add(c.into())
233
0
                        .map_err(crate::error::builder)?;
234
                }
235
            }
236
        }
237
0
        Ok(())
238
0
    }
239
240
0
    fn read_pem_certs(reader: &mut impl BufRead) -> crate::Result<Vec<Vec<u8>>> {
241
0
        rustls_pki_types::CertificateDer::pem_reader_iter(reader)
242
0
            .map(|result| match result {
243
0
                Ok(cert) => Ok(cert.as_ref().to_vec()),
244
0
                Err(_) => Err(crate::error::builder("invalid certificate encoding")),
245
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}
246
0
            .collect()
247
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]>>
248
}
249
250
impl Identity {
251
    /// Parses a DER-formatted PKCS #12 archive, using the specified password to decrypt the key.
252
    ///
253
    /// The archive should contain a leaf certificate and its private key, as well any intermediate
254
    /// certificates that allow clients to build a chain to a trusted root.
255
    /// The chain certificates should be in order from the leaf certificate towards the root.
256
    ///
257
    /// PKCS #12 archives typically have the file extension `.p12` or `.pfx`, and can be created
258
    /// with the OpenSSL `pkcs12` tool:
259
    ///
260
    /// ```bash
261
    /// openssl pkcs12 -export -out identity.pfx -inkey key.pem -in cert.pem -certfile chain_certs.pem
262
    /// ```
263
    ///
264
    /// # Examples
265
    ///
266
    /// ```
267
    /// # use std::fs::File;
268
    /// # use std::io::Read;
269
    /// # fn pkcs12() -> Result<(), Box<dyn std::error::Error>> {
270
    /// let mut buf = Vec::new();
271
    /// File::open("my-ident.pfx")?
272
    ///     .read_to_end(&mut buf)?;
273
    /// let pkcs12 = reqwest::Identity::from_pkcs12_der(&buf, "my-privkey-password")?;
274
    /// # drop(pkcs12);
275
    /// # Ok(())
276
    /// # }
277
    /// ```
278
    ///
279
    /// # Optional
280
    ///
281
    /// This requires the `native-tls` Cargo feature enabled.
282
    #[cfg(feature = "__native-tls")]
283
    pub fn from_pkcs12_der(der: &[u8], password: &str) -> crate::Result<Identity> {
284
        Ok(Identity {
285
            inner: ClientCert::Pkcs12(
286
                native_tls_crate::Identity::from_pkcs12(der, password)
287
                    .map_err(crate::error::builder)?,
288
            ),
289
        })
290
    }
291
292
    /// Parses a chain of PEM encoded X509 certificates, with the leaf certificate first.
293
    /// `key` is a PEM encoded PKCS #8 formatted private key for the leaf certificate.
294
    ///
295
    /// The certificate chain should contain any intermediate certificates that should be sent to
296
    /// clients to allow them to build a chain to a trusted root.
297
    ///
298
    /// A certificate chain here means a series of PEM encoded certificates concatenated together.
299
    ///
300
    /// # Examples
301
    ///
302
    /// ```
303
    /// # use std::fs;
304
    /// # fn pkcs8() -> Result<(), Box<dyn std::error::Error>> {
305
    /// let cert = fs::read("client.pem")?;
306
    /// let key = fs::read("key.pem")?;
307
    /// let pkcs8 = reqwest::Identity::from_pkcs8_pem(&cert, &key)?;
308
    /// # drop(pkcs8);
309
    /// # Ok(())
310
    /// # }
311
    /// ```
312
    ///
313
    /// # Optional
314
    ///
315
    /// This requires the `native-tls` Cargo feature enabled.
316
    #[cfg(feature = "__native-tls")]
317
    pub fn from_pkcs8_pem(pem: &[u8], key: &[u8]) -> crate::Result<Identity> {
318
        Ok(Identity {
319
            inner: ClientCert::Pkcs8(
320
                native_tls_crate::Identity::from_pkcs8(pem, key).map_err(crate::error::builder)?,
321
            ),
322
        })
323
    }
324
325
    /// Parses PEM encoded private key and certificate.
326
    ///
327
    /// The input should contain a PEM encoded private key
328
    /// and at least one PEM encoded certificate.
329
    ///
330
    /// Note: The private key must be in RSA, SEC1 Elliptic Curve or PKCS#8 format.
331
    ///
332
    /// # Examples
333
    ///
334
    /// ```
335
    /// # use std::fs::File;
336
    /// # use std::io::Read;
337
    /// # fn pem() -> Result<(), Box<dyn std::error::Error>> {
338
    /// let mut buf = Vec::new();
339
    /// File::open("my-ident.pem")?
340
    ///     .read_to_end(&mut buf)?;
341
    /// let id = reqwest::Identity::from_pem(&buf)?;
342
    /// # drop(id);
343
    /// # Ok(())
344
    /// # }
345
    /// ```
346
    ///
347
    /// # Optional
348
    ///
349
    /// This requires the `rustls(-...)` Cargo feature enabled.
350
    #[cfg(feature = "__rustls")]
351
0
    pub fn from_pem(buf: &[u8]) -> crate::Result<Identity> {
352
        use rustls_pki_types::{pem::SectionKind, PrivateKeyDer};
353
        use std::io::Cursor;
354
355
0
        let (key, certs) = {
356
0
            let mut pem = Cursor::new(buf);
357
0
            let mut sk = Vec::<rustls_pki_types::PrivateKeyDer>::new();
358
0
            let mut certs = Vec::<rustls_pki_types::CertificateDer>::new();
359
360
0
            while let Some((kind, data)) =
361
0
                rustls_pki_types::pem::from_buf(&mut pem).map_err(|_| {
362
0
                    crate::error::builder(TLSError::General(String::from(
363
0
                        "Invalid identity PEM file",
364
0
                    )))
365
0
                })?
366
            {
367
0
                match kind {
368
0
                    SectionKind::Certificate => certs.push(data.into()),
369
0
                    SectionKind::PrivateKey => sk.push(PrivateKeyDer::Pkcs8(data.into())),
370
0
                    SectionKind::RsaPrivateKey => sk.push(PrivateKeyDer::Pkcs1(data.into())),
371
0
                    SectionKind::EcPrivateKey => sk.push(PrivateKeyDer::Sec1(data.into())),
372
                    _ => {
373
0
                        return Err(crate::error::builder(TLSError::General(String::from(
374
0
                            "No valid certificate was found",
375
0
                        ))))
376
                    }
377
                }
378
            }
379
380
0
            if let (Some(sk), false) = (sk.pop(), certs.is_empty()) {
381
0
                (sk, certs)
382
            } else {
383
0
                return Err(crate::error::builder(TLSError::General(String::from(
384
0
                    "private key or certificate not found",
385
0
                ))));
386
            }
387
        };
388
389
0
        Ok(Identity {
390
0
            inner: ClientCert::Pem { key, certs },
391
0
        })
392
0
    }
393
394
    #[cfg(feature = "__native-tls")]
395
    pub(crate) fn add_to_native_tls(
396
        self,
397
        tls: &mut native_tls_crate::TlsConnectorBuilder,
398
    ) -> crate::Result<()> {
399
        match self.inner {
400
            ClientCert::Pkcs12(id) | ClientCert::Pkcs8(id) => {
401
                tls.identity(id);
402
                Ok(())
403
            }
404
            #[cfg(feature = "__rustls")]
405
            ClientCert::Pem { .. } => Err(crate::error::builder("incompatible TLS identity type")),
406
        }
407
    }
408
409
    #[cfg(feature = "__rustls")]
410
0
    pub(crate) fn add_to_rustls(
411
0
        self,
412
0
        config_builder: rustls::ConfigBuilder<
413
0
            rustls::ClientConfig,
414
0
            // Not sure here
415
0
            rustls::client::WantsClientCert,
416
0
        >,
417
0
    ) -> crate::Result<rustls::ClientConfig> {
418
0
        match self.inner {
419
0
            ClientCert::Pem { key, certs } => config_builder
420
0
                .with_client_auth_cert(certs, key)
421
0
                .map_err(crate::error::builder),
422
            #[cfg(feature = "__native-tls")]
423
            ClientCert::Pkcs12(..) | ClientCert::Pkcs8(..) => {
424
                Err(crate::error::builder("incompatible TLS identity type"))
425
            }
426
        }
427
0
    }
428
}
429
430
#[cfg(feature = "__rustls")]
431
impl CertificateRevocationList {
432
    /// Parses a PEM encoded CRL.
433
    ///
434
    /// # Examples
435
    ///
436
    /// ```
437
    /// # use std::fs::File;
438
    /// # use std::io::Read;
439
    /// # fn crl() -> Result<(), Box<dyn std::error::Error>> {
440
    /// let mut buf = Vec::new();
441
    /// File::open("my_crl.pem")?
442
    ///     .read_to_end(&mut buf)?;
443
    /// let crl = reqwest::tls::CertificateRevocationList::from_pem(&buf)?;
444
    /// # drop(crl);
445
    /// # Ok(())
446
    /// # }
447
    /// ```
448
    ///
449
    /// # Optional
450
    ///
451
    /// This requires the `rustls(-...)` Cargo feature enabled.
452
    #[cfg(feature = "__rustls")]
453
0
    pub fn from_pem(pem: &[u8]) -> crate::Result<CertificateRevocationList> {
454
        Ok(CertificateRevocationList {
455
            #[cfg(feature = "__rustls")]
456
0
            inner: rustls_pki_types::CertificateRevocationListDer::from_pem_slice(pem)
457
0
                .map_err(|_| crate::error::builder("invalid crl encoding"))?,
458
        })
459
0
    }
460
461
    /// Creates a collection of `CertificateRevocationList`s from a PEM encoded CRL bundle.
462
    /// Example byte sources may be `.crl` or `.pem` files.
463
    ///
464
    /// # Examples
465
    ///
466
    /// ```
467
    /// # use std::fs::File;
468
    /// # use std::io::Read;
469
    /// # fn crls() -> Result<(), Box<dyn std::error::Error>> {
470
    /// let mut buf = Vec::new();
471
    /// File::open("crl-bundle.crl")?
472
    ///     .read_to_end(&mut buf)?;
473
    /// let crls = reqwest::tls::CertificateRevocationList::from_pem_bundle(&buf)?;
474
    /// # drop(crls);
475
    /// # Ok(())
476
    /// # }
477
    /// ```
478
    ///
479
    /// # Optional
480
    ///
481
    /// This requires the `rustls(-...)` Cargo feature enabled.
482
    #[cfg(feature = "__rustls")]
483
0
    pub fn from_pem_bundle(pem_bundle: &[u8]) -> crate::Result<Vec<CertificateRevocationList>> {
484
0
        rustls_pki_types::CertificateRevocationListDer::pem_slice_iter(pem_bundle)
485
0
            .map(|result| match result {
486
0
                Ok(crl) => Ok(CertificateRevocationList { inner: crl }),
487
0
                Err(_) => Err(crate::error::builder("invalid crl encoding")),
488
0
            })
489
0
            .collect::<crate::Result<Vec<CertificateRevocationList>>>()
490
0
    }
491
492
    #[cfg(feature = "__rustls")]
493
0
    pub(crate) fn as_rustls_crl<'a>(&self) -> rustls_pki_types::CertificateRevocationListDer<'a> {
494
0
        self.inner.clone()
495
0
    }
496
}
497
498
impl fmt::Debug for Certificate {
499
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
500
0
        f.debug_struct("Certificate").finish()
501
0
    }
502
}
503
504
impl fmt::Debug for Identity {
505
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
506
0
        f.debug_struct("Identity").finish()
507
0
    }
508
}
509
510
#[cfg(feature = "__rustls")]
511
impl fmt::Debug for CertificateRevocationList {
512
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
513
0
        f.debug_struct("CertificateRevocationList").finish()
514
0
    }
515
}
516
517
/// A TLS protocol version.
518
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
519
pub struct Version(InnerVersion);
520
521
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
522
#[non_exhaustive]
523
enum InnerVersion {
524
    Tls1_0,
525
    Tls1_1,
526
    Tls1_2,
527
    Tls1_3,
528
}
529
530
// These could perhaps be From/TryFrom implementations, but those would be
531
// part of the public API so let's be careful
532
impl Version {
533
    /// Version 1.0 of the TLS protocol.
534
    pub const TLS_1_0: Version = Version(InnerVersion::Tls1_0);
535
    /// Version 1.1 of the TLS protocol.
536
    pub const TLS_1_1: Version = Version(InnerVersion::Tls1_1);
537
    /// Version 1.2 of the TLS protocol.
538
    pub const TLS_1_2: Version = Version(InnerVersion::Tls1_2);
539
    /// Version 1.3 of the TLS protocol.
540
    pub const TLS_1_3: Version = Version(InnerVersion::Tls1_3);
541
542
    #[cfg(feature = "__native-tls")]
543
    pub(crate) fn to_native_tls(self) -> Option<native_tls_crate::Protocol> {
544
        match self.0 {
545
            InnerVersion::Tls1_0 => Some(native_tls_crate::Protocol::Tlsv10),
546
            InnerVersion::Tls1_1 => Some(native_tls_crate::Protocol::Tlsv11),
547
            InnerVersion::Tls1_2 => Some(native_tls_crate::Protocol::Tlsv12),
548
            InnerVersion::Tls1_3 => None,
549
        }
550
    }
551
552
    #[cfg(feature = "__rustls")]
553
0
    pub(crate) fn from_rustls(version: rustls::ProtocolVersion) -> Option<Self> {
554
0
        match version {
555
0
            rustls::ProtocolVersion::SSLv2 => None,
556
0
            rustls::ProtocolVersion::SSLv3 => None,
557
0
            rustls::ProtocolVersion::TLSv1_0 => Some(Self(InnerVersion::Tls1_0)),
558
0
            rustls::ProtocolVersion::TLSv1_1 => Some(Self(InnerVersion::Tls1_1)),
559
0
            rustls::ProtocolVersion::TLSv1_2 => Some(Self(InnerVersion::Tls1_2)),
560
0
            rustls::ProtocolVersion::TLSv1_3 => Some(Self(InnerVersion::Tls1_3)),
561
0
            _ => None,
562
        }
563
0
    }
564
}
565
566
pub(crate) enum TlsBackend {
567
    // This is the default and HTTP/3 feature does not use it so suppress it.
568
    #[allow(dead_code)]
569
    #[cfg(feature = "__native-tls")]
570
    NativeTls,
571
    #[cfg(feature = "__native-tls")]
572
    BuiltNativeTls(native_tls_crate::TlsConnector),
573
    #[cfg(feature = "__rustls")]
574
    Rustls,
575
    #[cfg(feature = "__rustls")]
576
    BuiltRustls(rustls::ClientConfig),
577
    #[cfg(any(feature = "__native-tls", feature = "__rustls",))]
578
    UnknownPreconfigured,
579
}
580
581
impl fmt::Debug for TlsBackend {
582
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
583
0
        match self {
584
            #[cfg(feature = "__native-tls")]
585
            TlsBackend::NativeTls => write!(f, "NativeTls"),
586
            #[cfg(feature = "__native-tls")]
587
            TlsBackend::BuiltNativeTls(_) => write!(f, "BuiltNativeTls"),
588
            #[cfg(feature = "__rustls")]
589
0
            TlsBackend::Rustls => write!(f, "Rustls"),
590
            #[cfg(feature = "__rustls")]
591
0
            TlsBackend::BuiltRustls(_) => write!(f, "BuiltRustls"),
592
            #[cfg(any(feature = "__native-tls", feature = "__rustls",))]
593
0
            TlsBackend::UnknownPreconfigured => write!(f, "UnknownPreconfigured"),
594
        }
595
0
    }
596
}
597
598
#[allow(clippy::derivable_impls)]
599
impl Default for TlsBackend {
600
0
    fn default() -> TlsBackend {
601
        #[cfg(any(
602
            all(feature = "__rustls", not(feature = "__native-tls")),
603
            feature = "http3"
604
        ))]
605
        {
606
0
            TlsBackend::Rustls
607
        }
608
609
        #[cfg(all(feature = "__native-tls", not(feature = "http3")))]
610
        {
611
            TlsBackend::NativeTls
612
        }
613
0
    }
614
}
615
616
#[cfg(feature = "__rustls")]
617
0
pub(crate) fn rustls_store(certs: Vec<Certificate>) -> crate::Result<RootCertStore> {
618
0
    let mut root_cert_store = rustls::RootCertStore::empty();
619
0
    for cert in certs {
620
0
        cert.add_to_rustls(&mut root_cert_store)?;
621
    }
622
0
    Ok(root_cert_store)
623
0
}
624
625
#[cfg(feature = "__rustls")]
626
#[cfg(any(all(unix, not(target_os = "android")), target_os = "windows"))]
627
0
pub(crate) fn rustls_der(
628
0
    certs: Vec<Certificate>,
629
0
) -> crate::Result<Vec<rustls_pki_types::CertificateDer<'static>>> {
630
0
    let mut ders = Vec::with_capacity(certs.len());
631
0
    for cert in certs {
632
0
        match cert.original {
633
0
            Cert::Der(buf) => ders.push(buf.into()),
634
0
            Cert::Pem(buf) => {
635
0
                let mut reader = std::io::Cursor::new(buf);
636
0
                let pems = Certificate::read_pem_certs(&mut reader)?;
637
0
                for c in pems {
638
0
                    ders.push(c.into());
639
0
                }
640
            }
641
        }
642
    }
643
0
    Ok(ders)
644
0
}
645
646
#[cfg(feature = "__rustls")]
647
#[derive(Debug)]
648
pub(crate) struct NoVerifier;
649
650
#[cfg(feature = "__rustls")]
651
impl ServerCertVerifier for NoVerifier {
652
0
    fn verify_server_cert(
653
0
        &self,
654
0
        _end_entity: &rustls_pki_types::CertificateDer,
655
0
        _intermediates: &[rustls_pki_types::CertificateDer],
656
0
        _server_name: &ServerName,
657
0
        _ocsp_response: &[u8],
658
0
        _now: UnixTime,
659
0
    ) -> Result<ServerCertVerified, TLSError> {
660
0
        Ok(ServerCertVerified::assertion())
661
0
    }
662
663
0
    fn verify_tls12_signature(
664
0
        &self,
665
0
        _message: &[u8],
666
0
        _cert: &rustls_pki_types::CertificateDer,
667
0
        _dss: &DigitallySignedStruct,
668
0
    ) -> Result<HandshakeSignatureValid, TLSError> {
669
0
        Ok(HandshakeSignatureValid::assertion())
670
0
    }
671
672
0
    fn verify_tls13_signature(
673
0
        &self,
674
0
        _message: &[u8],
675
0
        _cert: &rustls_pki_types::CertificateDer,
676
0
        _dss: &DigitallySignedStruct,
677
0
    ) -> Result<HandshakeSignatureValid, TLSError> {
678
0
        Ok(HandshakeSignatureValid::assertion())
679
0
    }
680
681
0
    fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
682
0
        vec![
683
0
            SignatureScheme::RSA_PKCS1_SHA1,
684
0
            SignatureScheme::ECDSA_SHA1_Legacy,
685
0
            SignatureScheme::RSA_PKCS1_SHA256,
686
0
            SignatureScheme::ECDSA_NISTP256_SHA256,
687
0
            SignatureScheme::RSA_PKCS1_SHA384,
688
0
            SignatureScheme::ECDSA_NISTP384_SHA384,
689
0
            SignatureScheme::RSA_PKCS1_SHA512,
690
0
            SignatureScheme::ECDSA_NISTP521_SHA512,
691
0
            SignatureScheme::RSA_PSS_SHA256,
692
0
            SignatureScheme::RSA_PSS_SHA384,
693
0
            SignatureScheme::RSA_PSS_SHA512,
694
0
            SignatureScheme::ED25519,
695
0
            SignatureScheme::ED448,
696
        ]
697
0
    }
698
}
699
700
#[cfg(feature = "__rustls")]
701
#[derive(Debug)]
702
pub(crate) struct IgnoreHostname {
703
    roots: RootCertStore,
704
    signature_algorithms: WebPkiSupportedAlgorithms,
705
}
706
707
#[cfg(feature = "__rustls")]
708
impl IgnoreHostname {
709
0
    pub(crate) fn new(
710
0
        roots: RootCertStore,
711
0
        signature_algorithms: WebPkiSupportedAlgorithms,
712
0
    ) -> Self {
713
0
        Self {
714
0
            roots,
715
0
            signature_algorithms,
716
0
        }
717
0
    }
718
}
719
720
#[cfg(feature = "__rustls")]
721
impl ServerCertVerifier for IgnoreHostname {
722
0
    fn verify_server_cert(
723
0
        &self,
724
0
        end_entity: &rustls_pki_types::CertificateDer<'_>,
725
0
        intermediates: &[rustls_pki_types::CertificateDer<'_>],
726
0
        _server_name: &ServerName<'_>,
727
0
        _ocsp_response: &[u8],
728
0
        now: UnixTime,
729
0
    ) -> Result<ServerCertVerified, TLSError> {
730
0
        let cert = ParsedCertificate::try_from(end_entity)?;
731
732
0
        rustls::client::verify_server_cert_signed_by_trust_anchor(
733
0
            &cert,
734
0
            &self.roots,
735
0
            intermediates,
736
0
            now,
737
0
            self.signature_algorithms.all,
738
0
        )?;
739
0
        Ok(ServerCertVerified::assertion())
740
0
    }
741
742
0
    fn verify_tls12_signature(
743
0
        &self,
744
0
        message: &[u8],
745
0
        cert: &rustls_pki_types::CertificateDer<'_>,
746
0
        dss: &DigitallySignedStruct,
747
0
    ) -> Result<HandshakeSignatureValid, TLSError> {
748
0
        rustls::crypto::verify_tls12_signature(message, cert, dss, &self.signature_algorithms)
749
0
    }
750
751
0
    fn verify_tls13_signature(
752
0
        &self,
753
0
        message: &[u8],
754
0
        cert: &rustls_pki_types::CertificateDer<'_>,
755
0
        dss: &DigitallySignedStruct,
756
0
    ) -> Result<HandshakeSignatureValid, TLSError> {
757
0
        rustls::crypto::verify_tls13_signature(message, cert, dss, &self.signature_algorithms)
758
0
    }
759
760
0
    fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
761
0
        self.signature_algorithms.supported_schemes()
762
0
    }
763
}
764
765
/// Hyper extension carrying extra TLS layer information.
766
/// Made available to clients on responses when `tls_info` is set.
767
#[derive(Clone)]
768
pub struct TlsInfo {
769
    pub(crate) peer_certificate: Option<Vec<u8>>,
770
}
771
772
impl TlsInfo {
773
    /// Get the DER encoded leaf certificate of the peer.
774
0
    pub fn peer_certificate(&self) -> Option<&[u8]> {
775
0
        self.peer_certificate.as_ref().map(|der| &der[..])
776
0
    }
777
}
778
779
impl std::fmt::Debug for TlsInfo {
780
0
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
781
0
        f.debug_struct("TlsInfo").finish()
782
0
    }
783
}
784
785
#[cfg(test)]
786
mod tests {
787
    use super::*;
788
789
    #[cfg(feature = "__native-tls")]
790
    #[test]
791
    fn certificate_from_der_invalid() {
792
        Certificate::from_der(b"not der").unwrap_err();
793
    }
794
795
    #[cfg(feature = "__native-tls")]
796
    #[test]
797
    fn certificate_from_pem_invalid() {
798
        Certificate::from_pem(b"not pem").unwrap_err();
799
    }
800
801
    #[cfg(feature = "__native-tls")]
802
    #[test]
803
    fn identity_from_pkcs12_der_invalid() {
804
        Identity::from_pkcs12_der(b"not der", "nope").unwrap_err();
805
    }
806
807
    #[cfg(feature = "__native-tls")]
808
    #[test]
809
    fn identity_from_pkcs8_pem_invalid() {
810
        Identity::from_pkcs8_pem(b"not pem", b"not key").unwrap_err();
811
    }
812
813
    #[cfg(feature = "__rustls")]
814
    #[test]
815
    fn identity_from_pem_invalid() {
816
        Identity::from_pem(b"not pem").unwrap_err();
817
    }
818
819
    #[cfg(feature = "__rustls")]
820
    #[test]
821
    fn identity_from_pem_pkcs1_key() {
822
        let pem = b"-----BEGIN CERTIFICATE-----\n\
823
            -----END CERTIFICATE-----\n\
824
            -----BEGIN RSA PRIVATE KEY-----\n\
825
            -----END RSA PRIVATE KEY-----\n";
826
827
        Identity::from_pem(pem).unwrap();
828
    }
829
830
    #[test]
831
    fn certificates_from_pem_bundle() {
832
        const PEM_BUNDLE: &[u8] = b"
833
            -----BEGIN CERTIFICATE-----
834
            MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5
835
            MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
836
            Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
837
            A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
838
            Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl
839
            ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j
840
            QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr
841
            ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr
842
            BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM
843
            YyRIHN8wfdVoOw==
844
            -----END CERTIFICATE-----
845
846
            -----BEGIN CERTIFICATE-----
847
            MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5
848
            MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
849
            Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
850
            A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
851
            Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi
852
            9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk
853
            M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB
854
            /zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB
855
            MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw
856
            CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW
857
            1KyLa2tJElMzrdfkviT8tQp21KW8EA==
858
            -----END CERTIFICATE-----
859
        ";
860
861
        assert!(Certificate::from_pem_bundle(PEM_BUNDLE).is_ok())
862
    }
863
864
    #[cfg(feature = "__rustls")]
865
    #[test]
866
    fn crl_from_pem() {
867
        let pem = b"-----BEGIN X509 CRL-----\n-----END X509 CRL-----\n";
868
869
        CertificateRevocationList::from_pem(pem).unwrap();
870
    }
871
872
    #[cfg(feature = "__rustls")]
873
    #[test]
874
    fn invalid_crl_from_pem() {
875
        CertificateRevocationList::from_pem(b"Invalid").unwrap_err();
876
    }
877
878
    #[cfg(feature = "__rustls")]
879
    #[test]
880
    fn crl_from_pem_bundle() {
881
        let pem_bundle = std::fs::read("tests/support/crl.pem").unwrap();
882
883
        let result = CertificateRevocationList::from_pem_bundle(&pem_bundle);
884
885
        assert!(result.is_ok());
886
        let result = result.unwrap();
887
        assert_eq!(result.len(), 1);
888
    }
889
}