Skip to content

Commit

Permalink
Add s2n-tls provider
Browse files Browse the repository at this point in the history
  • Loading branch information
goatgoose committed Jan 10, 2025
1 parent ba89a32 commit d7e0d8a
Show file tree
Hide file tree
Showing 9 changed files with 698 additions and 444 deletions.
681 changes: 381 additions & 300 deletions aws/sdk/benchmarks/previous-release-comparison/Cargo.lock

Large diffs are not rendered by default.

217 changes: 92 additions & 125 deletions aws/sdk/benchmarks/s3-express/Cargo.lock

Large diffs are not rendered by default.

54 changes: 54 additions & 0 deletions rust-runtime/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions rust-runtime/aws-smithy-http-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ rustls-ring = ["dep:rustls", "rustls?/ring", "dep:hyper-rustls", "hyper-1"]
rustls-aws-lc = ["dep:rustls", "rustls?/aws_lc_rs", "dep:hyper-rustls", "hyper-1"]
rustls-aws-lc-fips = ["dep:rustls", "rustls?/fips", "dep:hyper-rustls", "hyper-1"]

s2n-tls = ["dep:s2n-tls", "dep:s2n-tls-hyper", "hyper-1"]

[dependencies]
aws-smithy-async = { path = "../aws-smithy-async" }
aws-smithy-runtime-api = { path = "../aws-smithy-runtime-api", features = ["client"] }
Expand All @@ -83,6 +85,8 @@ http-1x = { package = "http", version = "1" , optional = true }
http-body-1x = { package = "http-body", version = "1", optional = true}
hyper-rustls = { version = "0.27", features = ["http2", "http1", "native-tokio", "tls12"], default-features = false, optional = true }
rustls = { version = "0.23", default-features = false, optional = true }
s2n-tls-hyper = { version = "0.0.1", optional = true }
s2n-tls = { version = "0.3", optional = true }
tower = { version = "0.5.1", optional = true }
# end hyper 1.x stack deps

Expand Down Expand Up @@ -119,6 +123,11 @@ name = "client-aws-lc"
required-features = ["rustls-aws-lc", "rustls-aws-lc-fips"]
doc-scrape-examples = true

[[example]]
name = "client-s2n-tls"
required-features = ["s2n-tls"]
doc-scrape-examples = true

[[example]]
name = "custom-dns"
required-features = ["rustls-ring"]
Expand Down
12 changes: 12 additions & 0 deletions rust-runtime/aws-smithy-http-client/examples/client-s2n-tls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

use aws_smithy_http_client::{tls, Builder};

fn main() {
let _client = Builder::new()
.tls_provider(tls::Provider::S2ntls)
.build_https();
}
43 changes: 43 additions & 0 deletions rust-runtime/aws-smithy-http-client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,16 @@ cfg_tls! {
);
self.wrap_connector(https_connector)
}
},
#[cfg(feature = "s2n-tls")]
tls::Provider::S2ntls => {
if self.enable_cached_tls {
let https_connector = tls::s2n_tls_provider::cached_connectors::cached_https();
self.wrap_connector(https_connector)
} else {
let https_connector = tls::s2n_tls_provider::build_connector::wrap_connector(http_connector);
self.wrap_connector(https_connector)
}
}
}
}
Expand Down Expand Up @@ -970,4 +980,37 @@ mod test {
);
assert_elapsed!(now, Duration::from_secs(2));
}

#[tokio::test]
async fn s2n_tls_provider() {
// Create an HttpConnector with the s2n-tls provider.
let client = Builder::new()
.tls_provider(tls::Provider::S2ntls)
.build_https();
let connector_settings = HttpConnectorSettings::builder().build();
let runtime_components = RuntimeComponentsBuilder::for_tests()
.with_time_source(Some(SystemTimeSource::new()))
.build()
.unwrap();
let connector = client.http_connector(&connector_settings, &runtime_components);

// Ensure that s2n-tls is used as the underlying TLS provider when selected.
//
// s2n-tls-hyper will error when given an invalid scheme. Ensure that this error is produced
// from s2n-tls-hyper, and not another TLS provider.
let error = connector
.call(HttpRequest::get("notascheme://amazon.com").unwrap())
.await
.unwrap_err();
let error = error.into_source();
let s2n_error = error
.source()
.unwrap()
.downcast_ref::<s2n_tls_hyper::error::Error>()
.unwrap();
assert!(matches!(
s2n_error,
s2n_tls_hyper::error::Error::InvalidScheme
));
}
}
60 changes: 56 additions & 4 deletions rust-runtime/aws-smithy-http-client/src/client/tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
use crate::cfg::cfg_rustls;
use crate::cfg::{cfg_rustls, cfg_s2n_tls};

/// Choice of underlying cryptography library
#[derive(Debug, Eq, PartialEq, Clone)]
Expand All @@ -15,9 +15,9 @@ pub enum Provider {
))]
/// TLS provider based on [rustls](https://github.com/rustls/rustls)
Rustls(rustls_provider::CryptoMode),
// TLS provider based on [S2N](https://github.com/aws/s2n-tls)
// S2n,
// TODO(hyper1) s2n support
/// TLS provider based on [s2n-tls](https://github.com/aws/s2n-tls)
#[cfg(feature = "s2n-tls")]
S2ntls,
// TODO(hyper1): consider native-tls support?
}

Expand Down Expand Up @@ -181,3 +181,55 @@ cfg_rustls! {
}
}
}

