Skip to content

Commit

Permalink
feat: add option to skip domain name verification of servers
Browse files Browse the repository at this point in the history
  • Loading branch information
Fritiofhedstrom committed Aug 4, 2023
1 parent ee5a170 commit f9d07b2
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 24 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 8 additions & 12 deletions commons/zenoh-cfg-properties/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,24 +343,15 @@ pub const ZN_MAX_SESSIONS_MULTICAST_KEY: u64 = 0x84;
pub const ZN_MAX_SESSIONS_MULTICAST_STR: &str = "max_sessions_multicast";
pub const ZN_MAX_SESSIONS_MULTICAST_DEFAULT: &str = "1024";

/// The file path containing the TLS server private key.
/// String key: `"tls_client_private_key"`.
/// Accepted values: `<file path>`.
/// Default value: None.
/// The file path containing the TLS client private key.
pub const ZN_TLS_CLIENT_PRIVATE_KEY_KEY: u64 = 0x85;
pub const ZN_TLS_CLIENT_PRIVATE_KEY_STR: &str = "tls_client_private_key";

/// The file path containing the TLS server certificate.
/// String key: `"tls_client_private_key"`.
/// Accepted values: `<file path>`.
/// Default value: None.
/// The file path containing the TLS client certificate.
pub const ZN_TLS_CLIENT_CERTIFICATE_KEY: u64 = 0x86;
pub const ZN_TLS_CLIENT_CERTIFICATE_STR: &str = "tls_client_certificate";

/// The file path containing the TLS server certificate.
/// String key: `"tls_private_key"`.
/// Accepted values: `"true"`, `"false"`.
/// Default value: `"false"`.
/// Whether to use tls with client authentication
pub const ZN_TLS_CLIENT_AUTH_KEY: u64 = 0x87;
pub const ZN_TLS_CLIENT_AUTH_STR: &str = "tls_client_auth";
pub const ZN_TLS_CLIENT_AUTH_DEFAULT: &str = ZN_FALSE;
Expand All @@ -372,3 +363,8 @@ pub const ZN_TLS_CLIENT_AUTH_DEFAULT: &str = ZN_FALSE;
pub const ZN_QUERIES_DEFAULT_TIMEOUT_KEY: u64 = 0x88;
pub const ZN_QUERIES_DEFAULT_TIMEOUT_STR: &str = "local_routing";
pub const ZN_QUERIES_DEFAULT_TIMEOUT_DEFAULT: &str = "10000";

/// Whether or not to verify that servers have certs valid for their ip or common name
pub const ZN_TLS_SERVER_NAME_VERIFICATION_KEY: u64 = 0x89;
pub const ZN_TLS_SERVER_NAME_VERIFICATION_STR: &str = "server_name_verification";
pub const ZN_TLS_SERVER_NAME_VERIFICATION_DEFAULT: &str = ZN_TRUE;
1 change: 1 addition & 0 deletions commons/zenoh-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ validated_struct::validator! {
client_auth: Option<bool>,
client_private_key: Option<String>,
client_certificate: Option<String>,
server_name_verification: Option<bool>
},
pub compression: #[derive(Default)]
/// **Experimental** compression feature.
Expand Down
1 change: 1 addition & 0 deletions io/zenoh-links/zenoh-link-tls/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ description = "Internal crate for zenoh."

[dependencies]
async-rustls = { workspace = true }
rustls = { workspace = true }
async-std = { workspace = true }
async-trait = { workspace = true }
futures = { workspace = true }
Expand Down
12 changes: 11 additions & 1 deletion io/zenoh-links/zenoh-link-tls/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use async_std::net::ToSocketAddrs;
use async_trait::async_trait;
use config::{
TLS_CLIENT_AUTH, TLS_CLIENT_CERTIFICATE_FILE, TLS_CLIENT_PRIVATE_KEY_FILE,
TLS_ROOT_CA_CERTIFICATE_FILE, TLS_SERVER_CERTIFICATE_FILE, TLS_SERVER_PRIVATE_KEY_FILE,
TLS_ROOT_CA_CERTIFICATE_FILE, TLS_SERVER_CERTIFICATE_FILE, TLS_SERVER_PRIVATE_KEY_FILE, TLS_SERVER_NAME_VERIFICATION,
};
use zenoh_cfg_properties::Properties;
use zenoh_config::{Config, ZN_FALSE, ZN_TRUE};
Expand All @@ -33,6 +33,7 @@ use zenoh_protocol::core::{endpoint::Address, Locator};
use zenoh_result::{bail, zerror, ZResult};

mod unicast;
mod verify;
pub use unicast::*;

// Default MTU (TLS PDU) in bytes.
Expand Down Expand Up @@ -99,6 +100,12 @@ impl ConfigurationInspector<Config> for TlsConfigurator {
tls_client_certificate.into(),
);
}
if let Some(server_name_verification) = c.server_name_verification() {
match server_name_verification {
true => properties.insert(TLS_SERVER_NAME_VERIFICATION.into(), ZN_TRUE.into()),
false => properties.insert(TLS_SERVER_NAME_VERIFICATION.into(), ZN_FALSE.into()),
};
}

Ok(properties)
}
Expand Down Expand Up @@ -136,6 +143,9 @@ pub mod config {

pub const TLS_CLIENT_AUTH: &str = ZN_TLS_CLIENT_AUTH_STR;
pub const TLS_CLIENT_AUTH_DEFAULT: &str = ZN_TLS_CLIENT_AUTH_DEFAULT;

pub const TLS_SERVER_NAME_VERIFICATION: &str = ZN_TLS_SERVER_NAME_VERIFICATION_STR;
pub const TLS_SERVER_NAME_VERIFICATION_DEFAULT: &str = ZN_TLS_SERVER_NAME_VERIFICATION_DEFAULT;
}

pub async fn get_tls_addr(address: &Address<'_>) -> ZResult<SocketAddr> {
Expand Down
53 changes: 42 additions & 11 deletions io/zenoh-links/zenoh-link-tls/src/unicast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
// ZettaScale Zenoh Team, <[email protected]>
//
use crate::{
config::*, get_tls_addr, get_tls_host, get_tls_server_name, TLS_ACCEPT_THROTTLE_TIME,
TLS_DEFAULT_MTU, TLS_LINGER_TIMEOUT, TLS_LOCATOR_PREFIX,
config::*, get_tls_addr, get_tls_host, get_tls_server_name,
verify::WebPkiVerifierAnyServerName, TLS_ACCEPT_THROTTLE_TIME, TLS_DEFAULT_MTU,
TLS_LINGER_TIMEOUT, TLS_LOCATOR_PREFIX,
};
use async_rustls::rustls::server::AllowAnyAuthenticatedClient;
use async_rustls::rustls::version::TLS13;
Expand Down Expand Up @@ -603,6 +604,18 @@ impl TlsClientConfig {
client_auth = value.parse()?
}

let server_name_verification: bool =
if let Some(value) = config.get(TLS_SERVER_NAME_VERIFICATION) {
value
} else {
TLS_SERVER_NAME_VERIFICATION_DEFAULT
}
.parse()?;

if !server_name_verification {
log::warn!("Skipping name verification of servers");
}

// Allows mixed user-generated CA and webPKI CA
log::debug!("Loading default Web PKI certificates.");
let mut root_cert_store: RootCertStore = RootCertStore {
Expand Down Expand Up @@ -640,19 +653,37 @@ impl TlsClientConfig {
bail!("No private key found");
}

ClientConfig::builder()
let builder = ClientConfig::builder()
.with_safe_default_cipher_suites()
.with_safe_default_kx_groups()
.with_protocol_versions(&[&TLS13])
.unwrap()
.with_root_certificates(root_cert_store)
.with_single_cert(certs, keys.remove(0))
.expect("bad certificate/key")
.expect("Config parameters should be valid");

if server_name_verification {
builder
.with_root_certificates(root_cert_store)
.with_client_auth_cert(certs, keys.remove(0))
} else {
builder
.with_custom_certificate_verifier(Arc::new(WebPkiVerifierAnyServerName::new(
root_cert_store,
)))
.with_client_auth_cert(certs, keys.remove(0))
}
.expect("bad certificate/key")
} else {
ClientConfig::builder()
.with_safe_defaults()
.with_root_certificates(root_cert_store)
.with_no_client_auth()
let builder = ClientConfig::builder().with_safe_defaults();
if server_name_verification {
builder
.with_root_certificates(root_cert_store)
.with_no_client_auth()
} else {
builder
.with_custom_certificate_verifier(Arc::new(WebPkiVerifierAnyServerName::new(
root_cert_store,
)))
.with_no_client_auth()
}
};
Ok(TlsClientConfig { client_config: cc })
}
Expand Down
39 changes: 39 additions & 0 deletions io/zenoh-links/zenoh-link-tls/src/verify.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use std::time::SystemTime;
use rustls::client::verify_server_cert_signed_by_trust_anchor;
use rustls::server::ParsedCertificate;
use async_rustls::rustls::{client::{ServerCertVerifier, ServerCertVerified}, Certificate, ServerName, RootCertStore};

impl ServerCertVerifier for WebPkiVerifierAnyServerName {
/// Will verify the certificate is valid in the following ways:
/// - Signed by a trusted `RootCertStore` CA
/// - Not Expired
fn verify_server_cert(
&self,
end_entity: &Certificate,
intermediates: &[Certificate],
_server_name: &ServerName,
_scts: &mut dyn Iterator<Item = &[u8]>,
_ocsp_response: &[u8],
now: SystemTime,
) -> Result<ServerCertVerified, async_rustls::rustls::Error> {
let cert = ParsedCertificate::try_from(end_entity)?;
verify_server_cert_signed_by_trust_anchor(&cert, &self.roots, intermediates, now)?;
Ok(ServerCertVerified::assertion())
}
}

/// `ServerCertVerifier` that verifies that the server is signed by a trusted root, but allows any serverName
/// see the trait impl for more information.
pub struct WebPkiVerifierAnyServerName {
roots: RootCertStore,
}

#[allow(unreachable_pub)]
impl WebPkiVerifierAnyServerName {
/// Constructs a new `WebPkiVerifierAnyServerName`.
///
/// `roots` is the set of trust anchors to trust for issuing server certs.
pub fn new(roots: RootCertStore) -> Self {
Self { roots }
}
}

0 comments on commit f9d07b2

Please sign in to comment.