Coverage Report

Created: 2025-12-31 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/reqwest-0.12.24/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 `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")]
48
use 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
use rustls_pki_types::pem::PemObject;
55
#[cfg(feature = "__rustls")]
56
use rustls_pki_types::{ServerName, UnixTime};
57
use std::{
58
    fmt,
59
    io::{BufRead, BufReader},
60
};
61
62
/// Represents a X509 certificate revocation list.
63
#[cfg(feature = "__rustls")]
64
pub struct CertificateRevocationList {
65
    #[cfg(feature = "__rustls")]
66
    inner: rustls_pki_types::CertificateRevocationListDer<'static>,
67
}
68
69
/// Represents a server X509 certificate.
70
#[derive(Clone)]
71
pub struct Certificate {
72
    #[cfg(feature = "default-tls")]
73
    native: native_tls_crate::Certificate,
74
    #[cfg(feature = "__rustls")]
75
    original: Cert,
76
}
77
78
#[cfg(feature = "__rustls")]
79
#[derive(Clone)]
80
enum Cert {
81
    Der(Vec<u8>),
82
    Pem(Vec<u8>),
83
}
84
85
/// Represents a private key and X509 cert as a client certificate.
86
#[derive(Clone)]
87
pub struct Identity {
88
    #[cfg_attr(not(any(feature = "native-tls", feature = "__rustls")), allow(unused))]
89
    inner: ClientCert,
90
}
91
92
enum ClientCert {
93
    #[cfg(feature = "native-tls")]
94
    Pkcs12(native_tls_crate::Identity),
95
    #[cfg(feature = "native-tls")]
96
    Pkcs8(native_tls_crate::Identity),
97
    #[cfg(feature = "__rustls")]
98
    Pem {
99
        key: rustls_pki_types::PrivateKeyDer<'static>,
100
        certs: Vec<rustls_pki_types::CertificateDer<'static>>,
101
    },
102
}
103
104
impl Clone for ClientCert {
105
0
    fn clone(&self) -> Self {
106
0
        match self {
107
            #[cfg(feature = "native-tls")]
108
            Self::Pkcs8(i) => Self::Pkcs8(i.clone()),
109
            #[cfg(feature = "native-tls")]
110
            Self::Pkcs12(i) => Self::Pkcs12(i.clone()),
111
            #[cfg(feature = "__rustls")]
112
0
            ClientCert::Pem { key, certs } => ClientCert::Pem {
113
0
                key: key.clone_key(),
114
0
                certs: certs.clone(),
115
0
            },
116
            #[cfg_attr(
117
                any(feature = "native-tls", feature = "__rustls"),
118
                allow(unreachable_patterns)
119
            )]
120
            _ => unreachable!(),
121
        }
122
0
    }
123
}
124
125
impl Certificate {
126
    /// Create a `Certificate` from a binary DER encoded certificate
127
    ///
128
    /// # Examples
129
    ///
130
    /// ```
131
    /// # use std::fs::File;
132
    /// # use std::io::Read;
133
    /// # fn cert() -> Result<(), Box<dyn std::error::Error>> {
134
    /// let mut buf = Vec::new();
135
    /// File::open("my_cert.der")?
136
    ///     .read_to_end(&mut buf)?;
137
    /// let cert = reqwest::Certificate::from_der(&buf)?;
138
    /// # drop(cert);
139
    /// # Ok(())
140
    /// # }
141
    /// ```
142
0
    pub fn from_der(der: &[u8]) -> crate::Result<Certificate> {
143
0
        Ok(Certificate {
144
0
            #[cfg(feature = "default-tls")]
145
0
            native: native_tls_crate::Certificate::from_der(der).map_err(crate::error::builder)?,
146
0
            #[cfg(feature = "__rustls")]
147
0
            original: Cert::Der(der.to_owned()),
148
0
        })
149
0
    }
150
151
    /// Create a `Certificate` from a PEM encoded certificate
152
    ///
153
    /// # Examples
154
    ///
155
    /// ```
156
    /// # use std::fs::File;
157
    /// # use std::io::Read;
158
    /// # fn cert() -> Result<(), Box<dyn std::error::Error>> {
159
    /// let mut buf = Vec::new();
160
    /// File::open("my_cert.pem")?
161
    ///     .read_to_end(&mut buf)?;
162
    /// let cert = reqwest::Certificate::from_pem(&buf)?;
163
    /// # drop(cert);
164
    /// # Ok(())
165
    /// # }
166
    /// ```
167
0
    pub fn from_pem(pem: &[u8]) -> crate::Result<Certificate> {
168
0
        Ok(Certificate {
169
0
            #[cfg(feature = "default-tls")]
170
0
            native: native_tls_crate::Certificate::from_pem(pem).map_err(crate::error::builder)?,
171
0
            #[cfg(feature = "__rustls")]
172
0
            original: Cert::Pem(pem.to_owned()),
173
0
        })
174
0
    }
175
176
    /// Create a collection of `Certificate`s from a PEM encoded certificate bundle.
177
    /// Example byte sources may be `.crt`, `.cer` or `.pem` files.
178
    ///
179
    /// # Examples
180
    ///
181
    /// ```
182
    /// # use std::fs::File;
183
    /// # use std::io::Read;
184
    /// # fn cert() -> Result<(), Box<dyn std::error::Error>> {
185
    /// let mut buf = Vec::new();
186
    /// File::open("ca-bundle.crt")?
187
    ///     .read_to_end(&mut buf)?;
188
    /// let certs = reqwest::Certificate::from_pem_bundle(&buf)?;
189
    /// # drop(certs);
190
    /// # Ok(())
191
    /// # }
192
    /// ```
193
0
    pub fn from_pem_bundle(pem_bundle: &[u8]) -> crate::Result<Vec<Certificate>> {
194
0
        let mut reader = BufReader::new(pem_bundle);
195
196
0
        Self::read_pem_certs(&mut reader)?
197
0
            .iter()
198
0
            .map(|cert_vec| Certificate::from_der(cert_vec))
199
0
            .collect::<crate::Result<Vec<Certificate>>>()
200
0
    }
201
202
    #[cfg(feature = "default-tls")]
203
    pub(crate) fn add_to_native_tls(self, tls: &mut native_tls_crate::TlsConnectorBuilder) {
204
        tls.add_root_certificate(self.native);
205
    }
206
207
    #[cfg(feature = "__rustls")]
208
0
    pub(crate) fn add_to_rustls(
209
0
        self,
210
0
        root_cert_store: &mut rustls::RootCertStore,
211
0
    ) -> crate::Result<()> {
212
        use std::io::Cursor;
213
214
0
        match self.original {
215
0
            Cert::Der(buf) => root_cert_store
216
0
                .add(buf.into())
217
0
                .map_err(crate::error::builder)?,
218
0
            Cert::Pem(buf) => {
219
0
                let mut reader = Cursor::new(buf);
220
0
                let certs = Self::read_pem_certs(&mut reader)?;
221
0
                for c in certs {
222
0
                    root_cert_store
223
0
                        .add(c.into())
224
0
                        .map_err(crate::error::builder)?;
225
                }
226
            }
227
        }
228
0
        Ok(())
229
0
    }
230
231
0
    fn read_pem_certs(reader: &mut impl BufRead) -> crate::Result<Vec<Vec<u8>>> {
232
0
        rustls_pki_types::CertificateDer::pem_reader_iter(reader)
233
0
            .map(|result| match result {
234
0
                Ok(cert) => Ok(cert.as_ref().to_vec()),
235
0
                Err(_) => Err(crate::error::builder("invalid certificate encoding")),
236
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}
237
0
            .collect()
238
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]>>
239
}
240
241
impl Identity {
242
    /// Parses a DER-formatted PKCS #12 archive, using the specified password to decrypt the key.
243
    ///
244
    /// The archive should contain a leaf certificate and its private key, as well any intermediate
245
    /// certificates that allow clients to build a chain to a trusted root.
246
    /// The chain certificates should be in order from the leaf certificate towards the root.
247
    ///
248
    /// PKCS #12 archives typically have the file extension `.p12` or `.pfx`, and can be created
249
    /// with the OpenSSL `pkcs12` tool:
250
    ///
251
    /// ```bash
252
    /// openssl pkcs12 -export -out identity.pfx -inkey key.pem -in cert.pem -certfile chain_certs.pem
253
    /// ```
254
    ///
255
    /// # Examples
256
    ///
257
    /// ```
258
    /// # use std::fs::File;
259
    /// # use std::io::Read;
260
    /// # fn pkcs12() -> Result<(), Box<dyn std::error::Error>> {
261
    /// let mut buf = Vec::new();
262
    /// File::open("my-ident.pfx")?
263
    ///     .read_to_end(&mut buf)?;
264
    /// let pkcs12 = reqwest::Identity::from_pkcs12_der(&buf, "my-privkey-password")?;
265
    /// # drop(pkcs12);
266
    /// # Ok(())
267
    /// # }
268
    /// ```
269
    ///
270
    /// # Optional
271
    ///
272
    /// This requires the `native-tls` Cargo feature enabled.
273
    #[cfg(feature = "native-tls")]
274
    pub fn from_pkcs12_der(der: &[u8], password: &str) -> crate::Result<Identity> {
275
        Ok(Identity {
276
            inner: ClientCert::Pkcs12(
277
                native_tls_crate::Identity::from_pkcs12(der, password)
278
                    .map_err(crate::error::builder)?,
279
            ),
280
        })
281
    }
282
283
    /// Parses a chain of PEM encoded X509 certificates, with the leaf certificate first.
284
    /// `key` is a PEM encoded PKCS #8 formatted private key for the leaf certificate.
285
    ///
286
    /// The certificate chain should contain any intermediate certificates that should be sent to
287
    /// clients to allow them to build a chain to a trusted root.
288
    ///
289
    /// A certificate chain here means a series of PEM encoded certificates concatenated together.
290
    ///
291
    /// # Examples
292
    ///
293
    /// ```
294
    /// # use std::fs;
295
    /// # fn pkcs8() -> Result<(), Box<dyn std::error::Error>> {
296
    /// let cert = fs::read("client.pem")?;
297
    /// let key = fs::read("key.pem")?;
298
    /// let pkcs8 = reqwest::Identity::from_pkcs8_pem(&cert, &key)?;
299
    /// # drop(pkcs8);
300
    /// # Ok(())
301
    /// # }
302
    /// ```
303
    ///
304
    /// # Optional
305
    ///
306
    /// This requires the `native-tls` Cargo feature enabled.
307
    #[cfg(feature = "native-tls")]
308
    pub fn from_pkcs8_pem(pem: &[u8], key: &[u8]) -> crate::Result<Identity> {
309
        Ok(Identity {
310
            inner: ClientCert::Pkcs8(
311
                native_tls_crate::Identity::from_pkcs8(pem, key).map_err(crate::error::builder)?,
312
            ),
313
        })
314
    }
315
316
    /// Parses PEM encoded private key and certificate.
317
    ///
318
    /// The input should contain a PEM encoded private key
319
    /// and at least one PEM encoded certificate.
320
    ///
321
    /// Note: The private key must be in RSA, SEC1 Elliptic Curve or PKCS#8 format.
322
    ///
323
    /// # Examples
324
    ///
325
    /// ```
326
    /// # use std::fs::File;
327
    /// # use std::io::Read;
328
    /// # fn pem() -> Result<(), Box<dyn std::error::Error>> {
329
    /// let mut buf = Vec::new();
330
    /// File::open("my-ident.pem")?
331
    ///     .read_to_end(&mut buf)?;
332
    /// let id = reqwest::Identity::from_pem(&buf)?;
333
    /// # drop(id);
334
    /// # Ok(())
335
    /// # }
336
    /// ```
337
    ///
338
    /// # Optional
339
    ///
340
    /// This requires the `rustls-tls(-...)` Cargo feature enabled.
341
    #[cfg(feature = "__rustls")]
342
0
    pub fn from_pem(buf: &[u8]) -> crate::Result<Identity> {
343
        use rustls_pki_types::{pem::SectionKind, PrivateKeyDer};
344
        use std::io::Cursor;
345
346
0
        let (key, certs) = {
347
0
            let mut pem = Cursor::new(buf);
348
0
            let mut sk = Vec::<rustls_pki_types::PrivateKeyDer>::new();
349
0
            let mut certs = Vec::<rustls_pki_types::CertificateDer>::new();
350
351
0
            while let Some((kind, data)) =
352
0
                rustls_pki_types::pem::from_buf(&mut pem).map_err(|_| {
353
0
                    crate::error::builder(TLSError::General(String::from(
354
0
                        "Invalid identity PEM file",
355
0
                    )))
356
0
                })?
357
            {
358
0
                match kind {
359
0
                    SectionKind::Certificate => certs.push(data.into()),
360
0
                    SectionKind::PrivateKey => sk.push(PrivateKeyDer::Pkcs8(data.into())),
361
0
                    SectionKind::RsaPrivateKey => sk.push(PrivateKeyDer::Pkcs1(data.into())),
362
0
                    SectionKind::EcPrivateKey => sk.push(PrivateKeyDer::Sec1(data.into())),
363
                    _ => {
364
0
                        return Err(crate::error::builder(TLSError::General(String::from(
365
0
                            "No valid certificate was found",
366
0
                        ))))
367
                    }
368
                }
369
            }
370
371
0
            if let (Some(sk), false) = (sk.pop(), certs.is_empty()) {
372
0
                (sk, certs)
373
            } else {
374
0
                return Err(crate::error::builder(TLSError::General(String::from(
375
0
                    "private key or certificate not found",
376
0
                ))));
377
            }
378
        };
379
380
0
        Ok(Identity {
381
0
            inner: ClientCert::Pem { key, certs },
382
0
        })
383
0
    }
384
385
    #[cfg(feature = "native-tls")]
386
    pub(crate) fn add_to_native_tls(
387
        self,
388
        tls: &mut native_tls_crate::TlsConnectorBuilder,
389
    ) -> crate::Result<()> {
390
        match self.inner {
391
            ClientCert::Pkcs12(id) | ClientCert::Pkcs8(id) => {
392
                tls.identity(id);
393
                Ok(())
394
            }
395
            #[cfg(feature = "__rustls")]
396
            ClientCert::Pem { .. } => Err(crate::error::builder("incompatible TLS identity type")),
397
        }
398
    }
399
400
    #[cfg(feature = "__rustls")]
401
0
    pub(crate) fn add_to_rustls(
402
0
        self,
403
0
        config_builder: rustls::ConfigBuilder<
404
0
            rustls::ClientConfig,
405
0
            // Not sure here
406
0
            rustls::client::WantsClientCert,
407
0
        >,
408
0
    ) -> crate::Result<rustls::ClientConfig> {
409
0
        match self.inner {
410
0
            ClientCert::Pem { key, certs } => config_builder
411
0
                .with_client_auth_cert(certs, key)
412
0
                .map_err(crate::error::builder),
413
            #[cfg(feature = "native-tls")]
414
            ClientCert::Pkcs12(..) | ClientCert::Pkcs8(..) => {
415
                Err(crate::error::builder("incompatible TLS identity type"))
416
            }
417
        }
418
0
    }
419
}
420
421
#[cfg(feature = "__rustls")]
422
impl CertificateRevocationList {
423
    /// Parses a PEM encoded CRL.
424
    ///
425
    /// # Examples
426
    ///
427
    /// ```
428
    /// # use std::fs::File;
429
    /// # use std::io::Read;
430
    /// # fn crl() -> Result<(), Box<dyn std::error::Error>> {
431
    /// let mut buf = Vec::new();
432
    /// File::open("my_crl.pem")?
433
    ///     .read_to_end(&mut buf)?;
434
    /// let crl = reqwest::tls::CertificateRevocationList::from_pem(&buf)?;
435
    /// # drop(crl);
436
    /// # Ok(())
437
    /// # }
438
    /// ```
439
    ///
440
    /// # Optional
441
    ///
442
    /// This requires the `rustls-tls(-...)` Cargo feature enabled.
443
    #[cfg(feature = "__rustls")]
444
0
    pub fn from_pem(pem: &[u8]) -> crate::Result<CertificateRevocationList> {
445
0
        Ok(CertificateRevocationList {
446
0
            #[cfg(feature = "__rustls")]
447
0
            inner: rustls_pki_types::CertificateRevocationListDer::from(pem.to_vec()),
448
0
        })
449
0
    }
450
451
    /// Creates a collection of `CertificateRevocationList`s from a PEM encoded CRL bundle.
452
    /// Example byte sources may be `.crl` or `.pem` files.
453
    ///
454
    /// # Examples
455
    ///
456
    /// ```
457
    /// # use std::fs::File;
458
    /// # use std::io::Read;
459
    /// # fn crls() -> Result<(), Box<dyn std::error::Error>> {
460
    /// let mut buf = Vec::new();
461
    /// File::open("crl-bundle.crl")?
462
    ///     .read_to_end(&mut buf)?;
463
    /// let crls = reqwest::tls::CertificateRevocationList::from_pem_bundle(&buf)?;
464
    /// # drop(crls);
465
    /// # Ok(())
466
    /// # }
467
    /// ```
468
    ///
469
    /// # Optional
470
    ///
471
    /// This requires the `rustls-tls(-...)` Cargo feature enabled.
472
    #[cfg(feature = "__rustls")]
473
0
    pub fn from_pem_bundle(pem_bundle: &[u8]) -> crate::Result<Vec<CertificateRevocationList>> {
474
0
        rustls_pki_types::CertificateRevocationListDer::pem_slice_iter(pem_bundle)
475
0
            .map(|result| match result {
476
0
                Ok(crl) => Ok(CertificateRevocationList { inner: crl }),
477
0
                Err(_) => Err(crate::error::builder("invalid crl encoding")),
478
0
            })
479
0
            .collect::<crate::Result<Vec<CertificateRevocationList>>>()
480
0
    }
481
482
    #[cfg(feature = "__rustls")]
483
0
    pub(crate) fn as_rustls_crl<'a>(&self) -> rustls_pki_types::CertificateRevocationListDer<'a> {
484
0
        self.inner.clone()
485
0
    }
486
}
487
488
impl fmt::Debug for Certificate {
489
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
490
0
        f.debug_struct("Certificate").finish()
491
0
    }
