net: Add option to temporarily accept certs that failed the handshake.

This commit is contained in:
Josh Matthews 2020-05-29 13:35:43 -04:00
parent 433c154595
commit 6a6662195e
8 changed files with 73 additions and 13 deletions

1
Cargo.lock generated
View file

@ -3609,6 +3609,7 @@ dependencies = [
"pixels", "pixels",
"serde", "serde",
"servo_arc", "servo_arc",
"servo_rand",
"servo_url", "servo_url",
"std_test_override", "std_test_override",
"time", "time",

View file

@ -98,12 +98,16 @@ pub type Connector = HttpsConnector<HttpConnector>;
pub type TlsConfig = SslConnectorBuilder; pub type TlsConfig = SslConnectorBuilder;
#[derive(Clone)] #[derive(Clone)]
pub struct ExtraCerts(pub Arc<Mutex<Vec<Vec<u8>>>>); pub struct ExtraCerts(Arc<Mutex<Vec<Vec<u8>>>>);
impl ExtraCerts { impl ExtraCerts {
pub(crate) fn new() -> Self { pub(crate) fn new() -> Self {
Self(Arc::new(Mutex::new(vec![]))) Self(Arc::new(Mutex::new(vec![])))
} }
pub(crate) fn add(&self, bytes: Vec<u8>) {
self.0.lock().unwrap().push(bytes);
}
} }
struct Host(String); struct Host(String);

View file

@ -25,7 +25,7 @@ use net_traits::request::{
use net_traits::request::{CredentialsMode, Destination, Referrer, Request, RequestMode}; use net_traits::request::{CredentialsMode, Destination, Referrer, Request, RequestMode};
use net_traits::response::{Response, ResponseBody, ResponseType}; use net_traits::response::{Response, ResponseBody, ResponseType};
use net_traits::{FetchTaskTarget, NetworkError, ReferrerPolicy, ResourceFetchTiming}; use net_traits::{FetchTaskTarget, NetworkError, ReferrerPolicy, ResourceFetchTiming};
use net_traits::{ResourceAttribute, ResourceTimeValue}; use net_traits::{ResourceAttribute, ResourceTimeValue, ResourceTimingType};
use servo_arc::Arc as ServoArc; use servo_arc::Arc as ServoArc;
use servo_url::ServoUrl; use servo_url::ServoUrl;
use std::borrow::Cow; use std::borrow::Cow;
@ -282,7 +282,10 @@ pub fn main_fetch(
false false
}; };
if (same_origin && !cors_flag) || current_url.scheme() == "data" { if (same_origin && !cors_flag) ||
current_url.scheme() == "data" ||
current_url.scheme() == "chrome"
{
// Substep 1. // Substep 1.
request.response_tainting = ResponseTainting::Basic; request.response_tainting = ResponseTainting::Basic;
@ -606,6 +609,17 @@ fn range_not_satisfiable_error(response: &mut Response) {
response.raw_status = Some((StatusCode::RANGE_NOT_SATISFIABLE.as_u16(), reason.into())); response.raw_status = Some((StatusCode::RANGE_NOT_SATISFIABLE.as_u16(), reason.into()));
} }
fn create_blank_reply(url: ServoUrl, timing_type: ResourceTimingType) -> Response {
let mut response = Response::new(url, ResourceFetchTiming::new(timing_type));
response
.headers
.typed_insert(ContentType::from(mime::TEXT_HTML_UTF_8));
*response.body.lock().unwrap() = ResponseBody::Done(vec![]);
response.status = Some((StatusCode::OK, "OK".to_string()));
response.raw_status = Some((StatusCode::OK.as_u16(), b"OK".to_vec()));
response
}
/// [Scheme fetch](https://fetch.spec.whatwg.org#scheme-fetch) /// [Scheme fetch](https://fetch.spec.whatwg.org#scheme-fetch)
fn scheme_fetch( fn scheme_fetch(
request: &mut Request, request: &mut Request,
@ -617,15 +631,25 @@ fn scheme_fetch(
let url = request.current_url(); let url = request.current_url();
match url.scheme() { match url.scheme() {
"about" if url.path() == "blank" => { "about" if url.path() == "blank" => create_blank_reply(url, request.timing_type()),
let mut response = Response::new(url, ResourceFetchTiming::new(request.timing_type()));
response "chrome" if url.path() == "allowcert" => {
.headers let mut secret = None;
.typed_insert(ContentType::from(mime::TEXT_HTML_UTF_8)); let mut cert_bytes = None;
*response.body.lock().unwrap() = ResponseBody::Done(vec![]); for (name, value) in url.as_url().query_pairs() {
response.status = Some((StatusCode::OK, "OK".to_string())); match &*name {
response.raw_status = Some((StatusCode::OK.as_u16(), b"OK".to_vec())); "secret" => secret = Some(value),
response "bytes" => cert_bytes = base64::decode(value.as_bytes()).ok(),
_ => (),
}
}
if let (Some(secret), Some(bytes)) = (secret, cert_bytes) {
if secret.parse() == Ok(*net_traits::PRIVILEGED_SECRET) {
context.state.extra_certs.add(bytes);
}
}
create_blank_reply(url, request.timing_type())
}, },
"http" | "https" => http_fetch( "http" | "https" => http_fetch(

View file

@ -33,6 +33,7 @@ piston_image = { package = "image", version = "0.23" }
pixels = { path = "../pixels" } pixels = { path = "../pixels" }
serde = "1.0" serde = "1.0"
servo_arc = { path = "../servo_arc" } servo_arc = { path = "../servo_arc" }
servo_rand = { path = "../rand" }
servo_url = { path = "../url" } servo_url = { path = "../url" }
time = "0.1" time = "0.1"
url = "2.0" url = "2.0"

View file

@ -30,6 +30,7 @@ use ipc_channel::router::ROUTER;
use ipc_channel::Error as IpcError; use ipc_channel::Error as IpcError;
use mime::Mime; use mime::Mime;
use msg::constellation_msg::HistoryStateId; use msg::constellation_msg::HistoryStateId;
use servo_rand::RngCore;
use servo_url::{ImmutableOrigin, ServoUrl}; use servo_url::{ImmutableOrigin, ServoUrl};
use time::precise_time_ns; use time::precise_time_ns;
use webrender_api::{ImageData, ImageDescriptor, ImageKey}; use webrender_api::{ImageData, ImageDescriptor, ImageKey};
@ -811,3 +812,7 @@ impl WebrenderIpcSender {
} }
} }
} }
lazy_static! {
pub static ref PRIVILEGED_SECRET: u32 = servo_rand::ServoRng::new().next_u32();
}

View file

@ -821,6 +821,8 @@ impl FetchResponseListener for ParserContext {
let page = page.replace("${reason}", &reason); let page = page.replace("${reason}", &reason);
let page = let page =
page.replace("${bytes}", std::str::from_utf8(&bytes).unwrap_or_default()); page.replace("${bytes}", std::str::from_utf8(&bytes).unwrap_or_default());
let page =
page.replace("${secret}", &net_traits::PRIVILEGED_SECRET.to_string());
parser.push_string_input_chunk(page); parser.push_string_input_chunk(page);
parser.parse_sync(); parser.parse_sync();
} }

View file

@ -4,6 +4,25 @@
</head> </head>
<body> <body>
<p>${reason}</p> <p>${reason}</p>
<pre>${bytes}</pre> <pre id="bytes">${bytes}</pre>
<button id="leave" onclick="history.back()">Go back (recommended)</button>
<button id="allow">Allow certificate temporarily</button>
<script>
let bytes = document.getElementById('bytes').textContent;
let button = document.getElementById('allow');
let exitButton = document.getElementById('leave');
if (bytes.length) {
button.onclick = function() {
let xhr = new XMLHttpRequest();
xhr.open('GET', 'chrome:allowcert?secret=${secret}&bytes=' + btoa(bytes));
xhr.onloadend = function() {
location.reload(true);
};
xhr.send();
};
} else {
button.style.display = "none";
}
</script>
</body> </body>
</html> </html>

View file

@ -1,3 +1,7 @@
button {
cursor: default;
}
button, button,
input { input {
background: white; background: white;