Skip to content

Commit 15be32d

Browse files
behoskezhuw
authored andcommitted
Support client side tls certificates reload
This allows creating a client with dynamic tls certificates. When created this way, on reconnection the client will use latest tls certificates. This allows us to have auto-reloading of refreshed certificates stored anywhere in client side. Resolves #59.
1 parent 6bf26a1 commit 15be32d

File tree

10 files changed

+1067
-227
lines changed

10 files changed

+1067
-227
lines changed

Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ rust-version = "1.76"
1616

1717
[features]
1818
default = []
19-
tls = ["rustls", "rustls-pemfile", "futures-rustls"]
19+
tls = ["rustls", "rustls-webpki", "rustls-pemfile", "futures-rustls"]
2020
sasl = ["sasl-gssapi", "sasl-digest-md5"]
2121
sasl-digest-md5 = ["rsasl/unstable_custom_mechanism", "md5", "linkme", "hex"]
2222
sasl-gssapi = ["rsasl/gssapi"]
@@ -38,6 +38,7 @@ hashlink = "0.8.0"
3838
either = "1.9.0"
3939
uuid = { version = "1.4.1", features = ["v4"] }
4040
rustls = { version = "0.23.2", optional = true }
41+
rustls-webpki = { version = "0.103.4", optional = true }
4142
rustls-pemfile = { version = "2", optional = true }
4243
derive-where = "1.2.7"
4344
fastrand = "2.0.2"
@@ -67,6 +68,10 @@ rcgen = { version = "0.14.1", features = ["default", "x509-parser"] }
6768
serial_test = "3.0.0"
6869
asyncs = { version = "0.4.0", features = ["test"] }
6970
blocking = "1.6.0"
71+
rustls-pki-types = "1.12.0"
72+
x509-parser = "0.17.0"
73+
atomic-write-file = "0.2.3"
74+
notify = "7.0.0"
7075

7176
[package.metadata.cargo-all-features]
7277
skip_optional_dependencies = true

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ mod util;
4545
pub use self::acl::{Acl, Acls, AuthId, AuthUser, Permission};
4646
pub use self::error::Error;
4747
#[cfg(feature = "tls")]
48-
pub use self::tls::TlsOptions;
48+
pub use self::tls::*;
4949
pub use crate::client::*;
5050
#[cfg(feature = "sasl-digest-md5")]
5151
pub use crate::sasl::DigestMd5SaslOptions;

src/session/connection.rs

Lines changed: 23 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,15 @@ use bytes::buf::BufMut;
1010
use futures::io::BufReader;
1111
use futures::prelude::*;
1212
use futures_lite::AsyncReadExt;
13+
#[cfg(feature = "tls")]
14+
pub use futures_rustls::client::TlsStream;
1315
use ignore_result::Ignore;
1416
use tracing::{debug, trace};
1517

16-
#[cfg(feature = "tls")]
17-
mod tls {
18-
pub use std::sync::Arc;
19-
20-
pub use futures_rustls::client::TlsStream;
21-
pub use futures_rustls::TlsConnector;
22-
pub use rustls::pki_types::ServerName;
23-
pub use rustls::ClientConfig;
24-
}
25-
#[cfg(feature = "tls")]
26-
use tls::*;
27-
2818
use crate::deadline::Deadline;
2919
use crate::endpoint::{EndpointRef, IterableEndpoints};
20+
#[cfg(feature = "tls")]
21+
use crate::tls::TlsClient;
3022

3123
#[derive(Debug)]
3224
pub enum Connection {
@@ -170,31 +162,22 @@ impl Connection {
170162
#[derive(Clone)]
171163
pub struct Connector {
172164
#[cfg(feature = "tls")]
173-
tls: Option<TlsConnector>,
165+
tls: Option<TlsClient>,
174166
timeout: Duration,
175167
}
176168

177169
impl Connector {
178-
#[cfg(feature = "tls")]
179-
pub fn new() -> Self {
180-
Self { tls: None, timeout: Duration::from_secs(10) }
181-
}
182-
183-
#[cfg(not(feature = "tls"))]
184170
pub fn new() -> Self {
185-
Self { timeout: Duration::from_secs(10) }
186-
}
187-
188-
#[cfg(feature = "tls")]
189-
pub fn with_tls(config: ClientConfig) -> Self {
190-
Self { tls: Some(TlsConnector::from(Arc::new(config))), timeout: Duration::from_secs(10) }
171+
Self {
172+
#[cfg(feature = "tls")]
173+
tls: None,
174+
timeout: Duration::from_secs(10),
175+
}
191176
}
192177

193178
#[cfg(feature = "tls")]
194-
async fn connect_tls(&self, stream: TcpStream, host: &str) -> Result<Connection> {
195-
let domain = ServerName::try_from(host).unwrap().to_owned();
196-
let stream = self.tls.as_ref().unwrap().connect(domain, stream).await?;
197-
Ok(Connection::new_tls(stream))
179+
pub fn with_tls(client: TlsClient) -> Self {
180+
Self { tls: Some(client), timeout: Duration::from_secs(10) }
198181
}
199182

200183
pub fn timeout(&self) -> Duration {
@@ -205,34 +188,25 @@ impl Connector {
205188
self.timeout = timeout;
206189
}
207190

208-
pub async fn connect(&self, endpoint: EndpointRef<'_>, deadline: &mut Deadline) -> Result<Connection> {
191+
async fn connect_endpoint(&self, endpoint: EndpointRef<'_>) -> Result<Connection> {
209192
if endpoint.tls {
210193
#[cfg(feature = "tls")]
211-
if self.tls.is_none() {
212-
return Err(Error::new(ErrorKind::Unsupported, "tls not configured"));
213-
}
194+
return match self.tls.as_ref() {
195+
None => return Err(Error::new(ErrorKind::Unsupported, "tls not configured")),
196+
Some(client) => client.connect(endpoint.host, endpoint.port).await.map(Connection::new_tls),
197+
};
214198
#[cfg(not(feature = "tls"))]
215199
return Err(Error::new(ErrorKind::Unsupported, "tls not supported"));
216200
}
201+
TcpStream::connect((endpoint.host, endpoint.port)).await.map(Connection::new_raw)
202+
}
203+
204+
pub async fn connect(&self, endpoint: EndpointRef<'_>, deadline: &mut Deadline) -> Result<Connection> {
217205
select! {
206+
biased;
207+
r = self.connect_endpoint(endpoint) => r,
218208
_ = unsafe { Pin::new_unchecked(deadline) } => Err(Error::new(ErrorKind::TimedOut, "deadline exceed")),
219209
_ = Timer::after(self.timeout) => Err(Error::new(ErrorKind::TimedOut, format!("connection timeout{:?} exceed", self.timeout))),
220-
r = TcpStream::connect((endpoint.host, endpoint.port)) => {
221-
match r {
222-
Err(err) => Err(err),
223-
Ok(sock) => {
224-
let connection = if endpoint.tls {
225-
#[cfg(not(feature = "tls"))]
226-
unreachable!("tls not supported");
227-
#[cfg(feature = "tls")]
228-
self.connect_tls(sock, endpoint.host).await?
229-
} else {
230-
Connection::new_raw(sock)
231-
};
232-
Ok(connection)
233-
},
234-
}
235-
},
236210
}
237211
}
238212

src/session/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ impl Builder {
131131
}
132132
#[cfg(feature = "tls")]
133133
let connector = match self.tls {
134-
Some(options) => Connector::with_tls(options.into_config()?),
134+
Some(options) => Connector::with_tls(options.into_client()?),
135135
None => Connector::new(),
136136
};
137137
#[cfg(not(feature = "tls"))]

src/tls.rs

Lines changed: 0 additions & 173 deletions
This file was deleted.

0 commit comments

Comments
 (0)