Skip to content

Commit 6c4d909

Browse files
committed
download: statically bundle relevant trust anchors
1 parent fcd02c0 commit 6c4d909

File tree

7 files changed

+287
-8
lines changed

7 files changed

+287
-8
lines changed

Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,9 @@ http-body-util = "0.1.0"
140140
hyper = { version = "1.0", default-features = false, features = ["server", "http1"] }
141141
hyper-util = { version = "0.1.1", features = ["tokio"] }
142142
proptest = "1.1.0"
143+
rustls-webpki = { version = "0.103.3" }
144+
tokio-rustls = "0.26.4"
145+
webpki-root-certs = "1"
143146

144147
[build-dependencies]
145148
platforms = "3.4"

src/anchors.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// @generated by tests/static_roots.rs
2+
use rustls::pki_types::CertificateDer;
3+
4+
pub(crate) const RUSTUP_TRUST_ANCHORS: &[CertificateDer<'static>] = &[
5+
CertificateDer::from_slice(&[
6+
48, 130, 3, 95, 48, 130, 2, 71, 160, 3, 2, 1, 2, 2, 11, 4, 0, 0, 0, 0, 1, 33, 88, 83, 8,
7+
162, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 11, 5, 0, 48, 76, 49, 32, 48, 30, 6, 3,
8+
85, 4, 11, 19, 23, 71, 108, 111, 98, 97, 108, 83, 105, 103, 110, 32, 82, 111, 111, 116, 32,
9+
67, 65, 32, 45, 32, 82, 51, 49, 19, 48, 17, 6, 3, 85, 4, 10, 19, 10, 71, 108, 111, 98, 97,
10+
108, 83, 105, 103, 110, 49, 19, 48, 17, 6, 3, 85, 4, 3, 19, 10, 71, 108, 111, 98, 97, 108,
11+
83, 105, 103, 110, 48, 30, 23, 13, 48, 57, 48, 51, 49, 56, 49, 48, 48, 48, 48, 48, 90, 23,
12+
13, 50, 57, 48, 51, 49, 56, 49, 48, 48, 48, 48, 48, 90, 48, 76, 49, 32, 48, 30, 6, 3, 85,
13+
4, 11, 19, 23, 71, 108, 111, 98, 97, 108, 83, 105, 103, 110, 32, 82, 111, 111, 116, 32, 67,
14+
65, 32, 45, 32, 82, 51, 49, 19, 48, 17, 6, 3, 85, 4, 10, 19, 10, 71, 108, 111, 98, 97, 108,
15+
83, 105, 103, 110, 49, 19, 48, 17, 6, 3, 85, 4, 3, 19, 10, 71, 108, 111, 98, 97, 108, 83,
16+
105, 103, 110, 48, 130, 1, 34, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3,
17+
130, 1, 15, 0, 48, 130, 1, 10, 2, 130, 1, 1, 0, 204, 37, 118, 144, 121, 6, 120, 34, 22,
18+
245, 192, 131, 182, 132, 202, 40, 158, 253, 5, 118, 17, 197, 173, 136, 114, 252, 70, 2, 67,
19+
199, 178, 138, 157, 4, 95, 36, 203, 46, 75, 225, 96, 130, 70, 225, 82, 171, 12, 129, 71,
20+
112, 108, 221, 100, 209, 235, 245, 44, 163, 15, 130, 61, 12, 43, 174, 151, 215, 182, 20,
21+
134, 16, 121, 187, 59, 19, 128, 119, 140, 8, 225, 73, 210, 106, 98, 47, 31, 94, 250, 150,
22+
104, 223, 137, 39, 149, 56, 159, 6, 215, 62, 201, 203, 38, 89, 13, 115, 222, 176, 200, 233,
23+
38, 14, 131, 21, 198, 239, 91, 139, 210, 4, 96, 202, 73, 166, 40, 246, 105, 59, 246, 203,
24+
200, 40, 145, 229, 157, 138, 97, 87, 55, 172, 116, 20, 220, 116, 224, 58, 238, 114, 47, 46,
25+
156, 251, 208, 187, 191, 245, 61, 0, 225, 6, 51, 232, 130, 43, 174, 83, 166, 58, 22, 115,
26+
140, 221, 65, 14, 32, 58, 192, 180, 167, 161, 233, 178, 79, 144, 46, 50, 96, 233, 87, 203,
27+
185, 4, 146, 104, 104, 229, 56, 38, 96, 117, 178, 159, 119, 255, 145, 20, 239, 174, 32, 73,
28+
252, 173, 64, 21, 72, 209, 2, 49, 97, 25, 94, 184, 151, 239, 173, 119, 183, 100, 154, 122,
29+
191, 95, 193, 19, 239, 155, 98, 251, 13, 108, 224, 84, 105, 22, 169, 3, 218, 110, 233, 131,
30+
147, 113, 118, 198, 105, 133, 130, 23, 2, 3, 1, 0, 1, 163, 66, 48, 64, 48, 14, 6, 3, 85,
31+
29, 15, 1, 1, 255, 4, 4, 3, 2, 1, 6, 48, 15, 6, 3, 85, 29, 19, 1, 1, 255, 4, 5, 48, 3, 1,
32+
1, 255, 48, 29, 6, 3, 85, 29, 14, 4, 22, 4, 20, 143, 240, 75, 127, 168, 46, 69, 36, 174,
33+
77, 80, 250, 99, 154, 139, 222, 226, 221, 27, 188, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13,
34+
1, 1, 11, 5, 0, 3, 130, 1, 1, 0, 75, 64, 219, 192, 80, 170, 254, 200, 12, 239, 247, 150,
35+
84, 69, 73, 187, 150, 0, 9, 65, 172, 179, 19, 134, 134, 40, 7, 51, 202, 107, 230, 116, 185,
36+
186, 0, 45, 174, 164, 10, 211, 245, 241, 241, 15, 138, 191, 115, 103, 74, 131, 199, 68,
37+
123, 120, 224, 175, 110, 108, 111, 3, 41, 142, 51, 57, 69, 195, 142, 228, 185, 87, 108,
38+
170, 252, 18, 150, 236, 83, 198, 45, 228, 36, 108, 185, 148, 99, 251, 220, 83, 104, 103,
39+
86, 62, 131, 184, 207, 53, 33, 195, 201, 104, 254, 206, 218, 194, 83, 170, 204, 144, 138,
40+
233, 240, 93, 70, 140, 149, 221, 122, 88, 40, 26, 47, 29, 222, 205, 0, 55, 65, 143, 237,
41+
68, 109, 215, 83, 40, 151, 126, 243, 103, 4, 30, 21, 215, 138, 150, 180, 211, 222, 76, 39,
42+
164, 76, 27, 115, 115, 118, 244, 23, 153, 194, 31, 122, 14, 227, 45, 8, 173, 10, 28, 44,
43+
255, 60, 171, 85, 14, 15, 145, 126, 54, 235, 195, 87, 73, 190, 225, 46, 45, 124, 96, 139,
44+
195, 65, 81, 19, 35, 157, 206, 247, 50, 107, 148, 1, 168, 153, 231, 44, 51, 31, 58, 59, 37,
45+
210, 134, 64, 206, 59, 44, 134, 120, 201, 97, 47, 20, 186, 238, 219, 85, 111, 223, 132,
46+
238, 5, 9, 77, 189, 40, 216, 114, 206, 211, 98, 80, 101, 30, 235, 146, 151, 131, 49, 217,
47+
179, 181, 202, 71, 88, 63, 95,
48+
]),
49+
CertificateDer::from_slice(&[
50+
48, 130, 3, 65, 48, 130, 2, 41, 160, 3, 2, 1, 2, 2, 19, 6, 108, 159, 207, 153, 191, 140,
51+
10, 57, 226, 240, 120, 138, 67, 230, 150, 54, 91, 202, 48, 13, 6, 9, 42, 134, 72, 134, 247,
52+
13, 1, 1, 11, 5, 0, 48, 57, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 15, 48, 13,
53+
6, 3, 85, 4, 10, 19, 6, 65, 109, 97, 122, 111, 110, 49, 25, 48, 23, 6, 3, 85, 4, 3, 19, 16,
54+
65, 109, 97, 122, 111, 110, 32, 82, 111, 111, 116, 32, 67, 65, 32, 49, 48, 30, 23, 13, 49,
55+
53, 48, 53, 50, 54, 48, 48, 48, 48, 48, 48, 90, 23, 13, 51, 56, 48, 49, 49, 55, 48, 48, 48,
56+
48, 48, 48, 90, 48, 57, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 15, 48, 13, 6, 3,
57+
85, 4, 10, 19, 6, 65, 109, 97, 122, 111, 110, 49, 25, 48, 23, 6, 3, 85, 4, 3, 19, 16, 65,
58+
109, 97, 122, 111, 110, 32, 82, 111, 111, 116, 32, 67, 65, 32, 49, 48, 130, 1, 34, 48, 13,
59+
6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 130, 1, 15, 0, 48, 130, 1, 10, 2, 130,
60+
1, 1, 0, 178, 120, 128, 113, 202, 120, 213, 227, 113, 175, 71, 128, 80, 116, 125, 110, 216,
61+
215, 136, 118, 244, 153, 104, 247, 88, 33, 96, 249, 116, 132, 1, 47, 172, 2, 45, 134, 211,
62+
160, 67, 122, 78, 178, 164, 208, 54, 186, 1, 190, 141, 219, 72, 200, 7, 23, 54, 76, 244,
63+
238, 136, 35, 199, 62, 235, 55, 245, 181, 25, 248, 73, 104, 176, 222, 215, 185, 118, 56,
64+
29, 97, 158, 164, 254, 130, 54, 165, 229, 74, 86, 228, 69, 225, 249, 253, 180, 22, 250,
65+
116, 218, 156, 155, 53, 57, 47, 250, 176, 32, 80, 6, 108, 122, 208, 128, 178, 166, 249,
66+
175, 236, 71, 25, 143, 80, 56, 7, 220, 162, 135, 57, 88, 248, 186, 213, 169, 249, 72, 103,
67+
48, 150, 238, 148, 120, 94, 111, 137, 163, 81, 192, 48, 134, 102, 161, 69, 102, 186, 84,
68+
235, 163, 195, 145, 249, 72, 220, 255, 209, 232, 48, 45, 125, 45, 116, 112, 53, 215, 136,
69+
36, 247, 158, 196, 89, 110, 187, 115, 135, 23, 242, 50, 70, 40, 184, 67, 250, 183, 29, 170,
70+
202, 180, 242, 159, 36, 14, 45, 75, 247, 113, 92, 94, 105, 255, 234, 149, 2, 203, 56, 138,
71+
174, 80, 56, 111, 219, 251, 45, 98, 27, 197, 199, 30, 84, 225, 119, 224, 103, 200, 15, 156,
72+
135, 35, 214, 63, 64, 32, 127, 32, 128, 196, 128, 76, 62, 59, 36, 38, 142, 4, 174, 108,
73+
154, 200, 170, 13, 2, 3, 1, 0, 1, 163, 66, 48, 64, 48, 15, 6, 3, 85, 29, 19, 1, 1, 255, 4,
74+
5, 48, 3, 1, 1, 255, 48, 14, 6, 3, 85, 29, 15, 1, 1, 255, 4, 4, 3, 2, 1, 134, 48, 29, 6, 3,
75+
85, 29, 14, 4, 22, 4, 20, 132, 24, 204, 133, 52, 236, 188, 12, 148, 148, 46, 8, 89, 156,
76+
199, 178, 16, 78, 10, 8, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 11, 5, 0, 3, 130,
77+
1, 1, 0, 152, 242, 55, 90, 65, 144, 161, 26, 197, 118, 81, 40, 32, 54, 35, 14, 174, 230,
78+
40, 187, 170, 248, 148, 174, 72, 164, 48, 127, 27, 252, 36, 141, 75, 180, 200, 161, 151,
79+
246, 182, 241, 122, 112, 200, 83, 147, 204, 8, 40, 227, 152, 37, 207, 35, 164, 249, 222,
80+
33, 211, 124, 133, 9, 173, 78, 154, 117, 58, 194, 11, 106, 137, 120, 118, 68, 71, 24, 101,
81+
108, 141, 65, 142, 59, 127, 154, 203, 244, 181, 167, 80, 215, 5, 44, 55, 232, 3, 75, 173,
82+
233, 97, 160, 2, 110, 245, 242, 240, 197, 178, 237, 91, 183, 220, 250, 148, 92, 119, 158,
83+
19, 165, 127, 82, 173, 149, 242, 248, 147, 59, 222, 139, 92, 91, 202, 90, 82, 91, 96, 175,
84+
20, 247, 75, 239, 163, 251, 159, 64, 149, 109, 49, 84, 252, 66, 211, 199, 70, 31, 35, 173,
85+
217, 15, 72, 112, 154, 217, 117, 120, 113, 209, 114, 67, 52, 117, 110, 87, 89, 194, 2, 92,
86+
38, 96, 41, 207, 35, 25, 22, 142, 136, 67, 165, 212, 228, 203, 8, 251, 35, 17, 67, 232, 67,
87+
41, 114, 98, 161, 169, 93, 94, 8, 212, 144, 174, 184, 216, 206, 20, 194, 208, 85, 242, 134,
88+
246, 196, 147, 67, 119, 102, 97, 192, 185, 232, 65, 215, 151, 120, 96, 3, 110, 74, 114,
89+
174, 165, 209, 125, 186, 16, 158, 134, 108, 27, 138, 185, 89, 51, 248, 235, 196, 144, 190,
90+
241, 185,
91+
]),
92+
];