cfg_s2n_tls! {
/// s2n-tls based support and adapters
pub mod s2n_tls_provider {
pub(crate) mod cached_connectors {
use hyper_util::client::legacy as client;
use client::connect::HttpConnector;
use hyper_util::client::legacy::connect::dns::GaiResolver;
use super::build_connector::make_tls;

static CACHED_CONNECTOR: once_cell::sync::Lazy<
s2n_tls_hyper::connector::HttpsConnector<HttpConnector>,
> = once_cell::sync::Lazy::new(|| {
make_tls(GaiResolver::new())
});

pub(crate) fn cached_https() -> s2n_tls_hyper::connector::HttpsConnector<HttpConnector> {
CACHED_CONNECTOR.clone()
}
}

pub(crate) mod build_connector {
use hyper_util::client::legacy as client;
use client::connect::HttpConnector;
use s2n_tls::security::Policy;

pub(super) fn make_tls<R>(
resolver: R,
) -> s2n_tls_hyper::connector::HttpsConnector<HttpConnector<R>> {
// use the base connector through our `Connector` type to ensure defaults are consistent
let base_connector = crate::client::Connector::builder()
.base_connector_with_resolver(resolver);
wrap_connector(base_connector)
}

pub(crate) fn wrap_connector<R>(
mut http_connector: HttpConnector<R>,
) -> s2n_tls_hyper::connector::HttpsConnector<HttpConnector<R>> {
http_connector.enforce_http(false);
let config = {
let mut builder = s2n_tls::config::Config::builder();
let policy = Policy::from_version("20230317").unwrap();
builder.set_security_policy(&policy).unwrap();
builder.build().unwrap()
};
let mut builder = s2n_tls_hyper::connector::HttpsConnector::builder_with_http(http_connector, config);
builder.with_plaintext_http(true);
builder.build()
}
}
}
}
22 changes: 20 additions & 2 deletions rust-runtime/aws-smithy-http-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,15 @@ pub(crate) mod cfg {
#[cfg(any(
feature = "rustls-aws-lc",
feature = "rustls-aws-lc-fips",
feature = "rustls-ring"
feature = "rustls-ring",
feature = "s2n-tls",
))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "rustls-aws-lc", feature = "rustls-aws-lc-fips", feature = "rustls-ring"))))]
#[cfg_attr(docsrs, doc(cfg(any(
feature = "rustls-aws-lc",
feature = "rustls-aws-lc-fips",
feature = "rustls-ring",
feature = "s2n-tls",
))))]
$item
)*
}
Expand All @@ -76,6 +82,18 @@ pub(crate) mod cfg {
)*
}
}

macro_rules! cfg_s2n_tls {
($($item:item)*) => {
$(
#[cfg(feature = "s2n-tls")]
#[cfg_attr(docsrs, doc(cfg(feature = "s2n-tls")))]
$item
)*
}
}

pub(crate) use cfg_rustls;
pub(crate) use cfg_s2n_tls;
pub(crate) use cfg_tls;
}
44 changes: 31 additions & 13 deletions rust-runtime/aws-smithy-http-client/tests/smoke_test_clients.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
#![cfg(any(
feature = "rustls-ring",
feature = "rustls-aws-lc",
feature = "rustls-aws-lc-fips"
feature = "rustls-aws-lc-fips",
feature = "s2n-tls",
))]

use aws_smithy_async::time::SystemTimeSource;
Expand Down Expand Up @@ -54,14 +55,23 @@ async fn aws_lc_client() {
smoke_test_client(&client).await.unwrap();
}

#[cfg(feature = "s2n-tls")]
#[tokio::test]
async fn s2n_tls_client() {
let client = Builder::new()
.tls_provider(tls::Provider::S2ntls)
.build_https();
smoke_test_client(&client).await.unwrap();
}

#[cfg(feature = "default-tls")]
#[tokio::test]
async fn default_tls_client() {
let client = aws_smithy_http_client::default_client().expect("default TLS client created");
smoke_test_client(&client).await.unwrap();
}

#[cfg(feature = "rustls-ring")]
#[cfg(any(feature = "rustls-ring", feature = "s2n-tls"))]
#[tokio::test]
async fn custom_dns_client() {
use std::sync::atomic::{AtomicUsize, Ordering};
Expand All @@ -82,17 +92,25 @@ async fn custom_dns_client() {
})
}
}
let resolver = PassThroughResolver {
inner: GaiResolver::new(),
count: Default::default(),
};
let client = Builder::new()
.tls_provider(tls::Provider::Rustls(
tls::rustls_provider::CryptoMode::Ring,
))
.build_with_resolver(resolver.clone());
smoke_test_client(&client).await.unwrap();
assert_eq!(resolver.count.load(Ordering::Relaxed), 1);

let providers = [
#[cfg(feature = "rustls-ring")]
tls::Provider::Rustls(tls::rustls_provider::CryptoMode::Ring),
#[cfg(feature = "s2n-tls")]
tls::Provider::S2ntls,
];

for provider in providers {
let resolver = PassThroughResolver {
inner: GaiResolver::new(),
count: Default::default(),
};
let client = Builder::new()
.tls_provider(provider)
.build_with_resolver(resolver.clone());
smoke_test_client(&client).await.unwrap();
assert_eq!(resolver.count.load(Ordering::Relaxed), 1);
}
}

async fn smoke_test_client(client: &dyn HttpClient) -> Result<(), Box<dyn Error>> {
Expand Down

0 comments on commit d7e0d8a

Please sign in to comment.