Skip to content

Commit

Permalink
fix(771): Adding mTLS support in QUIC (#899)
Browse files Browse the repository at this point in the history
* refactor(tls-quic): moving shared code into zenoh-link-commons::tls

Signed-off-by: gabrik <[email protected]>

* fix(mtls-quic): adding support for mTLS in QUIC [no ci] - broken

Signed-off-by: gabrik <[email protected]>

* fix(mtls-quic): using current release of quinn at the cost of some duplicated code

Signed-off-by: gabrik <[email protected]>

* test(quic-mlts): added tests for QUIC with mTLS, using rustls 0.22 to workaround the default CryptoProvider panic

Signed-off-by: gabrik <[email protected]>

* chore: addressing comments

Signed-off-by: gabrik <[email protected]>

* Apply suggestions from code review

---------

Signed-off-by: gabrik <[email protected]>
Co-authored-by: Luca Cominardi <[email protected]>
  • Loading branch information
gabrik and Mallets authored Apr 24, 2024
1 parent 2fdddae commit 9a9832a
Show file tree
Hide file tree
Showing 12 changed files with 1,334 additions and 734 deletions.
22 changes: 14 additions & 8 deletions Cargo.lock

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

35 changes: 22 additions & 13 deletions io/zenoh-link-commons/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,35 +12,44 @@
# ZettaScale Zenoh Team, <[email protected]>
#
[package]
rust-version = { workspace = true }
name = "zenoh-link-commons"
version = { workspace = true }
repository = { workspace = true }
homepage = { workspace = true }
authors = { workspace = true }
edition = { workspace = true }
license = { workspace = true }
categories = { workspace = true }
description = "Internal crate for zenoh."
edition = { workspace = true }
homepage = { workspace = true }
license = { workspace = true }
name = "zenoh-link-commons"
repository = { workspace = true }
rust-version = { workspace = true }
version = { workspace = true }
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[features]
compression = []

[dependencies]
async-trait = { workspace = true }
base64 = { workspace = true, optional = true }
flume = { workspace = true }
futures = { workspace = true }
rustls = { workspace = true }
rustls-webpki = { workspace = true }
flume = { workspace = true }
tracing = {workspace = true}
serde = { workspace = true, features = ["default"] }
tokio = { workspace = true, features = [
"fs",
"io-util",
"net",
"sync",
"time",
] }
tokio-util = { workspace = true, features = ["rt"] }
tracing = { workspace = true }
webpki-roots = { workspace = true, optional = true }
zenoh-buffers = { workspace = true }
zenoh-codec = { workspace = true }
zenoh-config = { workspace = true }
zenoh-core = { workspace = true }
zenoh-protocol = { workspace = true }
zenoh-result = { workspace = true }
zenoh-util = { workspace = true }
zenoh-runtime = { workspace = true }
tokio = { workspace = true, features = ["io-util", "net", "fs", "sync", "time"] }
tokio-util = { workspace = true, features = ["rt"] }
futures = { workspace = true }
zenoh-util = { workspace = true }
33 changes: 20 additions & 13 deletions io/zenoh-links/zenoh-link-quic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,39 +12,46 @@
# ZettaScale Zenoh Team, <[email protected]>
#
[package]
rust-version = { workspace = true }
name = "zenoh-link-quic"
version = { workspace = true }
repository = { workspace = true }
homepage = { workspace = true }
authors = { workspace = true }
edition = { workspace = true }
license = { workspace = true }
categories = { workspace = true }
description = "Internal crate for zenoh."
edition = { workspace = true }
homepage = { workspace = true }
license = { workspace = true }
name = "zenoh-link-quic"
repository = { workspace = true }
rust-version = { workspace = true }
version = { workspace = true }
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
async-trait = { workspace = true }
base64 = { workspace = true }
futures = { workspace = true }
tracing = {workspace = true}
quinn = { workspace = true }
rustls-native-certs = { workspace = true }
rustls-pemfile = { workspace = true }
rustls-pki-types = { workspace = true }
rustls-webpki = { workspace = true }
secrecy = {workspace = true }
tokio = { workspace = true, features = ["io-util", "net", "fs", "sync", "time"] }
secrecy = { workspace = true }
tokio = { workspace = true, features = [
"fs",
"io-util",
"net",
"sync",
"time",
] }
tokio-util = { workspace = true, features = ["rt"] }
tracing = { workspace = true }
webpki-roots = { workspace = true }
zenoh-config = { workspace = true }
zenoh-core = { workspace = true }
zenoh-link-commons = { workspace = true }
zenoh-protocol = { workspace = true }
zenoh-result = { workspace = true }
zenoh-runtime = { workspace = true }
zenoh-sync = { workspace = true }
zenoh-util = { workspace = true }
zenoh-runtime = { workspace = true }

# Lock due to quinn not supporting rustls 0.22 yet
rustls = { version = "0.21", features = ["dangerous_configuration", "quic"] }
tokio-rustls = "0.24.1"
rustls-pemfile = { version = "1" }
122 changes: 19 additions & 103 deletions io/zenoh-links/zenoh-link-quic/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,17 @@
//!
//! [Click here for Zenoh's documentation](../zenoh/index.html)
use async_trait::async_trait;
use config::{
TLS_ROOT_CA_CERTIFICATE_BASE64, TLS_ROOT_CA_CERTIFICATE_FILE, TLS_SERVER_CERTIFICATE_BASE64,
TLS_SERVER_CERTIFICATE_FILE, TLS_SERVER_NAME_VERIFICATION, TLS_SERVER_PRIVATE_KEY_BASE64,
TLS_SERVER_PRIVATE_KEY_FILE,
};
use secrecy::ExposeSecret;
use std::net::SocketAddr;
use zenoh_config::Config;

use zenoh_core::zconfigurable;
use zenoh_link_commons::{ConfigurationInspector, LocatorInspector};
use zenoh_protocol::core::{
endpoint::{Address, Parameters},
Locator,
};
use zenoh_result::{bail, zerror, ZResult};
use zenoh_link_commons::LocatorInspector;
use zenoh_protocol::core::Locator;
use zenoh_result::ZResult;

mod unicast;
mod utils;
mod verify;
pub use unicast::*;
pub use utils::TlsConfigurator as QuicConfigurator;

// Default ALPN protocol
pub const ALPN_QUIC_HTTP: &[&[u8]] = &[b"hq-29"];
Expand Down Expand Up @@ -64,77 +56,6 @@ impl LocatorInspector for QuicLocatorInspector {
}
}

