Skip to content

Commit 8691db0

Browse files
authored
chore(tls): add examples for root and self-signed certificates (#792)
1 parent 8b768e7 commit 8691db0

8 files changed

Lines changed: 93 additions & 122 deletions

File tree

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,8 @@ path = "examples/emulation_twitter.rs"
245245
required-features = ["full", "tracing"]
246246

247247
[[example]]
248-
name = "set_cert_store"
249-
path = "examples/set_cert_store.rs"
248+
name = "cert_store"
249+
path = "examples/cert_store.rs"
250250
required-features = ["webpki-roots", "tracing"]
251251

252252
[[example]]

examples/cert_store.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
use std::time::Duration;
2+
3+
use wreq::{
4+
Client,
5+
tls::{CertStore, TlsInfo},
6+
};
7+
8+
/// Certificate Store Example
9+
///
10+
/// In most cases, you don't need to manually configure certificate stores. wreq automatically
11+
/// uses appropriate default certificates:
12+
/// - With `webpki-roots` feature enabled: Uses Mozilla's maintained root certificate collection
13+
/// - Without this feature: Uses system default certificate store paths
14+
///
15+
/// Manual certificate store configuration is only needed in the following special cases:
16+
///
17+
/// ## Scenarios requiring custom certificate store:
18+
///
19+
/// ### 1. Self-signed Certificates
20+
/// - Connect to internal services using self-signed certificates
21+
/// - Test servers in development environments
22+
///
23+
/// ### 2. Enterprise Internal CA
24+
/// - Add root certificates from enterprise internal certificate authorities
25+
/// - Access HTTPS services on corporate intranets
26+
///
27+
/// ### 3. Certificate Updates and Management
28+
/// - Dynamically update certificates in the certificate store
29+
/// - Remove revoked or expired certificates
30+
///
31+
/// ### 4. Compliance Requirements
32+
/// - Special compliance requirements for certain industries or regions
33+
/// - Need to use specific certificate collections
34+
///
35+
/// ### 5. Performance Optimization
36+
/// - Reduce certificate store size to improve TLS handshake performance
37+
/// - Include only necessary root certificates
38+
#[tokio::main]
39+
async fn main() -> wreq::Result<()> {
40+
tracing_subscriber::fmt()
41+
.with_max_level(tracing::Level::INFO)
42+
.init();
43+
44+
// Create a client with a custom certificate store using webpki-roots
45+
let client = Client::builder()
46+
.cert_store(CertStore::from_der_certs(
47+
webpki_root_certs::TLS_SERVER_ROOT_CERTS,
48+
)?)
49+
.build()?;
50+
51+
// Use the API you're already familiar with
52+
client.get("https://www.google.com").send().await?;
53+
54+
// Self-signed certificate Client
55+
// Skip certificate verification for self-signed certificates
56+
let client = Client::builder()
57+
.tls_info(true)
58+
.cert_verification(false)
59+
.build()?;
60+
61+
// Use the API you're already familiar with
62+
let resp = client.get("https://self-signed.badssl.com/").send().await?;
63+
if let Some(val) = resp.extensions().get::<TlsInfo>() {
64+
if let Some(peer_cert_der) = val.peer_certificate() {
65+
// Create self-signed certificate Store
66+
let self_signed_store = CertStore::from_der_certs(&[peer_cert_der])?;
67+
68+
// Create a client with self-signed certificate store
69+
let client = Client::builder()
70+
.cert_store(self_signed_store)
71+
.connect_timeout(Duration::from_secs(10))
72+
.build()?;
73+
74+
// Use the API you're already familiar with
75+
let resp = client.get("https://self-signed.badssl.com/").send().await?;
76+
println!("{}", resp.text().await?);
77+
}
78+
}
79+
80+
Ok(())
81+
}

examples/emulation_twitter.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ async fn main() -> wreq::Result<()> {
8585
headers
8686
};
8787

88-
// Original headers
8988
// The headers keep the original case and order
9089
let original_headers = {
9190
let mut original_headers = OriginalHeaders::new();

examples/set_cert_store.rs

Lines changed: 0 additions & 69 deletions
This file was deleted.

examples/tls_info.rs

Lines changed: 0 additions & 15 deletions
This file was deleted.

src/client/http/mod.rs

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,7 @@ use crate::{
6464
error::{self, BoxError, Error},
6565
proxy::Matcher as ProxyMatcher,
6666
redirect::{self, RedirectPolicy},
67-
tls::{
68-
AlpnProtocol, CertStore, CertificateInput, Identity, KeyLogPolicy, TlsConnectorBuilder,
69-
TlsVersion,
70-
},
67+
tls::{AlpnProtocol, CertStore, Identity, KeyLogPolicy, TlsConnectorBuilder, TlsVersion},
7168
};
7269

7370
/// An `Client` to make Requests with.
@@ -1028,33 +1025,6 @@ impl ClientBuilder {
10281025
self
10291026
}
10301027

1031-
// TLS options
1032-
1033-
/// Configures SSL/TLS certificate pinning for the client.
1034-
///
1035-
/// This method allows you to specify a set of PEM-encoded certificates that the client
1036-
/// will pin to, ensuring that only these certificates are trusted during SSL/TLS connections.
1037-
/// This provides an additional layer of security by preventing man-in-the-middle (MITM)
1038-
/// attacks, even if a malicious certificate is issued by a trusted Certificate Authority
1039-
/// (CA).
1040-
///
1041-
/// # Parameters
1042-
///
1043-
/// - `certs`: An iterator of DER-encoded certificates. Each certificate should be provided as a
1044-
/// byte slice (`&[u8]`).
1045-
#[inline]
1046-
pub fn ssl_pinning<'c, I>(mut self, certs: I) -> ClientBuilder
1047-
where
1048-
I: IntoIterator,
1049-
I::Item: Into<CertificateInput<'c>>,
1050-
{
1051-
match CertStore::from_der_certs(certs) {
1052-
Ok(store) => self.config.tls_cert_store = store,
1053-
Err(err) => self.config.error = Some(err),
1054-
}
1055-
self
1056-
}
1057-
10581028
/// Sets the identity to be used for client certificate authentication.
10591029
#[inline]
10601030
pub fn identity(mut self, identity: Identity) -> ClientBuilder {

src/tls/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub use self::{
1919
types::{
2020
AlpnProtocol, AlpsProtocol, CertificateCompressionAlgorithm, ExtensionType, TlsVersion,
2121
},
22-
x509::{CertStore, CertStoreBuilder, Certificate, CertificateInput, Identity},
22+
x509::{CertStore, CertStoreBuilder, Certificate, Identity},
2323
};
2424

2525
/// Http extension carrying extra TLS layer information.

tests/badssl.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::time::Duration;
22

33
use wreq::{
44
Client,
5-
tls::{AlpsProtocol, TlsInfo, TlsOptions, TlsVersion},
5+
tls::{AlpsProtocol, CertStore, TlsInfo, TlsOptions, TlsVersion},
66
};
77

88
macro_rules! join {
@@ -186,7 +186,7 @@ async fn test_aes_hw_override() -> wreq::Result<()> {
186186
}
187187

188188
#[tokio::test]
189-
async fn test_ssl_pinning() {
189+
async fn test_tls_self_signed_cert() {
190190
let client = wreq::Client::builder()
191191
.cert_verification(false)
192192
.connect_timeout(Duration::from_secs(360))
@@ -206,8 +206,13 @@ async fn test_ssl_pinning() {
206206
.and_then(|info| info.peer_certificate())
207207
.unwrap();
208208

209+
let self_signed_cert_store = CertStore::builder()
210+
.add_der_cert(peer_cert_der)
211+
.build()
212+
.unwrap();
213+
209214
let client = wreq::Client::builder()
210-
.ssl_pinning([peer_cert_der])
215+
.cert_store(self_signed_cert_store)
211216
.build()
212217
.unwrap();
213218

0 commit comments

Comments
 (0)