Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] feat: implement support for raw public keys in TLS #2937

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 69 additions & 72 deletions Cargo.lock

Large diffs are not rendered by default.

45 changes: 39 additions & 6 deletions iroh-base/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,41 @@ anyhow = { version = "1" }
blake3 = { version = "1.4.5", package = "iroh-blake3", optional = true }
data-encoding = { version = "2.3.3", optional = true }
hex = "0.4.3"
postcard = { version = "1", default-features = false, features = ["alloc", "use-std", "experimental-derive"], optional = true }
postcard = { version = "1", default-features = false, features = [
"alloc",
"use-std",
"experimental-derive",
], optional = true }
redb = { version = "2.0.0", optional = true }
serde = { version = "1", features = ["derive"] }
thiserror = "2"

# key module
aead = { version = "0.5.2", features = ["bytes"], optional = true }
derive_more = { version = "1.0.0", features = ["debug", "display", "from_str"], optional = true }
ed25519-dalek = { version = "2.0.0", features = ["serde", "rand_core"], optional = true }
derive_more = { version = "1.0.0", features = [
"debug",
"display",
"from_str",
], optional = true }
ed25519-dalek = { version = "2.0.0", features = [
"serde",
"rand_core",
"pkcs8",
"pem",
], optional = true }
once_cell = { version = "1.18.0", optional = true }
rand = { version = "0.8", optional = true }
rand_core = { version = "0.6.4", optional = true }
ssh-key = { version = "0.6.0", features = ["ed25519", "std", "rand_core"], optional = true }
ssh-key = { version = "0.6.0", features = [
"ed25519",
"std",
"rand_core",
], optional = true }
ttl_cache = { version = "0.5.1", optional = true }
crypto_box = { version = "0.9.1", features = ["serde", "chacha20"], optional = true }
crypto_box = { version = "0.9.1", features = [
"serde",
"chacha20",
], optional = true }
zeroize = { version = "1.5", optional = true }
url = { version = "2.5", features = ["serde"], optional = true }
# wasm
Expand All @@ -50,7 +70,20 @@ default = ["hash", "base32", "relay"]
hash = ["dep:blake3", "dep:data-encoding", "dep:postcard", "dep:derive_more", "base32"]
base32 = ["dep:data-encoding", "dep:postcard"]
redb = ["dep:redb"]
key = ["dep:ed25519-dalek", "dep:once_cell", "dep:rand", "dep:rand_core", "dep:ssh-key", "dep:ttl_cache", "dep:aead", "dep:crypto_box", "dep:zeroize", "dep:url", "dep:derive_more", "dep:getrandom"]
key = [
"dep:ed25519-dalek",
"dep:once_cell",
"dep:rand",
"dep:rand_core",
"dep:ssh-key",
"dep:ttl_cache",
"dep:aead",
"dep:crypto_box",
"dep:zeroize",
"dep:url",
"dep:derive_more",
"dep:getrandom",
]
wasm = ["getrandom?/js"]
relay = ["dep:url", "dep:derive_more"]

Expand Down
22 changes: 21 additions & 1 deletion iroh-base/src/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ use std::{
time::Duration,
};

use ed25519_dalek::{
pkcs8::{EncodePrivateKey, EncodePublicKey},
SignatureError, SigningKey, VerifyingKey,
};
pub use ed25519_dalek::{Signature, PUBLIC_KEY_LENGTH};
use ed25519_dalek::{SignatureError, SigningKey, VerifyingKey};
use once_cell::sync::OnceCell;
use rand_core::CryptoRngCore;
use serde::{Deserialize, Serialize};
use ssh_key::LineEnding;
use ttl_cache::TtlCache;
use zeroize::Zeroizing;

pub use self::encryption::SharedSecret;
use self::encryption::{public_ed_box, secret_ed_box};
Expand Down Expand Up @@ -146,6 +150,14 @@ impl PublicKey {
&self.0
}

/// Serializes the public key as PEM
pub fn serialize_public_pem(&self) -> String {
use ed25519_dalek::pkcs8::spki::der::pem::LineEnding;
let key = self.public();
key.to_public_key_pem(LineEnding::default())
.expect("key is valid")
}

fn public(&self) -> VerifyingKey {
get_or_create_crypto_keys(&self.0, |item| item.verifying_key).expect("key has been checked")
}
Expand Down Expand Up @@ -324,6 +336,14 @@ impl SecretKey {
self.secret.verifying_key().into()
}

/// Serializes the secret key as PEM
pub fn serialize_secret_pem(&self) -> Zeroizing<String> {
use ed25519_dalek::pkcs8::spki::der::pem::LineEnding;
self.secret
.to_pkcs8_pem(LineEnding::default())
.expect("key is valid")
}