#[derive(Default, Clone, Copy, Debug)]
pub struct QuicConfigurator;

impl ConfigurationInspector<Config> for QuicConfigurator {
fn inspect_config(&self, config: &Config) -> ZResult<String> {
let mut ps: Vec<(&str, &str)> = vec![];

let c = config.transport().link().tls();

match (c.root_ca_certificate(), c.root_ca_certificate_base64()) {
(Some(_), Some(_)) => {
bail!("Only one between 'root_ca_certificate' and 'root_ca_certificate_base64' can be present!")
}
(Some(ca_certificate), None) => {
ps.push((TLS_ROOT_CA_CERTIFICATE_FILE, ca_certificate));
}
(None, Some(ca_certificate)) => {
ps.push((
TLS_ROOT_CA_CERTIFICATE_BASE64,
ca_certificate.expose_secret(),
));
}
_ => {}
}

match (c.server_private_key(), c.server_private_key_base64()) {
(Some(_), Some(_)) => {
bail!("Only one between 'server_private_key' and 'server_private_key_base64' can be present!")
}
(Some(server_private_key), None) => {
ps.push((TLS_SERVER_PRIVATE_KEY_FILE, server_private_key));
}
(None, Some(server_private_key)) => {
ps.push((
TLS_SERVER_PRIVATE_KEY_BASE64,
server_private_key.expose_secret(),
));
}
_ => {}
}

match (c.server_certificate(), c.server_certificate_base64()) {
(Some(_), Some(_)) => {
bail!("Only one between 'server_certificate' and 'server_certificate_base64' can be present!")
}
(Some(server_certificate), None) => {
ps.push((TLS_SERVER_CERTIFICATE_FILE, server_certificate));
}
(None, Some(server_certificate)) => {
ps.push((
TLS_SERVER_CERTIFICATE_BASE64,
server_certificate.expose_secret(),
));
}
_ => {}
}

if let Some(server_name_verification) = c.server_name_verification() {
match server_name_verification {
true => ps.push((TLS_SERVER_NAME_VERIFICATION, "true")),
false => ps.push((TLS_SERVER_NAME_VERIFICATION, "false")),
};
}

let mut s = String::new();
Parameters::extend(ps.drain(..), &mut s);

Ok(s)
}
}

zconfigurable! {
// Default MTU (QUIC PDU) in bytes.
static ref QUIC_DEFAULT_MTU: u16 = QUIC_MAX_MTU;
Expand All @@ -157,25 +78,20 @@ pub mod config {
pub const TLS_SERVER_PRIVATE_KEY_RAW: &str = "server_private_key_raw";
pub const TLS_SERVER_PRIVATE_KEY_BASE64: &str = "server_private_key_base64";

pub const TLS_SERVER_CERTIFICATE_FILE: &str = "tls_server_certificate_file";
pub const TLS_SERVER_CERTIFICATE_RAW: &str = "tls_server_certificate_raw";
pub const TLS_SERVER_CERTIFICATE_BASE64: &str = "tls_server_certificate_base64";
pub const TLS_SERVER_CERTIFICATE_FILE: &str = "server_certificate_file";
pub const TLS_SERVER_CERTIFICATE_RAW: &str = "server_certificate_raw";
pub const TLS_SERVER_CERTIFICATE_BASE64: &str = "server_certificate_base64";

pub const TLS_SERVER_NAME_VERIFICATION: &str = "server_name_verification";
pub const TLS_SERVER_NAME_VERIFICATION_DEFAULT: &str = "true";
}
pub const TLS_CLIENT_PRIVATE_KEY_FILE: &str = "client_private_key_file";
pub const TLS_CLIENT_PRIVATE_KEY_RAW: &str = "client_private_key_raw";
pub const TLS_CLIENT_PRIVATE_KEY_BASE64: &str = "client_private_key_base64";

async fn get_quic_addr(address: &Address<'_>) -> ZResult<SocketAddr> {
match tokio::net::lookup_host(address.as_str()).await?.next() {
Some(addr) => Ok(addr),
None => bail!("Couldn't resolve QUIC locator address: {}", address),
}
}
pub const TLS_CLIENT_CERTIFICATE_FILE: &str = "client_certificate_file";
pub const TLS_CLIENT_CERTIFICATE_RAW: &str = "client_certificate_raw";
pub const TLS_CLIENT_CERTIFICATE_BASE64: &str = "client_certificate_base64";

pub fn base64_decode(data: &str) -> ZResult<Vec<u8>> {
use base64::engine::general_purpose;
use base64::Engine;
Ok(general_purpose::STANDARD
.decode(data)
.map_err(|e| zerror!("Unable to perform base64 decoding: {e:?}"))?)
pub const TLS_CLIENT_AUTH: &str = "client_auth";

pub const TLS_SERVER_NAME_VERIFICATION: &str = "server_name_verification";
pub const TLS_SERVER_NAME_VERIFICATION_DEFAULT: &str = "true";
}
Loading

0 comments on commit 9a9832a

Please sign in to comment.