src/download/mod.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -546,12 +546,14 @@ mod reqwest_be {
546546
use std::sync::{Arc, OnceLock};
547547
use std::time::Duration;
548548

549+
#[cfg(feature = "reqwest-rustls-tls")]
550+
use crate::anchors::RUSTUP_TRUST_ANCHORS;
549551
use anyhow::{Context, anyhow};
550552
use reqwest::{Client, ClientBuilder, Proxy, Response, header};
551553
#[cfg(feature = "reqwest-rustls-tls")]
552554
use rustls::crypto::aws_lc_rs;
553555
#[cfg(feature = "reqwest-rustls-tls")]
554-
use rustls_platform_verifier::BuilderVerifierExt;
556+
use rustls_platform_verifier::Verifier;
555557
use tokio_stream::StreamExt;
556558
use url::Url;
557559

@@ -607,15 +609,19 @@ mod reqwest_be {
607609
return Ok(client);
608610
}
609611

610-
let mut tls_config =
611-
rustls::ClientConfig::builder_with_provider(Arc::new(aws_lc_rs::default_provider()))
612-
.with_safe_default_protocol_versions()
613-
.unwrap()
614-
.with_platform_verifier()
612+
let provider = Arc::new(aws_lc_rs::default_provider());
613+
let verifier =
614+
Verifier::new_with_extra_roots(RUSTUP_TRUST_ANCHORS.iter().cloned(), provider.clone())
615615
.map_err(|err| {
616616
DownloadError::Message(format!("failed to initialize platform verifier: {err}"))
617-
})?
618-
.with_no_client_auth();
617+
})?;
618+
619+
let mut tls_config = rustls::ClientConfig::builder_with_provider(provider)
620+
.with_safe_default_protocol_versions()
621+
.unwrap()
622+
.dangerous() // We're using a rustls verifier, so it's okay
623+
.with_custom_certificate_verifier(Arc::new(verifier))
624+
.with_no_client_auth();
619625
tls_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
620626

