#![cfg(feature = "tls")]
use std::path::PathBuf;
use std::sync::Arc;
use oxihttp_core::OxiHttpError;
use oxitls::tls13::ClientBuilder;
use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};
use rustls::pki_types::{CertificateDer, ServerName, UnixTime};
use rustls::{DigitallySignedStruct, Error as RustlsError, SignatureScheme};
use tokio_rustls::TlsConnector;
#[derive(Debug)]
pub struct DangerousNoVerification {
provider: Arc<rustls::crypto::CryptoProvider>,
}
impl DangerousNoVerification {
pub fn new(provider: Arc<rustls::crypto::CryptoProvider>) -> Self {
Self { provider }
}
}
impl ServerCertVerifier for DangerousNoVerification {
fn verify_server_cert(
&self,
_end_entity: &CertificateDer<'_>,
_intermediates: &[CertificateDer<'_>],
_server_name: &ServerName<'_>,
_ocsp_response: &[u8],
_now: UnixTime,
) -> Result<ServerCertVerified, RustlsError> {
Ok(ServerCertVerified::assertion())
}
fn verify_tls12_signature(
&self,
message: &[u8],
cert: &CertificateDer<'_>,
dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, RustlsError> {
rustls::crypto::verify_tls12_signature(
message,
cert,
dss,
&self.provider.signature_verification_algorithms,
)
}
fn verify_tls13_signature(
&self,
message: &[u8],
cert: &CertificateDer<'_>,
dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, RustlsError> {
rustls::crypto::verify_tls13_signature(
message,
cert,
dss,
&self.provider.signature_verification_algorithms,
)
}
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
self.provider
.signature_verification_algorithms
.supported_schemes()
}
}
pub(crate) fn build_tls_connector(
trusted_certs_der: &[Vec<u8>],
alpn: &[String],
accept_invalid: bool,
webpki_roots: bool,
key_log_path: Option<PathBuf>,
early_data: bool,
) -> Result<TlsConnector, OxiHttpError> {
let mut builder = ClientBuilder::new().with_tls12_fallback();
if webpki_roots {
builder = builder.with_webpki_roots();
}
for cert_der in trusted_certs_der {
builder = builder
.with_trusted_cert_der(cert_der.clone())
.map_err(|e| OxiHttpError::Tls(e.to_string()))?;
}
if !alpn.is_empty() {
let alpn_refs: Vec<&str> = alpn.iter().map(String::as_str).collect();
builder = builder.with_alpn_protocols(alpn_refs.iter().copied());
}
if accept_invalid {
builder = builder.with_danger_accept_invalid_certs();
}
if let Some(path) = key_log_path {
builder = builder.with_key_log_file(path);
}
if early_data {
builder = builder.with_early_data();
}
let cfg = builder
.build()
.map_err(|e| OxiHttpError::Tls(e.to_string()))?;
Ok(TlsConnector::from(Arc::new(cfg)))
}
pub(crate) fn build_tls_connector_with_verifier(
verifier: Arc<dyn ServerCertVerifier>,
alpn: &[String],
early_data: bool,
) -> Result<TlsConnector, OxiHttpError> {
let provider = oxitls::pure_provider();
let cfg_builder = rustls::ClientConfig::builder_with_provider(provider)
.with_protocol_versions(&[&rustls::version::TLS13, &rustls::version::TLS12])
.map_err(|e| OxiHttpError::Tls(e.to_string()))?;
let with_verifier = cfg_builder
.dangerous()
.with_custom_certificate_verifier(verifier);
let mut cfg = with_verifier.with_no_client_auth();
if !alpn.is_empty() {
cfg.alpn_protocols = alpn.iter().map(|s| s.as_bytes().to_vec()).collect();
}
if early_data {
cfg.enable_early_data = true;
}
Ok(TlsConnector::from(Arc::new(cfg)))
}