Skip to content

Commit c70064a

Browse files
behoskezhuw
authored andcommitted
Support tls certificates reload and crls
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 reload refreshed certificates stored somewhere in client side. This commit also adds support for crls in cert verifier, so it will reject revoked server certs. Resolves #59.
1 parent 6bf26a1 commit c70064a

File tree

10 files changed

+1075
-227
lines changed

10 files changed

+1075
-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::{TlsCa, TlsCerts, TlsCertsBuilder, TlsCertsOptions, TlsDynamicCerts, TlsIdentity, TlsOptions};
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)