#[cfg(feature = "rustls-tls")]
pub mod rustls_tls {
use hyper_rustls::ConfigBuilderExt;
use rustls::{
self,
client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
pki_types::{CertificateDer, InvalidDnsNameError, PrivateKeyDer, ServerName},
ClientConfig, DigitallySignedStruct,
};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum Error {
#[error("identity PEM is invalid: {0}")]
InvalidIdentityPem(#[source] std::io::Error),
#[error("identity PEM is missing a private key: the key must be PKCS8 or RSA/PKCS1")]
MissingPrivateKey,
#[error("identity PEM is missing certificate")]
MissingCertificate,
#[error("invalid private key: {0}")]
InvalidPrivateKey(#[source] rustls::Error),
#[error("unknown private key format")]
UnknownPrivateKeyFormat,
#[error("failed to add a root certificate: {0}")]
AddRootCertificate(#[source] Box<dyn std::error::Error + Send + Sync>),
#[error("no valid native root CA certificates found")]
NoValidNativeRootCA(#[source] std::io::Error),
#[error("invalid server name: {0}")]
InvalidServerName(#[source] InvalidDnsNameError),
}
pub fn rustls_client_config(
identity_pem: Option<&[u8]>,
root_certs: Option<&[Vec<u8>]>,
accept_invalid: bool,
) -> Result<ClientConfig, Error> {
let config_builder = if let Some(certs) = root_certs {
ClientConfig::builder().with_root_certificates(root_store(certs)?)
} else {
#[cfg(feature = "webpki-roots")]
{
ClientConfig::builder().with_webpki_roots()
}
#[cfg(not(feature = "webpki-roots"))]
{
ClientConfig::builder()
.with_native_roots()
.map_err(Error::NoValidNativeRootCA)?
}
};
let mut client_config = if let Some((chain, pkey)) = identity_pem.map(client_auth).transpose()? {
config_builder
.with_client_auth_cert(chain, pkey)
.map_err(Error::InvalidPrivateKey)?
} else {
config_builder.with_no_client_auth()
};
if accept_invalid {
client_config
.dangerous()
.set_certificate_verifier(std::sync::Arc::new(NoCertificateVerification {}));
}
Ok(client_config)
}
fn root_store(root_certs: &[Vec<u8>]) -> Result<rustls::RootCertStore, Error> {
let mut root_store = rustls::RootCertStore::empty();
for der in root_certs {
root_store
.add(CertificateDer::from(der.to_owned()))
.map_err(|e| Error::AddRootCertificate(Box::new(e)))?;
}
Ok(root_store)
}
fn client_auth(data: &[u8]) -> Result<(Vec<CertificateDer<'static>>, PrivateKeyDer<'static>), Error> {
use rustls_pemfile::Item;
let mut cert_chain = Vec::new();
let mut pkcs8_key = None;
let mut pkcs1_key = None;
let mut sec1_key = None;
let mut reader = std::io::Cursor::new(data);
for item in rustls_pemfile::read_all(&mut reader)
.collect::<Result<Vec<_>, _>>()
.map_err(Error::InvalidIdentityPem)?
{
match item {
Item::X509Certificate(cert) => cert_chain.push(cert),
Item::Pkcs8Key(key) => pkcs8_key = Some(PrivateKeyDer::Pkcs8(key)),
Item::Pkcs1Key(key) => pkcs1_key = Some(PrivateKeyDer::from(key)),
Item::Sec1Key(key) => sec1_key = Some(PrivateKeyDer::from(key)),
_ => return Err(Error::UnknownPrivateKeyFormat),
}
}
let private_key = pkcs8_key
.or(pkcs1_key)
.or(sec1_key)
.ok_or(Error::MissingPrivateKey)?;
if cert_chain.is_empty() {
return Err(Error::MissingCertificate);
}
Ok((cert_chain, private_key))
}
#[derive(Debug)]
struct NoCertificateVerification {}
impl ServerCertVerifier for NoCertificateVerification {
fn verify_server_cert(
&self,
_end_entity: &CertificateDer,
_intermediates: &[CertificateDer],
_server_name: &ServerName,
_ocsp_response: &[u8],
_now: rustls::pki_types::UnixTime,
) -> Result<ServerCertVerified, rustls::Error> {
tracing::warn!("Server cert bypassed");
Ok(ServerCertVerified::assertion())
}
fn verify_tls13_signature(
&self,
_message: &[u8],
_cert: &CertificateDer,
_dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, rustls::Error> {
Ok(HandshakeSignatureValid::assertion())
}
fn verify_tls12_signature(
&self,
_message: &[u8],
_cert: &CertificateDer,
_dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, rustls::Error> {
Ok(HandshakeSignatureValid::assertion())
}
fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
use rustls::SignatureScheme;
vec![
SignatureScheme::RSA_PKCS1_SHA1,
SignatureScheme::ECDSA_SHA1_Legacy,
SignatureScheme::RSA_PKCS1_SHA256,
SignatureScheme::ECDSA_NISTP256_SHA256,
SignatureScheme::RSA_PKCS1_SHA384,
SignatureScheme::ECDSA_NISTP384_SHA384,
SignatureScheme::RSA_PKCS1_SHA512,
SignatureScheme::ECDSA_NISTP521_SHA512,
SignatureScheme::RSA_PSS_SHA256,
SignatureScheme::RSA_PSS_SHA384,
SignatureScheme::RSA_PSS_SHA512,
SignatureScheme::ED25519,
SignatureScheme::ED448,
]
}
}
}
#[cfg(feature = "openssl-tls")]
pub mod openssl_tls {
use openssl::{
pkey::PKey,
ssl::{SslConnector, SslConnectorBuilder, SslMethod},
x509::X509,
};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum Error {
#[error("failed to create OpenSSL HTTPS connector: {0}")]
CreateHttpsConnector(#[source] openssl::error::ErrorStack),
#[error("failed to create OpenSSL SSL connector: {0}")]
CreateSslConnector(#[source] SslConnectorError),
}
#[derive(Debug, Error)]
pub enum SslConnectorError {
#[error("failed to build SslConnectorBuilder: {0}")]
CreateBuilder(#[source] openssl::error::ErrorStack),
#[error("failed to deserialize PEM-encoded chain of certificates: {0}")]
DeserializeCertificateChain(#[source] openssl::error::ErrorStack),
#[error("failed to deserialize PEM-encoded private key: {0}")]
DeserializePrivateKey(#[source] openssl::error::ErrorStack),
#[error("failed to set private key: {0}")]
SetPrivateKey(#[source] openssl::error::ErrorStack),
#[error("failed to get a leaf certificate, the certificate chain is empty")]
GetLeafCertificate,
#[error("failed to set the leaf certificate: {0}")]
SetLeafCertificate(#[source] openssl::error::ErrorStack),
#[error("failed to append a certificate to the chain: {0}")]
AppendCertificate(#[source] openssl::error::ErrorStack),
#[error("failed to deserialize DER-encoded root certificate: {0}")]
DeserializeRootCertificate(#[source] openssl::error::ErrorStack),
#[error("failed to add a root certificate: {0}")]
AddRootCertificate(#[source] openssl::error::ErrorStack),
}
pub fn ssl_connector_builder(
identity_pem: Option<&Vec<u8>>,
root_certs: Option<&Vec<Vec<u8>>>,
) -> Result<SslConnectorBuilder, SslConnectorError> {
let mut builder =
SslConnector::builder(SslMethod::tls()).map_err(SslConnectorError::CreateBuilder)?;
if let Some(pem) = identity_pem {
let mut chain = X509::stack_from_pem(pem)
.map_err(SslConnectorError::DeserializeCertificateChain)?
.into_iter();
let leaf_cert = chain.next().ok_or(SslConnectorError::GetLeafCertificate)?;
builder
.set_certificate(&leaf_cert)
.map_err(SslConnectorError::SetLeafCertificate)?;
for cert in chain {
builder
.add_extra_chain_cert(cert)
.map_err(SslConnectorError::AppendCertificate)?;
}
let pkey = PKey::private_key_from_pem(pem).map_err(SslConnectorError::DeserializePrivateKey)?;
builder
.set_private_key(&pkey)
.map_err(SslConnectorError::SetPrivateKey)?;
}
if let Some(ders) = root_certs {
for der in ders {
let cert = X509::from_der(der).map_err(SslConnectorError::DeserializeRootCertificate)?;
builder
.cert_store_mut()
.add_cert(cert)
.map_err(SslConnectorError::AddRootCertificate)?;
}
}
Ok(builder)
}
}