From e80a0f3a891e8ab160d723bf55689d64e7930b93 Mon Sep 17 00:00:00 2001 From: "Alex S. Glomsaas" Date: Sat, 31 Mar 2018 21:09:42 +0200 Subject: [PATCH] Implement CertFP resolves #131 --- README.md | 2 ++ src/client/conn.rs | 11 ++++++++++- src/client/data/config.rs | 16 ++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b64055e..febb667 100644 --- a/README.md +++ b/README.md @@ -145,6 +145,8 @@ port = 6697 password = "" use_ssl = true cert_path = "cert.der" +client_cert_path = "client.der" +client_cert_pass = "password" encoding = "UTF-8" channels = ["#rust", "#haskell", "#fake"] umodes = "+RB-x" diff --git a/src/client/conn.rs b/src/client/conn.rs index 0bb11bc..e9552d2 100644 --- a/src/client/conn.rs +++ b/src/client/conn.rs @@ -6,7 +6,7 @@ use std::io::Read; use encoding::EncoderTrap; use encoding::label::encoding_from_whatwg_label; use futures::{Async, Poll, Future, Sink, StartSend, Stream}; -use native_tls::{Certificate, TlsConnector}; +use native_tls::{Certificate, TlsConnector, Pkcs12}; use tokio_core::reactor::Handle; use tokio_core::net::{TcpStream, TcpStreamNew}; use tokio_io::AsyncRead; @@ -135,6 +135,15 @@ impl Connection { builder.add_root_certificate(cert)?; info!("Added {} to trusted certificates.", cert_path); } + if let Some(client_cert_path) = config.client_cert_path() { + let client_cert_pass = config.client_cert_pass(); + let mut file = File::open(client_cert_path)?; + let mut client_cert_data = vec![]; + file.read_to_end(&mut client_cert_data)?; + let pkcs12_archive = Pkcs12::from_der(&client_cert_data, &client_cert_pass)?; + builder.identity(pkcs12_archive)?; + info!("Using {} for client certificate authentication.", client_cert_path); + } let connector = builder.build()?; let stream = Box::new(TcpStream::connect(&config.socket_addr()?, handle).map_err(|e| { let res: error::IrcError = e.into(); diff --git a/src/client/data/config.rs b/src/client/data/config.rs index 1f338bc..f72d99e 100644 --- a/src/client/data/config.rs +++ b/src/client/data/config.rs @@ -88,6 +88,10 @@ pub struct Config { pub use_ssl: Option, /// The path to the SSL certificate for this server in DER format. pub cert_path: Option, + /// The path to a SSL certificate to use for CertFP client authentication in DER format. + pub client_cert_path: Option, + /// The password for the certificate to use in CertFP authentication. + pub client_cert_pass: Option, /// The encoding type used for this connection. /// This is typically UTF-8, but could be something else. pub encoding: Option, @@ -419,6 +423,16 @@ impl Config { self.cert_path.as_ref().map(|s| &s[..]) } + /// Gets the path to the client authentication certificate in DER format if specified. + pub fn client_cert_path(&self) -> Option<&str> { + self.client_cert_path.as_ref().map(|s| &s[..]) + } + + /// Gets the password to the client authentication certificate. + pub fn client_cert_pass(&self) -> &str { + self.client_cert_pass.as_ref().map_or("", |s| &s[..]) + } + /// Gets the encoding to use for this connection. This requires the encode feature to work. /// This defaults to UTF-8 when not specified. pub fn encoding(&self) -> &str { @@ -557,6 +571,8 @@ mod test { port: Some(6667), use_ssl: Some(false), cert_path: None, + client_cert_path: None, + client_cert_pass: None, encoding: Some(format!("UTF-8")), channels: Some(vec![format!("#test"), format!("#test2")]), channel_keys: None,