diff options
author | Josh Matthews <josh@joshmatthews.net> | 2020-05-27 19:24:06 -0400 |
---|---|---|
committer | Josh Matthews <josh@joshmatthews.net> | 2020-06-09 15:03:18 -0400 |
commit | 1cdaf40eb24c26bc2d372a791ffb9a6a08d7a304 (patch) | |
tree | da3773c90431128a60d219356d143e7b865cb3f1 | |
parent | b7a640b5172ebcdea73179c5a33486930ef35e96 (diff) | |
download | servo-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.rs | 49 | ||||
-rw-r--r-- | components/net/resource_thread.rs | 18 | ||||
-rw-r--r-- | components/net/websocket_loader.rs | 4 |
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) |