authorgravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-10-01 23:56:02-07:00
committergravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-10-02 00:55:30-07:00
logbf28ad621ca5962e64fe4ab4c73a90d92204d181
tree1066a8dbc2a65fe5e0fd26c02e7aab4cc7064783
parent01e73fd4cffeccb05dd939ca75bcfb583fb252e2
signature Signed by SSH key SHA256:52mNGHRsVFBDED9IAX5pe+LRWUefqTbxEReunq21QvU

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

3 files changed, 90 insertions(+), 3 deletions(-)

Cargo.lock+74-3
......@@ -797,6 +797,16 @@ dependencies = [
797797 "libc",
798798]
799799
800[[package]]
801name = "core-foundation"
802version = "0.10.1"
803source = "registry+https://github.com/rust-lang/crates.io-index"
804checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
805dependencies = [
806 "core-foundation-sys",
807 "libc",
808]
809
800810[[package]]
801811name = "core-foundation-sys"
802812version = "0.8.7"
......@@ -810,7 +820,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
810820checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081"
811821dependencies = [
812822 "bitflags 1.3.2",
813 "core-foundation",
823 "core-foundation 0.9.4",
814824 "core-graphics-types",
815825 "foreign-types",
816826 "libc",
......@@ -823,7 +833,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
823833checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
824834dependencies = [
825835 "bitflags 1.3.2",
826 "core-foundation",
836 "core-foundation 0.9.4",
827837 "libc",
828838]
829839
......@@ -2478,6 +2488,12 @@ dependencies = [
24782488 "zeroize",
24792489]
24802490
2491[[package]]
2492name = "openssl-probe"
2493version = "0.2.1"
2494source = "registry+https://github.com/rust-lang/crates.io-index"
2495checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
2496
24812497[[package]]
24822498name = "orbclient"
24832499version = "0.3.55"
......@@ -3163,6 +3179,18 @@ dependencies = [
31633179 "zeroize",
31643180]
31653181
3182[[package]]
3183name = "rustls-native-certs"
3184version = "0.8.4"
3185source = "registry+https://github.com/rust-lang/crates.io-index"
3186checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d"
3187dependencies = [
3188 "openssl-probe",
3189 "rustls-pki-types",
3190 "schannel",
3191 "security-framework",
3192]
3193
31663194[[package]]
31673195name = "rustls-pki-types"
31683196version = "1.15.1"
......@@ -3204,6 +3232,15 @@ dependencies = [
32043232 "winapi-util",
32053233]
32063234
3235[[package]]
3236name = "schannel"
3237version = "0.1.29"
3238source = "registry+https://github.com/rust-lang/crates.io-index"
3239checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939"
3240dependencies = [
3241 "windows-sys 0.61.2",
3242]
3243
32073244[[package]]
32083245name = "scoped-tls"
32093246version = "1.0.1"
......@@ -3227,6 +3264,29 @@ dependencies = [
32273264 "tiny-skia",
32283265]
32293266
3267[[package]]
3268name = "security-framework"
3269version = "3.7.0"
3270source = "registry+https://github.com/rust-lang/crates.io-index"
3271checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
3272dependencies = [
3273 "bitflags 2.13.1",
3274 "core-foundation 0.10.1",
3275 "core-foundation-sys",
3276 "libc",
3277 "security-framework-sys",
3278]
3279
3280[[package]]
3281name = "security-framework-sys"
3282version = "2.17.0"
3283source = "registry+https://github.com/rust-lang/crates.io-index"
3284checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3"
3285dependencies = [
3286 "core-foundation-sys",
3287 "libc",
3288]
3289
32303290[[package]]
32313291name = "semver"
32323292version = "1.0.28"
......@@ -3518,6 +3578,7 @@ dependencies = [
35183578 "pollster",
35193579 "ring",
35203580 "rustc-demangle",
3581 "rustls-native-certs",
35213582 "sctk-adwaita",
35223583 "serde",
35233584 "serde_json",
......@@ -3533,6 +3594,7 @@ dependencies = [
35333594 "wayland-protocols",
35343595 "web-sys",
35353596 "web-time",
3597 "webpki-root-certs",
35363598 "wgpu",
35373599 "windows-sys 0.61.2",
35383600 "winit",
......@@ -4301,6 +4363,15 @@ dependencies = [
43014363 "wasm-bindgen",
43024364]
43034365
4366[[package]]
4367name = "webpki-root-certs"
4368version = "1.0.9"
4369source = "registry+https://github.com/rust-lang/crates.io-index"
4370checksum = "b96554aa2acc8ccdb7e1c9a58a7a68dd5d13bccc69cd124cb09406db612a1c9b"
4371dependencies = [
4372 "rustls-pki-types",
4373]
4374
43044375[[package]]
43054376name = "webpki-roots"
43064377version = "1.0.9"
......@@ -4820,7 +4891,7 @@ dependencies = [
48204891 "calloop 0.13.0",
48214892 "cfg_aliases",
48224893 "concurrent-queue",
4823 "core-foundation",
4894 "core-foundation 0.9.4",
48244895 "core-graphics",
48254896 "cursor-icon",
48264897 "dpi",
crates/snowbound/Cargo.toml+4
......@@ -37,6 +37,10 @@ accesskit_winit = { version = "0.34.0", default-features = false, features = ["r
3737# Updates: fetched over HTTPS, verified with ed25519 and SHA-256. The browser updates by
3838# reloading.
3939ureq = { version = "3.4", default-features = false, features = ["rustls"] }
40# The system's roots, so a proxy's or company's own certificate authority is trusted, then
41# Mozilla's for a system whose store is missing or stale.
42rustls-native-certs = "0.8"
43webpki-root-certs = "1.0"
4044ring = "0.17"
4145
4246# The browser: see arc/platforms.md.
crates/snowbound/src/update.rs+12
......@@ -22,6 +22,8 @@ use std::sync::{Arc, Mutex};
2222use std::time::Duration;
2323#[cfg(not(target_arch = "wasm32"))]
2424use std::time::Instant;
25#[cfg(not(target_arch = "wasm32"))]
26use ureq::tls::{Certificate, RootCerts, TlsConfig};
2527
2628/// Where the builds are published.
2729const BASE: &str = "https://file.paperclover.net/shr/snowbound/";
......@@ -473,7 +475,17 @@ fn download(_: &str, _: u64) -> Result<Vec<u8>, String> {
473475/// The `Fetch` the app uses.
474476#[cfg(not(target_arch = "wasm32"))]
475477fn download(path: &str, limit: u64) -> Result<Vec<u8>, String> {
478 let system = rustls_native_certs::load_native_certs().certs;
479 let bundled = webpki_root_certs::TLS_SERVER_ROOT_CERTS;
480 let roots = (system.iter().chain(bundled))
481 .map(|der| Certificate::from_der(der).to_owned())
482 .collect();
476483 let agent: ureq::Agent = ureq::Agent::config_builder()
484 .tls_config(
485 TlsConfig::builder()
486 .root_certs(RootCerts::Specific(Arc::new(roots)))
487 .build(),
488 )
477489 .timeout_global(Some(Duration::from_secs(10 * 60)))
478490 .timeout_connect(Some(Duration::from_secs(30)))
479491 .build()