pub extern crate openssl; extern crate postgres; use openssl::error::ErrorStack; use openssl::hash::MessageDigest; use openssl::nid::Nid; use openssl::ssl::{ConnectConfiguration, SslConnector, SslMethod, SslStream}; use postgres::tls::{Stream, TlsHandshake, TlsStream}; use std::error::Error; use std::fmt; use std::io::{self, Read, Write}; #[cfg(test)] mod test; pub struct OpenSsl { connector: SslConnector, config: Box Result<(), ErrorStack> + Sync + Send>, } impl fmt::Debug for OpenSsl { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("OpenSsl").finish() } } impl OpenSsl { pub fn new() -> Result { let connector = SslConnector::builder(SslMethod::tls())?.build(); Ok(OpenSsl::with_connector(connector)) } pub fn with_connector(connector: SslConnector) -> OpenSsl { OpenSsl { connector, config: Box::new(|_| Ok(())), } } pub fn callback(&mut self, f: F) where F: Fn(&mut ConnectConfiguration) -> Result<(), ErrorStack> + 'static + Sync + Send, { self.config = Box::new(f); } } impl TlsHandshake for OpenSsl { fn tls_handshake( &self, domain: &str, stream: Stream, ) -> Result, Box> { let mut ssl = self.connector.configure()?; (self.config)(&mut ssl)?; let stream = ssl.connect(domain, stream)?; Ok(Box::new(OpenSslStream(stream))) } } #[derive(Debug)] struct OpenSslStream(SslStream); impl Read for OpenSslStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } } impl Write for OpenSslStream { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } fn flush(&mut self) -> io::Result<()> { self.0.flush() } } impl TlsStream for OpenSslStream { fn get_ref(&self) -> &Stream { self.0.get_ref() } fn get_mut(&mut self) -> &mut Stream { self.0.get_mut() } fn tls_server_end_point(&self) -> Option> { let cert = self.0.ssl().peer_certificate()?; let algo_nid = cert.signature_algorithm().object().nid(); let signature_algorithms = algo_nid.signature_algorithms()?; let md = match signature_algorithms.digest { Nid::MD5 | Nid::SHA1 => MessageDigest::sha256(), nid => MessageDigest::from_nid(nid)?, }; let digest = cert.digest(md).ok()?; Some(digest.to_vec()) } }