Skip to content

Commit 67e03ba

Browse files
committed
Docs and refactorings
1 parent 3330999 commit 67e03ba

File tree

5 files changed

+65
-39
lines changed

5 files changed

+65
-39
lines changed

benches/tls_certs.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@ use wiremock::tls_certs::MockTlsCertificates;
88
// On the good old M1 processor it takes ~77 µs
99
pub fn tls_mock_tls_certificates_new(c: &mut Criterion) {
1010
c.bench_function("MockTlsCertificates::new", |b| {
11-
b.iter(|| MockTlsCertificates::new())
11+
b.iter(|| MockTlsCertificates::random())
1212
});
1313
}
1414

1515
#[cfg(feature = "tls")]
16-
// TODO measure with a charger connected
1716
pub fn tls_mock_tls_certificates_client(c: &mut Criterion) {
18-
let mock_tls_certificates = MockTlsCertificates::new();
17+
let mock_tls_certificates = MockTlsCertificates::random();
1918
c.bench_function("MockTlsCertificates::gen_client", |b| {
2019
b.iter(|| mock_tls_certificates.gen_client("[email protected]"))
2120
});

src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,16 @@
107107
//! The pool is designed to be invisible: it makes your life easier and your tests faster. If you
108108
//! end up having to worry about it, it's a bug: open an issue!
109109
//!
110+
//! ## HTTPS
111+
//!
112+
//! You may start a HTTPS server with `MockServer::start_https(MockServerTlsConfig)` method.
113+
//! The `MockServerTlsConfig` can be created from pregenerated TLS certificates, or you can
114+
//! generate self-signed server and client certificates with a `MockTlsCertificates` instance.
115+
//!
116+
//! HTTPS servers are not pooled yet.
117+
//!
118+
//! HTTPS functionality is gated by the `tls` feature.
119+
//!
110120
//! ## Prior art
111121
//!
112122
//! [`mockito`] and [`httpmock`] provide HTTP mocking for Rust.

src/mock_server/builder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ impl MockServerBuilder {
146146

147147
let rustls_config = RustlsConfig::from_der(
148148
vec![certs.server_cert_der, certs.root_cert_der],
149-
certs.server_key_der,
149+
certs.server_keypair_der,
150150
)
151151
.await
152152
.expect("Failed to build RustlsConfig");

src/mock_server/tls_certs.rs

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! Certificate generation.
1+
//! TLS Certificate generation helpers.
22
//!
33
// Based on https://github.com/rustls/rustls/blob/main/rustls/examples/internal/test_ca.rs
44
use std::{
@@ -39,116 +39,131 @@ const EE_KEY_USAGES: &[KeyUsagePurpose; 2] = &[
3939

4040
static SERIAL_NUMBER: AtomicU64 = AtomicU64::new(1);
4141

42+
/// Configuration for a mock server TLS setup.
4243
pub struct MockServerTlsConfig {
44+
/// Root CA certificate in DER format.
4345
pub root_cert_der: Vec<u8>,
46+
/// Server certificate in DER format.
4447
pub server_cert_der: Vec<u8>,
45-
pub server_key_der: Vec<u8>,
48+
/// Server keypair in DER format.
49+
pub server_keypair_der: Vec<u8>,
4650
}
4751

4852
impl MockServerTlsConfig {
4953
#[inline]
5054
pub fn from_der(
5155
root_cert_der: Vec<u8>,
5256
server_cert_der: Vec<u8>,
53-
server_key_der: Vec<u8>,
57+
server_keypair_der: Vec<u8>,
5458
) -> Self {
5559
Self {
5660
root_cert_der,
5761
server_cert_der,
58-
server_key_der,
62+
server_keypair_der,
5963
}
6064
}
6165

6266
/// Create a new `MockServerTlsConfig` from PEM-encoded certificates and key.
6367
///
6468
/// Panics if the data cannot be parsed as valid PEM.
65-
#[inline]
6669
pub fn from_pem(
6770
root_cert_pem: Vec<u8>,
6871
server_cert_pem: Vec<u8>,
69-
server_key_pem: Vec<u8>,
72+
server_keypair_pem: Vec<u8>,
7073
) -> Self {
7174
let root_cert_der = CertificateDer::from_pem_slice(&root_cert_pem)
7275
.expect("Failed to parse root certificate from PEM")
7376
.to_vec();
7477
let server_cert_der = CertificateDer::from_pem_slice(&server_cert_pem)
7578
.expect("Failed to parse server certificate from PEM")
7679
.to_vec();
77-
let server_key_der = PrivateKeyDer::from_pem_slice(&server_key_pem)
80+
let server_keypair_der = PrivateKeyDer::from_pem_slice(&server_keypair_pem)
7881
.expect("Failed to parse server key from PEM")
7982
.secret_der()
8083
.to_vec();
8184

8285
Self {
8386
root_cert_der,
8487
server_cert_der,
85-
server_key_der,
88+
server_keypair_der,
8689
}
8790
}
8891
}
8992

93+
/// Mock self-signed TLS certificates for testing purposes.
94+
///
95+
/// This struct generates a root CA certificate and a server certificate signed by it, along with a key pair for the
96+
/// server.
9097
pub struct MockTlsCertificates {
9198
pub root_cert: Certificate,
9299
pub server_cert: Certificate,
93-
pub server_key: KeyPair,
100+
pub server_keypair: KeyPair,
94101
}
95102

96103
impl MockTlsCertificates {
97-
/// Generate server certificates and key with "localhost" and "127.0.0.1" as hostnames.
104+
/// Generate server certificates and keypair with "localhost" and "127.0.0.1" as hostnames.
105+
///
106+
/// Ed25519 is used as the default signature algorithm.
98107
// On the good old M1 processor it takes ~77 µs
99108
#[inline]
100-
#[allow(clippy::new_without_default)]
101-
pub fn new() -> Self {
102-
Self::with_hostnames(default_hostnames())
109+
pub fn random() -> Self {
110+
Self::random_with_hostnames(default_hostnames())
103111
}
104112

105113
/// Generate server certificates and key with custom hostnames and IPs.
106-
pub fn with_hostnames(hostnames: impl Into<Vec<SanType>>) -> Self {
114+
pub fn random_with_hostnames(hostnames: impl Into<Vec<SanType>>) -> Self {
107115
let (root_cert, root_key) = gen_root_cert(DEFAULT_ALGORITHM);
108116
// We do not bother to have an intermediate certificate because CAs use them for flexibility only.
109-
let (server_cert, server_key) =
117+
let (server_cert, server_keypair) =
110118
gen_server_cert(&root_cert, &root_key, DEFAULT_ALGORITHM, hostnames.into());
111119

112120
Self {
113121
root_cert,
114122
server_cert,
115-
server_key,
123+
server_keypair,
116124
}
117125
}
118126

127+
/// Get the root CA certificate.
119128
#[inline]
120-
pub fn get_root_cert(&self) -> &Certificate {
129+
pub fn get_root_ca_cert(&self) -> &Certificate {
121130
&self.root_cert
122131
}
123132

133+
/// Get the server certificate signed by CA certificate, in DER format.
124134
#[inline]
125135
pub fn server_cert_der(&self) -> &CertificateDer {
126136
self.server_cert.der()
127137
}
128138

129-
pub fn server_private_key_der(&self) -> PrivateKeyDer {
130-
self.server_key
139+
/// Get the server keypair in DER format.
140+
pub fn server_private_keypair_der(&self) -> PrivateKeyDer {
141+
self.server_keypair
131142
.serialize_der()
132143
.try_into()
133144
.expect("Failed to deserialize a serialized key")
134145
}
135146

147+
/// Generate a client certificate signed by the CA certificate.
148+
///
149+
/// Each invocation generates a new keypair and a certificate.
136150
#[inline]
137-
pub fn gen_client_cert(&self, email: &str) -> (Certificate, KeyPair) {
151+
pub fn generate_client_cert(&self, email: &str) -> (Certificate, KeyPair) {
138152
gen_client_cert(
139153
&self.server_cert,
140-
&self.server_key,
154+
&self.server_keypair,
141155
DEFAULT_ALGORITHM,
142156
email,
143157
)
144158
}
145159

160+
/// Get the server configuration for use with a mock server.
146161
#[inline]
147162
pub fn get_server_config(&self) -> MockServerTlsConfig {
148163
MockServerTlsConfig {
149164
root_cert_der: self.root_cert.der().to_vec(),
150165
server_cert_der: self.server_cert.der().to_vec(),
151-
server_key_der: self.server_key.serialize_der(),
166+
server_keypair_der: self.server_keypair.serialize_der(),
152167
}
153168
}
154169
}
@@ -180,7 +195,7 @@ fn gen_root_cert(alg: &'static SignatureAlgorithm) -> (Certificate, KeyPair) {
180195

181196
fn gen_server_cert(
182197
signer_cert: &Certificate,
183-
signer_key: &KeyPair,
198+
signer_keypair: &KeyPair,
184199
alg: &'static SignatureAlgorithm,
185200
hostnames: Vec<SanType>,
186201
) -> (Certificate, KeyPair) {
@@ -195,13 +210,13 @@ fn gen_server_cert(
195210
params.key_usages = EE_KEY_USAGES.to_vec();
196211
params.subject_alt_names = hostnames;
197212

198-
let cert = params.signed_by(&keypair, signer_cert, signer_key).unwrap();
213+
let cert = params.signed_by(&keypair, signer_cert, signer_keypair).unwrap();
199214
(cert, keypair)
200215
}
201216

202217
fn gen_client_cert(
203218
signer_cert: &Certificate,
204-
signer_key: &KeyPair,
219+
signer_keypair: &KeyPair,
205220
alg: &'static SignatureAlgorithm,
206221
email: &str,
207222
) -> (Certificate, KeyPair) {
@@ -222,7 +237,7 @@ fn gen_client_cert(
222237
.unwrap_or_else(|_| panic!("Invalid email: {}", email)),
223238
)];
224239

225-
let cert = params.signed_by(&keypair, signer_cert, signer_key).unwrap();
240+
let cert = params.signed_by(&keypair, signer_cert, signer_keypair).unwrap();
226241
(cert, keypair)
227242
}
228243

tests/tls.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ mod tlstests {
44

55
#[async_std::test]
66
async fn test_tls_basic() {
7-
let certs = MockTlsCertificates::new();
7+
let certs = MockTlsCertificates::random();
88

99
let mock_server = wiremock::MockServer::builder()
1010
.start_https(certs.get_server_config())
@@ -17,7 +17,7 @@ mod tlstests {
1717

1818
#[async_std::test]
1919
async fn test_tls_invalid() {
20-
let certs = MockTlsCertificates::new();
20+
let certs = MockTlsCertificates::random();
2121

2222
let mock_server = wiremock::MockServer::builder()
2323
.start_https(certs.get_server_config())
@@ -38,15 +38,16 @@ mod tlstests {
3838

3939
#[async_std::test]
4040
async fn test_tls_anonymous() {
41-
let certs = MockTlsCertificates::new();
41+
let certs = MockTlsCertificates::random();
4242

4343
let mock_server = wiremock::MockServer::builder()
4444
.start_https(certs.get_server_config())
4545
.await;
4646
let uri = mock_server.uri();
4747

48-
let reqwest_root_certificate = reqwest::Certificate::from_der(certs.get_root_cert().der())
49-
.expect("Failed to create certificate from DER");
48+
let reqwest_root_certificate =
49+
reqwest::Certificate::from_der(certs.get_root_ca_cert().der())
50+
.expect("Failed to create certificate from DER");
5051
let client = reqwest::Client::builder()
5152
.add_root_certificate(reqwest_root_certificate)
5253
.use_rustls_tls() // It fails on MacOS with native-tls no mattter what, so use rustls.
@@ -62,16 +63,17 @@ mod tlstests {
6263

6364
#[async_std::test]
6465
async fn test_tls_with_client_cert() {
65-
let certs = MockTlsCertificates::new();
66+
let certs = MockTlsCertificates::random();
6667

6768
let mock_server = wiremock::MockServer::builder()
6869
.start_https(certs.get_server_config())
6970
.await;
7071
let uri = mock_server.uri();
7172

72-
let reqwest_root_certificate = reqwest::Certificate::from_der(certs.get_root_cert().der())
73-
.expect("Failed to create certificate from DER");
74-
let (client_cert, client_key) = certs.gen_client_cert("[email protected]");
73+
let reqwest_root_certificate =
74+
reqwest::Certificate::from_der(certs.get_root_ca_cert().der())
75+
.expect("Failed to create certificate from DER");
76+
let (client_cert, client_key) = certs.generate_client_cert("[email protected]");
7577
let client_cert_pem = client_cert.pem();
7678
let client_key_pem = client_key.serialize_pem();
7779
let client_cert =

0 commit comments

Comments
 (0)