Skip to content

Commit

Permalink
feat(client): allow to disable server cert verification on dangerous …
Browse files Browse the repository at this point in the history
…feature for all http version
  • Loading branch information
joelwurtz committed Feb 2, 2025
1 parent 4d339df commit e81aca9
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 74 deletions.
2 changes: 1 addition & 1 deletion client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ json = ["serde", "serde_json"]
websocket = ["http-ws"]
# feature for trusted local network:
# - http/2 clear text over plain tcp connection
# - http/3 connection to server with self signed certificates
# - allow invalid certificates for client in http/1, http/2 and/or http/3
dangerous = []

[dependencies]
Expand Down
90 changes: 24 additions & 66 deletions client/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ pub struct ClientBuilder {
local_addr: Option<SocketAddr>,
max_http_version: Version,
service: HttpService,
#[cfg(feature = "dangerous")]
allow_invalid_certificate: bool,
}

impl Default for ClientBuilder {
Expand All @@ -46,6 +48,8 @@ impl ClientBuilder {
local_addr: None,
max_http_version: max_http_version(),
service: base_service(),
#[cfg(feature = "dangerous")]
allow_invalid_certificate: false,
}
}

Expand Down Expand Up @@ -120,14 +124,22 @@ impl ClientBuilder {
#[cfg(feature = "openssl")]
/// enable openssl as tls connector.
pub fn openssl(mut self) -> Self {
self.connector = connector::openssl::connect(self.alpn_from_version());
self.connector = connector::openssl::connect(
self.alpn_from_version(),
#[cfg(feature = "dangerous")]
self.allow_invalid_certificate,
);
self
}

#[cfg(any(feature = "rustls", feature = "rustls-ring-crypto"))]
/// enable rustls as tls connector.
pub fn rustls(mut self) -> Self {
self.connector = connector::rustls::connect(self.alpn_from_version());
self.connector = connector::rustls::connect(
self.alpn_from_version(),
#[cfg(feature = "dangerous")]
self.allow_invalid_certificate,
);
self
}

Expand Down Expand Up @@ -324,6 +336,13 @@ impl ClientBuilder {
self
}

#[cfg(feature = "dangerous")]
/// Allow invalid certificate for tls connection.
pub fn allow_invalid_certificate(mut self) -> Self {
self.allow_invalid_certificate = true;
self
}

/// Finish the builder and construct [Client] instance.
pub fn finish(self) -> Client {
#[cfg(feature = "http3")]
Expand All @@ -346,71 +365,10 @@ impl ClientBuilder {

#[cfg(feature = "dangerous")]
{
use xitca_tls::rustls::{
self,
client::danger::HandshakeSignatureValid,
crypto::{verify_tls12_signature, verify_tls13_signature},
pki_types::{CertificateDer, ServerName, UnixTime},
DigitallySignedStruct,
};

#[derive(Debug)]
pub(crate) struct SkipServerVerification;

impl SkipServerVerification {
fn new() -> Arc<Self> {
Arc::new(Self)
}
}

impl rustls::client::danger::ServerCertVerifier for SkipServerVerification {
fn verify_server_cert(
&self,
_end_entity: &CertificateDer<'_>,
_intermediates: &[CertificateDer<'_>],
_server_name: &ServerName<'_>,
_ocsp: &[u8],
_now: UnixTime,
) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
Ok(rustls::client::danger::ServerCertVerified::assertion())
}

fn verify_tls12_signature(
&self,
message: &[u8],
cert: &CertificateDer<'_>,
dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, rustls::Error> {
verify_tls12_signature(
message,
cert,
dss,
&rustls::crypto::ring::default_provider().signature_verification_algorithms,
)
}

fn verify_tls13_signature(
&self,
message: &[u8],
cert: &CertificateDer<'_>,
dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, rustls::Error> {
verify_tls13_signature(
message,
cert,
dss,
&rustls::crypto::ring::default_provider().signature_verification_algorithms,
)
}

fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
rustls::crypto::ring::default_provider()
.signature_verification_algorithms
.supported_schemes()
}
if self.allow_invalid_certificate {
cfg.dangerous()
.set_certificate_verifier(crate::tls::dangerous::rustls::SkipServerVerification::new());
}

cfg.dangerous().set_certificate_verifier(SkipServerVerification::new());
}

let mut endpoint = match self.local_addr {
Expand Down
29 changes: 25 additions & 4 deletions client/src/tls/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ pub(crate) mod openssl {
}
}

pub(crate) fn connect(protocols: &[&[u8]]) -> Connector {
pub(crate) fn connect(protocols: &[&[u8]], #[cfg(feature = "dangerous")] allow_invalid_certs: bool) -> Connector {
let mut alpn = Vec::with_capacity(20);
for proto in protocols {
alpn.put_u8(proto.len() as u8);
Expand All @@ -81,6 +81,13 @@ pub(crate) mod openssl {
ssl.set_alpn_protos(&alpn)
.unwrap_or_else(|e| panic!("Can not set ALPN protocol: {e:?}"));

#[cfg(feature = "dangerous")]
{
if allow_invalid_certs {
ssl.set_verify(openssl::ssl::SslVerifyMode::NONE);
}
}

Box::new(ssl.build())
}
}
Expand All @@ -89,11 +96,10 @@ pub(crate) mod openssl {
pub(crate) mod rustls {
use std::sync::Arc;

use super::*;
use webpki_roots::TLS_SERVER_ROOTS;
use xitca_tls::rustls::{self, pki_types::ServerName, ClientConfig, ClientConnection, RootCertStore};

use super::*;

pub struct TlsConnector(Arc<ClientConfig>);

impl<'n> Service<(&'n str, TlsStream)> for TlsConnector {
Expand Down Expand Up @@ -123,7 +129,7 @@ pub(crate) mod rustls {
}
}

pub(crate) fn connect(protocols: &[&[u8]]) -> Connector {
pub(crate) fn connect(protocols: &[&[u8]], #[cfg(feature = "dangerous")] allow_invalid_certs: bool) -> Connector {
let mut root_certs = RootCertStore::empty();

root_certs.extend(TLS_SERVER_ROOTS.iter().cloned());
Expand All @@ -134,6 +140,21 @@ pub(crate) mod rustls {

config.alpn_protocols = protocols.iter().map(|p| p.to_vec()).collect();

#[cfg(feature = "dangerous")]
{
if allow_invalid_certs {
#[cfg(feature = "rustls-ring-crypto")]
{
config
.dangerous()
.set_certificate_verifier(crate::tls::dangerous::rustls::SkipServerVerification::new());
}

#[cfg(not(feature = "rustls-ring-crypto"))]
unimplemented!("cannot skip server verification without `rustls-ring-crypto` feature");
}
}

Box::new(TlsConnector(Arc::new(config)))
}
}
67 changes: 67 additions & 0 deletions client/src/tls/dangerous.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#[cfg(feature = "rustls-ring-crypto")]
pub(crate) mod rustls {
use std::sync::Arc;
use xitca_tls::rustls::{
self,
client::danger::HandshakeSignatureValid,
crypto::{verify_tls12_signature, verify_tls13_signature},
pki_types::{CertificateDer, ServerName, UnixTime},
DigitallySignedStruct,
};

#[derive(Debug)]
pub(crate) struct SkipServerVerification;

impl SkipServerVerification {
pub(crate) fn new() -> Arc<Self> {
Arc::new(Self)
}
}

impl rustls::client::danger::ServerCertVerifier for SkipServerVerification {
fn verify_server_cert(
&self,
_end_entity: &CertificateDer<'_>,
_intermediates: &[CertificateDer<'_>],
_server_name: &ServerName<'_>,
_ocsp: &[u8],
_now: UnixTime,
) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
Ok(rustls::client::danger::ServerCertVerified::assertion())
}

fn verify_tls12_signature(
&self,
message: &[u8],
cert: &CertificateDer<'_>,
dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, rustls::Error> {
verify_tls12_signature(
message,
cert,
dss,
&rustls::crypto::ring::default_provider().signature_verification_algorithms,
)
}

fn verify_tls13_signature(
&self,
message: &[u8],
cert: &CertificateDer<'_>,
dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, rustls::Error> {
verify_tls13_signature(
message,
cert,
dss,
&rustls::crypto::ring::default_provider().signature_verification_algorithms,
)
}

fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
rustls::crypto::ring::default_provider()
.signature_verification_algorithms
.supported_schemes()
}
}
}
2 changes: 2 additions & 0 deletions client/src/tls/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
pub(crate) mod connector;
#[cfg(feature = "dangerous")]
pub(crate) mod dangerous;

pub type TlsStream = Box<dyn xitca_io::io::AsyncIoDyn + Send>;
6 changes: 3 additions & 3 deletions test/tests/h3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use xitca_test::{test_h3_server, Error};
async fn h3_get() -> Result<(), Error> {
let mut handle = test_h3_server(fn_service(handle))?;

let c = Client::new();
let c = Client::builder().allow_invalid_certificate().finish();
let server_url = format!("https://localhost:{}/", handle.addr().port());

for _ in 0..3 {
Expand All @@ -37,7 +37,7 @@ async fn h3_no_host_header() -> Result<(), Error> {

let server_url = format!("https://{}/host", handle.ip_port_string());

let c = Client::new();
let c = Client::builder().allow_invalid_certificate().finish();

for _ in 0..3 {
let mut req = c.get(&server_url).version(Version::HTTP_3);
Expand All @@ -61,7 +61,7 @@ async fn h3_no_host_header() -> Result<(), Error> {
async fn h3_post() -> Result<(), Error> {
let mut handle = test_h3_server(fn_service(handle))?;

let c = Client::new();
let c = Client::builder().allow_invalid_certificate().finish();

let server_url = format!("https://localhost:{}/", handle.addr().port());

Expand Down

0 comments on commit e81aca9

Please sign in to comment.