Auto merge of #26716 - jdm:selfsigned, r=Manishearth,asajeffrey

Add UI for bypassing SSL handshake failures

There are several parts to these changes:
1. resurrecting the network error classification code to distinguish between SSL failures and other network errors
1. adding an SSL verification callback to support verifying certs against a list that can change at runtime, rather than just at program initialization
1. exposing a privileged chrome://allowcert URI which accepts the PEM cert contents along with a secret token
1. extracting the PEM cert contents out of the network layer when a handshake failure occurs, and getting them into the HTML that is parsed when an SSL failure occurs
1. adding a button in the handshake failure page that performs an XHR to chrome://allowcert with knowledge of the secret token and the PEM cert contents, before reloading the original URL that failed

The presence of the secret token means that while the chrome://allowcert URL is currently visible to web content, they cannot make use of it to inject arbitrary certs into the verification process.

---
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #26683
- [x] These changes do not require tests because the UI requires user activation and can't clearly be automated
This commit is contained in:
bors-servo 2020-06-09 21:59:09 -04:00 committed by GitHub
commit 0b0ea17dca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 362 additions and 41 deletions

View file

@ -731,9 +731,9 @@ impl FetchResponseListener for ParserContext {
FetchMetadata::Unfiltered(m) => m,
FetchMetadata::Filtered { unsafe_, .. } => unsafe_,
}),
Err(NetworkError::SslValidation(url, reason)) => {
ssl_error = Some(reason);
let mut meta = Metadata::default(url);
Err(NetworkError::SslValidation(reason, cert_bytes)) => {
ssl_error = Some((reason, cert_bytes));
let mut meta = Metadata::default(self.url.clone());
let mime: Option<Mime> = "text/html".parse().ok();
meta.set_content_type(mime.as_ref());
Some(meta)
@ -815,10 +815,14 @@ impl FetchResponseListener for ParserContext {
},
Some(ref mime) if mime.type_() == mime::TEXT && mime.subtype() == mime::HTML => {
// Handle text/html
if let Some(reason) = ssl_error {
if let Some((reason, bytes)) = ssl_error {
self.is_synthesized_document = true;
let page = resources::read_string(Resource::BadCertHTML);
let page = page.replace("${reason}", &reason);
let page =
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.parse_sync();
}