Skip to content

Commit

Permalink
feat(575): adding support for inline certificates/keys as base64 encoded
Browse files Browse the repository at this point in the history
Signed-off-by: gabrik <[email protected]>
  • Loading branch information
gabrik committed Oct 31, 2023
1 parent b3ba1c4 commit 146c6fe
Show file tree
Hide file tree
Showing 9 changed files with 173 additions and 23 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ async-global-executor = "2.3.1"
async-rustls = "0.4.0"
async-std = { version = "=1.12.0", default-features = false } # Default features are disabled due to some crates' requirements
async-trait = "0.1.60"
base64 = "0.21.0"
base64 = "0.21.4"
bincode = "1.3.3"
clap = "3.2.23"
const_format = "0.2.30"
Expand Down
5 changes: 5 additions & 0 deletions commons/zenoh-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,11 +288,16 @@ validated_struct::validator! {
pub tls: #[derive(Default)]
TLSConf {
root_ca_certificate: Option<String>,
root_ca_certificate_base64: Option<String>,
server_private_key: Option<String>,
server_private_key_base64: Option<String>,
server_certificate: Option<String>,
server_certificate_base64: Option<String>,
client_auth: Option<bool>,
client_private_key: Option<String>,
client_private_key_base64 : Option<String>,
client_certificate: Option<String>,
client_certificate_base64 : Option<String>,
server_name_verification: Option<bool>
},
pub unixpipe: #[derive(Default)]
Expand Down
1 change: 1 addition & 0 deletions io/zenoh-links/zenoh-link-quic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ zenoh-protocol = { workspace = true }
zenoh-result = { workspace = true }
zenoh-sync = { workspace = true }
zenoh-util = { workspace = true }
base64 = { workspace = true }
59 changes: 51 additions & 8 deletions io/zenoh-links/zenoh-link-quic/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
use async_std::net::ToSocketAddrs;
use async_trait::async_trait;
use config::{
TLS_ROOT_CA_CERTIFICATE_FILE, TLS_SERVER_CERTIFICATE_FILE, TLS_SERVER_NAME_VERIFICATION,
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 std::net::SocketAddr;
Expand All @@ -31,7 +32,7 @@ use zenoh_protocol::core::{
endpoint::{Address, Parameters},
Locator,
};
use zenoh_result::{bail, ZResult};
use zenoh_result::{bail, zerror, ZResult};

mod unicast;
mod verify;
Expand Down Expand Up @@ -72,15 +73,46 @@ impl ConfigurationInspector<Config> for QuicConfigurator {
let mut ps: Vec<(&str, &str)> = vec![];

let c = config.transport().link().tls();
if let Some(tls_ca_certificate) = c.root_ca_certificate() {
ps.push((TLS_ROOT_CA_CERTIFICATE_FILE, tls_ca_certificate));

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));
}
_ => {}
}
if let Some(tls_server_private_key) = c.server_private_key() {
ps.push((TLS_SERVER_PRIVATE_KEY_FILE, tls_server_private_key));

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));
}
_ => {}
}
if let Some(tls_server_certificate) = c.server_certificate() {
ps.push((TLS_SERVER_CERTIFICATE_FILE, tls_server_certificate));

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));
}
_ => {}
}

