From bf28ad621ca5962e64fe4ab4c73a90d92204d181 Mon Sep 17 00:00:00 2001 From: clover caruso Date: Thu, 1 Oct 2026 23:56:02 -0700 Subject: [PATCH] fix: trust the system's certificate authorities when checking for updates The update check pinned Mozilla's bundled roots, so behind a TLS-intercepting proxy whose root lives only in the system store it failed with "invalid peer certificate: UnknownIssuer". Downloads now trust the system's roots (keychain trust settings, the Windows root store, the distribution's CA bundle) plus the bundled ones, which cover a store that is missing or stale. Signature checks of builds are unchanged. Assisted-by: claude-opus-5.5 --- Cargo.lock | 77 ++++++++++++++++++++++++++++++++-- crates/snowbound/Cargo.toml | 4 ++ crates/snowbound/src/update.rs | 12 ++++++ 3 files changed, 90 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c2cb5cf51b66d2b27da859b94cb83bec511a2471..691bd7d2e613a220daea9f7f1f9d3417ede5e5b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -797,6 +797,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -810,7 +820,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" dependencies = [ "bitflags 1.3.2", - "core-foundation", + "core-foundation 0.9.4", "core-graphics-types", "foreign-types", "libc", @@ -823,7 +833,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" dependencies = [ "bitflags 1.3.2", - "core-foundation", + "core-foundation 0.9.4", "libc", ] @@ -2478,6 +2488,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + [[package]] name = "orbclient" version = "0.3.55" @@ -3163,6 +3179,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pki-types" version = "1.15.1" @@ -3204,6 +3232,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -3227,6 +3264,29 @@ dependencies = [ "tiny-skia", ] +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags 2.13.1", + "core-foundation 0.10.1", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "1.0.28" @@ -3518,6 +3578,7 @@ dependencies = [ "pollster", "ring", "rustc-demangle", + "rustls-native-certs", "sctk-adwaita", "serde", "serde_json", @@ -3533,6 +3594,7 @@ dependencies = [ "wayland-protocols", "web-sys", "web-time", + "webpki-root-certs", "wgpu", "windows-sys 0.61.2", "winit", @@ -4301,6 +4363,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-root-certs" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b96554aa2acc8ccdb7e1c9a58a7a68dd5d13bccc69cd124cb09406db612a1c9b" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webpki-roots" version = "1.0.9" @@ -4820,7 +4891,7 @@ dependencies = [ "calloop 0.13.0", "cfg_aliases", "concurrent-queue", - "core-foundation", + "core-foundation 0.9.4", "core-graphics", "cursor-icon", "dpi", diff --git a/crates/snowbound/Cargo.toml b/crates/snowbound/Cargo.toml index 594b3aa119add07135d763c973d321d7734d51a5..0906724eb78675c299a1747e70d79ab242654c1b 100644 --- a/crates/snowbound/Cargo.toml +++ b/crates/snowbound/Cargo.toml @@ -37,6 +37,10 @@ accesskit_winit = { version = "0.34.0", default-features = false, features = ["r # Updates: fetched over HTTPS, verified with ed25519 and SHA-256. The browser updates by # reloading. ureq = { version = "3.4", default-features = false, features = ["rustls"] } +# The system's roots, so a proxy's or company's own certificate authority is trusted, then +# Mozilla's for a system whose store is missing or stale. +rustls-native-certs = "0.8" +webpki-root-certs = "1.0" ring = "0.17" # The browser: see arc/platforms.md. diff --git a/crates/snowbound/src/update.rs b/crates/snowbound/src/update.rs index f49c497d0c162513642771dec651baa29edfc6a2..fd1f7c2c8e07cd2bebf38569ef7c39342ef273bb 100644 --- a/crates/snowbound/src/update.rs +++ b/crates/snowbound/src/update.rs @@ -22,6 +22,8 @@ use std::sync::{Arc, Mutex}; use std::time::Duration; #[cfg(not(target_arch = "wasm32"))] use std::time::Instant; +#[cfg(not(target_arch = "wasm32"))] +use ureq::tls::{Certificate, RootCerts, TlsConfig}; /// Where the builds are published. const BASE: &str = "https://file.paperclover.net/shr/snowbound/"; @@ -473,7 +475,17 @@ fn download(_: &str, _: u64) -> Result, String> { /// The `Fetch` the app uses. #[cfg(not(target_arch = "wasm32"))] fn download(path: &str, limit: u64) -> Result, String> { + let system = rustls_native_certs::load_native_certs().certs; + let bundled = webpki_root_certs::TLS_SERVER_ROOT_CERTS; + let roots = (system.iter().chain(bundled)) + .map(|der| Certificate::from_der(der).to_owned()) + .collect(); let agent: ureq::Agent = ureq::Agent::config_builder() + .tls_config( + TlsConfig::builder() + .root_certs(RootCerts::Specific(Arc::new(roots))) + .build(), + ) .timeout_global(Some(Duration::from_secs(10 * 60))) .timeout_connect(Some(Duration::from_secs(30))) .build() -- 2.54.0