Skip to content

Commit

Permalink
Add ALPN and signature algorithms to OpenSSL config
Browse files Browse the repository at this point in the history
  • Loading branch information
Darkspirit committed Nov 30, 2019
1 parent 69c7595 commit b811be7
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 66 deletions.
27 changes: 17 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 32 additions & 24 deletions components/net/connector.rs
Expand Up @@ -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,
Expand Down Expand Up @@ -42,21 +58,21 @@ impl Connect for HttpConnector {
}

pub type Connector = HttpsConnector<HttpConnector>;
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<Option<&str>> = e.errors().iter().nth(0).map(|e| e.reason());
Expand All @@ -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<E>(
ssl_connector_builder: SslConnectorBuilder,
executor: E,
) -> Client<Connector, Body>
pub fn create_http_client<E>(tls_config: TlsConfig, executor: E) -> Client<Connector, Body>
where
E: Executor<Box<dyn Future<Error = (), Item = ()> + 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"
);
7 changes: 3 additions & 4 deletions components/net/http_loader.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -90,15 +89,15 @@ 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)),
auth_cache: RwLock::new(AuthCache::new()),
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()),
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions components/net/resource_thread.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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(),
),
};
Expand All @@ -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(),
),
};
Expand Down
21 changes: 7 additions & 14 deletions components/net/tests/fetch.rs
Expand Up @@ -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;
Expand All @@ -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};
Expand Down Expand Up @@ -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!(),
}
Expand Down Expand Up @@ -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()),
Expand Down
16 changes: 8 additions & 8 deletions components/net/tests/main.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -87,11 +87,11 @@ fn new_fetch_context(
dc: Option<Sender<DevtoolsControlMsg>>,
fc: Option<EmbedderProxy>,
) -> 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),
Expand Down Expand Up @@ -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(|_| ())
Expand Down
7 changes: 4 additions & 3 deletions components/net/websocket_loader.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
}
Expand Down

0 comments on commit b811be7

Please sign in to comment.