diff --git a/Cargo.lock b/Cargo.lock index f6daa13a696..b9f0cc40ea2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -169,6 +169,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" + [[package]] name = "azure" version = "0.37.0" @@ -2354,9 +2360,9 @@ dependencies = [ [[package]] name = "http" -version = "0.1.17" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed324f0f0daf6ec10c474f150505af2c143f251722bf9dbd1261bd1f2ee2c1a" +checksum = "2790658cddc82e82b08e25176c431d7015a0adeb1718498715cbd20138a0bf68" dependencies = [ "bytes", "fnv", @@ -2392,9 +2398,9 @@ dependencies = [ [[package]] name = "hyper" -version = "0.12.33" +version = "0.12.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cb44cbce9d8ee4fb36e4c0ad7b794ac44ebaad924b9c8291a63215bb44c2c8f" +checksum = "9dbe6ed1438e1f8ad955a4701e9a944938e9519f6888d12d8558b645e247d5f6" dependencies = [ "bytes", "futures", @@ -2422,9 +2428,9 @@ dependencies = [ [[package]] name = "hyper-openssl" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06a137dee5fc025f1afdd4f9d1eb6405689e4c687d07b687ba287adb7d55f791" +checksum = "f52657b5cdb2a8067efd29a02e011b7cf656b473ec8a5c34e86645e85d763006" dependencies = [ "antidote", "bytes", @@ -3684,9 +3690,9 @@ checksum = "51ecbcb821e1bd256d456fe858aaa7f380b63863eab2eb86eee1bd9f33dd6682" [[package]] name = "openssl" -version = "0.10.11" +version = "0.10.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c24d3508b4fb6da175c10baac54c578b33f09c89ae90c6fe9788b3b4768efdc" +checksum = "3a3cc5799d98e1088141b8e01ff760112bbd9f19d850c124500566ca6901a585" dependencies = [ "bitflags", "cfg-if", @@ -3704,10 +3710,11 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" [[package]] name = "openssl-sys" -version = "0.9.35" +version = "0.9.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "912f301a749394e1025d9dcddef6106ddee9252620e6d0a0e5f8d0681de9b129" +checksum = "465d16ae7fc0e313318f7de5cecf57b2fbe7511fd213978b457e1c96ff46736f" dependencies = [ + "autocfg", "cc", "libc", "pkg-config", diff --git a/components/net/connector.rs b/components/net/connector.rs index 45eda71bd6e..dccc4d7547c 100644 --- a/components/net/connector.rs +++ b/components/net/connector.rs @@ -13,6 +13,22 @@ use openssl::x509; use tokio::prelude::future::Executor; pub const BUF_SIZE: usize = 32768; +pub const ALPN_H2_H1: &'static [u8] = b"\x02h2\x08http/1.1"; +pub const ALPN_H1: &'static [u8] = b"\x08http/1.1"; + +// See https://wiki.mozilla.org/Security/Server_Side_TLS for orientation. +const TLS1_2_CIPHERSUITES: &'static str = concat!( + "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:", + "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:", + "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:", + "ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA" +); +const SIGNATURE_ALGORITHMS: &'static str = concat!( + "ed448:ed25519:", + "ECDSA+SHA384:ECDSA+SHA256:", + "RSA-PSS+SHA512:RSA-PSS+SHA384:RSA-PSS+SHA256:", + "RSA+SHA512:RSA+SHA384:RSA+SHA256" +); pub struct HttpConnector { inner: HyperHttpConnector, @@ -42,21 +58,21 @@ impl Connect for HttpConnector { } pub type Connector = HttpsConnector; +pub type TlsConfig = SslConnectorBuilder; -pub fn create_ssl_connector_builder(certs: &str) -> SslConnectorBuilder { +pub fn create_tls_config(certs: &str, alpn: &[u8]) -> TlsConfig { // certs include multiple certificates. We could add all of them at once, // but if any of them were already added, openssl would fail to insert all // of them. let mut certs = certs; - let mut ssl_connector_builder = SslConnector::builder(SslMethod::tls()).unwrap(); + let mut cfg = SslConnector::builder(SslMethod::tls()).unwrap(); loop { let token = "-----END CERTIFICATE-----"; if let Some(index) = certs.find(token) { let (cert, rest) = certs.split_at(index + token.len()); certs = rest; let cert = x509::X509::from_pem(cert.as_bytes()).unwrap(); - ssl_connector_builder - .cert_store_mut() + cfg.cert_store_mut() .add_cert(cert) .or_else(|e| { let v: Option> = e.errors().iter().nth(0).map(|e| e.reason()); @@ -74,39 +90,31 @@ pub fn create_ssl_connector_builder(certs: &str) -> SslConnectorBuilder { break; } } - ssl_connector_builder - .set_cipher_list(DEFAULT_CIPHERS) - .expect("could not set ciphers"); - ssl_connector_builder.set_options( + cfg.set_alpn_protos(alpn) + .expect("could not set alpn protocols"); + cfg.set_cipher_list(TLS1_2_CIPHERSUITES) + .expect("could not set TLS 1.2 ciphersuites"); + cfg.set_sigalgs_list(SIGNATURE_ALGORITHMS) + .expect("could not set signature algorithms"); + cfg.set_options( SslOptions::NO_SSLV2 | SslOptions::NO_SSLV3 | SslOptions::NO_TLSV1 | SslOptions::NO_TLSV1_1 | SslOptions::NO_COMPRESSION, ); - ssl_connector_builder + + cfg } -pub fn create_http_client( - ssl_connector_builder: SslConnectorBuilder, - executor: E, -) -> Client +pub fn create_http_client(tls_config: TlsConfig, executor: E) -> Client where E: Executor + Send + 'static>> + Sync + Send + 'static, { - let connector = - HttpsConnector::with_connector(HttpConnector::new(), ssl_connector_builder).unwrap(); + let connector = HttpsConnector::with_connector(HttpConnector::new(), tls_config).unwrap(); + Client::builder() .http1_title_case_headers(true) .executor(executor) .build(connector) } - -// Prefer Forward Secrecy over plain RSA, AES-GCM over AES-CBC, ECDSA over RSA. -// A complete discussion of the issues involved in TLS configuration can be found here: -// https://wiki.mozilla.org/Security/Server_Side_TLS -const DEFAULT_CIPHERS: &'static str = concat!( - "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:", - "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:", - "ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:AES256-SHA:AES128-SHA" -); diff --git a/components/net/http_loader.rs b/components/net/http_loader.rs index 3ed84241736..efffa93b05e 100644 --- a/components/net/http_loader.rs +++ b/components/net/http_loader.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::connector::{create_http_client, Connector}; +use crate::connector::{create_http_client, Connector, TlsConfig}; use crate::cookie; use crate::cookie_storage::CookieStorage; use crate::decoder::Decoder; @@ -46,7 +46,6 @@ use net_traits::{CookieSource, FetchMetadata, NetworkError, ReferrerPolicy}; use net_traits::{ RedirectEndValue, RedirectStartValue, ResourceAttribute, ResourceFetchTiming, ResourceTimeValue, }; -use openssl::ssl::SslConnectorBuilder; use servo_arc::Arc; use servo_url::{ImmutableOrigin, ServoUrl}; use std::collections::{HashMap, HashSet}; @@ -90,7 +89,7 @@ pub struct HttpState { } impl HttpState { - pub fn new(ssl_connector_builder: SslConnectorBuilder) -> HttpState { + pub fn new(tls_config: TlsConfig) -> HttpState { HttpState { hsts_list: RwLock::new(HstsList::new()), cookie_jar: RwLock::new(CookieStorage::new(150)), @@ -98,7 +97,7 @@ impl HttpState { history_states: RwLock::new(HashMap::new()), http_cache: RwLock::new(HttpCache::new()), http_cache_state: Mutex::new(HashMap::new()), - client: create_http_client(ssl_connector_builder, HANDLE.lock().unwrap().executor()), + client: create_http_client(tls_config, HANDLE.lock().unwrap().executor()), } } } diff --git a/components/net/resource_thread.rs b/components/net/resource_thread.rs index 4be209f9d6d..c948055bc55 100644 --- a/components/net/resource_thread.rs +++ b/components/net/resource_thread.rs @@ -4,7 +4,7 @@ //! A thread that takes a URL and streams back the binary data. -use crate::connector::{create_http_client, create_ssl_connector_builder}; +use crate::connector::{create_http_client, create_tls_config, ALPN_H2_H1}; use crate::cookie; use crate::cookie_storage::CookieStorage; use crate::fetch::cors_cache::CorsCache; @@ -149,7 +149,7 @@ fn create_http_states( http_cache: RwLock::new(http_cache), http_cache_state: Mutex::new(HashMap::new()), client: create_http_client( - create_ssl_connector_builder(&certs), + create_tls_config(&certs, ALPN_H2_H1), HANDLE.lock().unwrap().executor(), ), }; @@ -162,7 +162,7 @@ fn create_http_states( http_cache: RwLock::new(HttpCache::new()), http_cache_state: Mutex::new(HashMap::new()), client: create_http_client( - create_ssl_connector_builder(&certs), + create_tls_config(&certs, ALPN_H2_H1), HANDLE.lock().unwrap().executor(), ), }; diff --git a/components/net/tests/fetch.rs b/components/net/tests/fetch.rs index 328ca734576..5b6031335cb 100644 --- a/components/net/tests/fetch.rs +++ b/components/net/tests/fetch.rs @@ -24,7 +24,7 @@ use hyper::body::Body; use hyper::{Request as HyperRequest, Response as HyperResponse}; use mime::{self, Mime}; use msg::constellation_msg::TEST_PIPELINE_ID; -use net::connector::create_ssl_connector_builder; +use net::connector::{create_tls_config, ALPN_H2_H1}; use net::fetch::cors_cache::CorsCache; use net::fetch::methods::{self, CancellationListener, FetchContext}; use net::filemanager_thread::FileManager; @@ -38,8 +38,7 @@ use net_traits::{ }; use servo_arc::Arc as ServoArc; use servo_url::{ImmutableOrigin, ServoUrl}; -use std::fs::File; -use std::io::Read; +use std::fs; use std::iter::FromIterator; use std::path::Path; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -218,13 +217,11 @@ fn test_fetch_file() { assert_eq!(content_type, mime::TEXT_CSS); let resp_body = fetch_response.body.lock().unwrap(); - let mut file = File::open(path).unwrap(); - let mut bytes = vec![]; - let _ = file.read_to_end(&mut bytes); + let file = fs::read(path).unwrap(); match *resp_body { ResponseBody::Done(ref val) => { - assert_eq!(val, &bytes); + assert_eq!(val, &file); }, _ => panic!(), } @@ -653,15 +650,11 @@ fn test_fetch_with_hsts() { .unwrap(); let (server, url) = make_ssl_server(handler, cert_path.clone(), key_path.clone()); - let mut ca_content = String::new(); - File::open(cert_path) - .unwrap() - .read_to_string(&mut ca_content) - .unwrap(); - let ssl_client = create_ssl_connector_builder(&ca_content); + let certs = fs::read_to_string(cert_path).expect("Couldn't find certificate file"); + let tls_config = create_tls_config(&certs, ALPN_H2_H1); let mut context = FetchContext { - state: Arc::new(HttpState::new(ssl_client)), + state: Arc::new(HttpState::new(tls_config)), user_agent: DEFAULT_USER_AGENT.into(), devtools_chan: None, filemanager: FileManager::new(create_embedder_proxy()), diff --git a/components/net/tests/main.rs b/components/net/tests/main.rs index e68cc293fa6..6f301692c0c 100644 --- a/components/net/tests/main.rs +++ b/components/net/tests/main.rs @@ -29,7 +29,7 @@ use hyper::server::conn::Http; use hyper::server::Server as HyperServer; use hyper::service::service_fn_ok; use hyper::{Body, Request as HyperRequest, Response as HyperResponse}; -use net::connector::create_ssl_connector_builder; +use net::connector::{create_tls_config, ALPN_H2_H1}; use net::fetch::cors_cache::CorsCache; use net::fetch::methods::{self, CancellationListener, FetchContext}; use net::filemanager_thread::FileManager; @@ -87,11 +87,11 @@ fn new_fetch_context( dc: Option>, fc: Option, ) -> FetchContext { - let ssl_connector = - create_ssl_connector_builder(&resources::read_string(Resource::SSLCertificates)); + let certs = resources::read_string(Resource::SSLCertificates); + let tls_config = create_tls_config(&certs, ALPN_H2_H1); let sender = fc.unwrap_or_else(|| create_embedder_proxy()); FetchContext { - state: Arc::new(HttpState::new(ssl_connector)), + state: Arc::new(HttpState::new(tls_config)), user_agent: DEFAULT_USER_AGENT.into(), devtools_chan: dc, filemanager: FileManager::new(sender), @@ -187,16 +187,16 @@ where let url = ServoUrl::parse(&url_string).unwrap(); let server = listener.incoming().map_err(|_| ()).for_each(move |sock| { - let mut ssl_builder = SslAcceptor::mozilla_modern(SslMethod::tls()).unwrap(); - ssl_builder + let mut tls_server_config = SslAcceptor::mozilla_intermediate_v5(SslMethod::tls()).unwrap(); + tls_server_config .set_certificate_file(&cert_path, SslFiletype::PEM) .unwrap(); - ssl_builder + tls_server_config .set_private_key_file(&key_path, SslFiletype::PEM) .unwrap(); let handler = handler.clone(); - ssl_builder + tls_server_config .build() .accept_async(sock) .map_err(|_| ()) diff --git a/components/net/websocket_loader.rs b/components/net/websocket_loader.rs index 744d6868d0c..3fd213e399b 100644 --- a/components/net/websocket_loader.rs +++ b/components/net/websocket_loader.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::connector::create_ssl_connector_builder; +use crate::connector::{create_tls_config, ALPN_H1}; use crate::cookie::Cookie; use crate::fetch::methods::should_be_blocked_due_to_bad_port; use crate::hosts::replace_host; @@ -167,8 +167,9 @@ impl<'a> Handler for Client<'a> { WebSocketErrorKind::Protocol, format!("Unable to parse domain from {}. Needed for SSL.", url), ))?; - let connector = create_ssl_connector_builder(&certs).build(); - connector + let tls_config = create_tls_config(&certs, ALPN_H1); + tls_config + .build() .connect(domain, stream) .map_err(WebSocketError::from) }