From 1caec3c3c5c72d80c21fd7696bade34876ef9145 Mon Sep 17 00:00:00 2001 From: Mathieu Amiot Date: Tue, 5 Mar 2019 21:12:24 +0100 Subject: [PATCH] WIP --- src/client.rs | 2 +- src/net/mod.rs | 12 +++++++++-- src/net/tls.rs | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 src/net/tls.rs diff --git a/src/client.rs b/src/client.rs index 24b3067..c5acdb5 100644 --- a/src/client.rs +++ b/src/client.rs @@ -209,7 +209,7 @@ impl NatsClient { if tls_required { match Url::parse(&cluster_uri) { Ok(url) => match url.host_str() { - Some(host) => future::ok(Either::B(connect_tls(host.to_string(), cluster_sa))), + Some(host) => future::ok(Either::B(connect_tls(host.to_string(), cluster_sa, None))), None => future::err(NatsError::TlsHostMissingError), }, Err(e) => future::err(e.into()), diff --git a/src/net/mod.rs b/src/net/mod.rs index a18b3b1..43f00ce 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -6,6 +6,9 @@ use std::sync::Arc; pub(crate) mod connection; mod connection_inner; +mod tls; +pub use self::tls::*; + use error::NatsError; use self::connection::NatsConnectionState; @@ -28,13 +31,18 @@ pub(crate) fn connect(addr: SocketAddr) -> impl Future impl Future { +pub(crate) fn connect_tls( + host: String, + addr: SocketAddr, + config: Option, +) -> impl Future { let inner_host = host.clone(); NatsConnectionInner::connect_tcp(&addr) .and_then(move |socket| { debug!(target: "nitox", "Connected through TCP, upgrading to TLS"); NatsConnectionInner::upgrade_tcp_to_tls(&host, socket) - }).map(move |socket| { + }) + .map(move |socket| { debug!(target: "nitox", "Connected through TCP over TLS"); NatsConnection { is_tls: true, diff --git a/src/net/tls.rs b/src/net/tls.rs new file mode 100644 index 0000000..8c2feb1 --- /dev/null +++ b/src/net/tls.rs @@ -0,0 +1,58 @@ +use error::NatsError; +use std::sync::Arc; +// Written by @wafflespeanut from @Naamio +use native_tls::{Certificate, Identity}; + +/// TLS configuration for the client. +#[derive(Clone, Default)] +pub struct NatsClientTlsConfig { + pub(crate) identity: Option, String)>>, + pub(crate) root_cert: Option>>, +} + +impl NatsClientTlsConfig { + /// Set the identity from a DER-formatted PKCS #12 archive using the the given password to decrypt the key. + pub fn pkcs12_identity(mut self, der_bytes: B, password: &str) -> Result + where + B: AsRef<[u8]>, + { + self.identity = Some(Arc::new((der_bytes.as_ref().into(), password.into()))); + self.identity()?; + Ok(self) + } + + /// Set the root certificate in DER-format. + pub fn root_cert_der(mut self, der_bytes: B) -> Result + where + B: AsRef<[u8]>, + { + self.root_cert = Some(Arc::new(der_bytes.as_ref().into())); + self.root_cert()?; + Ok(self) + } + + pub(crate) fn identity(&self) -> Result, NatsError> { + if let Some((b, p)) = self.identity.as_ref().map(|s| &**s) { + Ok(Some(Identity::from_pkcs12(b, p)?)) + } else { + Ok(None) + } + } + + pub(crate) fn root_cert(&self) -> Result, NatsError> { + if let Some(b) = self.root_cert.as_ref() { + Ok(Some(Certificate::from_der(b)?)) + } else { + Ok(None) + } + } +} + +impl ::std::fmt::Debug for NatsClientTlsConfig { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + f.debug_struct("NatsClientTlsConfig") + .field("identity_exists", &self.identity.is_some()) + .field("root_cert_exists", &self.root_cert.is_some()) + .finish() + } +}