summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rw-r--r--README.md2
-rw-r--r--android/build.gradle1
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/MullvadProblemReport.kt8
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt3
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt2
-rw-r--r--gui/tasks/distribution.js1
-rw-r--r--mullvad-daemon/src/lib.rs3
-rw-r--r--mullvad-jni/src/lib.rs9
-rw-r--r--mullvad-paths/src/resources.rs6
-rw-r--r--mullvad-problem-report/src/lib.rs18
-rw-r--r--mullvad-rpc/old_le_root_cert.pem (renamed from dist-assets/api_root_ca.pem)0
-rw-r--r--mullvad-rpc/src/bin/relay_list.rs3
-rw-r--r--mullvad-rpc/src/https_client_with_sni.rs56
-rw-r--r--mullvad-rpc/src/lib.rs13
-rw-r--r--mullvad-tests/src/lib.rs5
16 files changed, 37 insertions, 95 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e2b3ef5aba..7403c20729 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -33,6 +33,8 @@ Line wrap the file at 100 chars. Th
system cache is cleaned.
- Rename "Block when disconnected" setting to "Always require VPN" and add additional explanation
of the setting.
+- Embed TLS certificates used for HTTPS into the binary rather than loading them from disk at
+ runtime
#### Android
- Adjust the minimum supported Android version to correctly reflect the supported versions decided
diff --git a/README.md b/README.md
index 0c75b4ea1a..973f805f02 100644
--- a/README.md
+++ b/README.md
@@ -464,8 +464,6 @@ this procedure, the `integration-tests.sh` script can be used to run all integra
- **linux/** - Scripts and configuration files for the deb and rpm artifacts
- **pkg-scripts/** - Scripts bundled with and executed by the macOS pkg installer
- **windows/** - Windows NSIS installer configuration and assets
- - **api_root_ca.pem** - The root CA for the api.mullvad.net endpoint. The app uses certificate
- pinning
- **ca.crt** - The Mullvad relay server root CA. Bundled with the app and only OpenVPN relays
signed by this CA are trusted
diff --git a/android/build.gradle b/android/build.gradle
index 47ce428f2c..c020547402 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -110,7 +110,6 @@ lint.dependsOn lintKotlin
task copyExtraAssets(type: Copy) {
from "$repoRootPath/dist-assets"
- include "api_root_ca.pem"
include "relays.json"
into extraAssetsDirectory
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/MullvadProblemReport.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/MullvadProblemReport.kt
index 4c291bbc10..66a55503d6 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/MullvadProblemReport.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/MullvadProblemReport.kt
@@ -9,7 +9,7 @@ import kotlinx.coroutines.async
const val PROBLEM_REPORT_FILE = "problem_report.txt"
-class MullvadProblemReport(val logDirectory: File, val resourceDirectory: File) {
+class MullvadProblemReport(val logDirectory: File) {
private val problemReportPath = File(logDirectory, PROBLEM_REPORT_FILE)
private var collectJob: Deferred<Boolean>? = null
@@ -56,8 +56,7 @@ class MullvadProblemReport(val logDirectory: File, val resourceDirectory: File)
sendProblemReport(
userEmail,
userMessage,
- problemReportPath.absolutePath,
- resourceDirectory.absolutePath
+ problemReportPath.absolutePath
)
if (result) {
@@ -82,7 +81,6 @@ class MullvadProblemReport(val logDirectory: File, val resourceDirectory: File)
private external fun sendProblemReport(
userEmail: String,
userMessage: String,
- reportPath: String,
- resourceDir: String
+ reportPath: String
): Boolean
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt
index 7e5318c892..cf66311494 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt
@@ -15,7 +15,6 @@ import net.mullvad.mullvadvpn.ui.MainActivity
import net.mullvad.talpid.TalpidVpnService
import net.mullvad.talpid.util.EventNotifier
-private const val API_ROOT_CA_FILE = "api_root_ca.pem"
private const val RELAYS_FILE = "relays.json"
class MullvadVpnService : TalpidVpnService() {
@@ -167,7 +166,6 @@ class MullvadVpnService : TalpidVpnService() {
private fun prepareFiles() {
FileMigrator(File("/data/data/net.mullvad.mullvadvpn"), filesDir).apply {
- migrate(API_ROOT_CA_FILE)
migrate(RELAYS_FILE)
migrate("settings.json")
migrate("daemon.log")
@@ -180,7 +178,6 @@ class MullvadVpnService : TalpidVpnService() {
lastUpdatedTime() > File(filesDir, RELAYS_FILE).lastModified()
FileResourceExtractor(this).apply {
- extract(API_ROOT_CA_FILE)
extract(RELAYS_FILE, shouldOverwriteRelayList)
}
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt
index 60356f4b20..524d4ab00d 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt
@@ -66,7 +66,7 @@ class MainActivity : FragmentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- problemReport = MullvadProblemReport(filesDir, filesDir)
+ problemReport = MullvadProblemReport(filesDir)
setContentView(R.layout.main)
diff --git a/gui/tasks/distribution.js b/gui/tasks/distribution.js
index 61d9f2ae7a..30c0fe1f03 100644
--- a/gui/tasks/distribution.js
+++ b/gui/tasks/distribution.js
@@ -20,7 +20,6 @@ const config = {
compression: compression,
extraResources: [
{ from: distAssets('ca.crt'), to: '.' },
- { from: distAssets('api_root_ca.pem'), to: '.' },
{ from: distAssets('relays.json'), to: '.' },
{ from: root('CHANGELOG.md'), to: '.' },
],
diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs
index 0b5e6eaf6c..1b2bfc8fcc 100644
--- a/mullvad-daemon/src/lib.rs
+++ b/mullvad-daemon/src/lib.rs
@@ -465,11 +465,10 @@ where
command_channel: DaemonCommandChannel,
#[cfg(target_os = "android")] android_context: AndroidContext,
) -> Result<Self, Error> {
- let ca_path = resource_dir.join(mullvad_paths::resources::API_CA_FILENAME);
let (tunnel_state_machine_shutdown_tx, tunnel_state_machine_shutdown_signal) =
oneshot::channel();
- let mut rpc_runtime = mullvad_rpc::MullvadRpcRuntime::with_cache_dir(&cache_dir, &ca_path)
+ let mut rpc_runtime = mullvad_rpc::MullvadRpcRuntime::with_cache_dir(&cache_dir)
.map_err(Error::InitRpcFactory)?;
let rpc_handle = rpc_runtime.mullvad_rest_handle();
diff --git a/mullvad-jni/src/lib.rs b/mullvad-jni/src/lib.rs
index 09d03bc0a3..c46c2ba99f 100644
--- a/mullvad-jni/src/lib.rs
+++ b/mullvad-jni/src/lib.rs
@@ -851,21 +851,14 @@ pub extern "system" fn Java_net_mullvad_mullvadvpn_dataproxy_MullvadProblemRepor
userEmail: JString<'_>,
userMessage: JString<'_>,
outputPath: JString<'_>,
- resourceDir: JString<'_>,
) -> jboolean {
let env = JnixEnv::from(env);
let user_email = String::from_java(&env, userEmail);
let user_message = String::from_java(&env, userMessage);
let output_path_string = String::from_java(&env, outputPath);
- let resource_dir = String::from_java(&env, resourceDir);
let output_path = Path::new(&output_path_string);
- match mullvad_problem_report::send_problem_report(
- &user_email,
- &user_message,
- output_path,
- &resource_dir.as_ref(),
- ) {
+ match mullvad_problem_report::send_problem_report(&user_email, &user_message, output_path) {
Ok(()) => JNI_TRUE,
Err(error) => {
log::error!(
diff --git a/mullvad-paths/src/resources.rs b/mullvad-paths/src/resources.rs
index 2ae2e5e2b6..ed6845bdf0 100644
--- a/mullvad-paths/src/resources.rs
+++ b/mullvad-paths/src/resources.rs
@@ -1,7 +1,5 @@
use std::{env, path::PathBuf};
-pub const API_CA_FILENAME: &str = "api_root_ca.pem";
-
pub fn get_resource_dir() -> PathBuf {
match env::var_os("MULLVAD_RESOURCE_DIR") {
Some(path) => PathBuf::from(path),
@@ -31,7 +29,3 @@ pub fn get_default_resource_dir() -> PathBuf {
PathBuf::from(crate::APP_PATH)
}
}
-
-pub fn get_api_ca_path() -> PathBuf {
- get_resource_dir().join(API_CA_FILENAME)
-}
diff --git a/mullvad-problem-report/src/lib.rs b/mullvad-problem-report/src/lib.rs
index eaeafbbf85..019dd82f62 100644
--- a/mullvad-problem-report/src/lib.rs
+++ b/mullvad-problem-report/src/lib.rs
@@ -251,22 +251,6 @@ pub fn send_problem_report(
user_email: &str,
user_message: &str,
report_path: &Path,
- #[cfg(target_os = "android")] resource_dir: &Path,
-) -> Result<(), Error> {
- #[cfg(not(target_os = "android"))]
- let ca_path = mullvad_paths::resources::get_api_ca_path();
-
- #[cfg(target_os = "android")]
- let ca_path = resource_dir.join(mullvad_paths::resources::API_CA_FILENAME);
-
- send_problem_report_inner(user_email, user_message, report_path, &ca_path)
-}
-
-pub fn send_problem_report_inner(
- user_email: &str,
- user_message: &str,
- report_path: &Path,
- ca_path: &Path,
) -> Result<(), Error> {
let report_content = normalize_newlines(
read_file_lossy(report_path, REPORT_MAX_SIZE).map_err(|source| {
@@ -280,7 +264,7 @@ pub fn send_problem_report_inner(
ProblemReport::parse_metadata(&report_content).unwrap_or_else(|| metadata::collect());
let mut rpc_manager =
- mullvad_rpc::MullvadRpcRuntime::new(ca_path).map_err(Error::CreateRpcClientError)?;
+ mullvad_rpc::MullvadRpcRuntime::new().map_err(Error::CreateRpcClientError)?;
let rpc_client = mullvad_rpc::ProblemReportProxy::new(rpc_manager.mullvad_rest_handle());
rpc_client
diff --git a/dist-assets/api_root_ca.pem b/mullvad-rpc/old_le_root_cert.pem
index b2e43c9381..b2e43c9381 100644
--- a/dist-assets/api_root_ca.pem
+++ b/mullvad-rpc/old_le_root_cert.pem
diff --git a/mullvad-rpc/src/bin/relay_list.rs b/mullvad-rpc/src/bin/relay_list.rs
index 330d53bc11..4c76c27ac0 100644
--- a/mullvad-rpc/src/bin/relay_list.rs
+++ b/mullvad-rpc/src/bin/relay_list.rs
@@ -4,8 +4,7 @@ use futures01::future::Future;
use mullvad_rpc::{MullvadRpcRuntime, RelayListProxy};
fn main() {
- let mut runtime = MullvadRpcRuntime::new("dist-assets/api_root_ca.pem".as_ref())
- .expect("Failed to load runtime");
+ let mut runtime = MullvadRpcRuntime::new().expect("Failed to load runtime");
let relay_list_request = RelayListProxy::new(runtime.mullvad_rest_handle()).relay_list();
diff --git a/mullvad-rpc/src/https_client_with_sni.rs b/mullvad-rpc/src/https_client_with_sni.rs
index a73bc19f39..25c144fe0e 100644
--- a/mullvad-rpc/src/https_client_with_sni.rs
+++ b/mullvad-rpc/src/https_client_with_sni.rs
@@ -3,10 +3,8 @@ use hyper::{client::HttpConnector, service::Service, Uri};
use hyper_rustls::MaybeHttpsStream;
use std::{
fmt,
- fs::File,
future::Future,
io::{self, BufReader},
- path::Path,
pin::Pin,
str,
sync::Arc,
@@ -15,22 +13,8 @@ use std::{
use tokio_rustls::rustls;
use webpki::DNSNameRef;
-
-#[derive(err_derive::Error, Debug)]
-#[error(no_from)]
-pub enum Error {
- #[error(display = "Failed to parse cert file")]
- CertError,
-
- #[error(display = "Root certificate error")]
- RootCertError(webpki::Error),
-
- #[error(display = "Failed to read cert file")]
- ReadCertError(#[error(source)] io::Error),
-
- #[error(display = "Failed to read trust anchor")]
- ReadRootError(#[error(source)] io::Error),
-}
+// Old LetsEncrypt root certificate
+const OLD_ROOT_CERT: &[u8] = include_bytes!("../old_le_root_cert.pem");
/// A Connector for the `https` scheme.
#[derive(Clone)]
@@ -47,35 +31,31 @@ impl HttpsConnectorWithSni {
///
/// This uses hyper's default `HttpConnector`, and default `TlsConnector`.
/// If you wish to use something besides the defaults, use `From::from`.
- pub fn new<P: AsRef<Path>>(ca_path: P) -> Result<Self, Error> {
+ pub fn new() -> Self {
let mut http = HttpConnector::new();
http.enforce_http(false);
let mut config = rustls::ClientConfig::new();
config.enable_sni = true;
- config.root_store = Self::read_cert_store(ca_path)?;
+ config.root_store = Self::read_cert_store();
- Ok(HttpsConnectorWithSni::from((http, config)))
+ HttpsConnectorWithSni::from((http, config))
}
- fn read_cert_store(ca_path: impl AsRef<Path>) -> Result<rustls::RootCertStore, Error> {
+ fn read_cert_store() -> rustls::RootCertStore {
let mut cert_store = rustls::RootCertStore::empty();
-
- let cert_file = File::open(ca_path).map_err(Error::ReadCertError)?;
- let mut cert_reader = BufReader::new(&cert_file);
- let (_num_certs_added, num_failures) = cert_store
- .add_pem_file(&mut cert_reader)
- .map_err(|_| Error::CertError)?;
- // add_pem_file() returns an Ok(i32, i32), where the second integer represents the amount
- // of errors encountered. Go figure.
- if num_failures > 0 {
- return Err(Error::CertError);
+ let (num_certs_added, num_failures) = cert_store
+ .add_pem_file(&mut BufReader::new(OLD_ROOT_CERT))
+ .expect("Failed to add old root cert");
+ if num_failures > 0 || num_certs_added != 1 {
+ panic!("Failed to add old root cert");
}
- Ok(cert_store)
+ cert_store
}
+
/// Configure a hostname to use with SNI.
///
/// Configures the TLS connection handshake to request a certificate for a given domain,
@@ -146,3 +126,13 @@ impl Service<Uri> for HttpsConnectorWithSni {
Box::pin(fut)
}
}
+
+#[cfg(test)]
+mod test {
+ use super::HttpsConnectorWithSni;
+
+ #[test]
+ fn test_cert_loading() {
+ let _certs = HttpsConnectorWithSni::read_cert_store();
+ }
+}
diff --git a/mullvad-rpc/src/lib.rs b/mullvad-rpc/src/lib.rs
index de29ccd8e5..bbe7a1f7bd 100644
--- a/mullvad-rpc/src/lib.rs
+++ b/mullvad-rpc/src/lib.rs
@@ -43,8 +43,6 @@ pub struct MullvadRpcRuntime {
#[derive(err_derive::Error, Debug)]
pub enum Error {
- #[error(display = "Failed to construct a connector")]
- ConnectorError(#[error(source)] https_client_with_sni::Error),
#[error(display = "Failed to construct a rest client")]
RestError(#[error(source)] rest::Error),
#[error(display = "Failed to spawn a tokio runtime")]
@@ -53,24 +51,21 @@ pub enum Error {
impl MullvadRpcRuntime {
/// Create a new `MullvadRpcRuntime`.
- pub fn new(ca_path: &Path) -> Result<Self, Error> {
- let https_connector =
- HttpsConnectorWithSni::new(&ca_path).map_err(Error::ConnectorError)?;
+ pub fn new() -> Result<Self, Error> {
Ok(MullvadRpcRuntime {
cached_dns_resolver: CachedDnsResolver::new(API_HOST.to_owned(), None, API_IP),
runtime: event_loop::create_runtime()?,
- https_connector,
+ https_connector: HttpsConnectorWithSni::new(),
})
}
/// Create a new `MullvadRpcRuntime` using the specified cache directory.
- pub fn with_cache_dir(cache_dir: &Path, ca_path: &Path) -> Result<Self, Error> {
+ pub fn with_cache_dir(cache_dir: &Path) -> Result<Self, Error> {
let cache_file = cache_dir.join(API_IP_CACHE_FILENAME);
let cached_dns_resolver =
CachedDnsResolver::new(API_HOST.to_owned(), Some(cache_file), API_IP);
- let https_connector =
- HttpsConnectorWithSni::new(&ca_path).map_err(Error::ConnectorError)?;
+ let https_connector = HttpsConnectorWithSni::new();
Ok(MullvadRpcRuntime {
cached_dns_resolver,
diff --git a/mullvad-tests/src/lib.rs b/mullvad-tests/src/lib.rs
index 307d7e3765..38266139c1 100644
--- a/mullvad-tests/src/lib.rs
+++ b/mullvad-tests/src/lib.rs
@@ -5,7 +5,6 @@ use futures::sync::oneshot;
use jsonrpc_client_core::{Future, Transport};
use jsonrpc_client_ipc::IpcTransport;
use mullvad_ipc_client::DaemonRpcClient;
-use mullvad_paths::resources::API_CA_FILENAME;
use notify::{RawEvent, RecommendedWatcher, RecursiveMode, Watcher};
use std::{
cmp,
@@ -211,13 +210,9 @@ fn prepare_test_dirs() -> (TempDir, PathBuf, PathBuf, PathBuf) {
}
fn prepare_resource_dir(resource_dir: &Path) {
- let assets_dir = PathBuf::from(ASSETS_DIR);
- let api_certificate_src = assets_dir.join(API_CA_FILENAME);
let openvpn_binary = resource_dir.join(OPENVPN_EXECUTABLE_FILE);
let talpid_openvpn_plugin = resource_dir.join(TALPID_OPENVPN_PLUGIN_FILE);
- let api_certificate_dst = resource_dir.join(API_CA_FILENAME);
- fs::copy(api_certificate_src, api_certificate_dst).expect("Failed to copy API certificate");
fs::copy(MOCK_OPENVPN_EXECUTABLE_PATH, openvpn_binary)
.expect("Failed to copy mock OpenVPN binary");
File::create(talpid_openvpn_plugin).expect("Failed to create mock Talpid OpenVPN plugin");