mirror of
https://github.com/servo/servo.git
synced 2025-06-06 00:25:37 +00:00
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.
This commit is contained in:
parent
ab0f48f8e8
commit
bce7622cde
31 changed files with 575 additions and 4399 deletions
199
Cargo.lock
generated
199
Cargo.lock
generated
|
@ -226,11 +226,11 @@ dependencies = [
|
|||
"futures-io",
|
||||
"futures-util",
|
||||
"log",
|
||||
"openssl",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tokio-openssl",
|
||||
"tokio-rustls",
|
||||
"tungstenite",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1639,7 +1639,7 @@ dependencies = [
|
|||
"futures-sink",
|
||||
"nanorand",
|
||||
"pin-project",
|
||||
"spin",
|
||||
"spin 0.9.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2715,21 +2715,19 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-openssl"
|
||||
version = "0.9.2"
|
||||
name = "hyper-rustls"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6ee5d7a8f718585d1c3c61dfde28ef5b0bb14734b4db13f5ada856cdc6c612b"
|
||||
checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"http",
|
||||
"hyper",
|
||||
"linked_hash_set",
|
||||
"once_cell",
|
||||
"openssl",
|
||||
"openssl-sys",
|
||||
"parking_lot 0.12.0",
|
||||
"log",
|
||||
"rustls",
|
||||
"tokio",
|
||||
"tokio-openssl",
|
||||
"tower-layer",
|
||||
"tokio-rustls",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3342,21 +3340,6 @@ dependencies = [
|
|||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
|
||||
|
||||
[[package]]
|
||||
name = "linked_hash_set"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47186c6da4d81ca383c7c47c1bfc80f4b95f4720514d860a5407aaf4233f9588"
|
||||
dependencies = [
|
||||
"linked-hash-map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.3.8"
|
||||
|
@ -3849,7 +3832,7 @@ dependencies = [
|
|||
"headers",
|
||||
"http",
|
||||
"hyper",
|
||||
"hyper-openssl",
|
||||
"hyper-rustls",
|
||||
"hyper_serde",
|
||||
"immeta",
|
||||
"ipc-channel",
|
||||
|
@ -3862,12 +3845,12 @@ dependencies = [
|
|||
"mime_guess",
|
||||
"msg",
|
||||
"net_traits",
|
||||
"openssl",
|
||||
"openssl-sys",
|
||||
"percent-encoding",
|
||||
"pixels",
|
||||
"profile_traits",
|
||||
"rayon",
|
||||
"rustls",
|
||||
"rustls-pemfile",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"servo_allocator",
|
||||
|
@ -3878,12 +3861,13 @@ dependencies = [
|
|||
"std_test_override",
|
||||
"time 0.1.45",
|
||||
"tokio",
|
||||
"tokio-openssl",
|
||||
"tokio-rustls",
|
||||
"tokio-stream",
|
||||
"tokio-test",
|
||||
"tungstenite",
|
||||
"url",
|
||||
"uuid 1.3.4",
|
||||
"webpki-roots",
|
||||
"webrender_api",
|
||||
]
|
||||
|
||||
|
@ -3920,6 +3904,7 @@ dependencies = [
|
|||
"num-traits",
|
||||
"percent-encoding",
|
||||
"pixels",
|
||||
"rustls",
|
||||
"serde",
|
||||
"servo_arc",
|
||||
"servo_rand",
|
||||
|
@ -4202,44 +4187,6 @@ version = "0.2.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e30d8bc91859781f0a943411186324d580f2bbeb71b452fe91ae344806af3f1"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if 1.0.0",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"openssl-macros",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-macros"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d3d193fb1488ad46ffe3aaabc912cc931d02ee8518fe2959aea8ef52718b0c0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "orbclient"
|
||||
version = "0.3.42"
|
||||
|
@ -4881,6 +4828,21 @@ version = "0.6.28"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.16.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"spin 0.5.2",
|
||||
"untrusted",
|
||||
"web-sys",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rle-decode-fast"
|
||||
version = "1.0.3"
|
||||
|
@ -4945,14 +4907,46 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "1.0.2"
|
||||
name = "rustls"
|
||||
version = "0.21.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b"
|
||||
checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb"
|
||||
dependencies = [
|
||||
"log",
|
||||
"ring",
|
||||
"rustls-webpki 0.101.2",
|
||||
"sct",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2"
|
||||
dependencies = [
|
||||
"base64 0.21.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.100.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.101.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "513722fd73ad80a71f72b61009ea1b584bcfa1483ca93949c8f290298837fa59"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.14"
|
||||
|
@ -5180,6 +5174,16 @@ dependencies = [
|
|||
"webxr-api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sct"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sctk-adwaita"
|
||||
version = "0.5.3"
|
||||
|
@ -5821,6 +5825,12 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b72d540d5c565dbe1f891d7e21ceb21d2649508306782f1066989fccb0b363d3"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.8"
|
||||
|
@ -6355,14 +6365,12 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-openssl"
|
||||
version = "0.6.3"
|
||||
name = "tokio-rustls"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08f9ffb7809f1b20c1b398d92acf4cc719874b3b2b2d9ea2f09b4a80350878a"
|
||||
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"openssl",
|
||||
"openssl-sys",
|
||||
"rustls",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
|
@ -6413,12 +6421,6 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-layer"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62"
|
||||
|
||||
[[package]]
|
||||
name = "tower-service"
|
||||
version = "0.3.1"
|
||||
|
@ -6486,10 +6488,12 @@ dependencies = [
|
|||
"httparse",
|
||||
"log",
|
||||
"rand 0.8.5",
|
||||
"rustls",
|
||||
"sha1",
|
||||
"thiserror",
|
||||
"url",
|
||||
"utf-8",
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -6589,6 +6593,12 @@ version = "0.2.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||
|
||||
[[package]]
|
||||
name = "unwind-sys"
|
||||
version = "0.1.3"
|
||||
|
@ -6957,6 +6967,25 @@ dependencies = [
|
|||
"wgpu-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.23.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338"
|
||||
dependencies = [
|
||||
"rustls-webpki 0.100.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webrender"
|
||||
version = "0.61.0"
|
||||
|
|
|
@ -12,6 +12,7 @@ exclude = [".cargo"]
|
|||
[workspace.dependencies]
|
||||
accountable-refcell = "0.2.0"
|
||||
app_units = "0.7"
|
||||
async-tungstenite = { version = "0.22", features = ["tokio-rustls-webpki-roots"] }
|
||||
atomic_refcell = "0.1.6"
|
||||
arrayvec = "0.7"
|
||||
backtrace = "0.3"
|
||||
|
@ -35,6 +36,7 @@ headers = "0.3"
|
|||
html5ever = "0.26"
|
||||
http = "0.2"
|
||||
hyper = "0.14"
|
||||
hyper-rustls = { version = "0.24", default-features = false, features = ["webpki-tokio", "http1", "http2", "tls12", "logging", "acceptor"] }
|
||||
hyper_serde = "0.13"
|
||||
image = "0.24"
|
||||
indexmap = { version = "1.0.2", features = ["std"] }
|
||||
|
@ -57,6 +59,8 @@ quote = "1"
|
|||
rand = "0.7"
|
||||
rayon = "1"
|
||||
regex = "1.1"
|
||||
rustls = { version = "0.21.5", features = ["dangerous_configuration"] }
|
||||
rustls-pemfile = "1.0.3"
|
||||
serde = "1.0.60"
|
||||
serde_bytes = "0.11"
|
||||
serde_json = "1.0"
|
||||
|
@ -73,11 +77,15 @@ surfman-chains-api = "0.2"
|
|||
thin-slice = "0.1.0"
|
||||
time = "0.1.41"
|
||||
tokio = "1"
|
||||
tokio-rustls = "0.24"
|
||||
tungstenite = "0.19"
|
||||
unicode-bidi = "0.3.4"
|
||||
unicode-script = "0.5"
|
||||
url = "2.0"
|
||||
uuid = { version = "1.3.4", features = ["v4"] }
|
||||
webdriver = "0.48.0"
|
||||
webpki-roots = "0.23"
|
||||
webpki = "0.22"
|
||||
webrender = { git = "https://github.com/servo/webrender", features = ["capture"] }
|
||||
webrender_api = { git = "https://github.com/servo/webrender" }
|
||||
winapi = "0.3"
|
||||
|
|
|
@ -113,9 +113,14 @@ pub struct Opts {
|
|||
/// Print the version and exit.
|
||||
pub is_printing_version: bool,
|
||||
|
||||
/// Path to SSL certificates.
|
||||
/// Path to PEM encoded SSL CA certificate store.
|
||||
pub certificate_path: Option<String>,
|
||||
|
||||
/// Whether or not to completely ignore SSL certificate validation errors.
|
||||
/// TODO: We should see if we can eliminate the need for this by fixing
|
||||
/// https://github.com/servo/servo/issues/30080.
|
||||
pub ignore_certificate_errors: bool,
|
||||
|
||||
/// Unminify Javascript.
|
||||
pub unminify_js: bool,
|
||||
|
||||
|
@ -408,6 +413,7 @@ pub fn default_opts() -> Opts {
|
|||
is_printing_version: false,
|
||||
shaders_dir: None,
|
||||
certificate_path: None,
|
||||
ignore_certificate_errors: false,
|
||||
unminify_js: false,
|
||||
local_script_source: None,
|
||||
print_pwm: false,
|
||||
|
@ -524,6 +530,11 @@ pub fn from_cmdline_args(mut opts: Options, args: &[String]) -> ArgumentParsingR
|
|||
"Path to find SSL certificates",
|
||||
"/home/servo/resources/certs",
|
||||
);
|
||||
opts.optflag(
|
||||
"",
|
||||
"ignore-certificate-errors",
|
||||
"Whether or not to completely ignore certificate errors",
|
||||
);
|
||||
opts.optopt(
|
||||
"",
|
||||
"content-process",
|
||||
|
@ -767,6 +778,7 @@ pub fn from_cmdline_args(mut opts: Options, args: &[String]) -> ArgumentParsingR
|
|||
is_printing_version,
|
||||
shaders_dir: opt_match.opt_str("shaders").map(Into::into),
|
||||
certificate_path: opt_match.opt_str("certificate-path"),
|
||||
ignore_certificate_errors: opt_match.opt_present("ignore-certificate-errors"),
|
||||
unminify_js: opt_match.opt_present("unminify-js"),
|
||||
local_script_source: opt_match.opt_str("local-script-source"),
|
||||
print_pwm: opt_match.opt_present("print-pwm"),
|
||||
|
|
|
@ -6,7 +6,6 @@ license = "MPL-2.0"
|
|||
edition = "2018"
|
||||
publish = false
|
||||
autotests = false # Inhibit lookup for tests/*.rs without [[test]] sections
|
||||
build = "build.rs"
|
||||
|
||||
[lib]
|
||||
name = "net"
|
||||
|
@ -16,7 +15,7 @@ doctest = false
|
|||
|
||||
[dependencies]
|
||||
async-recursion = "0.3.2"
|
||||
async-tungstenite = { version = "0.22", features = ["tokio-openssl"] }
|
||||
async-tungstenite = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
brotli = "3"
|
||||
bytes = "1"
|
||||
|
@ -33,7 +32,7 @@ generic-array = "0.14"
|
|||
headers = { workspace = true }
|
||||
http = { workspace = true }
|
||||
hyper = { workspace = true, features = ["client", "http1", "http2", "tcp", "stream"] }
|
||||
hyper-openssl = "0.9.1"
|
||||
hyper-rustls = { workspace = true }
|
||||
hyper_serde = { workspace = true }
|
||||
immeta = "0.4"
|
||||
ipc-channel = { workspace = true }
|
||||
|
@ -46,12 +45,12 @@ mime = { workspace = true }
|
|||
mime_guess = { workspace = true }
|
||||
msg = { path = "../msg" }
|
||||
net_traits = { path = "../net_traits" }
|
||||
openssl = "0.10"
|
||||
openssl-sys = "0.9"
|
||||
percent-encoding = { workspace = true }
|
||||
pixels = { path = "../pixels" }
|
||||
profile_traits = { path = "../profile_traits" }
|
||||
rayon = { workspace = true }
|
||||
rustls = { workspace = true }
|
||||
rustls-pemfile = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
servo_allocator = { path = "../allocator" }
|
||||
|
@ -61,16 +60,17 @@ servo_url = { path = "../url" }
|
|||
sha2 = "0.10"
|
||||
time = { workspace = true }
|
||||
tokio = { workspace = true, features = ["sync", "macros", "rt-multi-thread"] }
|
||||
tokio-rustls = { workspace = true }
|
||||
tokio-stream = "0.1"
|
||||
tungstenite = "0.19"
|
||||
tungstenite = { workspace = true }
|
||||
url = { workspace = true }
|
||||
uuid = { workspace = true }
|
||||
webrender_api = { workspace = true }
|
||||
webpki-roots = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
futures = {version = "0.3", features = ["compat"]}
|
||||
std_test_override = { path = "../std_test_override" }
|
||||
tokio-openssl = "0.6"
|
||||
tokio-test = "0.4"
|
||||
tokio-stream = { version = "0.1", features = ["net"] }
|
||||
hyper = { workspace = true, features = ["full"] }
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
fn main() {
|
||||
let version =
|
||||
std::env::var("DEP_OPENSSL_VERSION_NUMBER").expect("missing DEP_OPENSSL_VERSION_NUMBER");
|
||||
let actual = u64::from_str_radix(&version, 16).unwrap();
|
||||
let minimum = 0x10101000;
|
||||
if actual < minimum {
|
||||
panic!(
|
||||
"Your OpenSSL version is older than 1.1.1 ({:x}), you have: {:x}",
|
||||
minimum, actual
|
||||
);
|
||||
}
|
||||
}
|
|
@ -9,80 +9,30 @@ use http::uri::{Authority, Uri as Destination};
|
|||
use hyper::client::HttpConnector as HyperHttpConnector;
|
||||
use hyper::rt::Executor;
|
||||
use hyper::{service::Service, Body, Client};
|
||||
use hyper_openssl::HttpsConnector;
|
||||
use openssl::ex_data::Index;
|
||||
use openssl::ssl::{
|
||||
Ssl, SslConnector, SslConnectorBuilder, SslContext, SslMethod, SslOptions, SslVerifyMode,
|
||||
};
|
||||
use openssl::x509::{self, X509StoreContext};
|
||||
use std::collections::hash_map::{Entry, HashMap};
|
||||
use hyper_rustls::HttpsConnector as HyperRustlsHttpsConnector;
|
||||
use rustls::client::WebPkiVerifier;
|
||||
use rustls::{Certificate, ClientConfig, OwnedTrustAnchor, RootCertStore, ServerName};
|
||||
use std::collections::hash_map::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
pub const BUF_SIZE: usize = 32768;
|
||||
pub const ALPN_H2_H1: &'static [u8] = b"\x02h2\x08http/1.1";
|
||||
pub const ALPN_H1: &'static [u8] = b"\x08http/1.1";
|
||||
|
||||
// See https://wiki.mozilla.org/Security/Server_Side_TLS for orientation.
|
||||
const TLS1_2_CIPHERSUITES: &'static str = concat!(
|
||||
"ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:",
|
||||
"ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:",
|
||||
"ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:",
|
||||
"ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA@SECLEVEL=2"
|
||||
);
|
||||
const SIGNATURE_ALGORITHMS: &'static str = concat!(
|
||||
"ed448:ed25519:",
|
||||
"ECDSA+SHA384:ECDSA+SHA256:",
|
||||
"RSA-PSS+SHA512:RSA-PSS+SHA384:RSA-PSS+SHA256:",
|
||||
"RSA+SHA512:RSA+SHA384:RSA+SHA256"
|
||||
);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ConnectionCerts {
|
||||
certs: Arc<Mutex<HashMap<String, (Vec<u8>, u32)>>>,
|
||||
}
|
||||
|
||||
impl ConnectionCerts {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
certs: Arc::new(Mutex::new(HashMap::new())),
|
||||
}
|
||||
}
|
||||
|
||||
fn store(&self, host: String, cert_bytes: Vec<u8>) {
|
||||
let mut certs = self.certs.lock().unwrap();
|
||||
let entry = certs.entry(host).or_insert((cert_bytes, 0));
|
||||
entry.1 += 1;
|
||||
}
|
||||
|
||||
pub(crate) fn remove(&self, host: String) -> Option<Vec<u8>> {
|
||||
match self.certs.lock().unwrap().entry(host) {
|
||||
Entry::Vacant(_) => return None,
|
||||
Entry::Occupied(mut e) => {
|
||||
e.get_mut().1 -= 1;
|
||||
if e.get().1 == 0 {
|
||||
return Some((e.remove_entry().1).0);
|
||||
}
|
||||
Some(e.get().0.clone())
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct HttpConnector {
|
||||
pub struct ServoHttpConnector {
|
||||
inner: HyperHttpConnector,
|
||||
}
|
||||
|
||||
impl HttpConnector {
|
||||
fn new() -> HttpConnector {
|
||||
impl ServoHttpConnector {
|
||||
fn new() -> ServoHttpConnector {
|
||||
let mut inner = HyperHttpConnector::new();
|
||||
inner.enforce_http(false);
|
||||
inner.set_happy_eyeballs_timeout(None);
|
||||
HttpConnector { inner }
|
||||
ServoHttpConnector { inner }
|
||||
}
|
||||
}
|
||||
|
||||
impl Service<Destination> for HttpConnector {
|
||||
impl Service<Destination> for ServoHttpConnector {
|
||||
type Response = <HyperHttpConnector as Service<Destination>>::Response;
|
||||
type Error = <HyperHttpConnector as Service<Destination>>::Error;
|
||||
type Future = <HyperHttpConnector as Service<Destination>>::Future;
|
||||
|
@ -118,119 +68,85 @@ impl Service<Destination> for HttpConnector {
|
|||
}
|
||||
}
|
||||
|
||||
pub type Connector = HttpsConnector<HttpConnector>;
|
||||
pub type TlsConfig = SslConnectorBuilder;
|
||||
pub type Connector = HyperRustlsHttpsConnector<ServoHttpConnector>;
|
||||
pub type TlsConfig = ClientConfig;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ExtraCerts(Arc<Mutex<Vec<Vec<u8>>>>);
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct CertificateErrorOverrideManagerInternal {
|
||||
/// A mapping of certificates and their hosts, which have seen certificate errors.
|
||||
/// This is used to later create an override in this [CertificateErrorOverrideManager].
|
||||
certificates_failing_to_verify: HashMap<ServerName, Certificate>,
|
||||
/// A list of certificates that should be accepted despite encountering verification
|
||||
/// errors.
|
||||
overrides: Vec<Certificate>,
|
||||
}
|
||||
|
||||
impl ExtraCerts {
|
||||
/// This data structure is used to track certificate verification errors and overrides.
|
||||
/// It tracks:
|
||||
/// - A list of [Certificate]s with verification errors mapped by their [ServerName]
|
||||
/// - A list of [Certificate]s for which to ignore verification errors.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct CertificateErrorOverrideManager(Arc<Mutex<CertificateErrorOverrideManagerInternal>>);
|
||||
|
||||
impl CertificateErrorOverrideManager {
|
||||
pub fn new() -> Self {
|
||||
Self(Arc::new(Mutex::new(vec![])))
|
||||
Self(Default::default())
|
||||
}
|
||||
|
||||
pub fn add(&self, bytes: Vec<u8>) {
|
||||
self.0.lock().unwrap().push(bytes);
|
||||
/// Add a certificate to this manager's list of certificates for which to ignore
|
||||
/// validation errors.
|
||||
pub fn add_override(&self, certificate: &Certificate) {
|
||||
self.0.lock().unwrap().overrides.push(certificate.clone());
|
||||
}
|
||||
|
||||
/// Given the a string representation of a sever host name, remove information about
|
||||
/// a [Certificate] with verification errors. If a certificate with
|
||||
/// verification errors was found, return it, otherwise None.
|
||||
pub(crate) fn remove_certificate_failing_verification(
|
||||
&self,
|
||||
host: &str,
|
||||
) -> Option<Certificate> {
|
||||
let server_name = match ServerName::try_from(host) {
|
||||
Ok(name) => name,
|
||||
Err(error) => {
|
||||
warn!("Could not convert host string into RustTLS ServerName: {error:?}");
|
||||
return None;
|
||||
},
|
||||
};
|
||||
self.0
|
||||
.lock()
|
||||
.unwrap()
|
||||
.certificates_failing_to_verify
|
||||
.remove(&server_name)
|
||||
}
|
||||
}
|
||||
|
||||
struct Host(String);
|
||||
|
||||
lazy_static! {
|
||||
static ref EXTRA_INDEX: Index<SslContext, ExtraCerts> = SslContext::new_ex_index().unwrap();
|
||||
static ref CONNECTION_INDEX: Index<SslContext, ConnectionCerts> =
|
||||
SslContext::new_ex_index().unwrap();
|
||||
static ref HOST_INDEX: Index<Ssl, Host> = Ssl::new_ex_index().unwrap();
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum CACertificates {
|
||||
Default,
|
||||
Override(RootCertStore),
|
||||
}
|
||||
|
||||
/// Create a [TlsConfig] to use for managing a HTTP connection. This currently creates
|
||||
/// a rustls [ClientConfig].
|
||||
///
|
||||
/// FIXME: The `ignore_certificate_errors` argument ignores all certificate errors. This
|
||||
/// is used when running the WPT tests, because rustls currently rejects the WPT certificiate.
|
||||
/// See https://github.com/servo/servo/issues/30080
|
||||
pub fn create_tls_config(
|
||||
certs: &str,
|
||||
alpn: &[u8],
|
||||
extra_certs: ExtraCerts,
|
||||
connection_certs: ConnectionCerts,
|
||||
ca_certificates: CACertificates,
|
||||
ignore_certificate_errors: bool,
|
||||
override_manager: CertificateErrorOverrideManager,
|
||||
) -> 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.
|
||||
let mut certs = certs;
|
||||
let mut cfg = SslConnector::builder(SslMethod::tls()).unwrap();
|
||||
loop {
|
||||
let token = "-----END CERTIFICATE-----";
|
||||
if let Some(index) = certs.find(token) {
|
||||
let (cert, rest) = certs.split_at(index + token.len());
|
||||
certs = rest;
|
||||
let cert = x509::X509::from_pem(cert.as_bytes()).unwrap();
|
||||
cfg.cert_store_mut()
|
||||
.add_cert(cert)
|
||||
.or_else(|e| {
|
||||
let v: Option<Option<&str>> = e.errors().iter().nth(0).map(|e| e.reason());
|
||||
if v == Some(Some("cert already in hash table")) {
|
||||
warn!("Cert already in hash table. Ignoring.");
|
||||
// Ignore error X509_R_CERT_ALREADY_IN_HASH_TABLE which means the
|
||||
// certificate is already in the store.
|
||||
Ok(())
|
||||
} else {
|
||||
Err(e)
|
||||
}
|
||||
})
|
||||
.expect("could not set CA file");
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
cfg.set_alpn_protos(alpn)
|
||||
.expect("could not set alpn protocols");
|
||||
cfg.set_cipher_list(TLS1_2_CIPHERSUITES)
|
||||
.expect("could not set TLS 1.2 ciphersuites");
|
||||
cfg.set_sigalgs_list(SIGNATURE_ALGORITHMS)
|
||||
.expect("could not set signature algorithms");
|
||||
cfg.set_options(
|
||||
SslOptions::NO_SSLV2 |
|
||||
SslOptions::NO_SSLV3 |
|
||||
SslOptions::NO_TLSV1 |
|
||||
SslOptions::NO_TLSV1_1 |
|
||||
SslOptions::NO_COMPRESSION,
|
||||
let verifier = CertificateVerificationOverrideVerifier::new(
|
||||
ca_certificates,
|
||||
ignore_certificate_errors,
|
||||
override_manager,
|
||||
);
|
||||
|
||||
cfg.set_ex_data(*EXTRA_INDEX, extra_certs);
|
||||
cfg.set_ex_data(*CONNECTION_INDEX, connection_certs);
|
||||
cfg.set_verify_callback(SslVerifyMode::PEER, |verified, x509_store_context| {
|
||||
if verified {
|
||||
return true;
|
||||
}
|
||||
|
||||
let ssl_idx = X509StoreContext::ssl_idx().unwrap();
|
||||
let ssl = x509_store_context.ex_data(ssl_idx).unwrap();
|
||||
|
||||
// Obtain the cert bytes for this connection.
|
||||
let cert = match x509_store_context.current_cert() {
|
||||
Some(cert) => cert,
|
||||
None => return false,
|
||||
};
|
||||
let pem = match cert.to_pem() {
|
||||
Ok(pem) => pem,
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
||||
let ssl_context = ssl.ssl_context();
|
||||
|
||||
// Ensure there's an entry stored in the set of known connection certs for this connection.
|
||||
if let Some(host) = ssl.ex_data(*HOST_INDEX) {
|
||||
let connection_certs = ssl_context.ex_data(*CONNECTION_INDEX).unwrap();
|
||||
connection_certs.store((*host).0.clone(), pem.clone());
|
||||
}
|
||||
|
||||
// Fall back to the dynamic set of allowed certs.
|
||||
let extra_certs = ssl_context.ex_data(*EXTRA_INDEX).unwrap();
|
||||
for cert in &*extra_certs.0.lock().unwrap() {
|
||||
if pem == *cert {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
});
|
||||
|
||||
cfg
|
||||
rustls::ClientConfig::builder()
|
||||
.with_safe_defaults()
|
||||
.with_custom_certificate_verifier(Arc::new(verifier))
|
||||
.with_no_client_auth()
|
||||
}
|
||||
|
||||
struct TokioExecutor {}
|
||||
|
@ -244,14 +160,95 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn create_http_client(tls_config: TlsConfig) -> Client<Connector, Body> {
|
||||
let mut connector = HttpsConnector::with_connector(HttpConnector::new(), tls_config).unwrap();
|
||||
connector.set_callback(|configuration, destination| {
|
||||
if let Some(host) = destination.host() {
|
||||
configuration.set_ex_data(*HOST_INDEX, Host(host.to_owned()));
|
||||
struct CertificateVerificationOverrideVerifier {
|
||||
webpki_verifier: WebPkiVerifier,
|
||||
ignore_certificate_errors: bool,
|
||||
override_manager: CertificateErrorOverrideManager,
|
||||
}
|
||||
|
||||
impl CertificateVerificationOverrideVerifier {
|
||||
fn new(
|
||||
ca_certficates: CACertificates,
|
||||
ignore_certificate_errors: bool,
|
||||
override_manager: CertificateErrorOverrideManager,
|
||||
) -> Self {
|
||||
let root_cert_store = match ca_certficates {
|
||||
CACertificates::Default => {
|
||||
let mut root_cert_store = rustls::RootCertStore::empty();
|
||||
root_cert_store.add_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.0.iter().map(
|
||||
|trust_anchor| {
|
||||
OwnedTrustAnchor::from_subject_spki_name_constraints(
|
||||
trust_anchor.subject,
|
||||
trust_anchor.spki,
|
||||
trust_anchor.name_constraints,
|
||||
)
|
||||
},
|
||||
));
|
||||
root_cert_store
|
||||
},
|
||||
CACertificates::Override(root_cert_store) => root_cert_store,
|
||||
};
|
||||
|
||||
Self {
|
||||
// See https://github.com/rustls/rustls/blame/v/0.21.6/rustls/src/client/builder.rs#L141
|
||||
// This is the default verifier for Rustls that we are wrapping.
|
||||
webpki_verifier: WebPkiVerifier::new(root_cert_store, None),
|
||||
ignore_certificate_errors,
|
||||
override_manager,
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl rustls::client::ServerCertVerifier for CertificateVerificationOverrideVerifier {
|
||||
fn verify_server_cert(
|
||||
&self,
|
||||
end_entity: &Certificate,
|
||||
intermediates: &[Certificate],
|
||||
server_name: &ServerName,
|
||||
scts: &mut dyn Iterator<Item = &[u8]>,
|
||||
ocsp_response: &[u8],
|
||||
now: std::time::SystemTime,
|
||||
) -> Result<rustls::client::ServerCertVerified, rustls::Error> {
|
||||
let error = match self.webpki_verifier.verify_server_cert(
|
||||
end_entity,
|
||||
intermediates,
|
||||
server_name,
|
||||
scts,
|
||||
ocsp_response,
|
||||
now,
|
||||
) {
|
||||
Ok(result) => return Ok(result),
|
||||
Err(error) => error,
|
||||
};
|
||||
|
||||
if self.ignore_certificate_errors {
|
||||
warn!("Ignoring certficate error: {error:?}");
|
||||
return Ok(rustls::client::ServerCertVerified::assertion());
|
||||
}
|
||||
|
||||
// If there's an override for this certificate, just accept it.
|
||||
for cert_with_exception in &*self.override_manager.0.lock().unwrap().overrides {
|
||||
if *end_entity == *cert_with_exception {
|
||||
return Ok(rustls::client::ServerCertVerified::assertion());
|
||||
}
|
||||
}
|
||||
self.override_manager
|
||||
.0
|
||||
.lock()
|
||||
.unwrap()
|
||||
.certificates_failing_to_verify
|
||||
.insert(server_name.clone(), end_entity.clone());
|
||||
Err(error)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_http_client(tls_config: TlsConfig) -> Client<Connector, Body> {
|
||||
let connector = hyper_rustls::HttpsConnectorBuilder::new()
|
||||
.with_tls_config(tls_config)
|
||||
.https_or_http()
|
||||
.enable_http1()
|
||||
.enable_http2()
|
||||
.wrap_connector(ServoHttpConnector::new());
|
||||
|
||||
Client::builder()
|
||||
.http1_title_case_headers(true)
|
||||
|
|
|
@ -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())
|
||||
},
|
||||
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
* 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_http_client, ConnectionCerts, Connector, ExtraCerts, TlsConfig};
|
||||
use crate::connector::{
|
||||
create_http_client, create_tls_config, CACertificates, CertificateErrorOverrideManager,
|
||||
Connector,
|
||||
};
|
||||
use crate::cookie;
|
||||
use crate::cookie_storage::CookieStorage;
|
||||
use crate::decoder::Decoder;
|
||||
|
@ -98,12 +101,12 @@ pub struct HttpState {
|
|||
pub auth_cache: RwLock<AuthCache>,
|
||||
pub history_states: RwLock<HashMap<HistoryStateId, Vec<u8>>>,
|
||||
pub client: Client<Connector, Body>,
|
||||
pub extra_certs: ExtraCerts,
|
||||
pub connection_certs: ConnectionCerts,
|
||||
pub override_manager: CertificateErrorOverrideManager,
|
||||
}
|
||||
|
||||
impl HttpState {
|
||||
pub fn new(tls_config: TlsConfig) -> HttpState {
|
||||
pub fn new() -> HttpState {
|
||||
let override_manager = CertificateErrorOverrideManager::new();
|
||||
HttpState {
|
||||
hsts_list: RwLock::new(HstsList::new()),
|
||||
cookie_jar: RwLock::new(CookieStorage::new(150)),
|
||||
|
@ -111,9 +114,12 @@ impl HttpState {
|
|||
history_states: RwLock::new(HashMap::new()),
|
||||
http_cache: RwLock::new(HttpCache::new()),
|
||||
http_cache_state: Mutex::new(HashMap::new()),
|
||||
client: create_http_client(tls_config),
|
||||
extra_certs: ExtraCerts::new(),
|
||||
connection_certs: ConnectionCerts::new(),
|
||||
client: create_http_client(create_tls_config(
|
||||
CACertificates::Default,
|
||||
false, /* ignore_certificate_errors */
|
||||
override_manager.clone(),
|
||||
)),
|
||||
override_manager,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -652,18 +658,12 @@ async fn obtain_response(
|
|||
let send_start = precise_time_ms();
|
||||
|
||||
let host = request.uri().host().unwrap_or("").to_owned();
|
||||
let host_clone = request.uri().host().unwrap_or("").to_owned();
|
||||
let connection_certs = context.state.connection_certs.clone();
|
||||
let connection_certs_clone = context.state.connection_certs.clone();
|
||||
|
||||
let override_manager = context.state.override_manager.clone();
|
||||
let headers = headers.clone();
|
||||
|
||||
client
|
||||
.request(request)
|
||||
.and_then(move |res| {
|
||||
// We no longer need to track the cert for this connection.
|
||||
connection_certs.remove(host);
|
||||
|
||||
let send_end = precise_time_ms();
|
||||
|
||||
// TODO(#21271) response_start: immediately after receiving first byte of response
|
||||
|
@ -696,8 +696,11 @@ async fn obtain_response(
|
|||
};
|
||||
future::ready(Ok((Decoder::detect(res), msg)))
|
||||
})
|
||||
.map_err(move |e| {
|
||||
NetworkError::from_hyper_error(&e, connection_certs_clone.remove(host_clone))
|
||||
.map_err(move |error| {
|
||||
NetworkError::from_hyper_error(
|
||||
&error,
|
||||
override_manager.remove_certificate_failing_verification(host.as_str()),
|
||||
)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
|
|
@ -46,6 +46,3 @@ pub mod test {
|
|||
pub use crate::hosts::{parse_hostsfile, replace_host_table};
|
||||
pub use crate::http_loader::HttpState;
|
||||
}
|
||||
|
||||
// This dependency gives `build.rs` access to the `DEP_OPENSSL_VERSION_NUMBER` env variable.
|
||||
use openssl_sys as _;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
//! A thread that takes a URL and streams back the binary data.
|
||||
|
||||
use crate::connector::{
|
||||
create_http_client, create_tls_config, ConnectionCerts, ExtraCerts, ALPN_H2_H1,
|
||||
create_http_client, create_tls_config, CACertificates, CertificateErrorOverrideManager,
|
||||
};
|
||||
use crate::cookie;
|
||||
use crate::cookie_storage::CookieStorage;
|
||||
|
@ -19,7 +19,6 @@ use crate::storage_thread::StorageThreadFactory;
|
|||
use crate::websocket_loader;
|
||||
use crossbeam_channel::Sender;
|
||||
use devtools_traits::DevtoolsControlMsg;
|
||||
use embedder_traits::resources::{self, Resource};
|
||||
use embedder_traits::EmbedderProxy;
|
||||
use hyper_serde::Serde;
|
||||
use ipc_channel::ipc::{self, IpcReceiver, IpcReceiverSet, IpcSender};
|
||||
|
@ -39,19 +38,30 @@ use net_traits::{ResourceThreads, WebSocketDomAction};
|
|||
use profile_traits::mem::ProfilerChan as MemProfilerChan;
|
||||
use profile_traits::mem::{Report, ReportKind, ReportsChan};
|
||||
use profile_traits::time::ProfilerChan;
|
||||
use rustls::RootCertStore;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use servo_arc::Arc as ServoArc;
|
||||
use servo_url::{ImmutableOrigin, ServoUrl};
|
||||
use std::borrow::{Cow, ToOwned};
|
||||
use std::collections::HashMap;
|
||||
use std::fs::{self, File};
|
||||
use std::io::prelude::*;
|
||||
use std::fs::File;
|
||||
use std::io::{self, prelude::*, BufReader};
|
||||
use std::ops::Deref;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
/// Load a file with CA certificate and produce a RootCertStore with the results.
|
||||
fn load_root_cert_store_from_file(file_path: String) -> io::Result<RootCertStore> {
|
||||
let mut root_cert_store = RootCertStore::empty();
|
||||
|
||||
let mut pem = BufReader::new(File::open(file_path)?);
|
||||
let certs = rustls_pemfile::certs(&mut pem)?;
|
||||
root_cert_store.add_parsable_certificates(&certs);
|
||||
Ok(root_cert_store)
|
||||
}
|
||||
|
||||
/// Returns a tuple of (public, private) senders to the new threads.
|
||||
pub fn new_resource_threads(
|
||||
user_agent: Cow<'static, str>,
|
||||
|
@ -61,7 +71,19 @@ pub fn new_resource_threads(
|
|||
embedder_proxy: EmbedderProxy,
|
||||
config_dir: Option<PathBuf>,
|
||||
certificate_path: Option<String>,
|
||||
ignore_certificate_errors: bool,
|
||||
) -> (ResourceThreads, ResourceThreads) {
|
||||
let ca_certificates = match certificate_path {
|
||||
Some(path) => match load_root_cert_store_from_file(path) {
|
||||
Ok(root_cert_store) => CACertificates::Override(root_cert_store),
|
||||
Err(error) => {
|
||||
warn!("Could not load CA file. Falling back to defaults. {error:?}");
|
||||
CACertificates::Default
|
||||
},
|
||||
},
|
||||
None => CACertificates::Default,
|
||||
};
|
||||
|
||||
let (public_core, private_core) = new_core_resource_thread(
|
||||
user_agent,
|
||||
devtools_sender,
|
||||
|
@ -69,7 +91,8 @@ pub fn new_resource_threads(
|
|||
mem_profiler_chan,
|
||||
embedder_proxy,
|
||||
config_dir.clone(),
|
||||
certificate_path,
|
||||
ca_certificates,
|
||||
ignore_certificate_errors,
|
||||
);
|
||||
let storage: IpcSender<StorageThreadMsg> = StorageThreadFactory::new(config_dir);
|
||||
(
|
||||
|
@ -86,7 +109,8 @@ pub fn new_core_resource_thread(
|
|||
mem_profiler_chan: MemProfilerChan,
|
||||
embedder_proxy: EmbedderProxy,
|
||||
config_dir: Option<PathBuf>,
|
||||
certificate_path: Option<String>,
|
||||
ca_certificates: CACertificates,
|
||||
ignore_certificate_errors: bool,
|
||||
) -> (CoreResourceThread, CoreResourceThread) {
|
||||
let (public_setup_chan, public_setup_port) = ipc::channel().unwrap();
|
||||
let (private_setup_chan, private_setup_port) = ipc::channel().unwrap();
|
||||
|
@ -100,13 +124,15 @@ pub fn new_core_resource_thread(
|
|||
devtools_sender,
|
||||
time_profiler_chan,
|
||||
embedder_proxy,
|
||||
certificate_path.clone(),
|
||||
ca_certificates.clone(),
|
||||
ignore_certificate_errors,
|
||||
);
|
||||
|
||||
let mut channel_manager = ResourceChannelManager {
|
||||
resource_manager,
|
||||
config_dir,
|
||||
certificate_path,
|
||||
ca_certificates,
|
||||
ignore_certificate_errors,
|
||||
};
|
||||
|
||||
mem_profiler_chan.run_with_memory_reporting(
|
||||
|
@ -123,12 +149,14 @@ pub fn new_core_resource_thread(
|
|||
struct ResourceChannelManager {
|
||||
resource_manager: CoreResourceManager,
|
||||
config_dir: Option<PathBuf>,
|
||||
certificate_path: Option<String>,
|
||||
ca_certificates: CACertificates,
|
||||
ignore_certificate_errors: bool,
|
||||
}
|
||||
|
||||
fn create_http_states(
|
||||
config_dir: Option<&Path>,
|
||||
certificate_path: Option<String>,
|
||||
ca_certificates: CACertificates,
|
||||
ignore_certificate_errors: bool,
|
||||
) -> (Arc<HttpState>, Arc<HttpState>) {
|
||||
let mut hsts_list = HstsList::from_servo_preload();
|
||||
let mut auth_cache = AuthCache::new();
|
||||
|
@ -140,14 +168,7 @@ fn create_http_states(
|
|||
read_json_from_file(&mut cookie_jar, config_dir, "cookie_jar.json");
|
||||
}
|
||||
|
||||
let certs = match certificate_path {
|
||||
Some(ref path) => fs::read_to_string(path).expect("Couldn't not find certificate file"),
|
||||
None => resources::read_string(Resource::SSLCertificates),
|
||||
};
|
||||
|
||||
let extra_certs = ExtraCerts::new();
|
||||
let connection_certs = ConnectionCerts::new();
|
||||
|
||||
let override_manager = CertificateErrorOverrideManager::new();
|
||||
let http_state = HttpState {
|
||||
hsts_list: RwLock::new(hsts_list),
|
||||
cookie_jar: RwLock::new(cookie_jar),
|
||||
|
@ -156,18 +177,14 @@ 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,
|
||||
extra_certs.clone(),
|
||||
connection_certs.clone(),
|
||||
ca_certificates.clone(),
|
||||
ignore_certificate_errors,
|
||||
override_manager.clone(),
|
||||
)),
|
||||
extra_certs,
|
||||
connection_certs,
|
||||
override_manager,
|
||||
};
|
||||
|
||||
let extra_certs = ExtraCerts::new();
|
||||
let connection_certs = ConnectionCerts::new();
|
||||
|
||||
let override_manager = CertificateErrorOverrideManager::new();
|
||||
let private_http_state = HttpState {
|
||||
hsts_list: RwLock::new(HstsList::from_servo_preload()),
|
||||
cookie_jar: RwLock::new(CookieStorage::new(150)),
|
||||
|
@ -176,13 +193,11 @@ 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,
|
||||
extra_certs.clone(),
|
||||
connection_certs.clone(),
|
||||
ca_certificates,
|
||||
ignore_certificate_errors,
|
||||
override_manager.clone(),
|
||||
)),
|
||||
extra_certs,
|
||||
connection_certs,
|
||||
override_manager,
|
||||
};
|
||||
|
||||
(Arc::new(http_state), Arc::new(private_http_state))
|
||||
|
@ -198,7 +213,8 @@ impl ResourceChannelManager {
|
|||
) {
|
||||
let (public_http_state, private_http_state) = create_http_states(
|
||||
self.config_dir.as_ref().map(Deref::deref),
|
||||
self.certificate_path.clone(),
|
||||
self.ca_certificates.clone(),
|
||||
self.ignore_certificate_errors,
|
||||
);
|
||||
|
||||
let mut rx_set = IpcReceiverSet::new().unwrap();
|
||||
|
@ -455,7 +471,8 @@ pub struct CoreResourceManager {
|
|||
sw_managers: HashMap<ImmutableOrigin, IpcSender<CustomResponseMediator>>,
|
||||
filemanager: FileManager,
|
||||
thread_pool: Arc<CoreResourceThreadPool>,
|
||||
certificate_path: Option<String>,
|
||||
ca_certificates: CACertificates,
|
||||
ignore_certificate_errors: bool,
|
||||
}
|
||||
|
||||
/// The state of the thread-pool used by CoreResource.
|
||||
|
@ -589,7 +606,8 @@ impl CoreResourceManager {
|
|||
devtools_sender: Option<Sender<DevtoolsControlMsg>>,
|
||||
_profiler_chan: ProfilerChan,
|
||||
embedder_proxy: EmbedderProxy,
|
||||
certificate_path: Option<String>,
|
||||
ca_certificates: CACertificates,
|
||||
ignore_certificate_errors: bool,
|
||||
) -> CoreResourceManager {
|
||||
let pool = CoreResourceThreadPool::new(16);
|
||||
let pool_handle = Arc::new(pool);
|
||||
|
@ -599,7 +617,8 @@ impl CoreResourceManager {
|
|||
sw_managers: Default::default(),
|
||||
filemanager: FileManager::new(embedder_proxy, Arc::downgrade(&pool_handle)),
|
||||
thread_pool: pool_handle,
|
||||
certificate_path,
|
||||
ca_certificates,
|
||||
ignore_certificate_errors,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -725,7 +744,8 @@ impl CoreResourceManager {
|
|||
event_sender,
|
||||
action_receiver,
|
||||
http_state.clone(),
|
||||
self.certificate_path.clone(),
|
||||
self.ca_certificates.clone(),
|
||||
self.ignore_certificate_errors,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ use hyper::Body;
|
|||
use hyper::{Request as HyperRequest, Response as HyperResponse};
|
||||
use mime::{self, Mime};
|
||||
use msg::constellation_msg::TEST_PIPELINE_ID;
|
||||
use net::connector::{create_tls_config, ConnectionCerts, ExtraCerts, ALPN_H2_H1};
|
||||
use net::fetch::cors_cache::CorsCache;
|
||||
use net::fetch::methods::{self, CancellationListener, FetchContext};
|
||||
use net::filemanager_thread::FileManager;
|
||||
|
@ -756,24 +755,10 @@ fn test_fetch_with_hsts() {
|
|||
*response.body_mut() = MESSAGE.to_vec().into();
|
||||
};
|
||||
|
||||
let cert_path = Path::new("../../resources/self_signed_certificate_for_testing.crt")
|
||||
.canonicalize()
|
||||
.unwrap();
|
||||
let key_path = Path::new("../../resources/privatekey_for_testing.key")
|
||||
.canonicalize()
|
||||
.unwrap();
|
||||
let (server, url) = make_ssl_server(handler, cert_path.clone(), key_path.clone());
|
||||
|
||||
let certs = fs::read_to_string(cert_path).expect("Couldn't find certificate file");
|
||||
let tls_config = create_tls_config(
|
||||
&certs,
|
||||
ALPN_H2_H1,
|
||||
ExtraCerts::new(),
|
||||
ConnectionCerts::new(),
|
||||
);
|
||||
let (server, url) = make_ssl_server(handler);
|
||||
|
||||
let mut context = FetchContext {
|
||||
state: Arc::new(HttpState::new(tls_config)),
|
||||
state: Arc::new(HttpState::new()),
|
||||
user_agent: DEFAULT_USER_AGENT.into(),
|
||||
devtools_chan: None,
|
||||
filemanager: Arc::new(Mutex::new(FileManager::new(
|
||||
|
@ -787,6 +772,12 @@ fn test_fetch_with_hsts() {
|
|||
))),
|
||||
};
|
||||
|
||||
// The server certificate is self-signed, so we need to add an override
|
||||
// so that the connection works properly.
|
||||
for certificate in server.certificates.as_ref().unwrap().iter() {
|
||||
context.state.override_manager.add_override(certificate);
|
||||
}
|
||||
|
||||
{
|
||||
let mut list = context.state.hsts_list.write().unwrap();
|
||||
list.push(
|
||||
|
@ -821,25 +812,12 @@ fn test_load_adds_host_to_hsts_list_when_url_is_https() {
|
|||
));
|
||||
*response.body_mut() = b"Yay!".to_vec().into();
|
||||
};
|
||||
let cert_path = Path::new("../../resources/self_signed_certificate_for_testing.crt")
|
||||
.canonicalize()
|
||||
.unwrap();
|
||||
let key_path = Path::new("../../resources/privatekey_for_testing.key")
|
||||
.canonicalize()
|
||||
.unwrap();
|
||||
let (server, mut url) = make_ssl_server(handler, cert_path.clone(), key_path.clone());
|
||||
|
||||
let (server, mut url) = make_ssl_server(handler);
|
||||
url.as_mut_url().set_scheme("https").unwrap();
|
||||
|
||||
let certs = fs::read_to_string(cert_path).expect("Couldn't find certificate file");
|
||||
let tls_config = create_tls_config(
|
||||
&certs,
|
||||
ALPN_H2_H1,
|
||||
ExtraCerts::new(),
|
||||
ConnectionCerts::new(),
|
||||
);
|
||||
|
||||
let mut context = FetchContext {
|
||||
state: Arc::new(HttpState::new(tls_config)),
|
||||
state: Arc::new(HttpState::new()),
|
||||
user_agent: DEFAULT_USER_AGENT.into(),
|
||||
devtools_chan: None,
|
||||
filemanager: Arc::new(Mutex::new(FileManager::new(
|
||||
|
@ -853,6 +831,12 @@ fn test_load_adds_host_to_hsts_list_when_url_is_https() {
|
|||
))),
|
||||
};
|
||||
|
||||
// The server certificate is self-signed, so we need to add an override
|
||||
// so that the connection works properly.
|
||||
for certificate in server.certificates.as_ref().unwrap().iter() {
|
||||
context.state.override_manager.add_override(certificate);
|
||||
}
|
||||
|
||||
let mut request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
|
||||
.method(Method::GET)
|
||||
.body(None)
|
||||
|
@ -885,29 +869,12 @@ fn test_fetch_self_signed() {
|
|||
let handler = move |_: HyperRequest<Body>, response: &mut HyperResponse<Body>| {
|
||||
*response.body_mut() = b"Yay!".to_vec().into();
|
||||
};
|
||||
let client_cert_path = Path::new("../../resources/certs").canonicalize().unwrap();
|
||||
let cert_path = Path::new("../../resources/self_signed_certificate_for_testing.crt")
|
||||
.canonicalize()
|
||||
.unwrap();
|
||||
let key_path = Path::new("../../resources/privatekey_for_testing.key")
|
||||
.canonicalize()
|
||||
.unwrap();
|
||||
let (_server, mut url) = make_ssl_server(handler, cert_path.clone(), key_path.clone());
|
||||
|
||||
let (server, mut url) = make_ssl_server(handler);
|
||||
url.as_mut_url().set_scheme("https").unwrap();
|
||||
|
||||
let cert_data = fs::read_to_string(cert_path.clone()).expect("Couldn't find certificate file");
|
||||
let client_cert_data =
|
||||
fs::read_to_string(client_cert_path.clone()).expect("Couldn't find certificate file");
|
||||
let extra_certs = ExtraCerts::new();
|
||||
let tls_config = create_tls_config(
|
||||
&client_cert_data,
|
||||
ALPN_H2_H1,
|
||||
extra_certs.clone(),
|
||||
ConnectionCerts::new(),
|
||||
);
|
||||
|
||||
let mut context = FetchContext {
|
||||
state: Arc::new(HttpState::new(tls_config)),
|
||||
state: Arc::new(HttpState::new()),
|
||||
user_agent: DEFAULT_USER_AGENT.into(),
|
||||
devtools_chan: None,
|
||||
filemanager: Arc::new(Mutex::new(FileManager::new(
|
||||
|
@ -936,16 +903,11 @@ fn test_fetch_self_signed() {
|
|||
Some(NetworkError::SslValidation(..))
|
||||
));
|
||||
|
||||
extra_certs.add(cert_data.as_bytes().into());
|
||||
|
||||
// FIXME: something weird happens inside the SSL server after the first
|
||||
// connection encounters a verification error, and it no longer
|
||||
// accepts new connections that should work fine. We are forced
|
||||
// to start a new server and connect to that to verfiy that
|
||||
// the self-signed cert is now accepted.
|
||||
|
||||
let (server, mut url) = make_ssl_server(handler, cert_path.clone(), key_path.clone());
|
||||
url.as_mut_url().set_scheme("https").unwrap();
|
||||
// The server certificate is self-signed, so we need to add an override
|
||||
// so that the connection works properly.
|
||||
for certificate in server.certificates.as_ref().unwrap().iter() {
|
||||
context.state.override_manager.add_override(certificate);
|
||||
}
|
||||
|
||||
let mut request = RequestBuilder::new(url.clone(), Referrer::NoReferrer)
|
||||
.method(Method::GET)
|
||||
|
|
|
@ -22,10 +22,8 @@ mod resource_thread;
|
|||
mod subresource_integrity;
|
||||
|
||||
use core::convert::Infallible;
|
||||
use core::pin::Pin;
|
||||
use crossbeam_channel::{unbounded, Sender};
|
||||
use devtools_traits::DevtoolsControlMsg;
|
||||
use embedder_traits::resources::{self, Resource};
|
||||
use embedder_traits::{EmbedderProxy, EventLoopWaker};
|
||||
use futures::future::ready;
|
||||
use futures::StreamExt;
|
||||
|
@ -33,7 +31,6 @@ use hyper::server::conn::Http;
|
|||
use hyper::server::Server as HyperServer;
|
||||
use hyper::service::{make_service_fn, service_fn};
|
||||
use hyper::{Body, Request as HyperRequest, Response as HyperResponse};
|
||||
use net::connector::{create_tls_config, ConnectionCerts, ExtraCerts, ALPN_H2_H1};
|
||||
use net::fetch::cors_cache::CorsCache;
|
||||
use net::fetch::methods::{self, CancellationListener, FetchContext};
|
||||
use net::filemanager_thread::FileManager;
|
||||
|
@ -43,16 +40,19 @@ use net_traits::filemanager_thread::FileTokenCheck;
|
|||
use net_traits::request::Request;
|
||||
use net_traits::response::Response;
|
||||
use net_traits::{FetchTaskTarget, ResourceFetchTiming, ResourceTimingType};
|
||||
use openssl::ssl::{Ssl, SslAcceptor, SslFiletype, SslMethod};
|
||||
use rustls::{self, Certificate, PrivateKey};
|
||||
use rustls_pemfile::{certs, pkcs8_private_keys};
|
||||
use servo_arc::Arc as ServoArc;
|
||||
use servo_url::ServoUrl;
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufReader};
|
||||
use std::net::TcpListener as StdTcpListener;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::{Arc, Mutex, Weak};
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::runtime::{Builder, Runtime};
|
||||
use tokio_openssl::SslStream;
|
||||
use tokio_rustls::{self, TlsAcceptor};
|
||||
use tokio_stream::wrappers::TcpListenerStream;
|
||||
use tokio_test::block_on;
|
||||
|
||||
|
@ -102,17 +102,10 @@ fn new_fetch_context(
|
|||
fc: Option<EmbedderProxy>,
|
||||
pool_handle: Option<Weak<CoreResourceThreadPool>>,
|
||||
) -> FetchContext {
|
||||
let certs = resources::read_string(Resource::SSLCertificates);
|
||||
let tls_config = create_tls_config(
|
||||
&certs,
|
||||
ALPN_H2_H1,
|
||||
ExtraCerts::new(),
|
||||
ConnectionCerts::new(),
|
||||
);
|
||||
let sender = fc.unwrap_or_else(|| create_embedder_proxy());
|
||||
|
||||
FetchContext {
|
||||
state: Arc::new(HttpState::new(tls_config)),
|
||||
state: Arc::new(HttpState::new()),
|
||||
user_agent: DEFAULT_USER_AGENT.into(),
|
||||
devtools_chan: dc.map(|dc| Arc::new(Mutex::new(dc))),
|
||||
filemanager: Arc::new(Mutex::new(FileManager::new(
|
||||
|
@ -167,6 +160,7 @@ fn fetch_with_cors_cache(request: &mut Request, cache: &mut CorsCache) -> Respon
|
|||
|
||||
pub(crate) struct Server {
|
||||
pub close_channel: tokio::sync::oneshot::Sender<()>,
|
||||
pub certificates: Option<Vec<Certificate>>,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
|
@ -205,11 +199,39 @@ where
|
|||
};
|
||||
|
||||
HANDLE.lock().unwrap().spawn(server);
|
||||
let server = Server { close_channel: tx };
|
||||
(server, url)
|
||||
(
|
||||
Server {
|
||||
close_channel: tx,
|
||||
certificates: None,
|
||||
},
|
||||
url,
|
||||
)
|
||||
}
|
||||
|
||||
fn make_ssl_server<H>(handler: H, cert_path: PathBuf, key_path: PathBuf) -> (Server, ServoUrl)
|
||||
/// Given a path to a file containing PEM certificates, load and parse them into
|
||||
/// a vector of RusTLS [Certificate]s.
|
||||
fn load_certificates_from_pem(path: &PathBuf) -> std::io::Result<Vec<Certificate>> {
|
||||
let file = File::open(path)?;
|
||||
let mut reader = BufReader::new(file);
|
||||
let certs = certs(&mut reader)?;
|
||||
Ok(certs.into_iter().map(Certificate).collect())
|
||||
}
|
||||
|
||||
/// Given a path to a file containing PEM keys, load and parse them into
|
||||
/// a vector of RusTLS [PrivateKey]s.
|
||||
fn load_private_key_from_file(path: &PathBuf) -> Result<PrivateKey, Box<dyn std::error::Error>> {
|
||||
let file = File::open(&path)?;
|
||||
let mut reader = BufReader::new(file);
|
||||
let mut keys = pkcs8_private_keys(&mut reader)?;
|
||||
|
||||
match keys.len() {
|
||||
0 => Err(format!("No PKCS8-encoded private key found in {path:?}").into()),
|
||||
1 => Ok(PrivateKey(keys.remove(0))),
|
||||
_ => Err(format!("More than one PKCS8-encoded private key found in {path:?}").into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn make_ssl_server<H>(handler: H) -> (Server, ServoUrl)
|
||||
where
|
||||
H: Fn(HyperRequest<Body>, &mut HyperResponse<Body>) + Send + Sync + 'static,
|
||||
{
|
||||
|
@ -219,13 +241,28 @@ where
|
|||
.lock()
|
||||
.unwrap()
|
||||
.block_on(async move { TcpListener::from_std(listener).unwrap() });
|
||||
|
||||
let url_string = format!("http://localhost:{}", listener.local_addr().unwrap().port());
|
||||
let mut listener = TcpListenerStream::new(listener);
|
||||
|
||||
let url = ServoUrl::parse(&url_string).unwrap();
|
||||
let (tx, mut rx) = tokio::sync::oneshot::channel::<()>();
|
||||
|
||||
let cert_path = Path::new("../../resources/self_signed_certificate_for_testing.crt")
|
||||
.canonicalize()
|
||||
.unwrap();
|
||||
let key_path = Path::new("../../resources/privatekey_for_testing.key")
|
||||
.canonicalize()
|
||||
.unwrap();
|
||||
let certificates = load_certificates_from_pem(&cert_path).expect("Invalid certificate");
|
||||
let key = load_private_key_from_file(&key_path).expect("Invalid key");
|
||||
|
||||
let config = rustls::ServerConfig::builder()
|
||||
.with_safe_defaults()
|
||||
.with_no_client_auth()
|
||||
.with_single_cert(certificates.clone(), key)
|
||||
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))
|
||||
.expect("Could not create rustls ServerConfig");
|
||||
let acceptor = TlsAcceptor::from(Arc::new(config));
|
||||
|
||||
let mut listener = TcpListenerStream::new(listener);
|
||||
let (tx, mut rx) = tokio::sync::oneshot::channel::<()>();
|
||||
let server = async move {
|
||||
loop {
|
||||
let stream = tokio::select! {
|
||||
|
@ -244,22 +281,16 @@ where
|
|||
.unwrap();
|
||||
let stream = TcpStream::from_std(stream).unwrap();
|
||||
|
||||
let mut tls_server_config =
|
||||
SslAcceptor::mozilla_intermediate_v5(SslMethod::tls()).unwrap();
|
||||
tls_server_config
|
||||
.set_certificate_file(&cert_path, SslFiletype::PEM)
|
||||
.unwrap();
|
||||
tls_server_config
|
||||
.set_private_key_file(&key_path, SslFiletype::PEM)
|
||||
.unwrap();
|
||||
|
||||
let tls_server_config = tls_server_config.build();
|
||||
let ssl = Ssl::new(tls_server_config.context()).unwrap();
|
||||
let mut stream = SslStream::new(ssl, stream).unwrap();
|
||||
|
||||
let _ = Pin::new(&mut stream).accept().await;
|
||||
|
||||
let handler = handler.clone();
|
||||
let acceptor = acceptor.clone();
|
||||
|
||||
let stream = match acceptor.accept(stream).await {
|
||||
Ok(stream) => stream,
|
||||
Err(_) => {
|
||||
eprintln!("Error handling TLS stream.");
|
||||
continue;
|
||||
},
|
||||
};
|
||||
|
||||
let _ = Http::new()
|
||||
.serve_connection(
|
||||
|
@ -276,6 +307,11 @@ where
|
|||
|
||||
HANDLE.lock().unwrap().spawn(server);
|
||||
|
||||
let server = Server { close_channel: tx };
|
||||
(server, url)
|
||||
(
|
||||
Server {
|
||||
close_channel: tx,
|
||||
certificates: Some(certificates),
|
||||
},
|
||||
url,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
use crate::create_embedder_proxy;
|
||||
use ipc_channel::ipc;
|
||||
use net::connector::CACertificates;
|
||||
use net::resource_thread::new_core_resource_thread;
|
||||
use net::test::parse_hostsfile;
|
||||
use net_traits::CoreResourceMsg;
|
||||
|
@ -27,7 +28,8 @@ fn test_exit() {
|
|||
MemProfilerChan(mtx),
|
||||
create_embedder_proxy(),
|
||||
None,
|
||||
None,
|
||||
CACertificates::Default,
|
||||
false, /* ignore_certificate_errors */
|
||||
);
|
||||
resource_thread.send(CoreResourceMsg::Exit(sender)).unwrap();
|
||||
receiver.recv().unwrap();
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
//! over events from the network and events from the DOM, using async/await to avoid
|
||||
//! the need for a dedicated thread per websocket.
|
||||
|
||||
use crate::connector::{create_tls_config, ALPN_H1};
|
||||
use crate::connector::{create_tls_config, CACertificates, TlsConfig};
|
||||
use crate::cookie::Cookie;
|
||||
use crate::fetch::methods::should_be_blocked_due_to_bad_port;
|
||||
use crate::hosts::replace_host;
|
||||
|
@ -19,7 +19,6 @@ use crate::http_loader::HttpState;
|
|||
use async_tungstenite::tokio::{client_async_tls_with_connector_and_config, ConnectStream};
|
||||
use async_tungstenite::WebSocketStream;
|
||||
use base64::Engine;
|
||||
use embedder_traits::resources::{self, Resource};
|
||||
use futures::future::TryFutureExt;
|
||||
use futures::sink::SinkExt;
|
||||
use futures::stream::StreamExt;
|
||||
|
@ -29,15 +28,14 @@ use ipc_channel::router::ROUTER;
|
|||
use net_traits::request::{RequestBuilder, RequestMode};
|
||||
use net_traits::{CookieSource, MessageData};
|
||||
use net_traits::{WebSocketDomAction, WebSocketNetworkEvent};
|
||||
use openssl::ssl::ConnectConfiguration;
|
||||
use servo_url::ServoUrl;
|
||||
use std::fs;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::runtime::Runtime;
|
||||
use tokio::select;
|
||||
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver};
|
||||
use tokio_rustls::TlsConnector;
|
||||
use tungstenite::error::Result as WebSocketResult;
|
||||
use tungstenite::error::{Error, ProtocolError, UrlError};
|
||||
use tungstenite::handshake::client::{Request, Response};
|
||||
|
@ -302,7 +300,7 @@ async fn start_websocket(
|
|||
resource_event_sender: IpcSender<WebSocketNetworkEvent>,
|
||||
protocols: Vec<String>,
|
||||
client: Request,
|
||||
tls_config: ConnectConfiguration,
|
||||
tls_config: TlsConfig,
|
||||
dom_action_receiver: IpcReceiver<WebSocketDomAction>,
|
||||
) -> Result<(), Error> {
|
||||
trace!("starting WS connection to {}", url);
|
||||
|
@ -330,8 +328,10 @@ async fn start_websocket(
|
|||
|
||||
let try_socket = TcpStream::connect((&*domain.to_string(), port)).await;
|
||||
let socket = try_socket.map_err(Error::Io)?;
|
||||
let connector = TlsConnector::from(Arc::new(tls_config));
|
||||
|
||||
let (stream, response) =
|
||||
client_async_tls_with_connector_and_config(client, socket, Some(tls_config), None).await?;
|
||||
client_async_tls_with_connector_and_config(client, socket, Some(connector), None).await?;
|
||||
|
||||
let protocol_in_use = process_ws_response(&http_state, &response, &url, &protocols)?;
|
||||
|
||||
|
@ -357,7 +357,8 @@ fn connect(
|
|||
resource_event_sender: IpcSender<WebSocketNetworkEvent>,
|
||||
dom_action_receiver: IpcReceiver<WebSocketDomAction>,
|
||||
http_state: Arc<HttpState>,
|
||||
certificate_path: Option<String>,
|
||||
ca_certificates: CACertificates,
|
||||
ignore_certificate_errors: bool,
|
||||
) -> Result<(), String> {
|
||||
let protocols = match req_builder.mode {
|
||||
RequestMode::WebSocket { protocols } => protocols,
|
||||
|
@ -382,11 +383,6 @@ fn connect(
|
|||
return Err("Port blocked".to_string());
|
||||
}
|
||||
|
||||
let certs = match certificate_path {
|
||||
Some(ref path) => fs::read_to_string(path).map_err(|e| e.to_string())?,
|
||||
None => resources::read_string(Resource::SSLCertificates),
|
||||
};
|
||||
|
||||
let client = match create_request(
|
||||
&req_url,
|
||||
&req_builder.origin.ascii_serialization(),
|
||||
|
@ -397,16 +393,12 @@ fn connect(
|
|||
Err(e) => return Err(e.to_string()),
|
||||
};
|
||||
|
||||
let tls_config = create_tls_config(
|
||||
&certs,
|
||||
ALPN_H1,
|
||||
http_state.extra_certs.clone(),
|
||||
http_state.connection_certs.clone(),
|
||||
let mut tls_config = create_tls_config(
|
||||
ca_certificates,
|
||||
ignore_certificate_errors,
|
||||
http_state.override_manager.clone(),
|
||||
);
|
||||
let tls_config = match tls_config.build().configure() {
|
||||
Ok(c) => c,
|
||||
Err(e) => return Err(e.to_string()),
|
||||
};
|
||||
tls_config.alpn_protocols = vec!["h2".to_string().into(), "http/1.1".to_string().into()];
|
||||
|
||||
let resource_event_sender2 = resource_event_sender.clone();
|
||||
match HANDLE.lock().unwrap().as_mut() {
|
||||
|
@ -436,7 +428,8 @@ pub fn init(
|
|||
resource_event_sender: IpcSender<WebSocketNetworkEvent>,
|
||||
dom_action_receiver: IpcReceiver<WebSocketDomAction>,
|
||||
http_state: Arc<HttpState>,
|
||||
certificate_path: Option<String>,
|
||||
ca_certificates: CACertificates,
|
||||
ignore_certificate_errors: bool,
|
||||
) {
|
||||
let resource_event_sender2 = resource_event_sender.clone();
|
||||
if let Err(e) = connect(
|
||||
|
@ -444,7 +437,8 @@ pub fn init(
|
|||
resource_event_sender,
|
||||
dom_action_receiver,
|
||||
http_state,
|
||||
certificate_path,
|
||||
ca_certificates,
|
||||
ignore_certificate_errors,
|
||||
) {
|
||||
warn!("Error starting websocket: {}", e);
|
||||
let _ = resource_event_sender2.send(WebSocketNetworkEvent::Fail);
|
||||
|
|
|
@ -31,6 +31,7 @@ msg = { path = "../msg" }
|
|||
num-traits = { workspace = true }
|
||||
percent-encoding = { workspace = true }
|
||||
pixels = { path = "../pixels" }
|
||||
rustls = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
servo_arc = { path = "../servo_arc" }
|
||||
servo_rand = { path = "../rand" }
|
||||
|
|
|
@ -30,6 +30,7 @@ use ipc_channel::router::ROUTER;
|
|||
use ipc_channel::Error as IpcError;
|
||||
use mime::Mime;
|
||||
use msg::constellation_msg::HistoryStateId;
|
||||
use rustls::Certificate;
|
||||
use servo_rand::RngCore;
|
||||
use servo_url::{ImmutableOrigin, ServoUrl};
|
||||
use time::precise_time_ns;
|
||||
|
@ -762,12 +763,11 @@ pub enum NetworkError {
|
|||
}
|
||||
|
||||
impl NetworkError {
|
||||
pub fn from_hyper_error(error: &HyperError, cert_bytes: Option<Vec<u8>>) -> Self {
|
||||
let s = error.to_string();
|
||||
if s.to_lowercase().contains("ssl") {
|
||||
NetworkError::SslValidation(s, cert_bytes.unwrap_or_default())
|
||||
} else {
|
||||
NetworkError::Internal(s)
|
||||
pub fn from_hyper_error(error: &HyperError, certificate: Option<Certificate>) -> Self {
|
||||
let error_string = error.to_string();
|
||||
match certificate {
|
||||
Some(certificate) => NetworkError::SslValidation(error_string, certificate.0),
|
||||
_ => NetworkError::Internal(error_string),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ use crate::dom::virtualmethods::vtable_for;
|
|||
use crate::network_listener::PreInvoke;
|
||||
use crate::realms::enter_realm;
|
||||
use crate::script_thread::ScriptThread;
|
||||
use base64::{engine::general_purpose, Engine as _};
|
||||
use content_security_policy::{self as csp, CspList};
|
||||
use dom_struct::dom_struct;
|
||||
use embedder_traits::resources::{self, Resource};
|
||||
|
@ -880,8 +881,8 @@ impl FetchResponseListener for ParserContext {
|
|||
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 encoded_bytes = general_purpose::STANDARD_NO_PAD.encode(&bytes);
|
||||
let page = page.replace("${bytes}", encoded_bytes.as_str());
|
||||
let page =
|
||||
page.replace("${secret}", &net_traits::PRIVILEGED_SECRET.to_string());
|
||||
parser.push_string_input_chunk(page);
|
||||
|
|
|
@ -857,6 +857,7 @@ fn create_constellation(
|
|||
embedder_proxy.clone(),
|
||||
config_dir,
|
||||
opts.certificate_path.clone(),
|
||||
opts.ignore_certificate_errors,
|
||||
);
|
||||
|
||||
let font_cache_thread = FontCacheThread::new(
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
// XPCShell script for generating a single file containing all certificates in PEM
|
||||
// format. You may run this in the browser toolbox's console
|
||||
// (Firefox -> devtools -> settings -> enable remote/chrome debugging,
|
||||
// followed by settings -> devtools menu -> browser toolbox) or the
|
||||
// xpcshell runner that comes with a built Firefox (./run-mozilla.sh ./xpcshell).
|
||||
// The variable `certstring` contains the final pem file. You can use `save(path)` to
|
||||
// save it to a file. `certlist` contains an array with the PEM certs as well as their names if you
|
||||
// want to filter them.
|
||||
|
||||
|
||||
// http://mxr.mozilla.org/mozilla-central/source/security/manager/pki/resources/content/pippki.js
|
||||
function getDERString(cert)
|
||||
{
|
||||
var length = {};
|
||||
var derArray = cert.getRawDER(length);
|
||||
var derString = '';
|
||||
for (var i = 0; i < derArray.length; i++) {
|
||||
derString += String.fromCharCode(derArray[i]);
|
||||
}
|
||||
return derString;
|
||||
}
|
||||
|
||||
// http://mxr.mozilla.org/mozilla-central/source/security/manager/pki/resources/content/pippki.js
|
||||
function getPEMString(cert)
|
||||
{
|
||||
var derb64 = btoa(getDERString(cert));
|
||||
// Wrap the Base64 string into lines of 64 characters,
|
||||
// with CRLF line breaks (as specified in RFC 1421).
|
||||
var wrapped = derb64.replace(/(\S{64}(?!$))/g, "$1\r\n");
|
||||
return "-----BEGIN CERTIFICATE-----\r\n"
|
||||
+ wrapped
|
||||
+ "\r\n-----END CERTIFICATE-----\r\n";
|
||||
}
|
||||
|
||||
let certdb = Components.classes["@mozilla.org/security/x509certdb;1"].createInstance(Ci.nsIX509CertDB);
|
||||
let enumerator = certdb.getCerts().getEnumerator();
|
||||
let certlist = [];
|
||||
let certstring="";
|
||||
while(enumerator.hasMoreElements()){
|
||||
let cert = enumerator.getNext().QueryInterface(Ci.nsIX509Cert);
|
||||
let pem = getPEMString(cert);
|
||||
let trusted = certdb.isCertTrusted(cert, Ci.nsIX509Cert.CA_CERT, Ci.nsIX509CertDB.TRUSTED_SSL);
|
||||
certlist.push({name: cert.commonName, pem: pem, trusted: trusted});
|
||||
if (trusted) {
|
||||
certstring+=pem;
|
||||
}
|
||||
}
|
||||
|
||||
function save(path) {
|
||||
// https://developer.mozilla.org/en-US/Add-ons/Code_snippets/File_I_O
|
||||
Components.utils.import("resource://gre/modules/FileUtils.jsm");
|
||||
var file = new FileUtils.File(path);
|
||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
// file is nsIFile, data is a string
|
||||
|
||||
// You can also optionally pass a flags parameter here. It defaults to
|
||||
// FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE;
|
||||
var ostream = FileUtils.openSafeFileOutputStream(file);
|
||||
|
||||
var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].
|
||||
createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
|
||||
converter.charset = "UTF-8";
|
||||
var istream = converter.convertToInputStream(certstring);
|
||||
|
||||
// The last argument (the callback) is optional.
|
||||
NetUtil.asyncCopy(istream, ostream, function(status) {
|
||||
if (!Components.isSuccessCode(status)) {
|
||||
// Handle error!
|
||||
return;
|
||||
}
|
||||
|
||||
// Data has been written to the file.
|
||||
});
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# 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/.
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
# https://wiki.mozilla.org/CA/Included_Certificates
|
||||
# 1. Mozilla's official CA database CSV file is downloaded with curl
|
||||
# and processed with awk.
|
||||
# 2. Rows end with `"\n`.
|
||||
# 3. Each row is split by ^" and "," into columns.
|
||||
# 4. Single and double quotes are removed from column 32.
|
||||
# 5. If column 13 (12 in the csv file) contains `Websites`
|
||||
# (some are Email-only), column 32 is printed, the raw certificate.
|
||||
# 6. All CA certs trusted for Websites are stored into the `certs` file.
|
||||
|
||||
url="https://ccadb-public.secure.force.com/mozilla/IncludedCACertificateReportPEMCSV"
|
||||
curl "${url}" -sSf | gawk -v RS="\"\n" -F'","|^"' \
|
||||
'{gsub("\047","",$(32));gsub("\"","",$(32));if($(13)~/Websites/)print $(32)}' \
|
||||
> ../resources/certs
|
|
@ -188,15 +188,10 @@ class MachCommands(CommandBase):
|
|||
)
|
||||
assert os.path.exists(servo_exe_dir)
|
||||
|
||||
# on msvc, we need to copy in some DLLs in to the servo.exe dir and the directory for unit tests.
|
||||
for ssl_lib in ["libssl.dll", "libcrypto.dll"]:
|
||||
ssl_path = path.join(env['OPENSSL_LIB_DIR'], "../bin", ssl_lib)
|
||||
shutil.copy(ssl_path, servo_exe_dir)
|
||||
shutil.copy(ssl_path, path.join(servo_exe_dir, "deps"))
|
||||
|
||||
build_path = path.join(servo_exe_dir, "build")
|
||||
assert os.path.exists(build_path)
|
||||
|
||||
# on msvc, we need to copy in some DLLs in to the servo.exe dir and the directory for unit tests.
|
||||
def package_generated_shared_libraries(libs, build_path, servo_exe_dir):
|
||||
for root, dirs, files in os.walk(build_path):
|
||||
remaining_libs = list(libs)
|
||||
|
@ -265,16 +260,6 @@ class MachCommands(CommandBase):
|
|||
if not self.is_android_build:
|
||||
return
|
||||
|
||||
openssl_dir = os.path.join(self.target_path, "native", "openssl")
|
||||
if not os.path.exists(openssl_dir):
|
||||
os.makedirs(openssl_dir)
|
||||
shutil.copy(os.path.join(self.android_support_dir(), "openssl.makefile"), openssl_dir)
|
||||
shutil.copy(os.path.join(self.android_support_dir(), "openssl.sh"), openssl_dir)
|
||||
|
||||
status = call(["make", "-f", "openssl.makefile"], env=env, cwd=openssl_dir)
|
||||
if status:
|
||||
return status
|
||||
|
||||
# Build the name of the package containing all GStreamer dependencies
|
||||
# according to the build target.
|
||||
android_lib = self.config["android"]["lib"]
|
||||
|
|
|
@ -500,19 +500,6 @@ class CommandBase(object):
|
|||
env.setdefault("CC", "clang-cl.exe")
|
||||
env.setdefault("CXX", "clang-cl.exe")
|
||||
|
||||
arch = effective_target.split('-')[0]
|
||||
vcpkg_arch = {
|
||||
"x86_64": "x64-windows",
|
||||
"i686": "x86-windows",
|
||||
"aarch64": "arm64-windows",
|
||||
}
|
||||
target_arch = vcpkg_arch[arch]
|
||||
openssl_base_dir = path.join(self.msvc_package_dir("openssl"), target_arch)
|
||||
|
||||
# Link openssl
|
||||
env["OPENSSL_INCLUDE_DIR"] = path.join(openssl_base_dir, "include")
|
||||
env["OPENSSL_LIB_DIR"] = path.join(openssl_base_dir, "lib")
|
||||
env["OPENSSL_LIBS"] = "libssl:libcrypto"
|
||||
# Link moztools, used for building SpiderMonkey
|
||||
moztools_paths = [
|
||||
path.join(self.msvc_package_dir("moztools"), "bin"),
|
||||
|
@ -625,9 +612,6 @@ class CommandBase(object):
|
|||
android_lib = self.config["android"]["lib"]
|
||||
android_arch = self.config["android"]["arch"]
|
||||
|
||||
# Build OpenSSL for android
|
||||
env["OPENSSL_VERSION"] = "1.1.1d"
|
||||
|
||||
# Check if the NDK version is 15
|
||||
if not os.path.isfile(path.join(env["ANDROID_NDK"], 'source.properties')):
|
||||
print("ANDROID_NDK should have file `source.properties`.")
|
||||
|
@ -639,11 +623,6 @@ class CommandBase(object):
|
|||
print("Currently only support NDK 15. Please re-run `./mach bootstrap-android`.")
|
||||
sys.exit(1)
|
||||
|
||||
openssl_dir = path.join(
|
||||
self.target_path, "native", "openssl", "openssl-{}".format(env["OPENSSL_VERSION"]))
|
||||
env['OPENSSL_LIB_DIR'] = openssl_dir
|
||||
env['OPENSSL_INCLUDE_DIR'] = path.join(openssl_dir, "include")
|
||||
env['OPENSSL_STATIC'] = 'TRUE'
|
||||
# Android builds also require having the gcc bits on the PATH and various INCLUDE
|
||||
# path munging if you do not want to install a standalone NDK. See:
|
||||
# https://dxr.mozilla.org/mozilla-central/source/build/autoconf/android.m4#139-161
|
||||
|
|
|
@ -19,8 +19,7 @@ from .base import Base
|
|||
# Please keep these in sync with the packages in README.md
|
||||
APT_PKGS = ['git', 'curl', 'autoconf', 'libx11-dev', 'libfreetype6-dev',
|
||||
'libgl1-mesa-dri', 'libglib2.0-dev', 'xorg-dev', 'gperf', 'g++',
|
||||
'build-essential', 'cmake', 'libssl-dev',
|
||||
'liblzma-dev', 'libxmu6', 'libxmu-dev',
|
||||
'build-essential', 'cmake', 'liblzma-dev', 'libxmu6', 'libxmu-dev',
|
||||
"libxcb-render0-dev", "libxcb-shape0-dev", "libxcb-xfixes0-dev",
|
||||
'libgles2-mesa-dev', 'libegl1-mesa-dev', 'libdbus-1-dev',
|
||||
'libharfbuzz-dev', 'ccache', 'clang', 'libunwind-dev',
|
||||
|
@ -31,8 +30,7 @@ DNF_PKGS = ['libtool', 'gcc-c++', 'libXi-devel', 'freetype-devel',
|
|||
'libunwind-devel', 'mesa-libGL-devel', 'mesa-libEGL-devel',
|
||||
'glib2-devel', 'libX11-devel', 'libXrandr-devel', 'gperf',
|
||||
'fontconfig-devel', 'cabextract', 'ttmkfdir', 'expat-devel',
|
||||
'rpm-build', 'openssl-devel', 'cmake',
|
||||
'libXcursor-devel', 'libXmu-devel',
|
||||
'rpm-build', 'cmake', 'libXcursor-devel', 'libXmu-devel',
|
||||
'dbus-devel', 'ncurses-devel', 'harfbuzz-devel', 'ccache',
|
||||
'clang', 'clang-libs', 'llvm', 'autoconf213', 'python3-devel',
|
||||
'gstreamer1-devel', 'gstreamer1-plugins-base-devel',
|
||||
|
|
|
@ -21,7 +21,6 @@ DEPS_URL = "https://github.com/servo/servo-build-deps/releases/download/msvc-dep
|
|||
DEPENDENCIES = {
|
||||
"llvm": "15.0.5",
|
||||
"moztools": "3.2",
|
||||
"openssl": "111.3.0+1.1.1c-vs2017-2019-09-18",
|
||||
}
|
||||
|
||||
URL_BASE = "https://gstreamer.freedesktop.org/data/pkg/windows/1.16.0/"
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<p>${reason}</p>
|
||||
<button id="leave" onclick="history.back()">Go back (recommended)</button>
|
||||
<button id="allow">Allow certificate temporarily</button>
|
||||
<pre id="bytes">${bytes}</pre>
|
||||
<div style="word-break: break-all; font-family: monospace" id="bytes">${bytes}</div>
|
||||
<script>
|
||||
let bytes = document.getElementById('bytes').textContent;
|
||||
let button = document.getElementById('allow');
|
||||
|
@ -18,7 +18,7 @@
|
|||
xhr.onloadend = function() {
|
||||
location.reload(true);
|
||||
};
|
||||
xhr.send("${secret}&" + btoa(bytes));
|
||||
xhr.send("${secret}&${bytes}");
|
||||
};
|
||||
} else {
|
||||
button.style.display = "none";
|
||||
|
|
3501
resources/certs
3501
resources/certs
File diff suppressed because it is too large
Load diff
|
@ -48,6 +48,12 @@ packages = [
|
|||
"wayland-sys",
|
||||
"bitflags",
|
||||
|
||||
# Duplicated by rustls and image.
|
||||
"spin",
|
||||
|
||||
# Duplicated by rustls and the version of webpki-roots required by async_tungstenite.
|
||||
"rustls-webpki",
|
||||
|
||||
# https://github.com/servo/servo/issues/26933
|
||||
"bytes",
|
||||
"futures",
|
||||
|
@ -112,7 +118,6 @@ files = [
|
|||
# Long encoded string
|
||||
"./tests/wpt/mozilla/tests/mozilla/resources/brotli.py",
|
||||
"./tests/wpt/webgl/meta/MANIFEST.json",
|
||||
"./support/android/openssl.sh",
|
||||
# Upstream code from Khronos/WebGL uses tabs for indentation
|
||||
"./tests/wpt/webgl/tests",
|
||||
# Vendored from upstream
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
.PHONY: all
|
||||
all: openssl
|
||||
@: # No-op to silence the "make: Nothing to be done for 'all'." message.
|
||||
|
||||
# From https://wiki.openssl.org/index.php/Android
|
||||
.PHONY: openssl
|
||||
openssl: openssl-${OPENSSL_VERSION}/libssl.so
|
||||
|
||||
openssl-${OPENSSL_VERSION}/libssl.so: openssl-${OPENSSL_VERSION}/Configure
|
||||
./openssl.sh ${ANDROID_NDK} ${OPENSSL_VERSION}
|
||||
|
||||
openssl-${OPENSSL_VERSION}/Configure:
|
||||
URL=https://servo-deps-2.s3.amazonaws.com/android-deps/openssl-${OPENSSL_VERSION}.tar.gz; \
|
||||
curl $$URL | tar xzf -
|
|
@ -1,246 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
# Cross-compile environment for Android on ARMv7 and x86
|
||||
#
|
||||
# Contents licensed under the terms of the OpenSSL license
|
||||
# http://www.openssl.org/source/license.html
|
||||
#
|
||||
# See http://wiki.openssl.org/index.php/FIPS_Library_and_Android
|
||||
# and http://wiki.openssl.org/index.php/Android
|
||||
|
||||
#####################################################################
|
||||
|
||||
# Set ANDROID_NDK_ROOT to you NDK location. For example,
|
||||
# /opt/android-ndk-r8e or /opt/android-ndk-r9. This can be done in a
|
||||
# login script. If ANDROID_NDK_ROOT is not specified, the script will
|
||||
# try to pick it up with the value of _ANDROID_NDK_ROOT below. If
|
||||
# ANDROID_NDK_ROOT is set, then the value is ignored.
|
||||
# _ANDROID_NDK="android-ndk-r8e"
|
||||
_ANDROID_NDK="android-ndk-r9"
|
||||
# _ANDROID_NDK="android-ndk-r10"
|
||||
|
||||
# Set _ANDROID_EABI to the EABI you want to use. You can find the
|
||||
# list in $ANDROID_NDK_ROOT/toolchains. This value is always used.
|
||||
# _ANDROID_EABI="x86-4.6"
|
||||
# _ANDROID_EABI="arm-linux-androideabi-4.6"
|
||||
|
||||
# Set _ANDROID_ARCH to the architecture you are building for.
|
||||
# This value is always used.
|
||||
# _ANDROID_ARCH=arch-x86
|
||||
|
||||
|
||||
case $RUST_TARGET in
|
||||
armv7*)
|
||||
_ANDROID_TARGET="arm-linux-androideabi"
|
||||
_ANDROID_ARCH="arch-arm"
|
||||
_ANDROID_GCC="arm-linux-androideabi"
|
||||
_OPENSSL_MACHINE="armv7"
|
||||
_OPENSSL_ARCH="arm"
|
||||
_OPENSSL_CONFIG="linux-generic32"
|
||||
;;
|
||||
arm*)
|
||||
_ANDROID_TARGET=$RUST_TARGET
|
||||
_ANDROID_ARCH="arch-arm"
|
||||
_ANDROID_GCC="arm-linux-androideabi"
|
||||
_OPENSSL_MACHINE="arm"
|
||||
_OPENSSL_ARCH="arm"
|
||||
_OPENSSL_CONFIG="linux-generic32"
|
||||
;;
|
||||
aarch64*)
|
||||
_ANDROID_TARGET=$RUST_TARGET
|
||||
_ANDROID_ARCH="arch-arm64"
|
||||
_ANDROID_GCC="aarch64-linux-android"
|
||||
_OPENSSL_MACHINE="armv7"
|
||||
_OPENSSL_ARCH="arm64"
|
||||
_OPENSSL_CONFIG="linux-generic64 -DB_ENDIAN"
|
||||
;;
|
||||
x86* | i686*)
|
||||
_ANDROID_TARGET=$RUST_TARGET
|
||||
_ANDROID_ARCH="arch-x86"
|
||||
_ANDROID_GCC="x86"
|
||||
_OPENSSL_MACHINE="x86"
|
||||
_OPENSSL_ARCH="x86"
|
||||
_OPENSSL_CONFIG="linux-generic32"
|
||||
;;
|
||||
*)
|
||||
echo "Error: Invalid TARGET platform: $RUST_TARGET"
|
||||
;;
|
||||
esac
|
||||
|
||||
_ANDROID_EABI="llvm"
|
||||
|
||||
|
||||
# Set _ANDROID_API to the API you want to use. You should set it
|
||||
# to one of: android-14, android-9, android-8, android-14, android-5
|
||||
# android-4, or android-3. You can't set it to the latest (for
|
||||
# example, API-17) because the NDK does not supply the platform. At
|
||||
# Android 5.0, there will likely be another platform added (android-22?).
|
||||
# This value is always used.
|
||||
# _ANDROID_API="android-14"
|
||||
_ANDROID_API="$ANDROID_PLATFORM"
|
||||
# _ANDROID_API="android-19"
|
||||
|
||||
#####################################################################
|
||||
|
||||
# If the user did not specify the NDK location, try and pick it up.
|
||||
# We expect something like ANDROID_NDK_ROOT=/opt/android-ndk-r8e
|
||||
# or ANDROID_NDK_ROOT=/usr/local/android-ndk-r8e.
|
||||
export ANDROID_NDK_ROOT=$1
|
||||
echo $ANDROID_NDK_ROOT
|
||||
# Error checking
|
||||
# ANDROID_NDK_ROOT should always be set by the user (even when not running this script)
|
||||
# http://groups.google.com/group/android-ndk/browse_thread/thread/a998e139aca71d77
|
||||
if [ -z "$ANDROID_NDK_ROOT" ] || [ ! -d "$ANDROID_NDK_ROOT" ]; then
|
||||
echo "Error: ANDROID_NDK_ROOT is not a valid path. Please edit this script."
|
||||
echo "$ANDROID_NDK_ROOT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Error checking
|
||||
if [ ! -d "$ANDROID_NDK_ROOT/toolchains" ]; then
|
||||
echo "Error: ANDROID_NDK_ROOT/toolchains is not a valid path. Please edit this script."
|
||||
echo "$ANDROID_NDK_ROOT/toolchains"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Error checking
|
||||
if [ ! -d "$ANDROID_NDK_ROOT/toolchains/$_ANDROID_EABI" ]; then
|
||||
echo "Error: ANDROID_EABI is not a valid path. Please edit this script."
|
||||
echo "$ANDROID_NDK_ROOT/toolchains/$_ANDROID_EABI"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#####################################################################
|
||||
|
||||
# Based on ANDROID_NDK_ROOT, try and pick up the required toolchain. We expect something like:
|
||||
# /opt/android-ndk-r83/toolchains/arm-linux-androideabi-4.7/prebuilt/linux-x86_64/bin
|
||||
# Once we locate the toolchain, we add it to the PATH. Note: this is the 'hard way' of
|
||||
# doing things according to the NDK documentation for Ice Cream Sandwich.
|
||||
# https://android.googlesource.com/platform/ndk/+/ics-mr0/docs/STANDALONE-TOOLCHAIN.html
|
||||
|
||||
ANDROID_TOOLCHAIN=""
|
||||
ANDROID_GCC_TOOLCHAIN=""
|
||||
for host in "linux-x86_64" "linux-x86" "darwin-x86_64" "darwin-x86"
|
||||
do
|
||||
if [ -d "$ANDROID_NDK_ROOT/toolchains/$_ANDROID_EABI/prebuilt/$host/bin" ]; then
|
||||
ANDROID_TOOLCHAIN="$ANDROID_NDK_ROOT/toolchains/$_ANDROID_EABI/prebuilt/$host/bin"
|
||||
ANDROID_GCC_TOOLCHAIN="$ANDROID_NDK_ROOT/toolchains/$_ANDROID_GCC-4.9/prebuilt/$host/$_ANDROID_TARGET/bin"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Error checking
|
||||
if [ -z "$ANDROID_TOOLCHAIN" ] || [ ! -d "$ANDROID_TOOLCHAIN" ]; then
|
||||
echo "Error: ANDROID_TOOLCHAIN is not valid. Please edit this script."
|
||||
echo "$ANDROID_TOOLCHAIN"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ANDROID_TOOLS="clang"
|
||||
|
||||
for tool in $ANDROID_TOOLS
|
||||
do
|
||||
# Error checking
|
||||
if [ ! -e "$ANDROID_TOOLCHAIN/$tool" ]; then
|
||||
echo "Error: Failed to find $tool. Please edit this script."
|
||||
echo "$ANDROID_TOOLCHAIN/$tool"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
GCC_TOOLS="ar ranlib ld"
|
||||
|
||||
for tool in $GCC_TOOLS
|
||||
do
|
||||
# Error checking
|
||||
if [ ! -e "$ANDROID_GCC_TOOLCHAIN/$tool" ]; then
|
||||
echo "Error: Failed to find $tool. Please edit this script."
|
||||
echo "$ANDROID_GCC_TOOLCHAIN/$tool"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Only modify/export PATH if ANDROID_TOOLCHAIN good
|
||||
if [ ! -z "$ANDROID_TOOLCHAIN" ]; then
|
||||
export ANDROID_TOOLCHAIN="$ANDROID_TOOLCHAIN"
|
||||
export PATH="$ANDROID_TOOLCHAIN":"$ANDROID_GCC_TOOLCHAIN":"$PATH"
|
||||
fi
|
||||
|
||||
#####################################################################
|
||||
|
||||
# For the Android SYSROOT. Can be used on the command line with --sysroot
|
||||
# https://android.googlesource.com/platform/ndk/+/ics-mr0/docs/STANDALONE-TOOLCHAIN.html
|
||||
export ANDROID_SYSROOT="$ANDROID_NDK_ROOT/sysroot"
|
||||
export SYSROOT="$ANDROID_SYSROOT"
|
||||
export NDK_SYSROOT="$ANDROID_SYSROOT"
|
||||
|
||||
# Error checking
|
||||
if [ -z "$ANDROID_SYSROOT" ] || [ ! -d "$ANDROID_SYSROOT" ]; then
|
||||
echo "Error: ANDROID_SYSROOT is not valid. Please edit this script."
|
||||
echo "$ANDROID_SYSROOT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#####################################################################
|
||||
|
||||
#####################################################################
|
||||
|
||||
# Most of these should be OK (MACHINE, SYSTEM, ARCH). RELEASE is ignored.
|
||||
export MACHINE=$_OPENSSL_MACHINE
|
||||
export RELEASE=2.6.37
|
||||
export SYSTEM=android
|
||||
export ARCH=$_OPENSSL_ARCH
|
||||
#export CROSS_COMPILE="$_ANDROID_TARGET-"
|
||||
|
||||
# For the Android toolchain
|
||||
# https://android.googlesource.com/platform/ndk/+/ics-mr0/docs/STANDALONE-TOOLCHAIN.html
|
||||
export SYSROOT="$ANDROID_SYSROOT"
|
||||
#export CROSS_SYSROOT="$ANDROID_SYSROOT"
|
||||
export NDK_SYSROOT="$ANDROID_SYSROOT"
|
||||
export ANDROID_NDK_SYSROOT="$ANDROID_SYSROOT"
|
||||
export ANDROID_API="$_ANDROID_API"
|
||||
|
||||
# CROSS_COMPILE and ANDROID_DEV are DFW (Don't Fiddle With). Its used by OpenSSL build system.
|
||||
# export CROSS_COMPILE="arm-linux-androideabi-"
|
||||
export ANDROID_DEV="$ANDROID_NDK_ROOT/platforms/$_ANDROID_API/$_ANDROID_ARCH/usr"
|
||||
export HOSTCC=gcc
|
||||
export CC=clang
|
||||
export RANLIB="$ANDROID_GCC_TOOLCHAIN/ranlib"
|
||||
export AR="$ANDROID_GCC_TOOLCHAIN/ar"
|
||||
export LD="$ANDROID_GCC_TOOLCHAIN/ld"
|
||||
|
||||
# See https://github.com/cocochpie/android-openssl/blob/master/build-all-arch.sh
|
||||
#+xCFLAGS="-DSHARED_EXTENSION=.so -fPIC -DOPENSSL_PIC -DDSO_DLFCN -DHAVE_DLFCN_H -B$ANDROID_DEV/lib -O3 -fomit-frame-pointer -Wall -D__ANDROID_API__=18 --target=armv7a-none-linux-androideabi --gcc-toolchain=$ANDROID_NDK_ROOT/toolchains/$_ANDROID_TARGET-4.9/prebuilt/$host --sysroot=$ANDROID_SYSROOT -I$ANDROID_DEV/include -I$ANDROID_DEV/include/$_ANDROID_TARGET -L$ANDROID_NDK_ROOT/platforms/$_ANDROID_API/$_ANDROID_ARCH/usr/lib -B$ANDROID_NDK_ROOT/platforms/$_ANDROID_API/$_ANDROID_ARCH/usr/lib"
|
||||
|
||||
xCFLAGS="-DSHARED_EXTENSION=.so -DOPENSSL_PIC -DDSO_DLFCN -DHAVE_DLFCN_H \
|
||||
-fPIC -fomit-frame-pointer \
|
||||
-Wall -Wno-error=macro-redefined \
|
||||
-O3 \
|
||||
-I$ANDROID_SYSROOT/usr/include/$_ANDROID_TARGET \
|
||||
-I$ANDROID_DEV/include \
|
||||
-B$ANDROID_DEV/lib -B$ANDROID_NDK_ROOT/platforms/$_ANDROID_API/$_ANDROID_ARCH/usr/lib \
|
||||
-L$ANDROID_NDK_ROOT/platforms/$_ANDROID_API/$_ANDROID_ARCH/usr/lib -L$ANDROID_NDK_ROOT/toolchains/$_ANDROID_GCC-4.9/prebuilt/$host/lib/gcc/$_ANDROID_TARGET/4.9.x/ \
|
||||
--gcc-toolchain=$ANDROID_GCC_TOOLCHAIN \
|
||||
--sysroot=$ANDROID_SYSROOT \
|
||||
--target=$RUST_TARGET"
|
||||
|
||||
VERBOSE=1
|
||||
if [ ! -z "$VERBOSE" ] && [ "$VERBOSE" != "0" ]; then
|
||||
echo "ANDROID_NDK_ROOT: $ANDROID_NDK_ROOT"
|
||||
echo "ANDROID_ARCH: $_ANDROID_ARCH"
|
||||
echo "ANDROID_EABI: $_ANDROID_EABI"
|
||||
echo "ANDROID_API: $ANDROID_API"
|
||||
echo "ANDROID_SYSROOT: $ANDROID_SYSROOT"
|
||||
echo "ANDROID_TOOLCHAIN: $ANDROID_TOOLCHAIN"
|
||||
echo "FIPS_SIG: $FIPS_SIG"
|
||||
echo "CROSS_COMPILE: $CROSS_COMPILE"
|
||||
echo "ANDROID_DEV: $ANDROID_DEV"
|
||||
fi
|
||||
|
||||
cd openssl-$2
|
||||
perl -pi -e 's/install: all install_docs install_sw/install: install_docs install_sw/g' Makefile.org
|
||||
|
||||
# The code being built isn't maintained by us, so we redirect stderr to stdout
|
||||
# so that the warnings don't clutter up buildbot
|
||||
./Configure shared -no-ssl2 -no-ssl3 -no-comp -no-hw -no-engine --openssldir=/usr/local/ssl/$ANDROID_API $_OPENSSL_CONFIG $xCFLAGS 2>&1
|
||||
make depend 2>&1
|
||||
make all 2>&1
|
|
@ -464480,7 +464480,7 @@
|
|||
[]
|
||||
],
|
||||
"executorservo.py": [
|
||||
"89aaf00352f4142a311bb34c1d8dd57b8ff22b0c",
|
||||
"a8ec38699616c5baf7a3b43b8149b89746308f35",
|
||||
[]
|
||||
],
|
||||
"executorservodriver.py": [
|
||||
|
|
|
@ -38,6 +38,9 @@ def build_servo_command(test, test_url_func, browser, binary, pause_after_test,
|
|||
extra_args=None, debug_opts="replace-surrogates"):
|
||||
args = [
|
||||
"--hard-fail", "-u", "Servo/wptrunner",
|
||||
# See https://github.com/servo/servo/issues/30080.
|
||||
# For some reason rustls does not like the certificate generated by the WPT tooling.
|
||||
"--ignore-certificate-errors",
|
||||
"-z", test_url_func(test),
|
||||
]
|
||||
if debug_opts:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue