summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorLinus Färnstrand <linus@mullvad.net>2018-06-13 17:24:07 +0200
committerEmīls Piņķis <emils@mullvad.net>2018-07-05 16:05:05 +0100
commit891b91867a8b56616fc70b4ab982ad598bef2e54 (patch)
treefb16dc4fda26151483e096e2da031ce869e4d62d
parentb2a815aa5454d3351d60b21123bf3c8f076094b0 (diff)
downloadmullvadvpn-891b91867a8b56616fc70b4ab982ad598bef2e54.tar.xz
mullvadvpn-891b91867a8b56616fc70b4ab982ad598bef2e54.zip
Use bundled CA
-rw-r--r--mullvad-daemon/src/bin/list-relays.rs4
-rw-r--r--mullvad-daemon/src/geoip.rs5
-rw-r--r--mullvad-daemon/src/main.rs19
-rw-r--r--mullvad-paths/src/lib.rs2
-rw-r--r--mullvad-paths/src/resources.rs6
-rw-r--r--mullvad-problem-report/src/main.rs4
-rw-r--r--mullvad-rpc/Cargo.toml5
-rw-r--r--mullvad-rpc/src/https_client_with_sni.rs74
-rw-r--r--mullvad-rpc/src/lib.rs20
-rw-r--r--mullvad-rpc/src/rest.rs13
10 files changed, 87 insertions, 65 deletions
diff --git a/mullvad-daemon/src/bin/list-relays.rs b/mullvad-daemon/src/bin/list-relays.rs
index 581ef06d1a..a330297e20 100644
--- a/mullvad-daemon/src/bin/list-relays.rs
+++ b/mullvad-daemon/src/bin/list-relays.rs
@@ -9,6 +9,7 @@
#[macro_use]
extern crate error_chain;
+extern crate mullvad_paths;
extern crate mullvad_rpc;
extern crate serde_json;
@@ -17,7 +18,8 @@ error_chain!{}
quick_main!(run);
fn run() -> Result<()> {
- let mut rpc_manager = mullvad_rpc::MullvadRpcFactory::new();
+ let ca_path = mullvad_paths::resources::get_api_ca_path();
+ let mut rpc_manager = mullvad_rpc::MullvadRpcFactory::new(ca_path);
let rpc_http_handle = rpc_manager
.new_connection()
.chain_err(|| "Unable to connect RPC")?;
diff --git a/mullvad-daemon/src/geoip.rs b/mullvad-daemon/src/geoip.rs
index 4118ed7871..01f42ec6c9 100644
--- a/mullvad-daemon/src/geoip.rs
+++ b/mullvad-daemon/src/geoip.rs
@@ -4,7 +4,7 @@ use mullvad_types::location::GeoIpLocation;
use serde_json;
-static URI: &str = "https://am.i.mullvad.net/json";
+const URI: &str = "https://am.i.mullvad.net/json";
error_chain! {
errors {
@@ -18,12 +18,13 @@ error_chain! {
}
}
+
pub fn send_location_request(
request_sender: mullvad_rpc::rest::RequestSender,
) -> Box<Future<Item = GeoIpLocation, Error = Error>> {
let (response_tx, response_rx) = futures::sync::oneshot::channel();
let request = mullvad_rpc::rest::create_get_request(URI.parse().unwrap());
- let future = futures::Sink::send(request_sender, (request, response_tx))
+ let future = futures::Sink::send(request_sender.clone(), (request, response_tx))
.map_err(|e| Error::with_chain(e, ErrorKind::NoResponse))
.and_then(|_| response_rx.map_err(|e| Error::with_chain(e, ErrorKind::NoResponse)))
.and_then(|response_result| response_result.map_err(Error::from))
diff --git a/mullvad-daemon/src/main.rs b/mullvad-daemon/src/main.rs
index d5e50f88b0..d2dc1da4f7 100644
--- a/mullvad-daemon/src/main.rs
+++ b/mullvad-daemon/src/main.rs
@@ -199,7 +199,7 @@ struct Daemon {
settings: settings::Settings,
accounts_proxy: AccountsProxy<HttpHandle>,
version_proxy: AppVersionProxy<HttpHandle>,
- http_handle: mullvad_rpc::rest::RequestSender,
+ https_handle: mullvad_rpc::rest::RequestSender,
tokio_remote: tokio_core::reactor::Remote,
relay_selector: relays::RelaySelector,
firewall: FirewallProxy,
@@ -220,19 +220,20 @@ impl Daemon {
!rpc_uniqueness_check::is_another_instance_running(),
ErrorKind::DaemonIsAlreadyRunning
);
+ let ca_path = resource_dir.join(mullvad_paths::resources::API_CA_FILENAME);
- let mut rpc_manager = mullvad_rpc::MullvadRpcFactory::with_cache_dir(&cache_dir);
+ let mut rpc_manager = mullvad_rpc::MullvadRpcFactory::with_cache_dir(&cache_dir, &ca_path);
- let (rpc_handle, http_handle, tokio_remote) =
+ let (rpc_handle, https_handle, tokio_remote) =
mullvad_rpc::event_loop::create(move |core| {
let handle = core.handle();
let rpc = rpc_manager.new_connection_on_event_loop(&handle);
- let http = mullvad_rpc::rest::create_http_client(&handle);
+ let https_handle = mullvad_rpc::rest::create_https_client(&ca_path, &handle);
let remote = core.remote();
- (rpc, http, remote)
+ (rpc, https_handle, remote)
}).chain_err(|| "Unable to initialize network event loop")?;
let rpc_handle = rpc_handle.chain_err(|| "Unable to create RPC client")?;
- let http_handle = http_handle.chain_err(|| "Unable to create HTTP client")?;
+ let https_handle = https_handle.chain_err(|| "Unable to create am.i.mullvad client")?;
let relay_selector =
Self::create_relay_selector(rpc_handle.clone(), &resource_dir, &cache_dir);
@@ -257,7 +258,7 @@ impl Daemon {
settings: settings::Settings::load().chain_err(|| "Unable to read settings")?,
accounts_proxy: AccountsProxy::new(rpc_handle.clone()),
version_proxy: AppVersionProxy::new(rpc_handle),
- http_handle,
+ https_handle,
tokio_remote,
relay_selector,
firewall: FirewallProxy::new(&cache_dir).chain_err(|| ErrorKind::FirewallError)?,
@@ -432,9 +433,9 @@ impl Daemon {
};
Self::oneshot_send(tx, geo_ip_location, "current location");
} else {
- let http_handle = self.http_handle.clone();
+ let https_handle = self.https_handle.clone();
self.tokio_remote.spawn(move |_| {
- geoip::send_location_request(http_handle)
+ geoip::send_location_request(https_handle)
.map(move |location| Self::oneshot_send(tx, location, "current location"))
.map_err(|e| {
warn!("Unable to fetch GeoIP location: {}", e.display_chain());
diff --git a/mullvad-paths/src/lib.rs b/mullvad-paths/src/lib.rs
index 12c209c718..e7a8ffbc9e 100644
--- a/mullvad-paths/src/lib.rs
+++ b/mullvad-paths/src/lib.rs
@@ -48,7 +48,7 @@ pub use cache::cache_dir;
mod logs;
pub use logs::{get_log_dir, log_dir};
-mod resources;
+pub mod resources;
pub use resources::get_resource_dir;
mod rpc_address;
diff --git a/mullvad-paths/src/resources.rs b/mullvad-paths/src/resources.rs
index 4f60a88287..60c4406620 100644
--- a/mullvad-paths/src/resources.rs
+++ b/mullvad-paths/src/resources.rs
@@ -1,6 +1,8 @@
use std::env;
use std::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),
@@ -23,3 +25,7 @@ fn get_default_resource_dir() -> PathBuf {
}
}
}
+
+pub fn get_api_ca_path() -> PathBuf {
+ get_resource_dir().join(API_CA_FILENAME)
+}
diff --git a/mullvad-problem-report/src/main.rs b/mullvad-problem-report/src/main.rs
index 1f63d1aa19..0749aa2946 100644
--- a/mullvad-problem-report/src/main.rs
+++ b/mullvad-problem-report/src/main.rs
@@ -219,7 +219,9 @@ fn send_problem_report(user_email: &str, user_message: &str, report_path: &Path)
);
let metadata = collect_metadata();
- let mut rpc_manager = mullvad_rpc::MullvadRpcFactory::new();
+ let ca_path = mullvad_paths::resources::get_api_ca_path();
+
+ let mut rpc_manager = mullvad_rpc::MullvadRpcFactory::new(ca_path);
let rpc_http_handle = rpc_manager
.new_connection()
.chain_err(|| ErrorKind::RpcError)?;
diff --git a/mullvad-rpc/Cargo.toml b/mullvad-rpc/Cargo.toml
index 2f34fdd800..944de63245 100644
--- a/mullvad-rpc/Cargo.toml
+++ b/mullvad-rpc/Cargo.toml
@@ -15,10 +15,9 @@ lazy_static = "1.0"
serde_json = "1.0"
tokio-core = "0.1"
hyper = "0.11"
-hyper-tls = "0.1"
-native-tls = "0.1"
+hyper-openssl = "0.5"
tokio-service = "0.1"
-tokio-tls = "0.1"
+tokio-openssl = "0.2"
log = "0.4"
mullvad-types = { path = "../mullvad-types" }
diff --git a/mullvad-rpc/src/https_client_with_sni.rs b/mullvad-rpc/src/https_client_with_sni.rs
index 319576da5e..9c91cc8e7f 100644
--- a/mullvad-rpc/src/https_client_with_sni.rs
+++ b/mullvad-rpc/src/https_client_with_sni.rs
@@ -1,43 +1,43 @@
+extern crate tokio_openssl;
extern crate tokio_service;
-extern crate tokio_tls;
use std::fmt;
use std::io;
+use std::path::{Path, PathBuf};
use std::str;
use std::sync::Arc;
use futures::{Future, Poll};
use hyper::client::{Client, Connect, HttpConnector};
use hyper::{Body, Uri};
-use hyper_tls::MaybeHttpsStream;
+pub use hyper_openssl::openssl::error::ErrorStack;
+use hyper_openssl::openssl::ssl::{SslConnector, SslMethod};
use jsonrpc_client_http::ClientCreator;
-pub use native_tls::Error;
-use native_tls::TlsConnector;
use tokio_core::reactor::Handle;
+use self::tokio_openssl::{SslConnectorExt, SslStream};
use self::tokio_service::Service;
-use self::tokio_tls::TlsConnectorExt;
-
-/// Number of threads in the thread pool doing DNS resolutions.
-/// Since DNS is resolved via blocking syscall they must be run on separate threads.
-static DNS_THREADS: usize = 2;
pub struct HttpsClientWithSni {
sni_hostname: String,
+ ca_path: Box<Path>,
}
impl HttpsClientWithSni {
- pub fn new(sni_hostname: String) -> Self {
- HttpsClientWithSni { sni_hostname }
+ pub fn new<P: Into<PathBuf>>(sni_hostname: String, ca_path: P) -> Self {
+ HttpsClientWithSni {
+ sni_hostname,
+ ca_path: ca_path.into().into_boxed_path(),
+ }
}
}
impl ClientCreator for HttpsClientWithSni {
type Connect = HttpsConnectorWithSni<HttpConnector>;
- type Error = Error;
+ type Error = ErrorStack;
fn create(&self, handle: &Handle) -> Result<Client<Self::Connect, Body>, Self::Error> {
- let mut connector = HttpsConnectorWithSni::new(DNS_THREADS, handle)?;
+ let mut connector = HttpsConnectorWithSni::new(&self.ca_path, handle)?;
connector.set_sni_hostname(Some(self.sni_hostname.clone()));
let client = Client::configure().connector(connector).build(handle);
Ok(client)
@@ -49,7 +49,7 @@ impl ClientCreator for HttpsClientWithSni {
pub struct HttpsConnectorWithSni<T> {
sni_hostname: Option<String>,
http: T,
- tls: Arc<TlsConnector>,
+ tls: Arc<SslConnector>,
}
impl HttpsConnectorWithSni<HttpConnector> {
@@ -59,11 +59,14 @@ impl HttpsConnectorWithSni<HttpConnector> {
///
/// This uses hyper's default `HttpConnector`, and default `TlsConnector`.
/// If you wish to use something besides the defaults, use `From::from`.
- fn new(threads: usize, handle: &Handle) -> Result<Self, Error> {
- let mut http = HttpConnector::new(threads, handle);
+ pub fn new<P: AsRef<Path>>(ca_path: P, handle: &Handle) -> Result<Self, ErrorStack> {
+ let mut http = HttpConnector::new(::DNS_THREADS, handle);
http.enforce_http(false);
- let tls = TlsConnector::builder()?.build()?;
- Ok(HttpsConnectorWithSni::from((http, tls)))
+ let mut ssl_builder = SslConnector::builder(SslMethod::tls())?;
+ ssl_builder.set_ca_file(ca_path)?;
+ let ssl = ssl_builder.build();
+
+ Ok(HttpsConnectorWithSni::from((http, ssl)))
}
}
@@ -75,13 +78,13 @@ where
///
/// Configures the TLS connection handshake to request a certificate for a given domain,
/// instead of the domain obtained from the URI. Use `None` to use the domain from the URI.
- fn set_sni_hostname(&mut self, hostname: Option<String>) {
+ pub fn set_sni_hostname(&mut self, hostname: Option<String>) {
self.sni_hostname = hostname;
}
}
-impl<T> From<(T, TlsConnector)> for HttpsConnectorWithSni<T> {
- fn from(args: (T, TlsConnector)) -> HttpsConnectorWithSni<T> {
+impl<T> From<(T, SslConnector)> for HttpsConnectorWithSni<T> {
+ fn from(args: (T, SslConnector)) -> HttpsConnectorWithSni<T> {
HttpsConnectorWithSni {
sni_hostname: None,
http: args.0,
@@ -98,12 +101,17 @@ impl<T> fmt::Debug for HttpsConnectorWithSni<T> {
impl<T: Connect> Service for HttpsConnectorWithSni<T> {
type Request = Uri;
- type Response = MaybeHttpsStream<T::Output>;
+ type Response = SslStream<T::Output>;
type Error = io::Error;
type Future = HttpsConnecting<T::Output>;
fn call(&self, uri: Uri) -> Self::Future {
- let is_https = uri.scheme() == Some("https");
+ if uri.scheme() != Some("https") {
+ return HttpsConnecting(Box::new(::futures::future::err(io::Error::new(
+ io::ErrorKind::InvalidInput,
+ "invalid url, not https",
+ ))));
+ }
let maybe_host = self
.sni_hostname
.as_ref()
@@ -122,28 +130,22 @@ impl<T: Connect> Service for HttpsConnectorWithSni<T> {
let connecting = self.http.connect(uri);
let tls = self.tls.clone();
- let fut: BoxedFut<T::Output> = if is_https {
- let fut = connecting.and_then(move |tcp| {
- tls.connect_async(&host, tcp)
- .map(|conn| MaybeHttpsStream::Https(conn))
- .map_err(|e| io::Error::new(io::ErrorKind::Other, e))
- });
- Box::new(fut)
- } else {
- Box::new(connecting.map(|tcp| MaybeHttpsStream::Http(tcp)))
- };
- HttpsConnecting(fut)
+ let fut = connecting.and_then(move |tcp| {
+ tls.connect_async(&host, tcp)
+ .map_err(|e| io::Error::new(io::ErrorKind::Other, e))
+ });
+ HttpsConnecting(Box::new(fut))
}
}
-type BoxedFut<T> = Box<Future<Item = MaybeHttpsStream<T>, Error = io::Error>>;
+type BoxedFut<T> = Box<Future<Item = SslStream<T>, Error = io::Error>>;
/// A Future representing work to connect to a URL, and a TLS handshake.
pub struct HttpsConnecting<T>(BoxedFut<T>);
impl<T> Future for HttpsConnecting<T> {
- type Item = MaybeHttpsStream<T>;
+ type Item = SslStream<T>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
diff --git a/mullvad-rpc/src/lib.rs b/mullvad-rpc/src/lib.rs
index 02537adee3..6873fe926a 100644
--- a/mullvad-rpc/src/lib.rs
+++ b/mullvad-rpc/src/lib.rs
@@ -11,7 +11,7 @@ extern crate chrono;
extern crate error_chain;
extern crate futures;
extern crate hyper;
-extern crate hyper_tls;
+extern crate hyper_openssl;
#[macro_use]
extern crate jsonrpc_client_core;
extern crate jsonrpc_client_http;
@@ -19,7 +19,6 @@ extern crate jsonrpc_client_http;
extern crate lazy_static;
#[macro_use]
extern crate log;
-extern crate native_tls;
extern crate serde_json;
extern crate tokio_core;
@@ -40,7 +39,7 @@ use mullvad_types::version;
use std::collections::HashMap;
use std::net::{IpAddr, Ipv4Addr};
-use std::path::Path;
+use std::path::{Path, PathBuf};
use std::time::Duration;
pub mod event_loop;
@@ -50,7 +49,11 @@ mod cached_dns_resolver;
use cached_dns_resolver::CachedDnsResolver;
mod https_client_with_sni;
-use https_client_with_sni::HttpsClientWithSni;
+use https_client_with_sni::{HttpsClientWithSni, HttpsConnectorWithSni};
+
+/// Number of threads in the thread pool doing DNS resolutions.
+/// Since DNS is resolved via blocking syscall they must be run on separate threads.
+const DNS_THREADS: usize = 2;
const API_HOST: &str = "api.mullvad.net";
const RPC_TIMEOUT: Duration = Duration::from_secs(5);
@@ -63,23 +66,26 @@ lazy_static! {
/// A type that helps with the creation of RPC connections.
pub struct MullvadRpcFactory {
address_cache: Option<CachedDnsResolver>,
+ ca_path: PathBuf,
}
impl MullvadRpcFactory {
/// Create a new `MullvadRpcFactory`.
- pub fn new() -> Self {
+ pub fn new<P: Into<PathBuf>>(ca_path: P) -> Self {
MullvadRpcFactory {
address_cache: None,
+ ca_path: ca_path.into(),
}
}
/// Create a new `MullvadRpcFactory` using the specified cache directory.
- pub fn with_cache_dir(cache_dir: &Path) -> Self {
+ pub fn with_cache_dir<P: Into<PathBuf>>(cache_dir: &Path, ca_path: P) -> Self {
let cache_file = cache_dir.join(API_IP_CACHE_FILENAME);
let cached_dns_resolver = CachedDnsResolver::new(API_HOST.to_owned(), cache_file, *API_IP);
MullvadRpcFactory {
address_cache: Some(cached_dns_resolver),
+ ca_path: ca_path.into(),
}
}
@@ -101,7 +107,7 @@ impl MullvadRpcFactory {
F: FnOnce(HttpTransportBuilder<HttpsClientWithSni>)
-> jsonrpc_client_http::Result<HttpTransport>,
{
- let client = HttpsClientWithSni::new(API_HOST.to_owned());
+ let client = HttpsClientWithSni::new(API_HOST.to_owned(), self.ca_path.clone());
let transport_builder = HttpTransportBuilder::with_client(client).timeout(RPC_TIMEOUT);
let transport = create_transport(transport_builder)?;
diff --git a/mullvad-rpc/src/rest.rs b/mullvad-rpc/src/rest.rs
index 0d8ed16027..988dfba7c0 100644
--- a/mullvad-rpc/src/rest.rs
+++ b/mullvad-rpc/src/rest.rs
@@ -1,14 +1,16 @@
+use std::path::Path;
+
use futures::sync::{mpsc, oneshot};
use futures::{future, Future, Stream};
use hyper;
use hyper::client::Client;
use hyper::{Request, StatusCode, Uri};
-use hyper_tls::HttpsConnector;
-use native_tls;
+use hyper_openssl::openssl::error::ErrorStack;
use tokio_core::reactor::Handle;
+use HttpsConnectorWithSni;
error_chain! {
errors {
@@ -19,9 +21,9 @@ error_chain! {
}
}
foreign_links {
- Tls(native_tls::Error);
Hyper(hyper::Error) #[doc = "An error occured in Hyper."];
Uri(hyper::error::UriError) #[doc = "The string given was not a valid URI."];
+ OpenSsl(ErrorStack) #[doc = "Error in OpenSSL"];
}
}
@@ -29,9 +31,10 @@ error_chain! {
pub type RequestSender = mpsc::UnboundedSender<(Request, oneshot::Sender<Result<Vec<u8>>>)>;
type RequestReceiver = mpsc::UnboundedReceiver<(Request, oneshot::Sender<Result<Vec<u8>>>)>;
-pub fn create_http_client(handle: &Handle) -> Result<RequestSender> {
- let connector = HttpsConnector::new(1, handle)?;
+pub fn create_https_client<P: AsRef<Path>>(ca_path: P, handle: &Handle) -> Result<RequestSender> {
+ let connector = HttpsConnectorWithSni::new(ca_path, handle)?;
let client = Client::configure().connector(connector).build(handle);
+
let (request_tx, request_rx) = mpsc::unbounded();
handle.spawn(create_request_processing_future(request_rx, client));
Ok(request_tx)