From 2d783b4b236b13a450489744abbf4ad4fa096801 Mon Sep 17 00:00:00 2001 From: Naveen Nathan Date: Sat, 28 Sep 2024 08:03:55 +1000 Subject: [PATCH 1/2] apps: ensure client verifies peer by default --- apps/src/client.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/src/client.rs b/apps/src/client.rs index f319b724c3..6c1ea1196b 100644 --- a/apps/src/client.rs +++ b/apps/src/client.rs @@ -110,6 +110,7 @@ pub fn connect( e )) })?; + config.verify_peer(true); } else { config.verify_peer(!args.no_verify); } From 74ade4aad279566f689c5ddc5c37e0a048ceae25 Mon Sep 17 00:00:00 2001 From: Naveen Nathan Date: Sat, 28 Sep 2024 21:28:14 +1000 Subject: [PATCH 2/2] apps: implement mutual tls with optional strict authentication --- apps/src/args.rs | 34 ++++++++++++++++++++++++++++++++++ apps/src/bin/quiche-server.rs | 16 ++++++++++++++++ apps/src/client.rs | 10 +++++++++- 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/apps/src/args.rs b/apps/src/args.rs index 18f1da1a8a..bb992260e9 100644 --- a/apps/src/args.rs +++ b/apps/src/args.rs @@ -289,6 +289,8 @@ Options: --session-file PATH File used to cache a TLS session for resumption. --source-port PORT Source port to use when connecting to the server [default: 0]. --initial-cwnd-packets PACKETS The initial congestion window size in terms of packet count [default: 10]. + --cert TLS certificate path for client authentication + --key TLS certificate key path for client authentication -h --help Show this screen. "; @@ -309,6 +311,8 @@ pub struct ClientArgs { pub source_port: u16, pub perform_migration: bool, pub send_priority_update: bool, + pub cert: Option, + pub key: Option, } impl Args for ClientArgs { @@ -386,6 +390,18 @@ impl Args for ClientArgs { let send_priority_update = args.get_bool("--send-priority-update"); + let cert = if args.get_bool("--cert") { + Some(args.get_str("--cert").to_string()) + } else { + None + }; + + let key = if args.get_bool("--key") { + Some(args.get_str("--key").to_string()) + } else { + None + }; + ClientArgs { version, dump_response_path, @@ -402,6 +418,8 @@ impl Args for ClientArgs { source_port, perform_migration, send_priority_update, + cert, + key, } } } @@ -424,6 +442,8 @@ impl Default for ClientArgs { source_port: 0, perform_migration: false, send_priority_update: false, + cert: None, + key: None, } } } @@ -464,6 +484,8 @@ Options: --disable-gso Disable GSO (linux only). --disable-pacing Disable pacing (linux only). --initial-cwnd-packets PACKETS The initial congestion window size in terms of packet count [default: 10]. + --trust-origin-ca-pem Path to the pem file of the client origin's CA for mutual TLS. + --trust-strict Enable mandatory client certificate presence when using mutual TLS. -h --help Show this screen. "; @@ -478,6 +500,8 @@ pub struct ServerArgs { pub disable_gso: bool, pub disable_pacing: bool, pub enable_pmtud: bool, + pub trust_origin_ca_pem: Option, + pub trust_strict: bool, } impl Args for ServerArgs { @@ -494,6 +518,14 @@ impl Args for ServerArgs { let disable_pacing = args.get_bool("--disable-pacing"); let enable_pmtud = args.get_bool("--enable-pmtud"); + let trust_origin_ca_pem = if args.get_bool("--trust-origin-ca-pem") { + Some(args.get_str("--trust-origin-ca-pem").to_string()) + } else { + None + }; + + let trust_strict = args.get_bool("--trust-strict"); + ServerArgs { listen, no_retry, @@ -504,6 +536,8 @@ impl Args for ServerArgs { disable_gso, disable_pacing, enable_pmtud, + trust_origin_ca_pem, + trust_strict, } } } diff --git a/apps/src/bin/quiche-server.rs b/apps/src/bin/quiche-server.rs index add38a7ac0..a6d2e69c2f 100644 --- a/apps/src/bin/quiche-server.rs +++ b/apps/src/bin/quiche-server.rs @@ -106,6 +106,14 @@ fn main() { config.load_cert_chain_from_pem_file(&args.cert).unwrap(); config.load_priv_key_from_pem_file(&args.key).unwrap(); + if let Some(ref trust_origin_ca_pem) = args.trust_origin_ca_pem { + config + .load_verify_locations_from_file(trust_origin_ca_pem) + .map_err(|e| format!("error loading origin CA file : {}", e)) + .unwrap(); + config.verify_peer(true); + } + config.set_application_protos(&conn_args.alpns).unwrap(); config.discover_pmtu(args.enable_pmtud); @@ -441,6 +449,14 @@ fn main() { (client.conn.is_in_early_data() || client.conn.is_established()) { + if args.trust_origin_ca_pem.is_some() && args.trust_strict && client.conn.peer_cert().is_none() { + info!("anonymous client connections disallowed due to trust-strict, closing connection"); + let reason = "certificate_required".as_bytes(); + // Using AlertDescription certificate_required(116) from + // TLS 1.3 RFC, see https://www.rfc-editor.org/rfc/rfc8446#section-6 + let _ = client.conn.close(false, 0x100 + 116, &reason); + } + // At this stage the ALPN negotiation succeeded and selected a // single application protocol name. We'll use this to construct // the correct type of HttpConn but `application_proto()` diff --git a/apps/src/client.rs b/apps/src/client.rs index 6c1ea1196b..261033dad1 100644 --- a/apps/src/client.rs +++ b/apps/src/client.rs @@ -99,7 +99,15 @@ pub fn connect( }; // Create the configuration for the QUIC connection. - let mut config = quiche::Config::new(args.version).unwrap(); + let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap(); + + if let Some(cert) = args.cert { + config.load_cert_chain_from_pem_file(&cert).unwrap(); + } + + if let Some(key) = args.key { + config.load_priv_key_from_pem_file(&key).unwrap(); + } if let Some(ref trust_origin_ca_pem) = args.trust_origin_ca_pem { config