aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2020-05-27 19:24:06 -0400
committerJosh Matthews <josh@joshmatthews.net>2020-06-09 15:03:18 -0400
commit1cdaf40eb24c26bc2d372a791ffb9a6a08d7a304 (patch)
treeda3773c90431128a60d219356d143e7b865cb3f1
parentb7a640b5172ebcdea73179c5a33486930ef35e96 (diff)
downloadservo-1cdaf40eb24c26bc2d372a791ffb9a6a08d7a304.tar.gz
servo-1cdaf40eb24c26bc2d372a791ffb9a6a08d7a304.zip
net: Add an SSL verification callback to support checking a dynamic list of certs.
-rw-r--r--components/net/connector.rs49
-rw-r--r--components/net/resource_thread.rs18
-rw-r--r--components/net/websocket_loader.rs4
3 files changed, 60 insertions, 11 deletions
diff --git a/components/net/connector.rs b/components/net/connector.rs
index 058a27c47d6..4369e236501 100644
--- a/components/net/connector.rs
+++ b/components/net/connector.rs
@@ -8,8 +8,12 @@ use hyper::client::HttpConnector as HyperHttpConnector;
use hyper::rt::Future;
use hyper::{Body, Client};
use hyper_openssl::HttpsConnector;
-use openssl::ssl::{SslConnector, SslConnectorBuilder, SslMethod, SslOptions};
-use openssl::x509;
+use openssl::ex_data::Index;
+use openssl::ssl::{
+ SslConnector, SslConnectorBuilder, SslContext, SslMethod, SslOptions, SslVerifyMode,
+};
+use openssl::x509::{self, X509StoreContext};
+use std::sync::{Arc, Mutex};
use tokio::prelude::future::Executor;
pub const BUF_SIZE: usize = 32768;
@@ -60,7 +64,20 @@ impl Connect for HttpConnector {
pub type Connector = HttpsConnector<HttpConnector>;
pub type TlsConfig = SslConnectorBuilder;
-pub fn create_tls_config(certs: &str, alpn: &[u8]) -> TlsConfig {
+#[derive(Clone)]
+pub(crate) struct ExtraCerts(pub Arc<Mutex<Vec<Vec<u8>>>>);
+
+impl ExtraCerts {
+ pub(crate) fn new() -> Self {
+ Self(Arc::new(Mutex::new(vec![])))
+ }
+}
+
+lazy_static! {
+ static ref INDEX: Index<SslContext, ExtraCerts> = SslContext::new_ex_index().unwrap();
+}
+
+pub(crate) fn create_tls_config(certs: &str, alpn: &[u8], extra_certs: ExtraCerts) -> 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.
@@ -104,6 +121,32 @@ pub fn create_tls_config(certs: &str, alpn: &[u8]) -> TlsConfig {
SslOptions::NO_COMPRESSION,
);
+ cfg.set_ex_data(*INDEX, extra_certs);
+ cfg.set_verify_callback(SslVerifyMode::PEER, |verified, x509_store_context| {
+ if verified {
+ return true;
+ }
+ if let Some(cert) = x509_store_context.current_cert() {
+ match cert.to_pem() {
+ Ok(pem) => {
+ let ssl_idx = X509StoreContext::ssl_idx().unwrap();
+ let ssl = x509_store_context.ex_data(ssl_idx).unwrap();
+ let ssl_context = ssl.ssl_context();
+ let extra_certs = ssl_context.ex_data(*INDEX).unwrap();
+ for cert in &*extra_certs.0.lock().unwrap() {
+ if pem == *cert {
+ return true;
+ }
+ }
+ false
+ },
+ Err(_) => false,
+ }
+ } else {
+ false
+ }
+ });
+
cfg
}
diff --git a/components/net/resource_thread.rs b/components/net/resource_thread.rs
index 28a397e78e6..10a83fbc04c 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_tls_config, ALPN_H2_H1};
+use crate::connector::{create_http_client, create_tls_config, ExtraCerts, ALPN_H2_H1};
use crate::cookie;
use crate::cookie_storage::CookieStorage;
use crate::fetch::cors_cache::CorsCache;
@@ -127,7 +127,7 @@ struct ResourceChannelManager {
fn create_http_states(
config_dir: Option<&Path>,
certificate_path: Option<String>,
-) -> (Arc<HttpState>, Arc<HttpState>) {
+) -> (Arc<HttpState>, Arc<HttpState>, ExtraCerts) {
let mut hsts_list = HstsList::from_servo_preload();
let mut auth_cache = AuthCache::new();
let http_cache = HttpCache::new();
@@ -143,6 +143,8 @@ fn create_http_states(
None => resources::read_string(Resource::SSLCertificates),
};
+ let extra_certs = ExtraCerts::new();
+
let http_state = HttpState {
hsts_list: RwLock::new(hsts_list),
cookie_jar: RwLock::new(cookie_jar),
@@ -151,7 +153,7 @@ fn create_http_states(
http_cache: RwLock::new(http_cache),
http_cache_state: Mutex::new(HashMap::new()),
client: create_http_client(
- create_tls_config(&certs, ALPN_H2_H1),
+ create_tls_config(&certs, ALPN_H2_H1, extra_certs.clone()),
HANDLE.lock().unwrap().as_ref().unwrap().executor(),
),
};
@@ -164,12 +166,16 @@ fn create_http_states(
http_cache: RwLock::new(HttpCache::new()),
http_cache_state: Mutex::new(HashMap::new()),
client: create_http_client(
- create_tls_config(&certs, ALPN_H2_H1),
+ create_tls_config(&certs, ALPN_H2_H1, extra_certs.clone()),
HANDLE.lock().unwrap().as_ref().unwrap().executor(),
),
};
- (Arc::new(http_state), Arc::new(private_http_state))
+ (
+ Arc::new(http_state),
+ Arc::new(private_http_state),
+ extra_certs,
+ )
}
impl ResourceChannelManager {
@@ -180,7 +186,7 @@ impl ResourceChannelManager {
private_receiver: IpcReceiver<CoreResourceMsg>,
memory_reporter: IpcReceiver<ReportsChan>,
) {
- let (public_http_state, private_http_state) = create_http_states(
+ let (public_http_state, private_http_state, extra_certs) = create_http_states(
self.config_dir.as_ref().map(Deref::deref),
self.certificate_path.clone(),
);
diff --git a/components/net/websocket_loader.rs b/components/net/websocket_loader.rs
index 69d3c430fcb..fee98bbd8d0 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_tls_config, ALPN_H1};
+use crate::connector::{create_tls_config, ExtraCerts, ALPN_H1};
use crate::cookie::Cookie;
use crate::fetch::methods::should_be_blocked_due_to_bad_port;
use crate::hosts::replace_host;
@@ -167,7 +167,7 @@ impl<'a> Handler for Client<'a> {
WebSocketErrorKind::Protocol,
format!("Unable to parse domain from {}. Needed for SSL.", url),
))?;
- let tls_config = create_tls_config(&certs, ALPN_H1);
+ let tls_config = create_tls_config(&certs, ALPN_H1, ExtraCerts::new());
tls_config
.build()
.connect(domain, stream)