621627
let client = client_generic()

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ fn component_for_bin(binary: &str) -> Option<&'static str> {
7070

7171
#[macro_use]
7272
pub mod cli;
73+
#[cfg(feature = "reqwest-rustls-tls")]
74+
mod anchors;
7375
mod command;
7476
mod config;
7577
mod diskio;

tests/suite/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ mod cli_v1;
1010
mod cli_v2;
1111
mod dist_install;
1212
mod known_triples;
13+
mod static_roots;

tests/suite/static_roots.rs

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
//! Connects to a known set of `HOSTS`, captures the root certificates for the
2+
//! certificate chain presented, and writes them to `src/anchors.rs` in a way
3+
//! that is easy to consume for use as `extra_roots` in rustls-platform-verifier.
4+
5+
use std::{
6+
fs,
7+
process::Command,
8+
sync::{Arc, Mutex},
9+
};
10+
11+
use rustls::{
12+
DigitallySignedStruct, Error, RootCertStore, SignatureScheme,
13+
client::{
14+
WebPkiServerVerifier,
15+
danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
16+
},
17+
crypto::{CryptoProvider, aws_lc_rs},
18+
pki_types::{CertificateDer, ServerName, TrustAnchor, UnixTime},
19+
};
20+
use tempfile::NamedTempFile;
21+
use tokio::net::TcpStream;
22+
use tokio_rustls::TlsConnector;
23+
use webpki::{EndEntityCert, anchor_from_trusted_cert};
24+
use webpki_root_certs::TLS_SERVER_ROOT_CERTS;
25+
26+
#[tokio::test]
27+
async fn store_static_roots() {
28+
let provider = Arc::new(aws_lc_rs::default_provider());
29+
let mut root_store = RootCertStore::empty();
30+
let mut roots = Vec::with_capacity(TLS_SERVER_ROOT_CERTS.len());
31+
for cert_der in TLS_SERVER_ROOT_CERTS {
32+
let ta = anchor_from_trusted_cert(cert_der).unwrap();
33+
roots.push((cert_der, ta.clone()));
34+
root_store.roots.push(ta);
35+
}
36+
37+
let root_store = Arc::new(root_store);
38+
let inner = WebPkiServerVerifier::builder_with_provider(root_store.clone(), provider.clone())
39+
.build()
40+
.unwrap();
41+
42+
let verifier = Arc::new(TrackRootVerifier {
43+
root: Mutex::default(),
44+
roots: root_store,
45+
inner,
46+
provider: provider.clone(),
47+
});
48+
49+
let config = Arc::new(
50+
rustls::ClientConfig::builder_with_provider(provider)
51+
.with_safe_default_protocol_versions()
52+
.unwrap()
53+
.dangerous()
54+
.with_custom_certificate_verifier(verifier.clone())
55+
.with_no_client_auth(),
56+
);
57+
58+
let mut code = "// @generated by tests/static_roots.rs\n".to_string();
59+
code.push_str("use rustls::pki_types::CertificateDer;\n\n");
60+
code.push_str("pub(crate) const RUSTUP_TRUST_ANCHORS: &[CertificateDer<'static>] = &[\n");
61+
let connector = TlsConnector::from(config);
62+
for &host in HOSTS {
63+
connector
64+
.connect(
65+
ServerName::try_from(host).unwrap(),
66+
TcpStream::connect((host, 443)).await.unwrap(),
67+
)
68+
.await
69+
.unwrap();
70+
71+
let root = verifier.root.lock().unwrap().take().unwrap();
72+
let root_cert = roots
73+
.iter()
74+
.find_map(|(cert_der, ta)| match ta == &root {
75+
true => Some(cert_der),
76+
false => None,
77+
})
78+
.unwrap();
79+
80+
code.push_str(&format!(
81+
" CertificateDer::from_slice(&{:?}),\n",
82+
root_cert.as_ref()
83+
));
84+
}
85+
code.push_str("];\n");
86+
87+
let tmp = NamedTempFile::new().unwrap();
88+
fs::write(&tmp, &code).unwrap();
89+
Command::new("rustfmt").arg(tmp.path()).status().unwrap();
90+
let new = fs::read_to_string(&tmp).unwrap();
91+
92+
let old = fs::read_to_string(PATH).unwrap();
93+
if old != new {
94+
fs::rename(tmp.path(), PATH).unwrap();
95+
panic!("anchors.rs is outdated; updated it");
96+
}
97+
}
98+
99+
const PATH: &str = "src/anchors.rs";
100+
101+
#[derive(Debug)]
102+
struct TrackRootVerifier {
103+
root: Mutex<Option<TrustAnchor<'static>>>,
104+
inner: Arc<WebPkiServerVerifier>,
105+
roots: Arc<RootCertStore>,
106+
provider: Arc<CryptoProvider>,
107+
}
108+
109+
impl ServerCertVerifier for TrackRootVerifier {
110+
fn verify_server_cert(
111+
&self,
112+
end_entity: &CertificateDer<'_>,
113+
intermediates: &[CertificateDer<'_>],
114+
server_name: &ServerName<'_>,
115+
ocsp_response: &[u8],
116+
now: UnixTime,
117+
) -> Result<ServerCertVerified, Error> {
118+
let verified = self.inner.verify_server_cert(
119+
end_entity,
120+
intermediates,
121+
server_name,
122+
ocsp_response,
123+
now,
124+
)?;
125+
126+
let cert = EndEntityCert::try_from(end_entity)
127+
.map_err(|e| Error::General(format!("invalid end entity certificate: {e}")))?;
128+
129+
let path = cert
130+
.verify_for_usage(
131+
&self.provider.signature_verification_algorithms.all,
132+
&self.roots.roots,
133+
intermediates,
134+
now,
135+
webpki::KeyUsage::server_auth(),
136+
None,
137+
None,
138+
)
139+
.unwrap();
140+
141+
let mut root = self.root.lock().unwrap();
142+
*root = Some(path.anchor().to_owned());
143+
Ok(verified)
144+
}
145+
146+
fn verify_tls12_signature(
147+
&self,
148+
message: &[u8],
149+
cert: &CertificateDer<'_>,
150+
dss: &DigitallySignedStruct,
151+
) -> Result<HandshakeSignatureValid, Error> {
152+
self.inner.verify_tls12_signature(message, cert, dss)
153+
}
154+
155+
fn verify_tls13_signature(
156+
&self,
157+
message: &[u8],
158+
cert: &CertificateDer<'_>,
159+
dss: &DigitallySignedStruct,
160+
) -> Result<HandshakeSignatureValid, Error> {
161+
self.inner.verify_tls13_signature(message, cert, dss)
162+
}
163+
164+
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
165+
self.inner.supported_verify_schemes()
166+
}
167+
}
168+
169+
const HOSTS: &[&str] = &[
170+
"fastly-static.rust-lang.org",
171+
"cloudfront-static.rust-lang.org",
172+
];

0 commit comments

Comments
 (0)