1 1 | /*
|
2 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
3 3 | * SPDX-License-Identifier: Apache-2.0
|
4 4 | */
|
5 5 |
|
6 6 | #![cfg(any(feature = "__rustls", feature = "s2n-tls",))]
|
7 7 |
|
8 8 | mod common {
|
9 + | #[allow(dead_code)]
|
10 + | pub(crate) mod client;
|
9 11 | pub(crate) mod tls;
|
10 12 | }
|
11 13 |
|
12 14 | use aws_smithy_async::time::SystemTimeSource;
|
13 15 | #[cfg(all(feature = "rustls-aws-lc", feature = "rt-tokio"))]
|
14 16 | use aws_smithy_http_client::pool::{Client as PoolClient, ConnectionPool};
|
15 17 | use aws_smithy_http_client::tls;
|
16 18 | #[cfg(any(feature = "rustls-aws-lc", feature = "s2n-tls"))]
|
17 19 | use aws_smithy_http_client::tls::{ServerName, TlsContext};
|
18 20 | use aws_smithy_runtime_api::box_error::BoxError;
|
19 21 | use aws_smithy_runtime_api::client::http::{HttpClient, HttpConnector, HttpConnectorSettings};
|
20 22 | use aws_smithy_runtime_api::client::orchestrator::HttpRequest;
|
21 23 | use aws_smithy_runtime_api::client::runtime_components::RuntimeComponentsBuilder;
|
22 24 | use aws_smithy_types::byte_stream::ByteStream;
|
25 + | #[cfg(feature = "rt-tokio")]
|
26 + | use common::client::PartitionedConnectionPool;
|
27 + | use common::client::{BackendConfig, HttpsClientBackend, HyperUtilLegacyPool};
|
23 28 | use common::tls as test_tls;
|
24 29 | use http_1x::{Method, Request, Response, StatusCode};
|
25 30 | use http_body_util::{BodyExt, Full};
|
26 31 | use hyper::body::{Bytes, Incoming};
|
27 32 | use hyper::service::service_fn;
|
28 33 | use hyper_util::rt::{TokioExecutor, TokioIo};
|
29 34 | use hyper_util::server::conn::auto::Builder;
|
30 35 | use std::net::SocketAddr;
|
31 36 | use std::sync::Arc;
|
32 37 | use std::time::Duration;
|
33 38 | use tokio::net::TcpListener;
|
34 39 | use tokio::task::JoinHandle;
|
35 40 | use tracing::{debug, error};
|
36 41 |
|
37 - | struct TestServer {
|
38 - | _handle: JoinHandle<()>,
|
39 - | listen_addr: SocketAddr,
|
40 - | conn_count: Arc<()>,
|
42 + | /// HTTPS echo server with configurable ALPN and observable connection lifetime.
|
43 + | struct TlsEchoServer {
|
44 + | task: JoinHandle<()>,
|
45 + | addr: SocketAddr,
|
46 + | active_connections: Arc<()>,
|
41 47 | }
|
42 48 |
|
43 - | impl TestServer {
|
44 - | /// Return the number of active connections to this server
|
45 - | fn conn_count(&self) -> usize {
|
46 - | // 1 reference for the struct MockProxyServer, 1 reference for the
|
47 - | // socket task.
|
48 - | Arc::strong_count(&self.conn_count)
|
49 - | .checked_sub(2)
|
50 - | .expect("de-count 2 refs")
|
49 + | impl TlsEchoServer {
|
50 + | /// Starts a server advertising HTTP/2 and HTTP/1 protocols.
|
51 + | async fn start() -> Result<Self, BoxError> {
|
52 + | Self::start_with_alpn(&[b"h2", b"http/1.1", b"http/1.0"]).await
|
51 53 | }
|
52 - | }
|
53 - |
|
54 - | async fn server() -> Result<TestServer, BoxError> {
|
55 - | server_with_alpn(&[b"h2", b"http/1.1", b"http/1.0"]).await
|
56 - | }
|
57 - |
|
58 - | async fn server_with_alpn(alpn_protocols: &[&[u8]]) -> Result<TestServer, BoxError> {
|
59 - | let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
|
60 - | let addr = listener.local_addr().unwrap();
|
61 54 |
|
55 + | /// Starts a server advertising the given ALPN protocols in order.
|
56 + | async fn start_with_alpn(alpn_protocols: &[&[u8]]) -> Result<Self, BoxError> {
|
57 + | let listener = TcpListener::bind("127.0.0.1:0").await?;
|
58 + | let addr = listener.local_addr()?;
|
62 59 | debug!("Starting to serve on https://{}", addr);
|
63 60 |
|
64 - | let tls_acceptor = test_tls::server_tls_acceptor(alpn_protocols)?;
|
61 + | let tls_acceptor = test_tls::SERVER_IDENTITY.acceptor(alpn_protocols)?;
|
65 62 | let service = service_fn(echo);
|
63 + | let active_connections = Arc::new(());
|
64 + | let listener_connections = active_connections.clone();
|
66 65 |
|
67 - | let conn_count = Arc::new(());
|
68 - | let server_conn_count = conn_count.clone();
|
69 - |
|
70 - | let server = async move {
|
66 + | let task = tokio::spawn(async move {
|
71 67 | loop {
|
72 68 | let (tcp_stream, remote_addr) = listener.accept().await.unwrap();
|
73 69 | debug!("accepted connection from: {}", remote_addr);
|
74 70 |
|
75 71 | let tls_acceptor = tls_acceptor.clone();
|
76 - | let connection_conn_count = server_conn_count.clone();
|
72 + | let connection = listener_connections.clone();
|
77 73 | tokio::spawn(async move {
|
78 - | let _connection_conn_count = connection_conn_count;
|
74 + | let _connection = connection;
|
79 75 | let tls_stream = match tls_acceptor.accept(tcp_stream).await {
|
80 76 | Ok(tls_stream) => tls_stream,
|
81 77 | Err(err) => {
|
82 78 | error!("failed to perform tls handshake: {err:#}");
|
83 79 | return;
|
84 80 | }
|
85 81 | };
|
86 82 | if let Err(err) = Builder::new(TokioExecutor::new())
|
87 83 | .serve_connection(TokioIo::new(tls_stream), service)
|
88 84 | .await
|
89 85 | {
|
90 86 | error!("failed to serve connection: {err:#}");
|
91 87 | }
|
92 88 | });
|
93 89 | }
|
94 - | };
|
95 - |
|
96 - | let server_task = tokio::spawn(server);
|
90 + | });
|
97 91 |
|
98 - | Ok(TestServer {
|
99 - | _handle: server_task,
|
100 - | listen_addr: addr,
|
101 - | conn_count,
|
92 + | Ok(Self {
|
93 + | task,
|
94 + | addr,
|
95 + | active_connections,
|
102 96 | })
|
97 + | }
|
98 + |
|
99 + | fn addr(&self) -> SocketAddr {
|
100 + | self.addr
|
101 + | }
|
102 + |
|
103 + | /// Returns the number of accepted connections that remain open.
|
104 + | fn active_connection_count(&self) -> usize {
|
105 + | // The server value and listener task each hold one baseline reference.
|
106 + | Arc::strong_count(&self.active_connections)
|
107 + | .checked_sub(2)
|
108 + | .expect("active connection reference count includes both owners")
|
109 + | }
|
110 + | }
|
111 + |
|
112 + | impl Drop for TlsEchoServer {
|
113 + | fn drop(&mut self) {
|
114 + | self.task.abort();
|
115 + | }
|
103 116 | }
|
104 117 |
|
105 - | // Custom echo service, handling two different routes and a
|
106 - | // catch-all 404 responder.
|
118 + | /// Handles the request paths exercised by the TLS contracts.
|
107 119 | async fn echo(req: Request<Incoming>) -> Result<Response<Full<Bytes>>, hyper::Error> {
|
108 120 | let mut response = Response::new(Full::default());
|
109 121 | match (req.method(), req.uri().path()) {
|
110 122 | // default route.
|
111 123 | (&Method::GET, "/") => {
|
112 124 | *response.body_mut() = Full::from("Hello TLS!");
|
113 125 | }
|
114 126 | // echo service route.
|
115 127 | (&Method::POST, "/echo") => {
|
116 128 | *response.body_mut() = Full::from(req.into_body().collect().await?.to_bytes());
|
117 129 | }
|
118 130 | // Catch-all 404.
|
119 131 | _ => {
|
120 132 | *response.status_mut() = StatusCode::NOT_FOUND;
|
121 133 | }
|
122 134 | };
|
123 135 | Ok(response)
|
124 136 | }
|
125 137 |
|
138 + | async fn native_ca_rejects_test_certificate(
|
139 + | backend: &dyn HttpsClientBackend,
|
140 + | provider: tls::Provider,
|
141 + | expected_error: &str,
|
142 + | ) {
|
143 + | let client = backend.build_https(
|
144 + | BackendConfig::default(),
|
145 + | provider,
|
146 + | tls::TlsContext::default(),
|
147 + | );
|
148 + | let error = run_tls_test(&client)
|
149 + | .await
|
150 + | .expect_err("the native trust store must reject the test certificate");
|
151 + | let error = format!("{error:?}");
|
152 + | assert!(
|
153 + | error.contains(expected_error),
|
154 + | "expected TLS error containing {expected_error:?}, got {error}"
|
155 + | );
|
156 + | }
|
157 + |
|
158 + | async fn custom_ca_accepts_test_certificate(
|
159 + | backend: &dyn HttpsClientBackend,
|
160 + | provider: tls::Provider,
|
161 + | ) {
|
162 + | let client = backend.build_https(
|
163 + | BackendConfig::default(),
|
164 + | provider,
|
165 + | test_tls::SERVER_IDENTITY.client_context(),
|
166 + | );
|
167 + | run_tls_test(&client).await.unwrap();
|
168 + | }
|
169 + |
|
170 + | #[cfg(feature = "rustls-aws-lc")]
|
171 + | fn rustls_aws_lc() -> tls::Provider {
|
172 + | tls::Provider::Rustls(tls::rustls_provider::CryptoMode::AwsLc)
|
173 + | }
|
174 + |
|
126 175 | #[cfg(feature = "rustls-aws-lc")]
|
127 - | #[should_panic(expected = "InvalidCertificate(UnknownIssuer)")]
|
128 176 | #[tokio::test]
|
129 - | async fn test_rustls_aws_lc_native_ca() {
|
130 - | let client = aws_smithy_http_client::Builder::new()
|
131 - | .tls_provider(tls::Provider::Rustls(
|
132 - | tls::rustls_provider::CryptoMode::AwsLc,
|
133 - | ))
|
134 - | .build_https();
|
177 + | async fn test_rustls_aws_lc_native_ca_with_hyper_util_legacy_pool() {
|
178 + | native_ca_rejects_test_certificate(
|
179 + | &HyperUtilLegacyPool,
|
180 + | rustls_aws_lc(),
|
181 + | "InvalidCertificate(UnknownIssuer)",
|
182 + | )
|
183 + | .await;
|
184 + | }
|
135 185 |
|
136 - | run_tls_test(&client).await.unwrap()
|
186 + | #[cfg(feature = "rustls-aws-lc")]
|
187 + | #[cfg(feature = "rt-tokio")]
|
188 + | #[tokio::test]
|
189 + | async fn test_rustls_aws_lc_native_ca_with_partitioned_connection_pool() {
|
190 + | native_ca_rejects_test_certificate(
|
191 + | &PartitionedConnectionPool,
|
192 + | rustls_aws_lc(),
|
193 + | "InvalidCertificate(UnknownIssuer)",
|
194 + | )
|
195 + | .await;
|
137 196 | }
|
138 197 |
|
139 198 | #[cfg(feature = "rustls-aws-lc")]
|
140 199 | #[tokio::test]
|
141 - | async fn test_rustls_aws_lc_custom_ca() {
|
142 - | let client = aws_smithy_http_client::Builder::new()
|
143 - | .tls_provider(tls::Provider::Rustls(
|
144 - | tls::rustls_provider::CryptoMode::AwsLc,
|
145 - | ))
|
146 - | .tls_context(test_tls::server_tls_context())
|
147 - | .build_https();
|
200 + | async fn test_rustls_aws_lc_custom_ca_with_hyper_util_legacy_pool() {
|
201 + | custom_ca_accepts_test_certificate(&HyperUtilLegacyPool, rustls_aws_lc()).await;
|
202 + | }
|
148 203 |
|
149 - | run_tls_test(&client).await.unwrap()
|
204 + | #[cfg(feature = "rustls-aws-lc")]
|
205 + | #[cfg(feature = "rt-tokio")]
|
206 + | #[tokio::test]
|
207 + | async fn test_rustls_aws_lc_custom_ca_with_partitioned_connection_pool() {
|
208 + | custom_ca_accepts_test_certificate(&PartitionedConnectionPool, rustls_aws_lc()).await;
|
150 209 | }
|
151 210 |
|
152 211 | #[cfg(all(feature = "rustls-aws-lc", feature = "rt-tokio"))]
|
153 212 | #[tokio::test]
|
154 213 | async fn partitioned_pool_falls_back_to_h1_after_alpn() {
|
155 - | let server = server_with_alpn(&[b"http/1.1"]).await.unwrap();
|
214 + | let server = TlsEchoServer::start_with_alpn(&[b"http/1.1"])
|
215 + | .await
|
216 + | .unwrap();
|
156 217 | let pool = ConnectionPool::builder()
|
157 218 | .tls_provider(tls::Provider::Rustls(
|
158 219 | tls::rustls_provider::CryptoMode::AwsLc,
|
159 220 | ))
|
160 - | .tls_context(test_tls::server_tls_context())
|
221 + | .tls_context(test_tls::SERVER_IDENTITY.client_context())
|
161 222 | .build_https()
|
162 223 | .expect("valid HTTPS pool");
|
163 224 | let client = PoolClient::new(&pool).expect("anonymous partition exists");
|
164 225 | let connector_settings = HttpConnectorSettings::builder().build();
|
165 226 | let runtime_components = RuntimeComponentsBuilder::for_tests()
|
166 227 | .with_time_source(Some(SystemTimeSource::new()))
|
167 228 | .build()
|
168 229 | .unwrap();
|
169 230 | let connector = client.http_connector(&connector_settings, &runtime_components);
|
170 - | let endpoint = format!("https://localhost:{}/", server.listen_addr.port());
|
231 + | let endpoint = format!("https://localhost:{}/", server.addr().port());
|
171 232 |
|
172 233 | for _ in 0..2 {
|
173 234 | let mut response = connector
|
174 235 | .call(HttpRequest::get(&endpoint).unwrap())
|
175 236 | .await
|
176 237 | .expect("HTTP/1 request over TLS should succeed");
|
177 238 | let body = ByteStream::new(response.take_body())
|
178 239 | .collect()
|
179 240 | .await
|
180 241 | .expect("response body should be readable")
|
181 242 | .into_bytes();
|
182 243 | assert_eq!(b"Hello TLS!", &body[..]);
|
183 244 | }
|
184 - | assert_eq!(1, server.conn_count());
|
245 + | assert_eq!(1, server.active_connection_count());
|
185 246 | }
|
186 247 |
|
187 248 | #[cfg(all(feature = "rustls-aws-lc", feature = "rt-tokio"))]
|
188 249 | #[tokio::test]
|
189 250 | async fn partitioned_pool_narrows_alpn_for_h1_required_request() {
|
190 - | let server = server_with_alpn(&[b"h2", b"http/1.1"]).await.unwrap();
|
251 + | let server = TlsEchoServer::start_with_alpn(&[b"h2", b"http/1.1"])
|
252 + | .await
|
253 + | .unwrap();
|
191 254 | let pool = ConnectionPool::builder()
|
192 255 | .tls_provider(tls::Provider::Rustls(
|
193 256 | tls::rustls_provider::CryptoMode::AwsLc,
|
194 257 | ))
|
195 - | .tls_context(test_tls::server_tls_context())
|
258 + | .tls_context(test_tls::SERVER_IDENTITY.client_context())
|
196 259 | .build_https()
|
197 260 | .expect("valid HTTPS pool");
|
198 261 | let client = PoolClient::new(&pool).expect("anonymous partition exists");
|
199 262 | let connector_settings = HttpConnectorSettings::builder().build();
|
200 263 | let runtime_components = RuntimeComponentsBuilder::for_tests()
|
201 264 | .with_time_source(Some(SystemTimeSource::new()))
|
202 265 | .build()
|
203 266 | .unwrap();
|
204 267 | let connector = client.http_connector(&connector_settings, &runtime_components);
|
205 - | let endpoint = format!("https://localhost:{}/", server.listen_addr.port());
|
268 + | let endpoint = format!("https://localhost:{}/", server.addr().port());
|
206 269 | let mut request = HttpRequest::new(ByteStream::default().into_inner());
|
207 270 | request
|
208 271 | .set_method("CONNECT")
|
209 272 | .expect("CONNECT is a valid HTTP method");
|
210 273 | request
|
211 274 | .set_uri(endpoint.as_str())
|
212 275 | .expect("valid server URI");
|
213 276 |
|
214 277 | let response = connector
|
215 278 | .call(request)
|
216 279 | .await
|
217 280 | .expect("HTTP/1-required request should narrow the ALPN offer");
|
218 281 |
|
219 282 | assert_eq!(StatusCode::NOT_FOUND.as_u16(), response.status().as_u16());
|
220 - | assert_eq!(1, server.conn_count());
|
283 + | assert_eq!(1, server.active_connection_count());
|
221 284 | }
|
222 285 |
|
223 286 | #[cfg(feature = "rustls-aws-lc")]
|
224 - | #[tokio::test(start_paused = false)]
|
225 - | // can't have paused clock due to <https://github.com/hyperium/hyper/issues/3950>
|
226 - | async fn test_rustls_aws_lc_custom_ca_with_timeout() {
|
287 + | async fn custom_ca_connection_obeys_idle_timeout(backend: &dyn HttpsClientBackend) {
|
227 288 | const TIMEOUT: Duration = Duration::from_secs(10);
|
228 - | let client = aws_smithy_http_client::Builder::new()
|
229 - | .pool_idle_timeout(TIMEOUT)
|
230 - | .tls_provider(tls::Provider::Rustls(
|
231 - | tls::rustls_provider::CryptoMode::AwsLc,
|
232 - | ))
|
233 - | .tls_context(test_tls::server_tls_context())
|
234 - | .build_https();
|
235 - |
|
289 + | let client = backend.build_https(
|
290 + | BackendConfig {
|
291 + | pool_idle_timeout: Some(TIMEOUT),
|
292 + | ..Default::default()
|
293 + | },
|
294 + | rustls_aws_lc(),
|
295 + | test_tls::SERVER_IDENTITY.client_context(),
|
296 + | );
|
236 297 | run_tls_test_with_idle_timeout(&client, Some(TIMEOUT))
|
237 298 | .await
|
238 - | .unwrap()
|
299 + | .unwrap();
|
300 + | }
|
301 + |
|
302 + | #[cfg(feature = "rustls-aws-lc")]
|
303 + | #[tokio::test(start_paused = false)]
|
304 + | // can't have paused clock due to <https://github.com/hyperium/hyper/issues/3950>
|
305 + | async fn test_rustls_aws_lc_custom_ca_idle_timeout_with_hyper_util_legacy_pool() {
|
306 + | custom_ca_connection_obeys_idle_timeout(&HyperUtilLegacyPool).await;
|
307 + | }
|
308 + |
|
309 + | #[cfg(feature = "rustls-aws-lc")]
|
310 + | #[cfg(feature = "rt-tokio")]
|
311 + | #[tokio::test(start_paused = false)]
|
312 + | // can't have paused clock due to <https://github.com/hyperium/hyper/issues/3950>
|
313 + | async fn test_rustls_aws_lc_custom_ca_idle_timeout_with_partitioned_connection_pool() {
|
314 + | custom_ca_connection_obeys_idle_timeout(&PartitionedConnectionPool).await;
|
315 + | }
|
316 + |
|
317 + | #[cfg(feature = "rustls-aws-lc-fips")]
|
318 + | fn rustls_aws_lc_fips() -> tls::Provider {
|
319 + | tls::Provider::Rustls(tls::rustls_provider::CryptoMode::AwsLcFips)
|
239 320 | }
|
240 321 |
|
241 322 | #[cfg(feature = "rustls-aws-lc-fips")]
|
242 - | #[should_panic(expected = "InvalidCertificate(UnknownIssuer)")]
|
243 323 | #[tokio::test]
|
244 - | async fn test_rustls_aws_lc_fips_native_ca() {
|
245 - | let client = aws_smithy_http_client::Builder::new()
|
246 - | .tls_provider(tls::Provider::Rustls(
|
247 - | tls::rustls_provider::CryptoMode::AwsLcFips,
|
248 - | ))
|
249 - | .build_https();
|
324 + | async fn test_rustls_aws_lc_fips_native_ca_with_hyper_util_legacy_pool() {
|
325 + | native_ca_rejects_test_certificate(
|
326 + | &HyperUtilLegacyPool,
|
327 + | rustls_aws_lc_fips(),
|
328 + | "InvalidCertificate(UnknownIssuer)",
|
329 + | )
|
330 + | .await;
|
331 + | }
|
250 332 |
|
251 - | run_tls_test(&client).await.unwrap()
|
333 + | #[cfg(feature = "rustls-aws-lc-fips")]
|
334 + | #[cfg(feature = "rt-tokio")]
|
335 + | #[tokio::test]
|
336 + | async fn test_rustls_aws_lc_fips_native_ca_with_partitioned_connection_pool() {
|
337 + | native_ca_rejects_test_certificate(
|
338 + | &PartitionedConnectionPool,
|
339 + | rustls_aws_lc_fips(),
|
340 + | "InvalidCertificate(UnknownIssuer)",
|
341 + | )
|
342 + | .await;
|
252 343 | }
|
253 344 |
|
254 345 | #[cfg(feature = "rustls-aws-lc-fips")]
|
255 346 | #[tokio::test]
|
256 - | async fn test_rustls_aws_lc_fips_custom_ca() {
|
257 - | let client = aws_smithy_http_client::Builder::new()
|
258 - | .tls_provider(tls::Provider::Rustls(
|
259 - | tls::rustls_provider::CryptoMode::AwsLcFips,
|
260 - | ))
|
261 - | .tls_context(test_tls::server_tls_context())
|
262 - | .build_https();
|
347 + | async fn test_rustls_aws_lc_fips_custom_ca_with_hyper_util_legacy_pool() {
|
348 + | custom_ca_accepts_test_certificate(&HyperUtilLegacyPool, rustls_aws_lc_fips()).await;
|
349 + | }
|
263 350 |
|
264 - | run_tls_test(&client).await.unwrap()
|
351 + | #[cfg(feature = "rustls-aws-lc-fips")]
|
352 + | #[cfg(feature = "rt-tokio")]
|
353 + | #[tokio::test]
|
354 + | async fn test_rustls_aws_lc_fips_custom_ca_with_partitioned_connection_pool() {
|
355 + | custom_ca_accepts_test_certificate(&PartitionedConnectionPool, rustls_aws_lc_fips()).await;
|
356 + | }
|
357 + |
|
358 + | #[cfg(feature = "rustls-ring")]
|
359 + | fn rustls_ring() -> tls::Provider {
|
360 + | tls::Provider::Rustls(tls::rustls_provider::CryptoMode::Ring)
|
265 361 | }
|
266 362 |
|
267 363 | #[cfg(feature = "rustls-ring")]
|
268 - | #[should_panic(expected = "InvalidCertificate(UnknownIssuer)")]
|
269 364 | #[tokio::test]
|
270 - | async fn test_rustls_ring_native_ca() {
|
271 - | let client = aws_smithy_http_client::Builder::new()
|
272 - | .tls_provider(tls::Provider::Rustls(
|
273 - | tls::rustls_provider::CryptoMode::Ring,
|
274 - | ))
|
275 - | .build_https();
|
365 + | async fn test_rustls_ring_native_ca_with_hyper_util_legacy_pool() {
|
366 + | native_ca_rejects_test_certificate(
|
367 + | &HyperUtilLegacyPool,
|
368 + | rustls_ring(),
|
369 + | "InvalidCertificate(UnknownIssuer)",
|
370 + | )
|
371 + | .await;
|
372 + | }
|
276 373 |
|
277 - | run_tls_test(&client).await.unwrap()
|
374 + | #[cfg(feature = "rustls-ring")]
|
375 + | #[cfg(feature = "rt-tokio")]
|
376 + | #[tokio::test]
|
377 + | async fn test_rustls_ring_native_ca_with_partitioned_connection_pool() {
|
378 + | native_ca_rejects_test_certificate(
|
379 + | &PartitionedConnectionPool,
|
380 + | rustls_ring(),
|
381 + | "InvalidCertificate(UnknownIssuer)",
|
382 + | )
|
383 + | .await;
|
278 384 | }
|
279 385 |
|
280 386 | #[cfg(feature = "rustls-ring")]
|
281 387 | #[tokio::test]
|
282 - | async fn test_rustls_ring_custom_ca() {
|
283 - | let client = aws_smithy_http_client::Builder::new()
|
284 - | .tls_provider(tls::Provider::Rustls(
|
285 - | tls::rustls_provider::CryptoMode::Ring,
|
286 - | ))
|
287 - | .tls_context(test_tls::server_tls_context())
|
288 - | .build_https();
|
388 + | async fn test_rustls_ring_custom_ca_with_hyper_util_legacy_pool() {
|
389 + | custom_ca_accepts_test_certificate(&HyperUtilLegacyPool, rustls_ring()).await;
|
390 + | }
|
289 391 |
|
290 - | run_tls_test(&client).await.unwrap()
|
392 + | #[cfg(feature = "rustls-ring")]
|
393 + | #[cfg(feature = "rt-tokio")]
|
394 + | #[tokio::test]
|
395 + | async fn test_rustls_ring_custom_ca_with_partitioned_connection_pool() {
|
396 + | custom_ca_accepts_test_certificate(&PartitionedConnectionPool, rustls_ring()).await;
|
291 397 | }
|
292 398 |
|
293 399 | #[cfg(all(aws_sdk_unstable, feature = "rustls-ring"))]
|
294 - | #[should_panic(expected = "InvalidCertificate(UnknownIssuer)")]
|
295 - | #[tokio::test]
|
296 - | async fn test_rustls_custom_provider_native_ca() {
|
297 - | let provider = rustls::crypto::ring::default_provider();
|
298 - | let client = aws_smithy_http_client::Builder::new()
|
299 - | .tls_provider(tls::Provider::Rustls(
|
300 - | tls::rustls_provider::CryptoMode::Custom(provider),
|
400 + | fn rustls_custom_provider() -> tls::Provider {
|
401 + | tls::Provider::Rustls(tls::rustls_provider::CryptoMode::Custom(
|
402 + | rustls::crypto::ring::default_provider(),
|
301 403 | ))
|
302 - | .build_https();
|
303 - |
|
304 - | run_tls_test(&client).await.unwrap()
|
305 404 | }
|
306 405 |
|
307 406 | #[cfg(all(aws_sdk_unstable, feature = "rustls-ring"))]
|
308 407 | #[tokio::test]
|
309 - | async fn test_rustls_custom_provider_custom_ca() {
|
310 - | let ring_provider = rustls::crypto::ring::default_provider();
|
311 - | let client = aws_smithy_http_client::Builder::new()
|
312 - | .tls_provider(tls::Provider::Rustls(
|
313 - | tls::rustls_provider::CryptoMode::Custom(ring_provider),
|
314 - | ))
|
315 - | .tls_context(test_tls::server_tls_context())
|
316 - | .build_https();
|
317 - | run_tls_test(&client).await.unwrap()
|
408 + | async fn test_rustls_custom_provider_native_ca_with_hyper_util_legacy_pool() {
|
409 + | native_ca_rejects_test_certificate(
|
410 + | &HyperUtilLegacyPool,
|
411 + | rustls_custom_provider(),
|
412 + | "InvalidCertificate(UnknownIssuer)",
|
413 + | )
|
414 + | .await;
|
318 415 | }
|
319 416 |
|
320 - | #[cfg(feature = "s2n-tls")]
|
321 - | #[should_panic(expected = "Certificate is untrusted")]
|
417 + | #[cfg(all(aws_sdk_unstable, feature = "rustls-ring"))]
|
418 + | #[cfg(feature = "rt-tokio")]
|
322 419 | #[tokio::test]
|
323 - | async fn test_s2n_native_ca() {
|
324 - | let client = aws_smithy_http_client::Builder::new()
|
325 - | .tls_provider(tls::Provider::S2nTls)
|
326 - | .build_https();
|
327 - |
|
328 - | run_tls_test(&client).await.unwrap()
|
420 + | async fn test_rustls_custom_provider_native_ca_with_partitioned_connection_pool() {
|
421 + | native_ca_rejects_test_certificate(
|
422 + | &PartitionedConnectionPool,
|
423 + | rustls_custom_provider(),
|
424 + | "InvalidCertificate(UnknownIssuer)",
|
425 + | )
|
426 + | .await;
|
329 427 | }
|
330 428 |
|
331 - | #[cfg(feature = "s2n-tls")]
|
429 + | #[cfg(all(aws_sdk_unstable, feature = "rustls-ring"))]
|
332 430 | #[tokio::test]
|
333 - | async fn test_s2n_tls_custom_ca() {
|
334 - | let client = aws_smithy_http_client::Builder::new()
|
335 - | .tls_provider(tls::Provider::S2nTls)
|
336 - | .tls_context(test_tls::server_tls_context())
|
337 - | .build_https();
|
338 - | run_tls_test(&client).await.unwrap()
|
431 + | async fn test_rustls_custom_provider_custom_ca_with_hyper_util_legacy_pool() {
|
432 + | custom_ca_accepts_test_certificate(&HyperUtilLegacyPool, rustls_custom_provider()).await;
|
339 433 | }
|
340 434 |
|
341 - | // Test: connecting to 127.0.0.1 fails (cert SANs only contain "localhost" and "sdktest.com")
|
342 - | #[cfg(feature = "rustls-aws-lc")]
|
343 - | #[should_panic(expected = "InvalidCertificate")]
|
435 + | #[cfg(all(aws_sdk_unstable, feature = "rustls-ring"))]
|
436 + | #[cfg(feature = "rt-tokio")]
|
344 437 | #[tokio::test]
|
345 - | async fn test_additional_server_names_ip_without_alt_names_fails() {
|
346 - | let client = aws_smithy_http_client::Builder::new()
|
347 - | .tls_provider(tls::Provider::Rustls(
|
348 - | tls::rustls_provider::CryptoMode::AwsLc,
|
349 - | ))
|
350 - | .tls_context(test_tls::server_tls_context())
|
351 - | .build_https();
|
352 - |
|
353 - | run_tls_test_to_ip(&client).await.unwrap()
|
438 + | async fn test_rustls_custom_provider_custom_ca_with_partitioned_connection_pool() {
|
439 + | custom_ca_accepts_test_certificate(&PartitionedConnectionPool, rustls_custom_provider()).await;
|
354 440 | }
|
355 441 |
|
356 - | // Test: connecting to 127.0.0.1 with a non-matching additional server name fails (cert SANs only contain "localhost" and "sdktest.com")
|
357 - | #[cfg(feature = "rustls-aws-lc")]
|
358 - | #[should_panic(expected = "InvalidCertificate")]
|
442 + | #[cfg(feature = "s2n-tls")]
|
359 443 | #[tokio::test]
|
360 - | async fn test_additional_server_names_with_wrong_alt_name_fails() {
|
361 - | let client = aws_smithy_http_client::Builder::new()
|
362 - | .tls_provider(tls::Provider::Rustls(
|
363 - | tls::rustls_provider::CryptoMode::AwsLc,
|
364 - | ))
|
365 - | .tls_context(server_tls_context_with_additional_server_names(&[
|
366 - | "wrong.example.com",
|
367 - | ]))
|
368 - | .build_https();
|
369 - |
|
370 - | run_tls_test_to_ip(&client).await.unwrap()
|
444 + | async fn test_s2n_native_ca_with_hyper_util_legacy_pool() {
|
445 + | native_ca_rejects_test_certificate(
|
446 + | &HyperUtilLegacyPool,
|
447 + | tls::Provider::S2nTls,
|
448 + | "Certificate is untrusted",
|
449 + | )
|
450 + | .await;
|
371 451 | }
|
372 452 |
|
373 - | // Test: connecting to 127.0.0.1 succeeds when "localhost" is configured as an additional server name
|
374 - | #[cfg(feature = "rustls-aws-lc")]
|
453 + | #[cfg(feature = "s2n-tls")]
|
454 + | #[cfg(feature = "rt-tokio")]
|
375 455 | #[tokio::test]
|
376 - | async fn test_additional_server_names_with_matching_alt_name_succeeds() {
|
377 - | let client = aws_smithy_http_client::Builder::new()
|
378 - | .tls_provider(tls::Provider::Rustls(
|
379 - | tls::rustls_provider::CryptoMode::AwsLc,
|
380 - | ))
|
381 - | .tls_context(server_tls_context_with_additional_server_names(&[
|
382 - | "localhost",
|
383 - | ]))
|
384 - | .build_https();
|
385 - |
|
386 - | run_tls_test_to_ip(&client).await.unwrap()
|
456 + | async fn test_s2n_native_ca_with_partitioned_connection_pool() {
|
457 + | native_ca_rejects_test_certificate(
|
458 + | &PartitionedConnectionPool,
|
459 + | tls::Provider::S2nTls,
|
460 + | "Certificate is untrusted",
|
461 + | )
|
462 + | .await;
|
387 463 | }
|
388 464 |
|
389 - | // Test: connecting to localhost (which matches the cert) still works when additional server names are configured
|
390 - | #[cfg(feature = "rustls-aws-lc")]
|
465 + | #[cfg(feature = "s2n-tls")]
|
391 466 | #[tokio::test]
|
392 - | async fn test_additional_server_names_primary_name_still_works() {
|
393 - | let client = aws_smithy_http_client::Builder::new()
|
394 - | .tls_provider(tls::Provider::Rustls(
|
395 - | tls::rustls_provider::CryptoMode::AwsLc,
|
396 - | ))
|
397 - | .tls_context(server_tls_context_with_additional_server_names(&[
|
398 - | "sdktest.com",
|
399 - | ]))
|
400 - | .build_https();
|
401 - |
|
402 - | // Connect via localhost — primary name verification should pass without needing the fallback
|
403 - | run_tls_test(&client).await.unwrap()
|
467 + | async fn test_s2n_tls_custom_ca_with_hyper_util_legacy_pool() {
|
468 + | custom_ca_accepts_test_certificate(&HyperUtilLegacyPool, tls::Provider::S2nTls).await;
|
404 469 | }
|
405 470 |
|
406 - | /// A [`TlsContext`] trusting the test server certificate and accepting the given
|
407 - | /// names in addition to the one the request is addressed to.
|
408 - | ///
|
409 - | /// The test certificate's SANs are `localhost` and `sdktest.com`, so a request to
|
410 - | /// `127.0.0.1` only passes verification when one of those is supplied here.
|
411 - | #[cfg(any(feature = "rustls-aws-lc", feature = "s2n-tls"))]
|
412 - | fn server_tls_context_with_additional_server_names(additional_server_names: &[&str]) -> TlsContext {
|
413 - | let additional_server_names = additional_server_names
|
414 - | .iter()
|
415 - | .map(|name| {
|
416 - | ServerName::try_from(name.to_string()).expect("additional server name is valid")
|
417 - | })
|
418 - | .collect();
|
419 - | TlsContext::builder()
|
420 - | .with_trust_store(test_tls::server_trust_store())
|
421 - | .with_additional_server_names(additional_server_names)
|
422 - | .build()
|
423 - | .expect("failed to build TlsContext with test server certificate")
|
471 + | #[cfg(feature = "s2n-tls")]
|
472 + | #[cfg(feature = "rt-tokio")]
|
473 + | #[tokio::test]
|
474 + | async fn test_s2n_tls_custom_ca_with_partitioned_connection_pool() {
|
475 + | custom_ca_accepts_test_certificate(&PartitionedConnectionPool, tls::Provider::S2nTls).await;
|
424 476 | }
|
425 477 |
|
426 478 | async fn run_tls_test(client: &dyn HttpClient) -> Result<(), BoxError> {
|
427 479 | run_tls_test_with_idle_timeout(client, None).await
|
428 480 | }
|
429 481 |
|
430 482 | async fn run_tls_test_with_idle_timeout(
|
431 483 | client: &dyn HttpClient,
|
432 484 | pool_timeout: Option<Duration>,
|
433 485 | ) -> Result<(), BoxError> {
|
434 - | let server = server().await?;
|
486 + | let server = TlsEchoServer::start().await?;
|
435 487 | let start = tokio::time::Instant::now();
|
436 - | assert_eq!(server.conn_count(), 0); // calibrate conn_count
|
437 - | let endpoint = format!("https://localhost:{}/", server.listen_addr.port());
|
488 + | assert_eq!(server.active_connection_count(), 0);
|
489 + | let endpoint = format!("https://localhost:{}/", server.addr().port());
|
438 490 |
|
439 491 | let connector_settings = HttpConnectorSettings::builder().build();
|
440 492 | let runtime_components = RuntimeComponentsBuilder::for_tests()
|
441 493 | .with_time_source(Some(SystemTimeSource::new()))
|
442 494 | .build()
|
443 495 | .unwrap();
|
444 496 | let connector = client.http_connector(&connector_settings, &runtime_components);
|
445 497 | let mut response = connector.call(HttpRequest::get(endpoint).unwrap()).await?;
|
446 498 |
|
447 499 | let sdk_body = response.take_body();
|
448 500 | let body_stream = ByteStream::new(sdk_body);
|
449 501 | let resp_bytes = body_stream.collect().await?.into_bytes();
|
450 502 | assert_eq!(b"Hello TLS!", &resp_bytes[..]);
|
451 503 |
|
452 504 | if let Some(pool_timeout) = pool_timeout {
|
453 - | assert_eq!(server.conn_count(), 1);
|
505 + | assert_eq!(server.active_connection_count(), 1);
|
454 506 | tokio::time::sleep_until(start + pool_timeout - Duration::from_secs(1)).await;
|
455 - | assert_eq!(server.conn_count(), 1);
|
507 + | assert_eq!(server.active_connection_count(), 1);
|
456 508 | tokio::time::sleep(Duration::from_secs(2)).await;
|
457 - | assert_eq!(server.conn_count(), 0);
|
509 + | assert_eq!(server.active_connection_count(), 0);
|
458 510 | }
|
459 511 | Ok(())
|
460 512 | }
|
461 513 |
|
462 514 | /// Like `run_tls_test` but connects via 127.0.0.1 instead of localhost.
|
463 515 | /// The test cert's SANs only include "localhost" and "sdktest.com", so
|
464 516 | /// connecting by IP will fail hostname verification unless additional
|
465 517 | /// server names are configured.
|
466 518 | #[cfg(any(feature = "rustls-aws-lc", feature = "s2n-tls"))]
|
467 519 | async fn run_tls_test_to_ip(client: &dyn HttpClient) -> Result<(), BoxError> {
|
468 - | let server = server().await?;
|
469 - | let endpoint = format!("https://127.0.0.1:{}/", server.listen_addr.port());
|
520 + | let server = TlsEchoServer::start().await?;
|
521 + | let endpoint = format!("https://127.0.0.1:{}/", server.addr().port());
|
470 522 |
|
471 523 | let connector_settings = HttpConnectorSettings::builder().build();
|
472 524 | let runtime_components = RuntimeComponentsBuilder::for_tests()
|
473 525 | .with_time_source(Some(SystemTimeSource::new()))
|
474 526 | .build()
|
475 527 | .unwrap();
|
476 528 | let connector = client.http_connector(&connector_settings, &runtime_components);
|
477 529 | let mut response = connector.call(HttpRequest::get(endpoint).unwrap()).await?;
|
478 530 |
|
479 531 | let sdk_body = response.take_body();
|
480 532 | let body_stream = ByteStream::new(sdk_body);
|
481 533 | let resp_bytes = body_stream.collect().await?.into_bytes();
|
482 534 | assert_eq!(b"Hello TLS!", &resp_bytes[..]);
|
483 535 | Ok(())
|
484 536 | }
|
485 537 |
|
486 - | // Test: connecting to 127.0.0.1 fails with s2n-tls (cert SANs only contain "localhost" and "sdktest.com")
|
487 - | #[cfg(feature = "s2n-tls")]
|
488 - | #[should_panic(expected = "Certificate is not valid for the supplied hostname")]
|
489 - | #[tokio::test]
|
490 - | async fn test_s2n_additional_server_names_ip_without_alt_names_fails() {
|
491 - | let client = aws_smithy_http_client::Builder::new()
|
492 - | .tls_provider(tls::Provider::S2nTls)
|
493 - | .tls_context(test_tls::server_tls_context())
|
494 - | .build_https();
|
538 + | #[cfg(any(feature = "rustls-aws-lc", feature = "s2n-tls"))]
|
539 + | mod additional_server_names {
|
540 + | //! Certificate-name contracts for each TLS provider and client backend.
|
495 541 |
|
496 - | run_tls_test_to_ip(&client).await.unwrap()
|
497 - | }
|
542 + | use super::*;
|
498 543 |
|
499 - | // Test: connecting to 127.0.0.1 with a non-matching additional server name fails with s2n-tls
|
500 - | #[cfg(feature = "s2n-tls")]
|
501 - | #[should_panic(expected = "Certificate is not valid for the supplied hostname")]
|
502 - | #[tokio::test]
|
503 - | async fn test_s2n_additional_server_names_with_wrong_alt_name_fails() {
|
504 - | let client = aws_smithy_http_client::Builder::new()
|
505 - | .tls_provider(tls::Provider::S2nTls)
|
506 - | .tls_context(server_tls_context_with_additional_server_names(&[
|
507 - | "wrong.example.com",
|
508 - | ]))
|
509 - | .build_https();
|
544 + | fn client_context(additional_server_names: &[&str]) -> TlsContext {
|
545 + | let additional_server_names = additional_server_names
|
546 + | .iter()
|
547 + | .map(|name| {
|
548 + | ServerName::try_from(name.to_string()).expect("additional server name is valid")
|
549 + | })
|
550 + | .collect();
|
551 + | test_tls::SERVER_IDENTITY
|
552 + | .client_context_builder()
|
553 + | .with_additional_server_names(additional_server_names)
|
554 + | .build()
|
555 + | .expect("additional server names produce a valid client context")
|
556 + | }
|
510 557 |
|
511 - | run_tls_test_to_ip(&client).await.unwrap()
|
512 - | }
|
558 + | async fn assert_ip_rejected(
|
559 + | backend: &dyn HttpsClientBackend,
|
560 + | provider: tls::Provider,
|
561 + | tls_context: TlsContext,
|
562 + | expected_error: &str,
|
563 + | ) {
|
564 + | let client = backend.build_https(BackendConfig::default(), provider, tls_context);
|
565 + | let error = run_tls_test_to_ip(&client)
|
566 + | .await
|
567 + | .expect_err("the certificate must not validate for the request IP");
|
568 + | let error = format!("{error:?}");
|
569 + | assert!(
|
570 + | error.contains(expected_error),
|
571 + | "expected TLS error containing {expected_error:?}, got {error}"
|
572 + | );
|
573 + | }
|
513 574 |
|
514 - | // Test: connecting to 127.0.0.1 succeeds with s2n-tls when "localhost" is configured as an additional server name
|
515 - | #[cfg(feature = "s2n-tls")]
|
516 - | #[tokio::test]
|
517 - | async fn test_s2n_additional_server_names_with_matching_alt_name_succeeds() {
|
518 - | let client = aws_smithy_http_client::Builder::new()
|
519 - | .tls_provider(tls::Provider::S2nTls)
|
520 - | .tls_context(server_tls_context_with_additional_server_names(&[
|
521 - | "localhost",
|
522 - | ]))
|
523 - | .build_https();
|
575 + | async fn assert_ip_accepted(backend: &dyn HttpsClientBackend, provider: tls::Provider) {
|
576 + | let client = backend.build_https(
|
577 + | BackendConfig::default(),
|
578 + | provider,
|
579 + | client_context(&["localhost"]),
|
580 + | );
|
581 + | run_tls_test_to_ip(&client).await.unwrap();
|
582 + | }
|
524 583 |
|
525 - | run_tls_test_to_ip(&client).await.unwrap()
|
526 - | }
|
584 + | async fn assert_primary_name_accepted(
|
585 + | backend: &dyn HttpsClientBackend,
|
586 + | provider: tls::Provider,
|
587 + | ) {
|
588 + | let client = backend.build_https(
|
589 + | BackendConfig::default(),
|
590 + | provider,
|
591 + | client_context(&["sdktest.com"]),
|
592 + | );
|
593 + | run_tls_test(&client).await.unwrap();
|
594 + | }
|
527 595 |
|
528 - | // Test: connecting to localhost (which matches the cert) still works with s2n-tls when additional server names are configured
|
529 - | #[cfg(feature = "s2n-tls")]
|
530 - | #[tokio::test]
|
531 - | async fn test_s2n_additional_server_names_primary_name_still_works() {
|
532 - | let client = aws_smithy_http_client::Builder::new()
|
533 - | .tls_provider(tls::Provider::S2nTls)
|
534 - | .tls_context(server_tls_context_with_additional_server_names(&[
|
535 - | "sdktest.com",
|
536 - | ]))
|
537 - | .build_https();
|
538 - |
|
539 - | // Connect via localhost — primary name verification should pass without needing the fallback
|
540 - | run_tls_test(&client).await.unwrap()
|
596 + | #[cfg(feature = "rustls-aws-lc")]
|
597 + | mod rustls_aws_lc {
|
598 + | use super::*;
|
599 + | use crate::rustls_aws_lc as provider;
|
600 + |
|
601 + | const CERTIFICATE_ERROR: &str = "InvalidCertificate";
|
602 + |
|
603 + | async fn missing_name_is_rejected(backend: &dyn HttpsClientBackend) {
|
604 + | assert_ip_rejected(
|
605 + | backend,
|
606 + | provider(),
|
607 + | test_tls::SERVER_IDENTITY.client_context(),
|
608 + | CERTIFICATE_ERROR,
|
609 + | )
|
610 + | .await;
|
611 + | }
|
612 + |
|
613 + | async fn wrong_name_is_rejected(backend: &dyn HttpsClientBackend) {
|
614 + | assert_ip_rejected(
|
615 + | backend,
|
616 + | provider(),
|
617 + | client_context(&["wrong.example.com"]),
|
618 + | CERTIFICATE_ERROR,
|
619 + | )
|
620 + | .await;
|
621 + | }
|
622 + |
|
623 + | async fn matching_name_is_accepted(backend: &dyn HttpsClientBackend) {
|
624 + | assert_ip_accepted(backend, provider()).await;
|
625 + | }
|
626 + |
|
627 + | async fn primary_name_is_preserved(backend: &dyn HttpsClientBackend) {
|
628 + | assert_primary_name_accepted(backend, provider()).await;
|
629 + | }
|
630 + |
|
631 + | mod hyper_util_legacy_pool {
|
632 + | use super::*;
|
633 + |
|
634 + | #[tokio::test]
|
635 + | async fn test_missing_name_is_rejected() {
|
636 + | missing_name_is_rejected(&HyperUtilLegacyPool).await;
|
637 + | }
|
638 + |
|
639 + | #[tokio::test]
|
640 + | async fn test_wrong_name_is_rejected() {
|
641 + | wrong_name_is_rejected(&HyperUtilLegacyPool).await;
|
642 + | }
|
643 + |
|
644 + | #[tokio::test]
|
645 + | async fn test_matching_name_is_accepted() {
|
646 + | matching_name_is_accepted(&HyperUtilLegacyPool).await;
|
647 + | }
|
648 + |
|
649 + | #[tokio::test]
|
650 + | async fn test_primary_name_is_preserved() {
|
651 + | primary_name_is_preserved(&HyperUtilLegacyPool).await;
|
652 + | }
|
653 + | }
|
654 + |
|
655 + | #[cfg(feature = "rt-tokio")]
|
656 + | mod partitioned_connection_pool {
|
657 + | use super::*;
|
658 + |
|
659 + | #[tokio::test]
|
660 + | async fn test_missing_name_is_rejected() {
|
661 + | missing_name_is_rejected(&PartitionedConnectionPool).await;
|
662 + | }
|
663 + |
|
664 + | #[tokio::test]
|
665 + | async fn test_wrong_name_is_rejected() {
|
666 + | wrong_name_is_rejected(&PartitionedConnectionPool).await;
|
667 + | }
|
668 + |
|
669 + | #[tokio::test]
|
670 + | async fn test_matching_name_is_accepted() {
|
671 + | matching_name_is_accepted(&PartitionedConnectionPool).await;
|
672 + | }
|
673 + |
|
674 + | #[tokio::test]
|
675 + | async fn test_primary_name_is_preserved() {
|
676 + | primary_name_is_preserved(&PartitionedConnectionPool).await;
|
677 + | }
|
678 + | }
|
679 + | }
|
680 + |
|
681 + | #[cfg(feature = "s2n-tls")]
|
682 + | mod s2n_tls {
|
683 + | use super::*;
|
684 + |
|
685 + | const CERTIFICATE_ERROR: &str = "Certificate is not valid for the supplied hostname";
|
686 + |
|
687 + | async fn missing_name_is_rejected(backend: &dyn HttpsClientBackend) {
|
688 + | assert_ip_rejected(
|
689 + | backend,
|
690 + | tls::Provider::S2nTls,
|
691 + | test_tls::SERVER_IDENTITY.client_context(),
|
692 + | CERTIFICATE_ERROR,
|
693 + | )
|
694 + | .await;
|
695 + | }
|
696 + |
|
697 + | async fn wrong_name_is_rejected(backend: &dyn HttpsClientBackend) {
|
698 + | assert_ip_rejected(
|
699 + | backend,
|
700 + | tls::Provider::S2nTls,
|
701 + | client_context(&["wrong.example.com"]),
|
702 + | CERTIFICATE_ERROR,
|
703 + | )
|
704 + | .await;
|
705 + | }
|
706 + |
|
707 + | async fn matching_name_is_accepted(backend: &dyn HttpsClientBackend) {
|
708 + | assert_ip_accepted(backend, tls::Provider::S2nTls).await;
|
709 + | }
|
710 + |
|
711 + | async fn primary_name_is_preserved(backend: &dyn HttpsClientBackend) {
|
712 + | assert_primary_name_accepted(backend, tls::Provider::S2nTls).await;
|
713 + | }
|
714 + |
|
715 + | mod hyper_util_legacy_pool {
|
716 + | use super::*;
|
717 + |
|
718 + | #[tokio::test]
|
719 + | async fn test_missing_name_is_rejected() {
|
720 + | missing_name_is_rejected(&HyperUtilLegacyPool).await;
|
721 + | }
|
722 + |
|
723 + | #[tokio::test]
|
724 + | async fn test_wrong_name_is_rejected() {
|
725 + | wrong_name_is_rejected(&HyperUtilLegacyPool).await;
|
726 + | }
|
727 + |
|
728 + | #[tokio::test]
|
729 + | async fn test_matching_name_is_accepted() {
|
730 + | matching_name_is_accepted(&HyperUtilLegacyPool).await;
|
731 + | }
|
732 + |
|
733 + | #[tokio::test]
|
734 + | async fn test_primary_name_is_preserved() {
|
735 + | primary_name_is_preserved(&HyperUtilLegacyPool).await;
|
736 + | }
|
737 + | }
|
738 + |
|
739 + | #[cfg(feature = "rt-tokio")]
|
740 + | mod partitioned_connection_pool {
|
741 + | use super::*;
|
742 + |
|
743 + | #[tokio::test]
|
744 + | async fn test_missing_name_is_rejected() {
|
745 + | missing_name_is_rejected(&PartitionedConnectionPool).await;
|
746 + | }
|
747 + |
|
748 + | #[tokio::test]
|
749 + | async fn test_wrong_name_is_rejected() {
|
750 + | wrong_name_is_rejected(&PartitionedConnectionPool).await;
|
751 + | }
|
752 + |
|
753 + | #[tokio::test]
|
754 + | async fn test_matching_name_is_accepted() {
|
755 + | matching_name_is_accepted(&PartitionedConnectionPool).await;
|
756 + | }
|
757 + |
|
758 + | #[tokio::test]
|
759 + | async fn test_primary_name_is_preserved() {
|
760 + | primary_name_is_preserved(&PartitionedConnectionPool).await;
|
761 + | }
|
762 + | }
|
763 + | }
|
541 764 | }
|