if let Some(server_name_verification) = c.server_name_verification() {
match server_name_verification {
true => ps.push((TLS_SERVER_NAME_VERIFICATION, "true")),
Expand Down Expand Up @@ -111,12 +143,15 @@ zconfigurable! {
pub mod config {
pub const TLS_ROOT_CA_CERTIFICATE_FILE: &str = "root_ca_certificate_file";
pub const TLS_ROOT_CA_CERTIFICATE_RAW: &str = "root_ca_certificate_raw";
pub const TLS_ROOT_CA_CERTIFICATE_BASE64: &str = "root_ca_certificate_base64";

pub const TLS_SERVER_PRIVATE_KEY_FILE: &str = "server_private_key_file";
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_NAME_VERIFICATION: &str = "server_name_verification";
pub const TLS_SERVER_NAME_VERIFICATION_DEFAULT: &str = "true";
Expand All @@ -128,3 +163,11 @@ async fn get_quic_addr(address: &Address<'_>) -> ZResult<SocketAddr> {
None => bail!("Couldn't resolve QUIC locator address: {}", address),
}
}

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:?}"))?)
}
7 changes: 7 additions & 0 deletions io/zenoh-links/zenoh-link-quic/src/unicast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// ZettaScale Zenoh Team, <[email protected]>
//

use crate::base64_decode;
use crate::{
config::*, get_quic_addr, verify::WebPkiVerifierAnyServerName, ALPN_QUIC_HTTP,
QUIC_ACCEPT_THROTTLE_TIME, QUIC_DEFAULT_MTU, QUIC_LOCATOR_PREFIX,
Expand Down Expand Up @@ -246,6 +247,8 @@ impl LinkManagerUnicastTrait for LinkManagerUnicastQuic {
// Read the certificates
let f = if let Some(value) = epconf.get(TLS_ROOT_CA_CERTIFICATE_RAW) {
value.as_bytes().to_vec()
} else if let Some(b64_certificate) = epconf.get(TLS_ROOT_CA_CERTIFICATE_BASE64) {
base64_decode(b64_certificate)?
} else if let Some(value) = epconf.get(TLS_ROOT_CA_CERTIFICATE_FILE) {
async_std::fs::read(value)
.await
Expand Down Expand Up @@ -334,6 +337,8 @@ impl LinkManagerUnicastTrait for LinkManagerUnicastQuic {

let f = if let Some(value) = epconf.get(TLS_SERVER_CERTIFICATE_RAW) {
value.as_bytes().to_vec()
} else if let Some(b64_certificate) = epconf.get(TLS_SERVER_CERTIFICATE_BASE64) {
base64_decode(b64_certificate)?
} else if let Some(value) = epconf.get(TLS_SERVER_CERTIFICATE_FILE) {
async_std::fs::read(value)
.await
Expand All @@ -350,6 +355,8 @@ impl LinkManagerUnicastTrait for LinkManagerUnicastQuic {
// Private keys
let f = if let Some(value) = epconf.get(TLS_SERVER_PRIVATE_KEY_RAW) {
value.as_bytes().to_vec()
} else if let Some(b64_key) = epconf.get(TLS_SERVER_PRIVATE_KEY_BASE64) {
base64_decode(b64_key)?
} else if let Some(value) = epconf.get(TLS_SERVER_PRIVATE_KEY_FILE) {
async_std::fs::read(value)
.await
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 @@ -41,3 +41,4 @@ zenoh-protocol = { workspace = true }
zenoh-result = { workspace = true }
zenoh-sync = { workspace = true }
zenoh-util = { workspace = true }
base64 = { workspace = true }
92 changes: 79 additions & 13 deletions io/zenoh-links/zenoh-link-tls/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ use async_rustls::rustls::ServerName;
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_NAME_VERIFICATION,
TLS_SERVER_PRIVATE_KEY_FILE,
TLS_CLIENT_AUTH, TLS_CLIENT_CERTIFICATE_BASE64, TLS_CLIENT_CERTIFICATE_FILE,
TLS_CLIENT_PRIVATE_KEY_BASE64, TLS_CLIENT_PRIVATE_KEY_FILE, 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_BASE_64, TLS_SERVER_PRIVATE_KEY_FILE,
};
use std::{convert::TryFrom, net::SocketAddr};
use zenoh_config::Config;
Expand Down Expand Up @@ -69,27 +70,79 @@ impl ConfigurationInspector<Config> for TlsConfigurator {
let mut ps: Vec<(&str, &str)> = vec![];

let c = config.transport().link().tls();
if let Some(ca_certificate) = c.root_ca_certificate() {
ps.push((TLS_ROOT_CA_CERTIFICATE_FILE, ca_certificate));

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));
}
_ => {}
}
if let Some(server_private_key) = c.server_private_key() {
ps.push((TLS_SERVER_PRIVATE_KEY_FILE, server_private_key));

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_BASE_64, server_private_key));
}
_ => {}
}
if let Some(server_certificate) = c.server_certificate() {
ps.push((TLS_SERVER_CERTIFICATE_FILE, server_certificate));

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));
}
_ => {}
}

if let Some(client_auth) = c.client_auth() {
match client_auth {
true => ps.push((TLS_CLIENT_AUTH, "true")),
false => ps.push((TLS_CLIENT_AUTH, "false")),
};
}
if let Some(client_private_key) = c.client_private_key() {
ps.push((TLS_CLIENT_PRIVATE_KEY_FILE, client_private_key));

match (c.client_private_key(), c.client_private_key_base64()) {
(Some(_), Some(_)) => {
bail!("Only one between 'client_private_key' and 'client_private_key_base64' can be present!")
}
(Some(client_private_key), None) => {
ps.push((TLS_CLIENT_PRIVATE_KEY_FILE, client_private_key));
}
(None, Some(client_private_key)) => {
ps.push((TLS_CLIENT_PRIVATE_KEY_BASE64, client_private_key));
}
_ => {}
}
if let Some(client_certificate) = c.client_certificate() {
ps.push((TLS_CLIENT_CERTIFICATE_FILE, client_certificate));

match (c.client_private_key(), c.client_private_key_base64()) {
(Some(_), Some(_)) => {
bail!("Only one between 'client_private_key' and 'client_private_key_base64' can be present!")
}
(Some(client_certificate), None) => {
ps.push((TLS_CLIENT_CERTIFICATE_FILE, client_certificate));
}
(None, Some(client_certificate)) => {
ps.push((TLS_CLIENT_CERTIFICATE_BASE64, client_certificate));
}
_ => {}
}

if let Some(server_name_verification) = c.server_name_verification() {
match server_name_verification {
true => ps.push((TLS_SERVER_NAME_VERIFICATION, "true")),
Expand Down Expand Up @@ -120,18 +173,23 @@ zconfigurable! {
pub mod config {
pub const TLS_ROOT_CA_CERTIFICATE_FILE: &str = "root_ca_certificate_file";
pub const TLS_ROOT_CA_CERTIFICATE_RAW: &str = "root_ca_certificate_raw";
pub const TLS_ROOT_CA_CERTIFICATE_BASE64: &str = "root_ca_certificate_base64";

pub const TLS_SERVER_PRIVATE_KEY_FILE: &str = "server_private_key_file";
pub const TLS_SERVER_PRIVATE_KEY_RAW: &str = "server_private_key_raw";
pub const TLS_SERVER_PRIVATE_KEY_BASE_64: &str = "server_private_key_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_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";

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 const TLS_CLIENT_AUTH: &str = "client_auth";

Expand All @@ -156,3 +214,11 @@ pub fn get_tls_host<'a>(address: &'a Address<'a>) -> ZResult<&'a str> {
pub fn get_tls_server_name(address: &Address<'_>) -> ZResult<ServerName> {
Ok(ServerName::try_from(get_tls_host(address)?).map_err(|e| zerror!(e))?)
}

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:?}"))?)
}
Loading

0 comments on commit 146c6fe

Please sign in to comment.