diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 3fc4770a0..6fea7cc07 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1009,6 +1009,7 @@ dependencies = [ "libc", "log", "phoenix-channel", + "rustls", "secrecy", "serde_json", "socket-factory", @@ -1034,6 +1035,7 @@ dependencies = [ "libc", "oslog", "phoenix-channel", + "rustls", "secrecy", "serde_json", "socket-factory", @@ -1064,8 +1066,8 @@ dependencies = [ "serde_json", "socket-factory", "thiserror", + "time", "tokio", - "tokio-tungstenite", "tracing", "tun", "url", @@ -1848,6 +1850,7 @@ dependencies = [ "ip_network", "libc", "phoenix-channel", + "rustls", "secrecy", "serde", "serde_json", @@ -1855,7 +1858,6 @@ dependencies = [ "socket-factory", "static_assertions", "tokio", - "tokio-tungstenite", "tracing", "tracing-subscriber", "url", @@ -1887,6 +1889,7 @@ dependencies = [ "output_vt100", "rand 0.8.5", "reqwest", + "rustls", "sadness-generator", "secrecy", "semver", @@ -1938,6 +1941,7 @@ dependencies = [ "phoenix-channel", "resolv-conf", "rtnetlink", + "rustls", "sd-notify", "secrecy", "serde", @@ -1993,6 +1997,7 @@ dependencies = [ "phoenix-channel", "proptest", "rand 0.8.5", + "rustls", "secrecy", "serde", "sha2", @@ -2839,9 +2844,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.26.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" +checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" dependencies = [ "futures-util", "http 1.1.0", @@ -2852,6 +2857,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", + "webpki-roots", ] [[package]] @@ -4700,6 +4706,53 @@ dependencies = [ "memchr", ] +[[package]] +name = "quinn" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp 0.5.2", + "rustc-hash", + "rustls", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddf517c03a109db8100448a4be38d498df8a210a99fe0e1b9eaf39e78c640efe" +dependencies = [ + "bytes", + "rand 0.8.5", + "ring", + "rustc-hash", + "rustls", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9096629c45860fc7fb143e125eb826b5e721e10be3263160c7d60ca832cf8c46" +dependencies = [ + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "quinn-udp" version = "0.5.4" @@ -4948,9 +5001,9 @@ checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "reqwest" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" +checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" dependencies = [ "base64 0.22.1", "bytes", @@ -4969,13 +5022,14 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "quinn", "rustls", "rustls-pemfile", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 0.1.2", + "sync_wrapper 1.0.0", "tokio", "tokio-rustls", "tokio-util", @@ -5061,6 +5115,12 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.4.0" @@ -5085,11 +5145,11 @@ dependencies = [ [[package]] name = "rustls" -version = "0.22.4" +version = "0.23.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" dependencies = [ - "log", + "once_cell", "ring", "rustls-pki-types", "rustls-webpki", @@ -5109,15 +5169,15 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.4.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" [[package]] name = "rustls-webpki" -version = "0.102.2" +version = "0.102.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" +checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" dependencies = [ "ring", "rustls-pki-types", @@ -5587,7 +5647,7 @@ dependencies = [ name = "socket-factory" version = "0.1.0" dependencies = [ - "quinn-udp", + "quinn-udp 0.5.4", "socket2", "tokio", "tracing", @@ -6367,9 +6427,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ "rustls", "rustls-pki-types", @@ -6389,9 +6449,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.21.0" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" +checksum = "c6989540ced10490aaf14e6bad2e3d33728a2813310a0c71d1574304c49631cd" dependencies = [ "futures-util", "log", @@ -6743,9 +6803,9 @@ dependencies = [ [[package]] name = "tungstenite" -version = "0.21.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +checksum = "6e2e2ce1e47ed2994fd43b04c8f618008d4cabdd5ee34027cf14f9d918edd9c8" dependencies = [ "byteorder", "bytes", @@ -6758,7 +6818,6 @@ dependencies = [ "rustls-pki-types", "sha1", "thiserror", - "url", "utf-8", ] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index e9332d28d..c89b8c66f 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -37,9 +37,10 @@ str0m = { version = "0.6.2", default-features = false } futures-bounded = "0.2.1" domain = { version = "0.10", features = ["serde"] } dns-lookup = "2.0" -tokio-tungstenite = "0.21" +tokio-tungstenite = "0.23.1" rtnetlink = { version = "0.14.1", default-features = false, features = ["tokio_socket"] } tokio = "1.39" +rustls = { version = "0.23.10", default-features = false, features = ["ring"] } connlib-client-android = { path = "connlib/clients/android" } connlib-client-apple = { path = "connlib/clients/apple" } diff --git a/rust/connlib/clients/android/Cargo.toml b/rust/connlib/clients/android/Cargo.toml index b1d421b19..689cfd000 100644 --- a/rust/connlib/clients/android/Cargo.toml +++ b/rust/connlib/clients/android/Cargo.toml @@ -22,6 +22,7 @@ jni = { version = "0.21.1", features = ["invocation"] } libc = "0.2" log = "0.4" phoenix-channel = { workspace = true } +rustls = { workspace = true } secrecy = { workspace = true } serde_json = "1" socket-factory = { workspace = true } diff --git a/rust/connlib/clients/android/src/lib.rs b/rust/connlib/clients/android/src/lib.rs index ff18b1029..dda1e01b9 100644 --- a/rust/connlib/clients/android/src/lib.rs +++ b/rust/connlib/clients/android/src/lib.rs @@ -342,6 +342,8 @@ fn connect( let log_filter = string_from_jstring!(env, log_filter); let handle = init_logging(&PathBuf::from(log_dir), log_filter); + install_rustls_crypto_provider(); + let callbacks = CallbackHandler { vm: env.get_java_vm().map_err(ConnectError::GetJavaVmFailed)?, callback_handler, @@ -574,3 +576,13 @@ fn protected_udp_socket_factory(callbacks: CallbackHandler) -> impl SocketFactor Ok(socket) } } + +/// Installs the `ring` crypto provider for rustls. +fn install_rustls_crypto_provider() { + let existing = rustls::crypto::ring::default_provider().install_default(); + + if existing.is_err() { + // On Android, connlib gets loaded as shared library by the JVM and may remain loaded even if we disconnect the tunnel. + tracing::debug!("Skipping install of crypto provider because we already have one."); + } +} diff --git a/rust/connlib/clients/apple/Cargo.toml b/rust/connlib/clients/apple/Cargo.toml index cc81689f4..d4a7a22d2 100644 --- a/rust/connlib/clients/apple/Cargo.toml +++ b/rust/connlib/clients/apple/Cargo.toml @@ -19,6 +19,7 @@ firezone-logging = { workspace = true } ip_network = "0.4" libc = "0.2" phoenix-channel = { workspace = true } +rustls = { workspace = true } secrecy = { workspace = true } serde_json = "1" socket-factory = { workspace = true } diff --git a/rust/connlib/clients/apple/src/lib.rs b/rust/connlib/clients/apple/src/lib.rs index 080ce099b..f6c6193e0 100644 --- a/rust/connlib/clients/apple/src/lib.rs +++ b/rust/connlib/clients/apple/src/lib.rs @@ -183,6 +183,8 @@ impl WrappedSession { callback_handler: ffi::CallbackHandler, ) -> Result { let logger = init_logging(log_dir.into(), log_filter)?; + install_rustls_crypto_provider(); + let secret = SecretString::from(token); let (private_key, public_key) = keypair(); @@ -251,3 +253,14 @@ impl WrappedSession { fn err_to_string(result: Result) -> Result { result.map_err(|e| format!("{e:#}")) } + +/// Installs the `ring` crypto provider for rustls. +fn install_rustls_crypto_provider() { + let existing = rustls::crypto::ring::default_provider().install_default(); + + if existing.is_err() { + // On Apple platforms, network extensions get terminated on disconnect and thus all memory is free'd. + // Therefore, this should not never happen unless the above is somehow no longer true. + tracing::warn!("Skipping install of crypto provider because we already have one."); + } +} diff --git a/rust/connlib/clients/shared/Cargo.toml b/rust/connlib/clients/shared/Cargo.toml index 161b22d51..ee97b24a9 100644 --- a/rust/connlib/clients/shared/Cargo.toml +++ b/rust/connlib/clients/shared/Cargo.toml @@ -18,19 +18,15 @@ secrecy = { workspace = true } serde = { version = "1.0", default-features = false, features = ["std", "derive"] } socket-factory = { workspace = true } thiserror = "1.0.63" +time = { version = "0.3.36", features = ["formatting"] } tokio = { workspace = true, features = ["sync"] } -tokio-tungstenite = { version = "0.21", default-features = false, features = ["connect", "handshake", "rustls-tls-webpki-roots"] } -tracing = { workspace = true } -tun = { workspace = true } -url = { version = "2.5.2", features = ["serde"] } - -[target.'cfg(target_os = "android")'.dependencies] tracing = { workspace = true, features = ["std", "attributes"] } +tun = { workspace = true } +url = { version = "2.4.1", features = ["serde"] } [dev-dependencies] chrono = { workspace = true } serde_json = { version = "1.0", features = ["std"] } -tokio = { workspace = true, features = ["macros", "rt"] } [lints] workspace = true diff --git a/rust/gateway/Cargo.toml b/rust/gateway/Cargo.toml index 308b24a0e..3e10b652f 100644 --- a/rust/gateway/Cargo.toml +++ b/rust/gateway/Cargo.toml @@ -24,13 +24,13 @@ futures-bounded = { workspace = true } ip_network = { version = "0.4", default-features = false } libc = { version = "0.2", default-features = false, features = ["std", "const-extern-fn", "extra_traits"] } phoenix-channel = { workspace = true } +rustls = { workspace = true } secrecy = { workspace = true } serde = { version = "1.0", default-features = false, features = ["std", "derive"] } snownet = { workspace = true } socket-factory = { workspace = true } static_assertions = "1.1.0" tokio = { workspace = true, features = ["sync", "macros", "rt-multi-thread", "fs", "signal"] } -tokio-tungstenite = { version = "0.21", default-features = false, features = ["connect", "handshake", "rustls-tls-webpki-roots"] } tracing = { workspace = true } tracing-subscriber = "0.3.17" url = { version = "2.5.2", default-features = false } diff --git a/rust/gateway/src/main.rs b/rust/gateway/src/main.rs index 392e694c9..e9a93a182 100644 --- a/rust/gateway/src/main.rs +++ b/rust/gateway/src/main.rs @@ -31,6 +31,10 @@ const ID_PATH: &str = "/var/lib/firezone/gateway_id"; #[tokio::main] async fn main() { + rustls::crypto::ring::default_provider() + .install_default() + .expect("Calling `install_default` only once per process should always succeed"); + // Enforce errors only being printed on a single line using the technique recommended in the anyhow docs: // https://docs.rs/anyhow/latest/anyhow/struct.Error.html#display-representations // diff --git a/rust/gui-client/src-tauri/Cargo.toml b/rust/gui-client/src-tauri/Cargo.toml index 484c7b4bd..4ea93e436 100644 --- a/rust/gui-client/src-tauri/Cargo.toml +++ b/rust/gui-client/src-tauri/Cargo.toml @@ -29,7 +29,8 @@ minidumper = "0.8.2" native-dialog = "0.7.0" output_vt100 = "0.1" rand = "0.8.5" -reqwest = { version = "0.12.4", default-features = false, features = ["stream", "rustls-tls"] } +reqwest = { version = "0.12.5", default-features = false, features = ["stream", "rustls-tls"] } +rustls = { workspace = true } sadness-generator = "0.5.0" secrecy = { workspace = true } semver = { version = "1.0.22", features = ["serde"] } diff --git a/rust/gui-client/src-tauri/src/bin/firezone-client-ipc.rs b/rust/gui-client/src-tauri/src/bin/firezone-client-ipc.rs index b5fbcb570..97b797359 100644 --- a/rust/gui-client/src-tauri/src/bin/firezone-client-ipc.rs +++ b/rust/gui-client/src-tauri/src/bin/firezone-client-ipc.rs @@ -1,3 +1,7 @@ fn main() -> anyhow::Result<()> { + rustls::crypto::ring::default_provider() + .install_default() + .expect("Calling `install_default` only once per process should always succeed"); + firezone_headless_client::run_only_ipc_service() } diff --git a/rust/gui-client/src-tauri/src/client.rs b/rust/gui-client/src-tauri/src/client.rs index 1769bd6fe..e9d507928 100644 --- a/rust/gui-client/src-tauri/src/client.rs +++ b/rust/gui-client/src-tauri/src/client.rs @@ -32,6 +32,10 @@ pub(crate) fn run() -> Result<()> { std::panic::set_hook(Box::new(tracing_panic::panic_hook)); let cli = Cli::parse(); + rustls::crypto::ring::default_provider() + .install_default() + .expect("Calling `install_default` only once per process should always succeed"); + match cli.command { None => { if cli.no_deep_links { diff --git a/rust/headless-client/Cargo.toml b/rust/headless-client/Cargo.toml index 7ef36545b..9a0431bea 100644 --- a/rust/headless-client/Cargo.toml +++ b/rust/headless-client/Cargo.toml @@ -19,6 +19,7 @@ futures = "0.3.30" humantime = "2.1" ip_network = { version = "0.4", default-features = false } phoenix-channel = { workspace = true } +rustls = { workspace = true } secrecy = { workspace = true } serde = { version = "1.0.204", features = ["derive"] } serde_json = "1.0.117" diff --git a/rust/headless-client/src/main.rs b/rust/headless-client/src/main.rs index 78874fa8f..f23c3e492 100644 --- a/rust/headless-client/src/main.rs +++ b/rust/headless-client/src/main.rs @@ -101,6 +101,10 @@ enum Cmd { } fn main() -> Result<()> { + rustls::crypto::ring::default_provider() + .install_default() + .expect("Calling `install_default` only once per process should always succeed"); + let mut cli = Cli::try_parse()?; // Modifying the environment of a running process is unsafe. If any other diff --git a/rust/relay/Cargo.toml b/rust/relay/Cargo.toml index c59ccc12b..0e6812405 100644 --- a/rust/relay/Cargo.toml +++ b/rust/relay/Cargo.toml @@ -23,6 +23,7 @@ opentelemetry_sdk = { version = "0.24.1", features = ["rt-tokio"] } phoenix-channel = { path = "../phoenix-channel" } proptest = { version = "1", optional = true } rand = "0.8.5" +rustls = { workspace = true } secrecy = { workspace = true } serde = { version = "1.0.204", features = ["derive"] } sha2 = "0.10.8" diff --git a/rust/relay/src/main.rs b/rust/relay/src/main.rs index 20002722d..9b8860ef4 100644 --- a/rust/relay/src/main.rs +++ b/rust/relay/src/main.rs @@ -96,6 +96,10 @@ enum LogFormat { #[tokio::main(flavor = "current_thread")] async fn main() -> Result<()> { + rustls::crypto::ring::default_provider() + .install_default() + .expect("Calling `install_default` only once per process should always succeed"); + let args = Args::parse(); setup_tracing(&args)?;