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 = [...@@ -797,6 +797,16 @@ dependencies = [
797 "libc",797 "libc",
798]798]
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
800[[package]]810[[package]]
801name = "core-foundation-sys"811name = "core-foundation-sys"
802version = "0.8.7"812version = "0.8.7"
...@@ -810,7 +820,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"...@@ -810,7 +820,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
810checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081"820checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081"
811dependencies = [821dependencies = [
812 "bitflags 1.3.2",822 "bitflags 1.3.2",
813 "core-foundation",823 "core-foundation 0.9.4",
814 "core-graphics-types",824 "core-graphics-types",
815 "foreign-types",825 "foreign-types",
816 "libc",826 "libc",
...@@ -823,7 +833,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"...@@ -823,7 +833,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
823checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"833checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
824dependencies = [834dependencies = [
825 "bitflags 1.3.2",835 "bitflags 1.3.2",
826 "core-foundation",836 "core-foundation 0.9.4",
827 "libc",837 "libc",
828]838]
829839
...@@ -2478,6 +2488,12 @@ dependencies = [...@@ -2478,6 +2488,12 @@ dependencies = [
2478 "zeroize",2488 "zeroize",
2479]2489]
24802490
2491[[package]]
2492name = "openssl-probe"
2493version = "0.2.1"
2494source = "registry+https://github.com/rust-lang/crates.io-index"
2495checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
2496
2481[[package]]2497[[package]]
2482name = "orbclient"2498name = "orbclient"
2483version = "0.3.55"2499version = "0.3.55"
...@@ -3163,6 +3179,18 @@ dependencies = [...@@ -3163,6 +3179,18 @@ dependencies = [
3163 "zeroize",3179 "zeroize",
3164]3180]
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
3166[[package]]3194[[package]]
3167name = "rustls-pki-types"3195name = "rustls-pki-types"
3168version = "1.15.1"3196version = "1.15.1"
...@@ -3204,6 +3232,15 @@ dependencies = [...@@ -3204,6 +3232,15 @@ dependencies = [
3204 "winapi-util",3232 "winapi-util",
3205]3233]
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
3207[[package]]3244[[package]]
3208name = "scoped-tls"3245name = "scoped-tls"
3209version = "1.0.1"3246version = "1.0.1"
...@@ -3227,6 +3264,29 @@ dependencies = [...@@ -3227,6 +3264,29 @@ dependencies = [
3227 "tiny-skia",3264 "tiny-skia",
3228]3265]
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
3230[[package]]3290[[package]]
3231name = "semver"3291name = "semver"
3232version = "1.0.28"3292version = "1.0.28"
...@@ -3518,6 +3578,7 @@ dependencies = [...@@ -3518,6 +3578,7 @@ dependencies = [
3518 "pollster",3578 "pollster",
3519 "ring",3579 "ring",
3520 "rustc-demangle",3580 "rustc-demangle",
3581 "rustls-native-certs",
3521 "sctk-adwaita",3582 "sctk-adwaita",
3522 "serde",3583 "serde",
3523 "serde_json",3584 "serde_json",
...@@ -3533,6 +3594,7 @@ dependencies = [...@@ -3533,6 +3594,7 @@ dependencies = [
3533 "wayland-protocols",3594 "wayland-protocols",
3534 "web-sys",3595 "web-sys",
3535 "web-time",3596 "web-time",
3597 "webpki-root-certs",
3536 "wgpu",3598 "wgpu",
3537 "windows-sys 0.61.2",3599 "windows-sys 0.61.2",
3538 "winit",3600 "winit",
...@@ -4301,6 +4363,15 @@ dependencies = [...@@ -4301,6 +4363,15 @@ dependencies = [
4301 "wasm-bindgen",4363 "wasm-bindgen",
4302]4364]
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
4304[[package]]4375[[package]]
4305name = "webpki-roots"4376name = "webpki-roots"
4306version = "1.0.9"4377version = "1.0.9"
...@@ -4820,7 +4891,7 @@ dependencies = [...@@ -4820,7 +4891,7 @@ dependencies = [
4820 "calloop 0.13.0",4891 "calloop 0.13.0",
4821 "cfg_aliases",4892 "cfg_aliases",
4822 "concurrent-queue",4893 "concurrent-queue",
4823 "core-foundation",4894 "core-foundation 0.9.4",
4824 "core-graphics",4895 "core-graphics",
4825 "cursor-icon",4896 "cursor-icon",
4826 "dpi",4897 "dpi",
crates/snowbound/Cargo.toml+4
...@@ -37,6 +37,10 @@ accesskit_winit = { version = "0.34.0", default-features = false, features = ["r...@@ -37,6 +37,10 @@ accesskit_winit = { version = "0.34.0", default-features = false, features = ["r
37# Updates: fetched over HTTPS, verified with ed25519 and SHA-256. The browser updates by37# Updates: fetched over HTTPS, verified with ed25519 and SHA-256. The browser updates by
38# reloading.38# reloading.
39ureq = { version = "3.4", default-features = false, features = ["rustls"] }39ureq = { 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"
40ring = "0.17"44ring = "0.17"
4145
42# The browser: see arc/platforms.md.46# The browser: see arc/platforms.md.
crates/snowbound/src/update.rs+12
...@@ -22,6 +22,8 @@ use std::sync::{Arc, Mutex};...@@ -22,6 +22,8 @@ use std::sync::{Arc, Mutex};
22use std::time::Duration;22use std::time::Duration;
23#[cfg(not(target_arch = "wasm32"))]23#[cfg(not(target_arch = "wasm32"))]
24use std::time::Instant;24use std::time::Instant;
25#[cfg(not(target_arch = "wasm32"))]
26use ureq::tls::{Certificate, RootCerts, TlsConfig};
2527
26/// Where the builds are published.28/// Where the builds are published.
27const BASE: &str = "https://file.paperclover.net/shr/snowbound/";29const BASE: &str = "https://file.paperclover.net/shr/snowbound/";
...@@ -473,7 +475,17 @@ fn download(_: &str, _: u64) -> Result<Vec<u8>, String> {...@@ -473,7 +475,17 @@ fn download(_: &str, _: u64) -> Result<Vec<u8>, String> {
473/// The `Fetch` the app uses.475/// The `Fetch` the app uses.
474#[cfg(not(target_arch = "wasm32"))]476#[cfg(not(target_arch = "wasm32"))]
475fn download(path: &str, limit: u64) -> Result<Vec<u8>, String> {477fn 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();
476 let agent: ureq::Agent = ureq::Agent::config_builder()483 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 )
477 .timeout_global(Some(Duration::from_secs(10 * 60)))489 .timeout_global(Some(Duration::from_secs(10 * 60)))
478 .timeout_connect(Some(Duration::from_secs(30)))490 .timeout_connect(Some(Duration::from_secs(30)))
479 .build()491 .build()