492
}
493
494
impl fmt::Debug for Identity {
495
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
496
0
        f.debug_struct("Identity").finish()
497
0
    }
498
}
499
500
#[cfg(feature = "__rustls")]
501
impl fmt::Debug for CertificateRevocationList {
502
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
503
0
        f.debug_struct("CertificateRevocationList").finish()
504
0
    }
505
}
506
507
/// A TLS protocol version.
508
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
509
pub struct Version(InnerVersion);
510
511
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
512
#[non_exhaustive]
513
enum 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
522
impl 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
0
    pub(crate) fn from_rustls(version: rustls::ProtocolVersion) -> Option<Self> {
544
0
        match version {
545
0
            rustls::ProtocolVersion::SSLv2 => None,
546
0
            rustls::ProtocolVersion::SSLv3 => None,
547
0
            rustls::ProtocolVersion::TLSv1_0 => Some(Self(InnerVersion::Tls1_0)),
548
0
            rustls::ProtocolVersion::TLSv1_1 => Some(Self(InnerVersion::Tls1_1)),
549
0
            rustls::ProtocolVersion::TLSv1_2 => Some(Self(InnerVersion::Tls1_2)),
550
0
            rustls::ProtocolVersion::TLSv1_3 => Some(Self(InnerVersion::Tls1_3)),
551
0
            _ => None,
552
        }
553
0
    }
