From a910118d5e3ab53e19e2b11347c5abaa93347ce6 Mon Sep 17 00:00:00 2001 From: Yuwei B Date: Mon, 11 May 2026 14:17:12 -0700 Subject: [PATCH] feat: add aws-lc-rs feature as alternative to ring crypto backend Add a new `aws-lc-rs` feature flag that allows users to opt-in to the AWS-LC crypto backend instead of ring. Ring remains the default via the `ring` feature in the default feature set. Changes: - Make `ring` dep optional, gated behind the new `ring` feature - Add `aws-lc-rs` optional dep - Add `ring` and `aws-lc-rs` features that propagate the backend choice to all sub-crates (quinn-jls, quinn-proto-jls, rustls-jls, iroh-quinn, iroh-quinn-proto, rustls, rcgen) - Replace hardcoded `ring::crypto` references in source with a feature-gated `crypto_provider` alias - Replace direct `ring::digest` SHA256 usage with feature-gated equivalent using `aws_lc_rs::digest` when aws-lc-rs is active This allows downstream crates (e.g. clash-rs) using aws-lc-rs as their primary crypto provider to avoid pulling in ring as a duplicate dependency, reducing binary size. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Cargo.lock | 82 +++++++++++++++++-- shadowquic/Cargo.toml | 39 +++++++-- .../src/shadowquic/quinn_wrapper/wrapper.rs | 13 +-- shadowquic/src/sunnyquic/dynamic_cert.rs | 4 + .../src/sunnyquic/iroh_wrapper/wrapper.rs | 13 +-- shadowquic/src/sunnyquic/mod.rs | 24 ++++-- 6 files changed, 144 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7235c92a..71a30c20 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -245,6 +245,29 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "aws-lc-rs" +version = "1.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec6fb3fe69024a75fa7e1bfb48aa6cf59706a101658ea01bfd33b2b248a038f" +dependencies = [ + "aws-lc-sys", + "untrusted 0.7.1", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f50037ee5e1e41e7b8f9d161680a725bd1626cb6f8c7e901f91f942850852fe7" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + [[package]] name = "axum" version = "0.8.8" @@ -388,6 +411,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" dependencies = [ "find-msvc-tools", + "jobserver", + "libc", "shlex", ] @@ -471,6 +496,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + [[package]] name = "colorchoice" version = "1.0.5" @@ -875,6 +909,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "dyn-clone" version = "1.0.20" @@ -1040,6 +1080,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "fsevent-sys" version = "4.1.0" @@ -1644,6 +1690,7 @@ version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de99ad8adc878ee0e68509ad256152ce23b8bbe45f5539d04e179630aca40a9" dependencies = [ + "aws-lc-rs", "bytes", "derive_more", "enum-assoc", @@ -1747,6 +1794,16 @@ dependencies = [ "syn", ] +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + [[package]] name = "js-sys" version = "0.3.94" @@ -2555,6 +2612,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32e3f04d716273d25e4923541e625e0084256f72cad7e2e7e50a0e0926aa739f" dependencies = [ + "aws-lc-rs", "bytes", "getrandom 0.3.4", "lru-slab", @@ -2669,6 +2727,7 @@ version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10b99e0098aa4082912d4c649628623db6aba77335e4f4569ff5083a6448b32e" dependencies = [ + "aws-lc-rs", "ring", "rustls-pki-types", "time", @@ -2744,7 +2803,7 @@ dependencies = [ "cfg-if", "getrandom 0.2.17", "libc", - "untrusted", + "untrusted 0.9.0", "windows-sys 0.52.0", ] @@ -2825,6 +2884,7 @@ version = "0.23.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" dependencies = [ + "aws-lc-rs", "once_cell", "ring", "rustls-pki-types", @@ -2840,6 +2900,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68483c81131e4f08f8d565632f8b9fec9f71e86f422648175ba03bbd84ea8228" dependencies = [ "aes-gcm", + "aws-lc-rs", "once_cell", "ring", "rustls-pki-types", @@ -2876,9 +2937,10 @@ version = "0.103.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" dependencies = [ + "aws-lc-rs", "ring", "rustls-pki-types", - "untrusted", + "untrusted 0.9.0", ] [[package]] @@ -3107,6 +3169,7 @@ dependencies = [ "anyhow", "arc-swap", "async-trait", + "aws-lc-rs", "brutal-core", "bytes", "clap", @@ -3376,9 +3439,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.46" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9da98b7d9b7dad93488a84b8248efc35352b0b2657397d4167e7ad67e5d535e5" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", @@ -3399,9 +3462,9 @@ checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.26" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cc610bac2dcee56805c99642447d4c5dbde4d01f752ffea0199aee1f601dc4" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" dependencies = [ "num-conv", "time-core", @@ -3726,6 +3789,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "untrusted" version = "0.9.0" @@ -4298,6 +4367,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" dependencies = [ "asn1-rs", + "aws-lc-rs", "data-encoding", "der-parser", "lazy_static", diff --git a/shadowquic/Cargo.toml b/shadowquic/Cargo.toml index 58a79140..31076782 100644 --- a/shadowquic/Cargo.toml +++ b/shadowquic/Cargo.toml @@ -9,7 +9,27 @@ description = { workspace = true } license = { workspace = true} readme = { workspace = true} [features] -default = ["shadowquic-quinn", "sunnyquic-iroh-quinn"] +default = ["shadowquic-quinn", "sunnyquic-iroh-quinn", "ring"] +ring = [ + "dep:ring", + "quinn?/rustls-ring", + "quinn_proto?/rustls-ring", + "rustls_jls?/ring", + "iroh-quinn?/rustls-ring", + "iroh-quinn-proto?/rustls-ring", + "rustls?/ring", + "rcgen/ring", +] +aws-lc-rs = [ + "dep:aws-lc-rs", + "quinn?/rustls-aws-lc-rs", + "quinn_proto?/rustls-aws-lc-rs", + "rustls_jls?/aws_lc_rs", + "iroh-quinn?/rustls-aws-lc-rs", + "iroh-quinn-proto?/rustls-aws-lc-rs", + "rustls?/aws-lc-rs", + "rcgen/aws_lc_rs", +] tokio-console = ["dep:console-subscriber","tokio/tracing"] shadowquic-quinn = ["dep:quinn","dep:rustls_jls", "dep:quinn_proto"] sunnyquic-gm-quic = ["dep:gm-quic","dep:qevent","dep:qbase","dep:qunreliable", "dep:rustls","dep:rustls-native-certs","dep:arc-swap","dep:notify"] @@ -22,14 +42,14 @@ tokio = {version = "1.49.0", features = ["io-util", "net","rt","macros","rt-mult tracing = "0.1.44" time = { version = "0.3.47", features = ["macros", "local-offset"] } tracing-subscriber = { version = "0.3.22", features = ["env-filter", "fmt", "ansi", "time", "local-time"]} -quinn = { package = "quinn-jls", version = "0.3.3", default-features = false, features = ["runtime-tokio", "rustls-ring"],optional = true} -quinn_proto = { package = "quinn-proto-jls", version = "0.3.3", default-features = false, features = ["rustls-ring"],optional = true} +quinn = { package = "quinn-jls", version = "0.3.3", default-features = false, features = ["runtime-tokio"], optional = true} +quinn_proto = { package = "quinn-proto-jls", version = "0.3.3", default-features = false, optional = true} #brutal-core = { git = "https://github.com/hrimfaxi/brutal_quinn.git", branch = "master" } brutal-core = { version = "0.1.0" } -rustls_jls = { package = "rustls-jls", version = "1.3.1", default-features = false, features = ["std","ring"],optional = true} +rustls_jls = { package = "rustls-jls", version = "1.3.1", default-features = false, features = ["std"], optional = true} -rcgen = { version = "0.14", default-features = false, features = ["crypto","ring"] } +rcgen = { version = "0.14", default-features = false, features = ["crypto"] } bytes = "1.11.0" async-trait = "0.1.89" webpki-roots = "1.0.5" @@ -44,14 +64,14 @@ gm-quic = { version = "0.4", default-features = false, optional = true} qevent = { version = "0.4", default-features = false, optional = true} qbase = { version = "0.4", default-features = false, optional = true} qunreliable = { version = "0.4", default-features = false, optional = true} -rustls = { version = "0.23", default-features = false, features = ["std","ring"], optional = true} +rustls = { version = "0.23", default-features = false, features = ["std"], optional = true} rustls-native-certs = {version = "0.8.3", optional = true} # iroh-quinn = { git = "https://github.com/hrimfaxi/iroh_quinn", branch = "main", package = "noq", optional = true, default-features = false, features = ["rustls-ring", "runtime-tokio"] } # iroh-quinn-proto = { git = "https://github.com/hrimfaxi/iroh_quinn", branch = "main", package = "noq-proto", optional = true, default-features = false, features = ["rustls-ring"] } -iroh-quinn ={ version = "0.16.1",optional = true, default-features = false, features = ["rustls-ring","runtime-tokio"]} -iroh-quinn-proto ={ version = "0.15.1",optional = true, default-features = false, features = ["rustls-ring"]} +iroh-quinn ={ version = "0.16.1",optional = true, default-features = false, features = ["runtime-tokio"]} +iroh-quinn-proto ={ version = "0.15.1",optional = true, default-features = false} notify = { version = "8.2.0", features = ["serde"], optional = true} @@ -59,7 +79,8 @@ arc-swap = { version = "1.8.1", optional = true } console-subscriber = { version = "0.5.0", optional = true } serde-saphyr = "0.0.18" -ring = "0.17.14" +aws-lc-rs = { version = "1", optional = true, default-features = false } +ring = { version = "0.17.14", optional = true } [target.'cfg(target_os="android")'.dependencies] sendfd = { version = "0.4.4", features = ["tokio"] } diff --git a/shadowquic/src/shadowquic/quinn_wrapper/wrapper.rs b/shadowquic/src/shadowquic/quinn_wrapper/wrapper.rs index b51f0a09..0973501f 100644 --- a/shadowquic/src/shadowquic/quinn_wrapper/wrapper.rs +++ b/shadowquic/src/shadowquic/quinn_wrapper/wrapper.rs @@ -18,7 +18,10 @@ use quinn::rustls::ServerConfig as RustlsServerConfig; use quinn::crypto::rustls::{QuicClientConfig, QuicServerConfig}; -use quinn::rustls::crypto::ring; +#[cfg(feature = "aws-lc-rs")] +use quinn::rustls::crypto::aws_lc_rs as crypto_provider; +#[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))] +use quinn::rustls::crypto::ring as crypto_provider; use crate::{ config::{ @@ -227,10 +230,10 @@ impl QuicClient for Endpoint { fn to_quinn_cipher_suite(suite: &CipherSuitePreference) -> quinn::rustls::SupportedCipherSuite { match suite { CipherSuitePreference::Chacha20Poly1305 => { - ring::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256 + crypto_provider::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256 } - CipherSuitePreference::Aes128Gcm => ring::cipher_suite::TLS13_AES_128_GCM_SHA256, - CipherSuitePreference::Aes256Gcm => ring::cipher_suite::TLS13_AES_256_GCM_SHA384, + CipherSuitePreference::Aes128Gcm => crypto_provider::cipher_suite::TLS13_AES_128_GCM_SHA256, + CipherSuitePreference::Aes256Gcm => crypto_provider::cipher_suite::TLS13_AES_256_GCM_SHA384, } } @@ -244,7 +247,7 @@ pub fn gen_client_cfg(cfg: &ShadowQuicClientCfg) -> quinn::ClientConfig { let builder = if let Some(cipher_suite_preference) = &cfg.cipher_suite_preference { let normalized = normalize_cipher_suite_preference(cipher_suite_preference); - let mut provider = ring::default_provider(); + let mut provider = crypto_provider::default_provider(); provider.cipher_suites = normalized.iter().map(to_quinn_cipher_suite).collect(); quinn::rustls::ClientConfig::builder_with_provider(Arc::new(provider)) diff --git a/shadowquic/src/sunnyquic/dynamic_cert.rs b/shadowquic/src/sunnyquic/dynamic_cert.rs index 83028d8c..15329095 100644 --- a/shadowquic/src/sunnyquic/dynamic_cert.rs +++ b/shadowquic/src/sunnyquic/dynamic_cert.rs @@ -36,8 +36,12 @@ impl DynamicCertResolver { .map_err(|x| SError::RustlsError(x.to_string()))?; // Create CertifiedKey + #[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))] let key = rustls::crypto::ring::sign::any_supported_type(&priv_key) .map_err(|_| SError::RustlsError("invalid private key".to_string()))?; + #[cfg(feature = "aws-lc-rs")] + let key = rustls::crypto::aws_lc_rs::sign::any_supported_type(&priv_key) + .map_err(|_| SError::RustlsError("invalid private key".to_string()))?; let certified_key = CertifiedKey::new(cert_der, key); Ok(certified_key) } diff --git a/shadowquic/src/sunnyquic/iroh_wrapper/wrapper.rs b/shadowquic/src/sunnyquic/iroh_wrapper/wrapper.rs index 938b125e..75de9554 100644 --- a/shadowquic/src/sunnyquic/iroh_wrapper/wrapper.rs +++ b/shadowquic/src/sunnyquic/iroh_wrapper/wrapper.rs @@ -13,9 +13,12 @@ use iroh_quinn::{ ClientConfig, MtuDiscoveryConfig, SendDatagramError, TransportConfig, VarInt, congestion::{BbrConfig, CubicConfig, NewRenoConfig}, }; +#[cfg(feature = "aws-lc-rs")] +use rustls::crypto::aws_lc_rs as crypto_provider; +#[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))] +use rustls::crypto::ring as crypto_provider; use rustls::{ RootCertStore, - crypto::ring, pki_types::{CertificateDer, pem::PemObject}, }; use socket2::{Domain, Protocol, Socket, Type}; @@ -286,10 +289,10 @@ async fn add_extra_path( fn to_rustls_cipher_suite(suite: &CipherSuitePreference) -> rustls::SupportedCipherSuite { match suite { CipherSuitePreference::Chacha20Poly1305 => { - ring::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256 + crypto_provider::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256 } - CipherSuitePreference::Aes128Gcm => ring::cipher_suite::TLS13_AES_128_GCM_SHA256, - CipherSuitePreference::Aes256Gcm => ring::cipher_suite::TLS13_AES_256_GCM_SHA384, + CipherSuitePreference::Aes128Gcm => crypto_provider::cipher_suite::TLS13_AES_128_GCM_SHA256, + CipherSuitePreference::Aes256Gcm => crypto_provider::cipher_suite::TLS13_AES_256_GCM_SHA384, } } @@ -312,7 +315,7 @@ pub fn gen_client_cfg(cfg: &SunnyQuicClientCfg) -> iroh_quinn::ClientConfig { let builder = if let Some(cipher_suite_preference) = &cfg.cipher_suite_preference { let normalized = normalize_cipher_suite_preference(cipher_suite_preference); - let mut provider = ring::default_provider(); + let mut provider = crypto_provider::default_provider(); provider.cipher_suites = normalized.iter().map(to_rustls_cipher_suite).collect(); rustls::ClientConfig::builder_with_provider(Arc::new(provider)) diff --git a/shadowquic/src/sunnyquic/mod.rs b/shadowquic/src/sunnyquic/mod.rs index db78262d..243824b6 100644 --- a/shadowquic/src/sunnyquic/mod.rs +++ b/shadowquic/src/sunnyquic/mod.rs @@ -34,10 +34,22 @@ pub use unimplemented::{Connection, EndClient, EndServer}; /// The hash is generated by SHA256(username:password) pub fn gen_sunny_user_hash(username: &str, password: &str) -> SunnyCredential { let hash_in = username.to_string() + ":" + password; - let hash_out = ring::digest::digest(&ring::digest::SHA256, hash_in.into_bytes().as_ref()); - let mut arr = [0u8; SUNNY_QUIC_AUTH_LEN]; - let hash_bytes = hash_out.as_ref(); - let len = arr.len().min(hash_bytes.len()); - arr[..len].copy_from_slice(&hash_bytes[..len]); - Arc::new(arr) + let hash_bytes_input = hash_in.into_bytes(); + #[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))] + let hash_bytes = { + let out = ring::digest::digest(&ring::digest::SHA256, hash_bytes_input.as_ref()); + let mut arr = [0u8; SUNNY_QUIC_AUTH_LEN]; + let len = arr.len().min(out.as_ref().len()); + arr[..len].copy_from_slice(&out.as_ref()[..len]); + arr + }; + #[cfg(feature = "aws-lc-rs")] + let hash_bytes = { + let out = aws_lc_rs::digest::digest(&aws_lc_rs::digest::SHA256, hash_bytes_input.as_ref()); + let mut arr = [0u8; SUNNY_QUIC_AUTH_LEN]; + let len = arr.len().min(out.as_ref().len()); + arr[..len].copy_from_slice(&out.as_ref()[..len]); + arr + }; + Arc::new(hash_bytes) }