aboutsummaryrefslogtreecommitdiffstats
path: root/components/net/fetch/methods.rs
diff options
context:
space:
mode:
authorMartin Robinson <mrobinson@igalia.com>2023-08-08 16:00:10 +0200
committerGitHub <noreply@github.com>2023-08-08 14:00:10 +0000
commitbce7622cde4cd10f6b3edf852d97ae9a540a0076 (patch)
treee8c09178e875b63e64b32a290840c6ff80d2c4e0 /components/net/fetch/methods.rs
parentab0f48f8e8a72542269c9e563fad4fa03273d2f3 (diff)
downloadservo-bce7622cde4cd10f6b3edf852d97ae9a540a0076.tar.gz
servo-bce7622cde4cd10f6b3edf852d97ae9a540a0076.zip
Switch to rustls and webpki-roots (#30025)
This change replaces OpenSSL with rustls and also the manually curated CA certs file with webpki-roots (effectively the same thing, but as a crate). Generally speaking the design of the network stack is the same. Changes: - Code around certificate overrides needed to be refactored to work with rustls so the various thread-safe list of certificates is refactored into `CertificateErrorOverrideManager` - hyper-rustls takes care of setting ALPN protocols for HTTP requests, so for WebSockets this is moved to the WebSocket code. - The safe set of cypher suites is chosen, which seem to correspond to the "Modern" configuration from [1]. This can be adjusted later. - Instead of passing a string of PEM CA certificates around, an enum is used that includes parsed Certificates (or the default which reads them from webpki-roots). - Code for starting up an SSL server for testing is cleaned up a little, due to the fact that the certificates need to be overriden explicitly now. This is due to the fact that the `webpki` crate is more stringent with self-signed certificates than SSL (CA certificates cannot used as end-entity certificates). [2] 1. https://wiki.mozilla.org/Security/Server_Side_TLS 2. https://github.com/briansmith/webpki/issues/114 Fixes #7888. Fixes #13749. Fixes #26835. Fixes #29291.
Diffstat (limited to 'components/net/fetch/methods.rs')
-rw-r--r--components/net/fetch/methods.rs74
1 files changed, 47 insertions, 27 deletions
diff --git a/components/net/fetch/methods.rs b/components/net/fetch/methods.rs
index fb40d40ac19..f11a203b3bc 100644
--- a/components/net/fetch/methods.rs
+++ b/components/net/fetch/methods.rs
@@ -9,7 +9,7 @@ use crate::filemanager_thread::{FileManager, FILE_CHUNK_SIZE};
use crate::http_loader::{determine_requests_referrer, http_fetch, HttpState};
use crate::http_loader::{set_default_accept, set_default_accept_language};
use crate::subresource_integrity::is_response_integrity_valid;
-use base64::Engine;
+use base64::{engine::general_purpose, Engine as _};
use content_security_policy as csp;
use crossbeam_channel::Sender;
use devtools_traits::DevtoolsControlMsg;
@@ -31,11 +31,12 @@ use net_traits::request::{
use net_traits::response::{Response, ResponseBody, ResponseType};
use net_traits::{FetchTaskTarget, NetworkError, ReferrerPolicy, ResourceFetchTiming};
use net_traits::{ResourceAttribute, ResourceTimeValue, ResourceTimingType};
+use rustls::Certificate;
use servo_arc::Arc as ServoArc;
use servo_url::ServoUrl;
use std::borrow::Cow;
use std::fs::File;
-use std::io::{BufReader, Seek, SeekFrom};
+use std::io::{self, BufReader, Seek, SeekFrom};
use std::mem;
use std::ops::Bound;
use std::str;
@@ -627,6 +628,48 @@ fn create_blank_reply(url: ServoUrl, timing_type: ResourceTimingType) -> Respons
response
}
+/// Handle a request from the user interface to ignore validation errors for a certificate.
+fn handle_allowcert_request(request: &mut Request, context: &FetchContext) -> io::Result<()> {
+ let error = |string| Err(io::Error::new(io::ErrorKind::Other, string));
+
+ let body = match request.body.as_mut() {
+ Some(body) => body,
+ None => return error("No body found"),
+ };
+
+ let stream = body.take_stream();
+ let stream = stream.lock().unwrap();
+ let (body_chan, body_port) = ipc::channel().unwrap();
+ let _ = stream.send(BodyChunkRequest::Connect(body_chan));
+ let _ = stream.send(BodyChunkRequest::Chunk);
+ let body_bytes = match body_port.recv().ok() {
+ Some(BodyChunkResponse::Chunk(bytes)) => bytes,
+ _ => return error("Certificate not sent in a single chunk"),
+ };
+
+ let split_idx = match body_bytes.iter().position(|b| *b == b'&') {
+ Some(split_idx) => split_idx,
+ None => return error("Could not find ampersand in data"),
+ };
+ let (secret, cert_base64) = body_bytes.split_at(split_idx);
+
+ let secret = str::from_utf8(secret).ok().and_then(|s| s.parse().ok());
+ if secret != Some(*net_traits::PRIVILEGED_SECRET) {
+ return error("Invalid secret sent. Ignoring request");
+ }
+
+ let cert_bytes = match general_purpose::STANDARD_NO_PAD.decode(&cert_base64[1..]) {
+ Ok(bytes) => bytes,
+ Err(_) => return error("Could not decode certificate base64"),
+ };
+
+ context
+ .state
+ .override_manager
+ .add_override(&Certificate(cert_bytes));
+ Ok(())
+}
+
/// [Scheme fetch](https://fetch.spec.whatwg.org#scheme-fetch)
async fn scheme_fetch(
request: &mut Request,
@@ -641,32 +684,9 @@ async fn scheme_fetch(
"about" if url.path() == "blank" => create_blank_reply(url, request.timing_type()),
"chrome" if url.path() == "allowcert" => {
- let data = request.body.as_mut().and_then(|body| {
- let stream = body.take_stream();
- let stream = stream.lock().unwrap();
- let (body_chan, body_port) = ipc::channel().unwrap();
- let _ = stream.send(BodyChunkRequest::Connect(body_chan));
- let _ = stream.send(BodyChunkRequest::Chunk);
- match body_port.recv().ok() {
- Some(BodyChunkResponse::Chunk(bytes)) => Some(bytes),
- _ => panic!("cert should be sent in a single chunk."),
- }
- });
- let data = data.as_ref().and_then(|b| {
- let idx = b.iter().position(|b| *b == b'&')?;
- Some(b.split_at(idx))
- });
-
- if let Some((secret, bytes)) = data {
- let secret = str::from_utf8(secret).ok().and_then(|s| s.parse().ok());
- if secret == Some(*net_traits::PRIVILEGED_SECRET) {
- if let Ok(bytes) = base64::engine::general_purpose::STANDARD.decode(&bytes[1..])
- {
- context.state.extra_certs.add(bytes);
- }
- }
+ if let Err(error) = handle_allowcert_request(request, context) {
+ warn!("Could not handle allowcert request: {error}");
}
-
create_blank_reply(url, request.timing_type())
},