554
}
555
556
pub(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
571
impl fmt::Debug for TlsBackend {
572
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
573
0
        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
0
            TlsBackend::Rustls => write!(f, "Rustls"),
580
            #[cfg(feature = "__rustls")]
581
0
            TlsBackend::BuiltRustls(_) => write!(f, "BuiltRustls"),
582
            #[cfg(any(feature = "native-tls", feature = "__rustls",))]
583
0
            TlsBackend::UnknownPreconfigured => write!(f, "UnknownPreconfigured"),
584
        }
585
0
    }
586
}
587
588
#[allow(clippy::derivable_impls)]
589
impl Default for TlsBackend {
590
0
    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
0
            TlsBackend::Rustls
602
        }
603
0
    }
604
}
605
606
#[cfg(feature = "__rustls")]
607
#[derive(Debug)]
608
pub(crate) struct NoVerifier;
609
610
#[cfg(feature = "__rustls")]
611
impl ServerCertVerifier for NoVerifier {
612
0
    fn verify_server_cert(
613
0
        &self,
614
0
        _end_entity: &rustls_pki_types::CertificateDer,
615
0
        _intermediates: &[rustls_pki_types::CertificateDer],
616
0
        _server_name: &ServerName,
617
0
        _ocsp_response: &[u8],
618
0
        _now: UnixTime,
619
0
    ) -> Result<ServerCertVerified, TLSError> {
620
0
        Ok(ServerCertVerified::assertion())
621
0
    }
622
623
0
    fn verify_tls12_signature(
624
0
        &self,
625
0
        _message: &[u8],
626
0
        _cert: &rustls_pki_types::CertificateDer,
627
0
        _dss: &DigitallySignedStruct,
628
0
    ) -> Result<HandshakeSignatureValid, TLSError> {
629
0
        Ok(HandshakeSignatureValid::assertion())
630
0
    }
631
632
0
    fn verify_tls13_signature(
633
0
        &self,
634
0
        _message: &[u8],
635
0
        _cert: &rustls_pki_types::CertificateDer,
636
0
        _dss: &DigitallySignedStruct,
637
0
    ) -> Result<HandshakeSignatureValid, TLSError> {
638
0
        Ok(HandshakeSignatureValid::assertion())
639
0
    }
640
641
0
    fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
642
0
        vec![
643
0
            SignatureScheme::RSA_PKCS1_SHA1,
644
0
            SignatureScheme::ECDSA_SHA1_Legacy,
645
0
            SignatureScheme::RSA_PKCS1_SHA256,
646
0
            SignatureScheme::ECDSA_NISTP256_SHA256,
647
0
            SignatureScheme::RSA_PKCS1_SHA384,
648
0
            SignatureScheme::ECDSA_NISTP384_SHA384,
649
0
            SignatureScheme::RSA_PKCS1_SHA512,
650
0
            SignatureScheme::ECDSA_NISTP521_SHA512,
651
0
            SignatureScheme::RSA_PSS_SHA256,
652
0
            SignatureScheme::RSA_PSS_SHA384,
653
0
            SignatureScheme::RSA_PSS_SHA512,
654
0
            SignatureScheme::ED25519,
655
0
            SignatureScheme::ED448,
656
        ]
657
0
    }
