Skip to content

Commit cabecec

Browse files
authored
Merge pull request #670 from swimos/client_crypto_provider
Sever client networking cryptographic provider initialisation
2 parents 4e0981d + 95fcce3 commit cabecec

File tree

12 files changed

+180
-88
lines changed

12 files changed

+180
-88
lines changed

client/swimos_client/Cargo.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ version = "0.1.0"
44
edition = "2021"
55

66
[features]
7-
default = []
8-
tls = ["swimos_remote/tls"]
7+
default = ["aws_lc_rs_provider"]
98
deflate = ["runtime/deflate"]
109
trust_dns = ["swimos_runtime/trust_dns"]
10+
ring_provider = ["swimos_remote/ring_provider"]
11+
aws_lc_rs_provider = ["swimos_remote/aws_lc_rs_provider"]
1112

1213
[dependencies]
1314
runtime = { path = "../runtime" }
@@ -25,4 +26,4 @@ tokio = { workspace = true, features = ["sync"] }
2526
futures = { workspace = true }
2627
futures-util = { workspace = true }
2728
tracing = { workspace = true }
28-
29+
rustls = { workspace = true }

client/swimos_client/src/lib.rs

Lines changed: 76 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -12,101 +12,136 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
#[cfg(not(feature = "deflate"))]
16-
use ratchet::NoExtProvider;
17-
use ratchet::WebSocketStream;
18-
use std::marker::PhantomData;
19-
use std::num::NonZeroUsize;
20-
use swimos_remote::websocket::RatchetClient;
15+
use std::{marker::PhantomData, num::NonZeroUsize, sync::Arc};
2116

