Skip to content

Commit 2fc7c09

Browse files
committed
feat: add optional CryptoProvider to the client Config
It adds a new field to the client `Config, expecting the `CryptoProvider` from the user. It uses aws-lc-rs or ring providers by default if any of these features are enabled. It's based on the suggestion comment at bitcoindevkit#135, reference: bitcoindevkit#135 (comment)
1 parent b415b5c commit 2fc7c09

File tree

4 files changed

+76
-7
lines changed

4 files changed

+76
-7
lines changed

src/client.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,14 @@ impl ClientType {
116116
config.validate_domain(),
117117
socks5,
118118
config.timeout(),
119+
config.crypto_provider(),
120+
)?,
121+
None => RawClient::new_ssl(
122+
url.as_str(),
123+
config.validate_domain(),
124+
config.timeout(),
125+
config.crypto_provider(),
119126
)?,
120-
None => {
121-
RawClient::new_ssl(url.as_str(), config.validate_domain(), config.timeout())?
122-
}
123127
};
124128

125129
Ok(ClientType::SSL(client))

src/config.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use std::time::Duration;
22

3+
#[cfg(any(feature = "use-rustls", feature = "use-rustls-ring"))]
4+
use rustls::crypto::CryptoProvider;
5+
36
/// Configuration for an electrum client
47
///
58
/// Refer to [`Client::from_config`] and [`ClientType::from_config`].
@@ -12,6 +15,9 @@ pub struct Config {
1215
socks5: Option<Socks5Config>,
1316
/// timeout in seconds, default None (depends on TcpStream default)
1417
timeout: Option<Duration>,
18+
#[cfg(any(feature = "use-rustls", feature = "use-rustls-ring"))]
19+
/// An optional [`CryptoProvider`] for users that don't want either default `aws-lc-rs` or `ring` providers
20+
crypto_provider: Option<CryptoProvider>,
1521
/// number of retry if any error, default 1
1622
retry: u8,
1723
/// when ssl, validate the domain, default true
@@ -60,6 +66,13 @@ impl ConfigBuilder {
6066
self
6167
}
6268

69+
#[cfg(any(feature = "use-rustls", feature = "use-rustls-ring"))]
70+
/// Sets the custom [`CryptoProvider`].
71+
pub fn crypto_provider(mut self, crypto_provider: Option<CryptoProvider>) -> Self {
72+
self.config.crypto_provider = crypto_provider;
73+
self
74+
}
75+
6376
/// Sets the retry attempts number
6477
pub fn retry(mut self, retry: u8) -> Self {
6578
self.config.retry = retry;
@@ -135,6 +148,14 @@ impl Config {
135148
pub fn builder() -> ConfigBuilder {
136149
ConfigBuilder::new()
137150
}
151+
152+
#[cfg(any(feature = "use-rustls", feature = "use-rustls-ring"))]
153+
/// Get the configuration for `crypto_provider`
154+
///
155+
/// Set this with [`ConfigBuilder::crypto_provider`]
156+
pub fn crypto_provider(&self) -> Option<&CryptoProvider> {
157+
self.crypto_provider.as_ref()
158+
}
138159
}
139160

140161
impl Default for Config {
@@ -144,6 +165,8 @@ impl Default for Config {
144165
timeout: None,
145166
retry: 1,
146167
validate_domain: true,
168+
#[cfg(any(feature = "use-rustls", feature = "use-rustls-ring"))]
169+
crypto_provider: None,
147170
}
148171
}
149172
}

src/raw_client.rs

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,17 @@ use openssl::ssl::{SslConnector, SslMethod, SslStream, SslVerifyMode};
3131
not(feature = "use-openssl")
3232
))]
3333
use rustls::{
34+
crypto::CryptoProvider,
3435
pki_types::ServerName,
3536
pki_types::{Der, TrustAnchor},
3637
ClientConfig, ClientConnection, RootCertStore, StreamOwned,
3738
};
3839

40+
#[cfg(feature = "use-rustls")]
41+
use rustls::crypto::aws_lc_rs::default_provider;
42+
#[cfg(feature = "use-rustls-ring")]
43+
use rustls::crypto::ring::default_provider;
44+
3945
#[cfg(any(feature = "default", feature = "proxy"))]
4046
use crate::socks::{Socks5Stream, TargetAddr, ToTargetAddr};
4147

@@ -368,6 +374,7 @@ impl RawClient<ElectrumSslStream> {
368374
socket_addrs: A,
369375
validate_domain: bool,
370376
timeout: Option<Duration>,
377+
crypto_provider: Option<&CryptoProvider>,
371378
) -> Result<Self, Error> {
372379
debug!(
373380
"new_ssl socket_addrs.domain():{:?} validate_domain:{} timeout:{:?}",
@@ -378,16 +385,27 @@ impl RawClient<ElectrumSslStream> {
378385
if validate_domain {
379386
socket_addrs.domain().ok_or(Error::MissingDomain)?;
380387
}
388+
389+
let crypto_provider = match crypto_provider {
390+
Some(provider) => provider.to_owned(),
391+
392+
#[cfg(feature = "use-rustls")]
393+
None => default_provider(),
394+
395+
#[cfg(feature = "use-rustls-ring")]
396+
None => default_provider(),
397+
};
398+
381399
match timeout {
382400
Some(timeout) => {
383401
let stream = connect_with_total_timeout(socket_addrs.clone(), timeout)?;
384402
stream.set_read_timeout(Some(timeout))?;
385403
stream.set_write_timeout(Some(timeout))?;
386-
Self::new_ssl_from_stream(socket_addrs, validate_domain, stream)
404+
Self::new_ssl_from_stream(socket_addrs, validate_domain, stream, crypto_provider)
387405
}
388406
None => {
389407
let stream = TcpStream::connect(socket_addrs.clone())?;
390-
Self::new_ssl_from_stream(socket_addrs, validate_domain, stream)
408+
Self::new_ssl_from_stream(socket_addrs, validate_domain, stream, crypto_provider)
391409
}
392410
}
393411
}
@@ -397,10 +415,13 @@ impl RawClient<ElectrumSslStream> {
397415
socket_addr: A,
398416
validate_domain: bool,
399417
tcp_stream: TcpStream,
418+
crypto_provider: CryptoProvider,
400419
) -> Result<Self, Error> {
401420
use std::convert::TryFrom;
402421

403-
let builder = ClientConfig::builder();
422+
let builder = ClientConfig::builder_with_provider(crypto_provider.into())
423+
.with_safe_default_protocol_versions()
424+
.map_err(|e| Error::CouldNotBuildWithSafeDefaultVersion(e))?;
404425

405426
let config = if validate_domain {
406427
socket_addr.domain().ok_or(Error::MissingDomain)?;
@@ -480,6 +501,7 @@ impl RawClient<ElectrumProxyStream> {
480501
validate_domain: bool,
481502
proxy: &crate::Socks5Config,
482503
timeout: Option<Duration>,
504+
crypto_provider: Option<&CryptoProvider>,
483505
) -> Result<RawClient<ElectrumSslStream>, Error> {
484506
let target = target_addr.to_target_addr()?;
485507

@@ -496,7 +518,22 @@ impl RawClient<ElectrumProxyStream> {
496518
stream.get_mut().set_read_timeout(timeout)?;
497519
stream.get_mut().set_write_timeout(timeout)?;
498520

499-
RawClient::new_ssl_from_stream(target, validate_domain, stream.into_inner())
521+
let crypto_provider = match crypto_provider {
522+
Some(provider) => provider.to_owned(),
523+
524+
#[cfg(feature = "use-rustls")]
525+
None => default_provider(),
526+
527+
#[cfg(feature = "use-rustls-ring")]
528+
None => default_provider(),
529+
};
530+
531+
RawClient::new_ssl_from_stream(
532+
target,
533+
validate_domain,
534+
stream.into_inner(),
535+
crypto_provider,
536+
)
500537
}
501538
}
502539

src/types.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,9 @@ pub enum Error {
318318
#[cfg(any(feature = "use-rustls", feature = "use-rustls-ring"))]
319319
/// Could not create a rustls client connection
320320
CouldNotCreateConnection(rustls::Error),
321+
#[cfg(any(feature = "use-rustls", feature = "use-rustls-ring"))]
322+
/// Could not create the `ClientConfig` with safe default protocol version
323+
CouldNotBuildWithSafeDefaultVersion(rustls::Error),
321324

322325
#[cfg(feature = "use-openssl")]
323326
/// Invalid OpenSSL method used
@@ -365,6 +368,8 @@ impl Display for Error {
365368
Error::MissingDomain => f.write_str("Missing domain while it was explicitly asked to validate it"),
366369
Error::CouldntLockReader => f.write_str("Couldn't take a lock on the reader mutex. This means that there's already another reader thread is running"),
367370
Error::Mpsc => f.write_str("Broken IPC communication channel: the other thread probably has exited"),
371+
#[cfg(any(feature = "use-rustls", feature = "use-rustls-ring"))]
372+
Error::CouldNotBuildWithSafeDefaultVersion(_) => f.write_str("Couldn't build the `ClientConfig` with safe default version"),
368373
}
369374
}
370375
}

0 commit comments

Comments
 (0)