658
}
659
660
#[cfg(feature = "__rustls")]
661
#[derive(Debug)]
662
pub(crate) struct IgnoreHostname {
663
    roots: RootCertStore,
664
    signature_algorithms: WebPkiSupportedAlgorithms,
665
}
666
667
#[cfg(feature = "__rustls")]
668
impl IgnoreHostname {
669
0
    pub(crate) fn new(
670
0
        roots: RootCertStore,
671
0
        signature_algorithms: WebPkiSupportedAlgorithms,
672
0
    ) -> Self {
673
0
        Self {
674
0
            roots,
675
0
            signature_algorithms,
676
0
        }
677
0
    }
678
}
679
680
#[cfg(feature = "__rustls")]
681
impl ServerCertVerifier for IgnoreHostname {
682
0
    fn verify_server_cert(
683
0
        &self,
684
0
        end_entity: &rustls_pki_types::CertificateDer<'_>,
685
0
        intermediates: &[rustls_pki_types::CertificateDer<'_>],
686
0
        _server_name: &ServerName<'_>,
687
0
        _ocsp_response: &[u8],
688
0
        now: UnixTime,
689
0
    ) -> Result<ServerCertVerified, TLSError> {
690
0
        let cert = ParsedCertificate::try_from(end_entity)?;
691
692
0
        rustls::client::verify_server_cert_signed_by_trust_anchor(
693
0
            &cert,
694
0
            &self.roots,
695
0
            intermediates,
696
0
            now,
697
0
            self.signature_algorithms.all,
698
0
        )?;
699
0
        Ok(ServerCertVerified::assertion())
700
0
    }
701
702
0
    fn verify_tls12_signature(
703
0
        &self,
704
0
        message: &[u8],
705
0
        cert: &rustls_pki_types::CertificateDer<'_>,
706
0
        dss: &DigitallySignedStruct,
707
0
    ) -> Result<HandshakeSignatureValid, TLSError> {
708
0
        rustls::crypto::verify_tls12_signature(message, cert, dss, &self.signature_algorithms)
709
0
    }
710
711
0
    fn verify_tls13_signature(
712
0
        &self,
713
0
        message: &[u8],
714
0
        cert: &rustls_pki_types::CertificateDer<'_>,
715
0
        dss: &DigitallySignedStruct,
716
0
    ) -> Result<HandshakeSignatureValid, TLSError> {
717
0
        rustls::crypto::verify_tls13_signature(message, cert, dss, &self.signature_algorithms)
718
0
    }
719
720
0
    fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
721
0
        self.signature_algorithms.supported_schemes()
722
0
    }
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)]
728
pub struct TlsInfo {
729
    pub(crate) peer_certificate: Option<Vec<u8>>,
730
}
731
732
impl TlsInfo {
733
    /// Get the DER encoded leaf certificate of the peer.
734
0
    pub fn peer_certificate(&self) -> Option<&[u8]> {
735
0
        self.peer_certificate.as_ref().map(|der| &der[..])
736
0
    }
737
}
738
739
impl std::fmt::Debug for TlsInfo {
740
0
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
741
0
        f.debug_struct("TlsInfo").finish()
742
0
    }
743
}
744
745
#[cfg(test)]
746
mod 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
}