2217
use futures_util::future::BoxFuture;
23-
#[cfg(feature = "deflate")]
24-
use ratchet::deflate::{DeflateConfig, DeflateExtProvider};
18+
use ratchet::{
19+
deflate::{DeflateConfig, DeflateExtProvider},
20+
WebSocketStream,
21+
};
22+
use rustls::crypto::CryptoProvider;
23+
use tokio::{sync::mpsc, sync::mpsc::error::SendError, sync::oneshot::error::RecvError};
24+
pub use url::Url;
25+
2526
use runtime::{
2627
start_runtime, ClientConfig, DownlinkRuntimeError, RawHandle, Transport, WebSocketConfig,
2728
};
2829
pub use runtime::{CommandError, Commander, RemotePath};
29-
use std::sync::Arc;
3030
pub use swimos_client_api::DownlinkConfig;
31-
pub use swimos_downlink::lifecycle::{
32-
BasicEventDownlinkLifecycle, BasicMapDownlinkLifecycle, BasicValueDownlinkLifecycle,
33-
EventDownlinkLifecycle, MapDownlinkLifecycle, ValueDownlinkLifecycle,
31+
pub use swimos_downlink::{
32+
lifecycle::BasicEventDownlinkLifecycle, lifecycle::BasicMapDownlinkLifecycle,
33+
lifecycle::BasicValueDownlinkLifecycle, lifecycle::EventDownlinkLifecycle,
34+
lifecycle::MapDownlinkLifecycle, lifecycle::ValueDownlinkLifecycle,
3435
};
3536
use swimos_downlink::{
3637
ChannelError, DownlinkTask, EventDownlinkModel, MapDownlinkHandle, MapDownlinkModel, MapKey,
3738
MapValue, NotYetSyncedError, ValueDownlinkModel, ValueDownlinkSet,
3839
};
3940
use swimos_form::Form;
40-
use swimos_remote::dns::Resolver;
41-
use swimos_remote::plain::TokioPlainTextNetworking;
42-
#[cfg(feature = "tls")]
43-
use swimos_remote::tls::{ClientConfig as TlsConfig, RustlsClientNetworking, TlsError};
44-
use swimos_remote::ClientConnections;
41+
pub use swimos_remote::tls::ClientConfig as TlsConfig;
42+
use swimos_remote::tls::TlsError;
43+
use swimos_remote::{
44+
dns::Resolver,
45+
plain::TokioPlainTextNetworking,
46+
tls::{CryptoProviderConfig, RustlsClientNetworking},
47+
websocket::RatchetClient,
48+
ClientConnections,
49+
};
4550
use swimos_runtime::downlink::{DownlinkOptions, DownlinkRuntimeConfig};
46-
use swimos_utilities::trigger;
47-
use swimos_utilities::trigger::promise;
48-
use tokio::sync::mpsc;
49-
use tokio::sync::mpsc::error::SendError;
50-
use tokio::sync::oneshot::error::RecvError;
51-
pub use url::Url;
51+
use swimos_utilities::{trigger, trigger::promise};
5252

5353
pub type DownlinkOperationResult<T> = Result<T, DownlinkRuntimeError>;
5454

55-
#[derive(Debug, Default)]
55+
#[derive(Default)]
5656
pub struct SwimClientBuilder {
57-
config: ClientConfig,
57+
client_config: ClientConfig,
5858
}
5959

6060
impl SwimClientBuilder {
61-
pub fn new(config: ClientConfig) -> SwimClientBuilder {
62-
SwimClientBuilder { config }
61+
pub fn new(client_config: ClientConfig) -> SwimClientBuilder {
62+
SwimClientBuilder { client_config }
6363
}
6464

6565
/// Sets the websocket configuration.
6666
pub fn set_websocket_config(mut self, to: WebSocketConfig) -> SwimClientBuilder {
67-
self.config.websocket = to;
67+
self.client_config.websocket = to;
6868
self
6969
}
7070

7171
/// Size of the buffers to communicate with the socket.
7272
pub fn set_remote_buffer_size(mut self, to: NonZeroUsize) -> SwimClientBuilder {
73-
self.config.remote_buffer_size = to;
73+
self.client_config.remote_buffer_size = to;
7474
self
7575
}
7676

7777
/// Sets the buffer size between the runtime and transport tasks.
7878
pub fn set_transport_buffer_size(mut self, to: NonZeroUsize) -> SwimClientBuilder {
79-
self.config.transport_buffer_size = to;
79+
self.client_config.transport_buffer_size = to;
8080
self
8181
}
8282

8383
/// Sets the deflate extension configuration for WebSocket connections.
8484
#[cfg(feature = "deflate")]
8585
pub fn set_deflate_config(mut self, to: DeflateConfig) -> SwimClientBuilder {
86-
self.config.websocket.deflate_config = Some(to);
86+
self.client_config.websocket.deflate_config = Some(to);
8787
self
8888
}
8989

90+
/// Enables TLS support.
91+
pub fn set_tls_config(self, tls_config: TlsConfig) -> SwimClientTlsBuilder {
92+
SwimClientTlsBuilder {
93+
client_config: self.client_config,
94+
tls_config,
95+
crypto_provider: Default::default(),
96+
}
97+
}
98+
9099
/// Builds the client.
91100
pub async fn build(self) -> (SwimClient, BoxFuture<'static, ()>) {
92-
let SwimClientBuilder { config } = self;
101+
let SwimClientBuilder { client_config } = self;
93102
open_client(
94-
config,
103+
client_config,
95104
TokioPlainTextNetworking::new(Arc::new(Resolver::new().await)),
96105
)
97106
.await
98107
}
108+
}
109+
110+
pub struct SwimClientTlsBuilder {
111+
client_config: ClientConfig,
112+
tls_config: TlsConfig,
113+
crypto_provider: CryptoProviderConfig,
114+
}
115+
116+
impl SwimClientTlsBuilder {
117+
/// Uses the process-default [`CryptoProvider`] for any TLS connections.
118+
///
119+
/// This is only used if the TLS configuration has been set.
120+
pub fn with_default_crypto_provider(mut self) -> Self {
121+
self.crypto_provider = CryptoProviderConfig::ProcessDefault;
122+
self
123+
}
124+
125+
/// Uses the provided [`CryptoProvider`] for any TLS connections.
126+
pub fn with_crypto_provider(mut self, provider: Arc<CryptoProvider>) -> Self {
127+
self.crypto_provider = CryptoProviderConfig::Provided(provider);
128+
self
129+
}
99130

100131
/// Builds the client using the provided TLS configuration.
101-
#[cfg(feature = "tls")]
102-
pub async fn build_tls(
103-
self,
104-
tls_config: TlsConfig,
105-
) -> Result<(SwimClient, BoxFuture<'static, ()>), TlsError> {
106-
let SwimClientBuilder { config } = self;
132+
pub async fn build(self) -> Result<(SwimClient, BoxFuture<'static, ()>), TlsError> {
133+
let SwimClientTlsBuilder {
134+
client_config,
135+
tls_config,
136+
crypto_provider,
137+
} = self;
107138
Ok(open_client(
108-
config,
109-
RustlsClientNetworking::try_from_config(Arc::new(Resolver::new().await), tls_config)?,
139+
client_config,
140+
RustlsClientNetworking::build(
141+
Arc::new(Resolver::new().await),
142+
tls_config,
143+
crypto_provider.try_build()?,
144+
)?,
110145
)
111146
.await)
112147
}

runtime/swimos_remote/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ edition = "2021"
77
[features]
88
default = []
99
tls = ["rustls", "webpki", "webpki-roots", "tokio-rustls", "rustls-pemfile"]
10+
ring_provider = []
11+
aws_lc_rs_provider = []
1012

1113
[dependencies]
1214
ratchet = { workspace = true, features = ["deflate", "split"] }

runtime/swimos_remote/src/tls/config/mod.rs

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
use rustls::crypto::CryptoProvider;
16-
use std::sync::Arc;
17-
1815
/// Supported certificate formats for TLS connections.
1916
pub enum CertFormat {
2017
Pem,
@@ -87,18 +84,14 @@ pub struct ServerConfig {
8784
/// `SSLKEYLOGFILE` environment variable, and writes keys into it. While this may be enabled,
8885
/// if `SSLKEYLOGFILE` is not set, it will do nothing.
8986
pub enable_log_file: bool,
90-
/// Process-wide [`CryptoProvider`] that must already have been installed as the default
91-
/// provider.
92-
pub provider: Arc<CryptoProvider>,
9387
}
9488

9589
impl ServerConfig {
96-
pub fn new(chain: CertChain, key: PrivateKey, provider: Arc<CryptoProvider>) -> Self {
90+
pub fn new(chain: CertChain, key: PrivateKey) -> Self {
9791
ServerConfig {
9892
chain,
9993
key,
10094
enable_log_file: false,
101-
provider,
10295
}
10396
}
10497
}
@@ -117,12 +110,3 @@ impl ClientConfig {
117110
}
118111
}
119112
}
120-
121-
impl Default for ClientConfig {
122-
fn default() -> Self {
123-
Self {
124-
use_webpki_roots: true,
125-
custom_roots: vec![],
126-
}
127-
}
128-
}

runtime/swimos_remote/src/tls/errors.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,10 @@ pub enum TlsError {
3232
/// Performing the TLS handshake failed.
3333
#[error("TLS handshake failed: {0}")]
3434
HandshakeFailed(std::io::Error),
35+
/// User specified that a cryptographic provider had been installed but none was found.
36+
#[error("No default cryptographic provider has been installed")]
37+
NoCryptoProviderInstalled,
38+
/// User specified more than one cryptographic provider feature flag. Only one may be specified.
39+
#[error("Ambiguous cryptographic provider feature flags specified. Only \"ring_provider\" or \"aws_lc_rs_provider\" may be specified")]
40+
InvalidCryptoProvider,
3541
}

runtime/swimos_remote/src/tls/mod.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,40 @@ pub use config::{
2323
pub use errors::TlsError;
2424
pub use maybe::MaybeTlsStream;
2525
pub use net::{RustlsClientNetworking, RustlsListener, RustlsNetworking, RustlsServerNetworking};
26+
use rustls::crypto::CryptoProvider;
27+
use std::sync::Arc;
28+
29+
#[derive(Default)]
30+
pub enum CryptoProviderConfig {
31+
ProcessDefault,
32+
#[default]
33+
FromFeatureFlags,
34+
Provided(Arc<CryptoProvider>),
35+
}
36+
37+
impl CryptoProviderConfig {
38+
pub fn try_build(self) -> Result<Arc<CryptoProvider>, TlsError> {
39+
match self {
40+
CryptoProviderConfig::ProcessDefault => CryptoProvider::get_default()
41+
.ok_or(TlsError::NoCryptoProviderInstalled)
42+
.cloned(),
43+
CryptoProviderConfig::FromFeatureFlags => {
44+
#[cfg(all(feature = "ring_provider", not(feature = "aws_lc_rs_provider")))]
45+
{
46+
return Arc::new(rustls::crypto::ring::default_provider());
47+
}
48+
49+
#[cfg(all(feature = "aws_lc_rs_provider", not(feature = "ring_provider")))]
50+
{
51+
return Arc::new(rustls::crypto::aws_lc_rs::default_provider());
52+
}
53+
54+
#[allow(unreachable_code)]
55+
{
56+
Err(TlsError::InvalidCryptoProvider)
57+
}
58+
}
59+
CryptoProviderConfig::Provided(provider) => Ok(provider),
60+
}
61+
}
62+
}

runtime/swimos_remote/src/tls/net/client.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use std::{net::SocketAddr, sync::Arc};
1616

1717
use futures::{future::BoxFuture, FutureExt};
18+
use rustls::crypto::CryptoProvider;
1819
use rustls::pki_types::ServerName;
1920
use rustls::RootCertStore;
2021

@@ -40,9 +41,10 @@ impl RustlsClientNetworking {
4041
}
4142
}
4243

43-
pub fn try_from_config(
44+
pub fn build(
4445
resolver: Arc<Resolver>,
4546
config: ClientConfig,
47+
provider: Arc<CryptoProvider>,
4648
) -> Result<Self, TlsError> {
4749
let ClientConfig {
4850
use_webpki_roots,
@@ -59,7 +61,8 @@ impl RustlsClientNetworking {
5961
}
6062
}
6163

62-
let config = rustls::ClientConfig::builder()
64+
let config = rustls::ClientConfig::builder_with_provider(provider)
65+
.with_safe_default_protocol_versions()?
6366
.with_root_certificates(root_store)
6467
.with_no_client_auth();
6568

runtime/swimos_remote/src/tls/net/server.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use futures::{
2222
stream::{unfold, BoxStream, FuturesUnordered},
2323
Future, FutureExt, Stream, StreamExt, TryStreamExt,
2424
};
25+
use rustls::crypto::CryptoProvider;
2526
use rustls::pki_types::PrivateKeyDer;
2627
use rustls::KeyLogFile;
2728
use rustls_pemfile::Item;
@@ -64,17 +65,15 @@ impl RustlsServerNetworking {
6465
pub fn new(acceptor: TlsAcceptor) -> Self {
6566
RustlsServerNetworking { acceptor }
6667
}
67-
}
68-
69-
impl TryFrom<ServerConfig> for RustlsServerNetworking {
70-
type Error = TlsError;
7168

72-
fn try_from(config: ServerConfig) -> Result<Self, Self::Error> {
69+
pub fn build(
70+
config: ServerConfig,
71+
provider: Arc<CryptoProvider>,
72+
) -> Result<RustlsServerNetworking, TlsError> {
7373
let ServerConfig {
7474
chain: CertChain(certs),
7575
key,
7676
enable_log_file,
77-
provider,
7877
} = config;
7978

8079
let mut chain = vec![];

0 commit comments

Comments
 (0)