/// Generate a new [`SecretKey`] with the default randomness generator.
pub fn generate() -> Self {
let mut rng = rand::rngs::OsRng;
Expand Down
12 changes: 9 additions & 3 deletions iroh/bench/src/quinn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ pub const ALPN: &[u8] = b"n0/quinn-bench/0";
/// Creates a server endpoint which runs on the given runtime
pub fn server_endpoint(rt: &tokio::runtime::Runtime, opt: &Opt) -> (SocketAddr, quinn::Endpoint) {
let secret_key = iroh::key::SecretKey::generate();
let crypto = iroh::tls::make_server_config(&secret_key, vec![ALPN.to_vec()], false).unwrap();
let crypto = iroh::tls::Authentication::X509
.make_server_config(&secret_key, vec![ALPN.to_vec()], false)
.unwrap();

let transport = transport_config(opt.max_streams, opt.initial_mtu);

Expand Down Expand Up @@ -67,8 +69,12 @@ pub async fn connect_client(
opt: Opt,
) -> Result<(::quinn::Endpoint, Connection)> {
let secret_key = iroh::key::SecretKey::generate();
let quic_client_config =
iroh::tls::make_client_config(&secret_key, None, vec![ALPN.to_vec()], false)?;
let quic_client_config = iroh::tls::Authentication::X509.make_client_config(
&secret_key,
None,
vec![ALPN.to_vec()],
false,
)?;
let mut config = quinn::ClientConfig::new(Arc::new(quic_client_config));

let transport = transport_config(opt.max_streams, opt.initial_mtu);
Expand Down
22 changes: 20 additions & 2 deletions iroh/src/endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ pub struct Builder {
insecure_skip_relay_cert_verify: bool,
addr_v4: Option<SocketAddrV4>,
addr_v6: Option<SocketAddrV6>,
tls_auth: tls::Authentication,
}

impl Default for Builder {
Expand All @@ -118,6 +119,7 @@ impl Default for Builder {
insecure_skip_relay_cert_verify: false,
addr_v4: None,
addr_v6: None,
tls_auth: tls::Authentication::X509,
}
}
}
Expand All @@ -133,6 +135,7 @@ impl Builder {
let relay_map = self.relay_mode.relay_map();
let secret_key = self.secret_key.unwrap_or_else(SecretKey::generate);
let static_config = StaticConfig {
tls_auth: self.tls_auth,
transport_config: Arc::new(self.transport_config.unwrap_or_default()),
keylog: self.keylog,
secret_key: secret_key.clone(),
Expand Down Expand Up @@ -306,6 +309,18 @@ impl Builder {
self
}

/// Use libp2p based self signed certificates for TLS.
pub fn tls_x509(mut self) -> Self {
self.tls_auth = tls::Authentication::X509;
self
}

/// Use TLS Raw Public Keys
pub fn tls_raw_public_keys(mut self) -> Self {
self.tls_auth = tls::Authentication::RawPublicKey;
self
}

#[cfg(feature = "discovery-pkarr-dht")]
#[cfg_attr(iroh_docsrs, doc(cfg(feature = "discovery-pkarr-dht")))]
/// Configures the endpoint to also use the mainline DHT with default settings.
Expand Down Expand Up @@ -422,6 +437,7 @@ impl Builder {
/// Configuration for a [`quinn::Endpoint`] that cannot be changed at runtime.
#[derive(Debug)]
struct StaticConfig {
tls_auth: tls::Authentication,
secret_key: SecretKey,
transport_config: Arc<quinn::TransportConfig>,
keylog: bool,
Expand All @@ -431,6 +447,7 @@ impl StaticConfig {
/// Create a [`quinn::ServerConfig`] with the specified ALPN protocols.
fn create_server_config(&self, alpn_protocols: Vec<Vec<u8>>) -> Result<ServerConfig> {
let server_config = make_server_config(
self.tls_auth,
&self.secret_key,
alpn_protocols,
self.transport_config.clone(),
Expand All @@ -445,12 +462,13 @@ impl StaticConfig {
// used by iroh::node::Node (or rather iroh::node::Builder) to create a plain Quinn
// endpoint.
pub fn make_server_config(
tls_auth: tls::Authentication,
secret_key: &SecretKey,
alpn_protocols: Vec<Vec<u8>>,
transport_config: Arc<TransportConfig>,
keylog: bool,
) -> Result<ServerConfig> {
let quic_server_config = tls::make_server_config(secret_key, alpn_protocols, keylog)?;
let quic_server_config = tls_auth.make_server_config(secret_key, alpn_protocols, keylog)?;
let mut server_config = ServerConfig::with_crypto(Arc::new(quic_server_config));
server_config.transport_config(transport_config);

Expand Down Expand Up @@ -635,7 +653,7 @@ impl Endpoint {
debug!("Attempting connection...");
let client_config = {
let alpn_protocols = vec![alpn.to_vec()];
let quic_client_config = tls::make_client_config(
let quic_client_config = tls::Authentication::X509.make_client_config(
&self.static_config.secret_key,
Some(node_id),
alpn_protocols,
Expand Down
Loading
Loading