Skip to content

Instantly share code, notes, and snippets.

@cmdln
Created November 12, 2018 16:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cmdln/7a22d546504863ad205fac3aa11aa520 to your computer and use it in GitHub Desktop.
Save cmdln/7a22d546504863ad205fac3aa11aa520 to your computer and use it in GitHub Desktop.
Using self-signed client, server certificates with hyper, hypper-openssl, and openssl
use hyper::{client::HttpConnector, Body, Client};
use hyper_openssl::HttpsConnector;
use openssl::{
pkcs12::Pkcs12,
ssl::{SslConnector, SslMethod, SslVerifyMode},
x509::X509,
};
use error::*;
use resource;
pub type HyperClient = Client<HttpsConnector<HttpConnector>, Body>;
pub fn configure_client(
threads: usize,
client_cert: Option<&str>,
ca_cert: Option<&str>,
) -> Result<HyperClient> {
let mut connector = HttpConnector::new(threads);
connector.enforce_http(false);
let mut builder = SslConnector::builder(SslMethod::tls())?;
if let Some(client_cert) = client_cert {
debug!("Adding client certificate");
let mut pkcs12 = decrypt_cert(client_cert).and_then(|(der, pass)| {
let pkcs12 = Pkcs12::from_der(&der)?;
pkcs12.parse(&pass.trim()).map_err(|error| error.into())
})?;
builder.set_certificate(&pkcs12.cert)?;
builder.set_private_key(&pkcs12.pkey)?;
if let Some(chain) = pkcs12.chain {
for cert in chain {
debug!("Chained cert {}", std::str::from_utf8(&cert.to_pem()?)?);
builder.add_extra_chain_cert(cert)?;
}
}
// TODO check that the CA cert in this repo is up to date with the server
builder.set_verify(SslVerifyMode::PEER);
}
if let Some(ca_cert) = ca_cert {
debug!("Adding ca certificate");
let ca_cert_buffer = resource::fetch_multipart_secret(ca_cert)?;
let ca_cert = X509::from_der(&ca_cert_buffer)?;
debug!("CA cert {}", std::str::from_utf8(&ca_cert.to_pem()?)?);
let mut store = builder.cert_store_mut();
store.add_cert(ca_cert)?;
}
let connector = HttpsConnector::with_connector(connector, builder)?;
Ok(Client::builder().build(connector))
}
/// Drive SOPS to decrypt the client certificate and its password.
fn decrypt_cert(client_cert_name: &str) -> Result<(Vec<u8>, String)> {
let cert = resource::fetch_multipart_secret(&format!("{}-cert", client_cert_name))?;
let pass = resource::fetch_secret(&format!("{}-pass", client_cert_name))?;
Ok((cert, pass))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment