diff options
| author | David Lönnhager <david.l@mullvad.net> | 2025-03-26 09:40:41 +0100 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2025-03-28 17:04:58 +0100 |
| commit | 200d4837f16cc9501bdeefc034d16646f56f303d (patch) | |
| tree | f38192648b661d914c2f152bb5a81628181a4a2e | |
| parent | 8fbf46194b975655f6b0e5131032d17ed47875fc (diff) | |
| download | mullvadvpn-200d4837f16cc9501bdeefc034d16646f56f303d.tar.xz mullvadvpn-200d4837f16cc9501bdeefc034d16646f56f303d.zip | |
Switch from staging to prod for version metadata
| -rw-r--r-- | .github/CODEOWNERS | 1 | ||||
| -rw-r--r-- | Cargo.lock | 3 | ||||
| -rw-r--r-- | installer-downloader/Cargo.toml | 1 | ||||
| -rw-r--r-- | installer-downloader/src/controller.rs | 12 | ||||
| -rw-r--r-- | mullvad-api/Cargo.toml | 1 | ||||
| -rw-r--r-- | mullvad-api/src/version.rs | 11 | ||||
| -rw-r--r-- | mullvad-update/meta/Cargo.toml | 1 | ||||
| -rw-r--r-- | mullvad-update/meta/src/main.rs | 3 | ||||
| -rw-r--r-- | mullvad-update/meta/src/platform.rs | 14 | ||||
| -rw-r--r-- | mullvad-update/src/format/key.rs | 3 | ||||
| -rw-r--r-- | mullvad-update/src/keys.rs | 41 | ||||
| -rw-r--r-- | mullvad-update/src/lib.rs | 2 | ||||
| -rw-r--r-- | mullvad-update/stagemole-pubkey | 1 | ||||
| -rw-r--r-- | mullvad-update/trusted-metadata-signing-pubkeys | 8 | ||||
| -rw-r--r-- | test/Cargo.lock | 1 |
15 files changed, 59 insertions, 44 deletions
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 44c9aac731..27fa5531dc 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -8,6 +8,7 @@ # Developer signing keys must be approved by team/tech leads /ci/keys/ @faern @raksooo @pinkisemils @albin-mullvad +/mullvad-update/trusted-metadata-signing-pubkeys @faern @raksooo @pinkisemils @albin-mullvad # Desktop build server files owned by desktop leads /ci/buildserver* @faern @raksooo diff --git a/Cargo.lock b/Cargo.lock index 37ad7063b9..43d8a8624f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2041,7 +2041,6 @@ dependencies = [ "serde", "talpid-platform-metadata", "tokio", - "vec1", "windows-sys 0.52.0", "winres", ] @@ -2496,7 +2495,6 @@ dependencies = [ "sha2", "tokio", "toml 0.8.19", - "vec1", ] [[package]] @@ -2638,7 +2636,6 @@ dependencies = [ "tokio-socks", "tower 0.5.1", "uuid", - "vec1", ] [[package]] diff --git a/installer-downloader/Cargo.toml b/installer-downloader/Cargo.toml index 98a6182b86..c24011d126 100644 --- a/installer-downloader/Cargo.toml +++ b/installer-downloader/Cargo.toml @@ -28,7 +28,6 @@ rand = { version = "0.8.5" } reqwest = { version = "0.12.9", default-features = false, features = ["rustls-tls"] } serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["rt-multi-thread", "fs"] } -vec1 = { workspace = true } talpid-platform-metadata = { path = "../talpid-platform-metadata" } mullvad-update = { path = "../mullvad-update", features = ["client"] } diff --git a/installer-downloader/src/controller.rs b/installer-downloader/src/controller.rs index fd9c931756..2e2b44e351 100644 --- a/installer-downloader/src/controller.rs +++ b/installer-downloader/src/controller.rs @@ -19,17 +19,13 @@ use tokio::{ sync::{mpsc, oneshot}, task::JoinHandle, }; -use vec1::vec1; - -/// ed25519 pubkey used to verify metadata from the Mullvad (stagemole) API -const VERSION_PROVIDER_PUBKEY: &str = include_str!("../../mullvad-update/stagemole-pubkey"); /// Pinned root certificate used when fetching version metadata const PINNED_CERTIFICATE: &[u8] = include_bytes!("../../mullvad-api/le_root_cert.pem"); /// Base URL for pulling metadata. Actual JSON files should be stored at `<base /// url>/<platform>.json` -const META_REPOSITORY_URL: &str = "https://api.stagemole.eu/app/releases/"; +const META_REPOSITORY_URL: &str = "https://api.mullvad.net/app/releases/"; /// Actions handled by an async worker task in [ActionMessageHandler]. enum TaskMessage { @@ -53,15 +49,11 @@ pub fn initialize_controller<T: AppDelegate + 'static>(delegate: &mut T, environ // Directory provider to use type DirProvider = crate::temp::TempDirProvider; - // Version info provider to use - let verifying_key = - mullvad_update::format::key::VerifyingKey::from_hex(VERSION_PROVIDER_PUBKEY) - .expect("valid key"); let cert = reqwest::Certificate::from_pem(PINNED_CERTIFICATE).expect("invalid cert"); let version_provider = HttpVersionInfoProvider { url: get_metadata_url(), pinned_certificate: Some(cert), - verifying_keys: vec1![verifying_key], + verifying_keys: mullvad_update::keys::TRUSTED_METADATA_SIGNING_PUBKEYS.clone(), }; AppController::initialize::<_, Downloader<T>, _, DirProvider>( diff --git a/mullvad-api/Cargo.toml b/mullvad-api/Cargo.toml index f55ab02f9a..57ace41064 100644 --- a/mullvad-api/Cargo.toml +++ b/mullvad-api/Cargo.toml @@ -47,7 +47,6 @@ tokio-rustls = { version = "0.26.0", features = [ tokio-socks = "0.5.1" rustls-pemfile = "2.1.3" uuid = { version = "1.4.1", features = ["v4"] } -vec1 = { workspace = true } mullvad-encrypted-dns-proxy = { path = "../mullvad-encrypted-dns-proxy" } mullvad-fs = { path = "../mullvad-fs" } diff --git a/mullvad-api/src/version.rs b/mullvad-api/src/version.rs index 26cbe1d2d3..8218b94701 100644 --- a/mullvad-api/src/version.rs +++ b/mullvad-api/src/version.rs @@ -4,7 +4,6 @@ use std::sync::Arc; use http::StatusCode; use mullvad_types::version::AppVersion; use mullvad_update::version::{VersionInfo, VersionParameters}; -use vec1::vec1; use super::rest; use super::APP_URL_PREFIX; @@ -23,9 +22,6 @@ pub struct AppVersionResponse { } impl AppVersionProxy { - /// Public key to use for `version_check_2` response - const VERSION_PROVIDER_PUBKEY: &str = include_str!("../../mullvad-update/stagemole-pubkey"); - /// Maximum size of `version_check_2` response const SIZE_LIMIT: usize = 1024 * 1024; @@ -65,18 +61,13 @@ impl AppVersionProxy { let path = format!("app/releases/{platform}.json"); let request = self.handle.factory.get(&path); - let verifying_key = - mullvad_update::format::key::VerifyingKey::from_hex(Self::VERSION_PROVIDER_PUBKEY) - .expect("valid key"); - let verifying_keys = vec1![verifying_key]; - async move { let request = request?.expected_status(&[StatusCode::OK]); let response = service.request(request).await?; let bytes = response.body_with_max_size(Self::SIZE_LIMIT).await?; let response = mullvad_update::format::SignedResponse::deserialize_and_verify( - &verifying_keys, + &mullvad_update::keys::TRUSTED_METADATA_SIGNING_PUBKEYS, &bytes, lowest_metadata_version, ) diff --git a/mullvad-update/meta/Cargo.toml b/mullvad-update/meta/Cargo.toml index 932b5780b2..7eba726e95 100644 --- a/mullvad-update/meta/Cargo.toml +++ b/mullvad-update/meta/Cargo.toml @@ -22,7 +22,6 @@ serde = { workspace = true } sha2 = "0.10" tokio = { version = "1", features = ["full"] } toml = "0.8" -vec1 = { workspace = true } mullvad-version = { path = "../../mullvad-version", features = ["serde"] } mullvad-update = { path = "../", features = ["client", "sign"] } diff --git a/mullvad-update/meta/src/main.rs b/mullvad-update/meta/src/main.rs index 51d2c5ba25..478213b82c 100644 --- a/mullvad-update/meta/src/main.rs +++ b/mullvad-update/meta/src/main.rs @@ -28,9 +28,6 @@ const DEFAULT_ROLLOUT: f32 = 1.; /// Lowest version to accept using 'verify' const MIN_VERIFY_METADATA_VERSION: usize = 0; -/// Verification public key -const VERIFYING_PUBKEY: &str = include_str!("../../stagemole-pubkey"); - /// A tool that generates signed Mullvad version metadata. /// /// Unsigned work is stored in `work/`, and signed work is stored in `signed/` diff --git a/mullvad-update/meta/src/platform.rs b/mullvad-update/meta/src/platform.rs index 00a391a925..e1f471f2e5 100644 --- a/mullvad-update/meta/src/platform.rs +++ b/mullvad-update/meta/src/platform.rs @@ -13,7 +13,6 @@ use std::{ sync::LazyLock, }; use tokio::{fs, io}; -use vec1::vec1; use crate::{ artifacts, @@ -22,7 +21,7 @@ use crate::{ /// Base URL for metadata found with `meta pull`. /// Actual JSON files should be stored at `<base url>/<platform>.json`. -const META_REPOSITORY_URL: &str = "https://releases.stagemole.eu/desktop/metadata/"; +const META_REPOSITORY_URL: &str = "https://releases.mullvad.net/desktop/metadata/"; /// TLS certificate to pin to for `meta pull`. static PINNED_CERTIFICATE: LazyLock<reqwest::Certificate> = LazyLock::new(|| { @@ -128,14 +127,10 @@ impl Platform { println!("Pulling {self} metadata from {url}..."); - // Pull latest metadata - let verifying_key = - key::VerifyingKey::from_hex(crate::VERIFYING_PUBKEY).expect("Invalid pubkey"); - let version_provider = HttpVersionInfoProvider { pinned_certificate: Some(PINNED_CERTIFICATE.clone()), url, - verifying_keys: vec1![verifying_key], + verifying_keys: mullvad_update::keys::TRUSTED_METADATA_SIGNING_PUBKEYS.clone(), }; let response = version_provider .get_versions(crate::MIN_VERIFY_METADATA_VERSION) @@ -236,11 +231,8 @@ impl Platform { println!("Verifying signature of {}...", signed_path.display()); let bytes = fs::read(signed_path).await.context("Failed to read file")?; - let public_key = key::VerifyingKey::from_hex(include_str!("../../stagemole-pubkey")) - .expect("Invalid pubkey"); - format::SignedResponse::deserialize_and_verify( - &vec1![public_key], + &mullvad_update::keys::TRUSTED_METADATA_SIGNING_PUBKEYS, &bytes, crate::MIN_VERIFY_METADATA_VERSION, ) diff --git a/mullvad-update/src/format/key.rs b/mullvad-update/src/format/key.rs index c61b2dd9e0..1f49efa5c4 100644 --- a/mullvad-update/src/format/key.rs +++ b/mullvad-update/src/format/key.rs @@ -75,8 +75,7 @@ impl Serialize for SecretKey { } /// ed25519 verifying key -#[derive(Debug, PartialEq, Eq)] -#[cfg_attr(test, derive(Clone))] +#[derive(Debug, PartialEq, Eq, Clone)] pub struct VerifyingKey(pub ed25519_dalek::VerifyingKey); impl fmt::Display for VerifyingKey { diff --git a/mullvad-update/src/keys.rs b/mullvad-update/src/keys.rs new file mode 100644 index 0000000000..9b0abf5c6b --- /dev/null +++ b/mullvad-update/src/keys.rs @@ -0,0 +1,41 @@ +//! Keys that may be used for verifying data + +use crate::format::key::VerifyingKey; +use std::sync::LazyLock; +use vec1::Vec1; + +/// Pubkeys used to verify metadata from the Mullvad API (production) +pub static TRUSTED_METADATA_SIGNING_PUBKEYS: LazyLock<Vec1<VerifyingKey>> = + LazyLock::new(|| parse_keys(include_str!("../trusted-metadata-signing-pubkeys"))); + +fn parse_keys(keys: &str) -> Vec1<VerifyingKey> { + let mut v = vec![]; + for key in keys.split('\n') { + let key = key.trim(); + if key.starts_with('#') || key.is_empty() { + continue; + } + v.push(VerifyingKey::from_hex(key).expect("invalid pubkey")); + } + v.try_into().expect("need at least one key") +} + +#[cfg(test)] +#[test] +fn test_parse_keys() { + let key1 = "AB4EF63FFDCC6BD5A19C30CD23B9DE03099407A04463418F17AE338B98AA09D4".to_lowercase(); + let key2 = "BB4EF63FFDCC6BD5A19C30CD23B9DE03099407A04463418F17AE338B98AA09D4".to_lowercase(); + let keys = parse_keys(&format!( + r#" +# test +{key1} +# test 2 +{key2} +"# + )); + assert_eq!(format!("{}", keys[0]), key1); + assert_eq!(format!("{}", keys[1]), key2); + + // Test that actual keys are validly parsed + let _prod = &*TRUSTED_METADATA_SIGNING_PUBKEYS; +} diff --git a/mullvad-update/src/lib.rs b/mullvad-update/src/lib.rs index 4efd060b4b..88e78034a7 100644 --- a/mullvad-update/src/lib.rs +++ b/mullvad-update/src/lib.rs @@ -6,6 +6,8 @@ mod client; #[cfg(feature = "client")] pub use client::*; +pub mod keys; + pub mod version; /// Parser and serializer for version metadata diff --git a/mullvad-update/stagemole-pubkey b/mullvad-update/stagemole-pubkey deleted file mode 100644 index 256a77bafc..0000000000 --- a/mullvad-update/stagemole-pubkey +++ /dev/null @@ -1 +0,0 @@ -a0cd8f582e3147d57f7c01ec0fd306c8315290cea55725c7d5c76f835b78b363
\ No newline at end of file diff --git a/mullvad-update/trusted-metadata-signing-pubkeys b/mullvad-update/trusted-metadata-signing-pubkeys new file mode 100644 index 0000000000..f5d427f980 --- /dev/null +++ b/mullvad-update/trusted-metadata-signing-pubkeys @@ -0,0 +1,8 @@ +# linus +c99b5e6e76bb7ab5b6fc3cdfe146faaa8afcfce0326822fe1629e00e666988b4 +# oskar +4f2faeeda078df4dc1eebfb217c475eec9635c65d8b075171c4cf1808356dde5 +# emils +299e8b06355031781623de7c9a013eb88b07aee80476e2938ce01a7b623d29d0 +# albin +af4f7762e3e13af87f2e8c8af8ce5cce456cd3390af6d881b1eb6f802786cc3f diff --git a/test/Cargo.lock b/test/Cargo.lock index 3cde6c40bd..80c061ad0e 100644 --- a/test/Cargo.lock +++ b/test/Cargo.lock @@ -2101,7 +2101,6 @@ dependencies = [ "tokio-socks", "tower 0.5.1", "uuid", - "vec1", ] [[package]] |
