Skip to content

Commit 22c2e22

Browse files
committed
Skip proxies with MITM root certificates by setting RUSTUP_USE_UNSAFE_SSL environment variable
1 parent b697df1 commit 22c2e22

14 files changed

+249
-16
lines changed

Cargo.lock

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

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,12 @@ Command | Description
580580
- `RUSTUP_UPDATE_ROOT` (default `https://static.rust-lang.org/rustup`)
581581
Sets the root URL for downloading self-updates.
582582

583+
- `RUSTUP_USE_UNSAFE_SSL` (default: none)
584+
If set, rustup will not validate the SSL certificate when downloading
585+
files. This parameter should be used only in exceptional circumstances
586+
when youre computer is behind a corporate proxy that injects its own
587+
certificates into HTTPS connections.
588+
583589
## Other installation methods
584590

585591
The primary installation method, as described at

rustup-init.sh

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -385,13 +385,21 @@ downloader() {
385385
else
386386
_dld='curl or wget' # to be used in error message of need_cmd
387387
fi
388+
389+
if [ -n "$RUSTUP_USE_UNSAFE_SSL" ]; then
390+
_curl_unsafe = "--insecure"
391+
_wget_unsafe = "--no-check-certificate"
392+
else
393+
_curl_unsafe = ""
394+
_wget_unsafe = ""
395+
fi
388396

389397
if [ "$1" = --check ]; then
390398
need_cmd "$_dld"
391399
elif [ "$_dld" = curl ]; then
392-
curl -sSfL "$1" -o "$2"
400+
curl -sSfL "$_curl_unsafe" "$1" -o "$2"
393401
elif [ "$_dld" = wget ]; then
394-
wget "$1" -O "$2"
402+
wget "$1" "$_wget_unsafe" -O "$2"
395403
else
396404
err "Unknown downloader" # should not reach here
397405
fi

src/download/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,6 @@ reqwest = { version = "0.9", optional = true }
2626
futures = "0.1"
2727
hyper = "0.12"
2828
tempdir = "0.3.4"
29+
tokio = "0.1.11"
30+
tokio-tls = "0.2.1"
31+
native-tls = "0.2.1"

src/download/src/lib.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ extern crate lazy_static;
1010
#[cfg(feature = "reqwest-backend")]
1111
extern crate reqwest;
1212

13+
use std::env;
1314
use std::path::Path;
1415
use url::Url;
1516

@@ -128,6 +129,10 @@ pub fn download_to_path_with_backend(
128129
})
129130
}
130131

132+
fn use_unsafe_ssl() -> bool {
133+
env::var_os("RUSTUP_USE_UNSAFE_SSL").is_some()
134+
}
135+
131136
/// Download via libcurl; encrypt with the native (or OpenSSl) TLS
132137
/// stack via libcurl
133138
#[cfg(feature = "curl-backend")]
@@ -136,6 +141,7 @@ pub mod curl {
136141
extern crate curl;
137142

138143
use self::curl::easy::Easy;
144+
use super::use_unsafe_ssl;
139145
use super::Event;
140146
use crate::errors::*;
141147
use std::cell::RefCell;
@@ -175,6 +181,10 @@ pub mod curl {
175181
.connect_timeout(Duration::new(30, 0))
176182
.chain_err(|| "failed to set connect timeout")?;
177183

184+
handle
185+
.ssl_verify_peer(!use_unsafe_ssl())
186+
.chain_err(|| "failed to configure unsafe SSL mode")?;
187+
178188
{
179189
let cberr = RefCell::new(None);
180190
let mut transfer = handle.transfer();
@@ -254,6 +264,7 @@ pub mod curl {
254264
pub mod reqwest_be {
255265
extern crate env_proxy;
256266

267+
use super::use_unsafe_ssl;
257268
use super::Event;
258269
use crate::errors::*;
259270
use reqwest::{header, Client, Proxy, Response};
@@ -302,6 +313,7 @@ pub mod reqwest_be {
302313
.gzip(false)
303314
.proxy(Proxy::custom(env_proxy))
304315
.timeout(Duration::from_secs(30))
316+
.danger_accept_invalid_certs(use_unsafe_ssl())
305317
.build()
306318
};
307319

@@ -374,7 +386,7 @@ pub mod reqwest_be {
374386
pub mod curl {
375387

376388
use super::Event;
377-
use errors::*;
389+
use crate::errors::*;
378390
use url::Url;
379391

380392
pub fn download(
@@ -390,7 +402,7 @@ pub mod curl {
390402
pub mod reqwest_be {
391403

392404
use super::Event;
393-
use errors::*;
405+
use crate::errors::*;
394406
use url::Url;
395407

396408
pub fn download(

src/download/tests/download-curl-resume.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ fn callback_gets_all_data_as_if_the_download_happened_all_at_once() {
3434
let target_path = tmpdir.path().join("downloaded");
3535
write_file(&target_path, "123");
3636

37-
let addr = serve_file(b"xxx45".to_vec());
37+
let addr = serve_file(b"xxx45".to_vec(), false);
3838

3939
let from_url = format!("http://{}", addr).parse().unwrap();
4040

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#![cfg(feature = "curl-backend")]
2+
3+
use download::*;
4+
5+
mod support;
6+
use crate::support::{file_contents, serve_file, tmp_dir};
7+
8+
/// There are two separate files because this crate caches curl handles
9+
/// and all tests in one file use either the safe or the unsafe handle
10+
11+
#[test]
12+
fn downloading_with_no_certificate() {
13+
let tmpdir = tmp_dir();
14+
let target_path = tmpdir.path().join("downloaded");
15+
16+
let addr = serve_file(b"12345".to_vec(), false);
17+
let from_url = format!("http://{}", addr).parse().unwrap();
18+
19+
download_to_path_with_backend(Backend::Curl, &from_url, &target_path, false, None)
20+
.expect("Test download failed");
21+
22+
assert_eq!(file_contents(&target_path), "12345");
23+
}
24+
25+
#[test]
26+
#[should_panic]
27+
fn downloading_with_bad_certificate() {
28+
let tmpdir = tmp_dir();
29+
let target_path = tmpdir.path().join("downloaded");
30+
31+
let addr = serve_file(b"12345".to_vec(), true);
32+
let from_url = format!("https://{}", addr).parse().unwrap();
33+
34+
std::env::remove_var("RUSTUP_USE_UNSAFE_SSL");
35+
36+
assert_eq!(std::env::var_os("RUSTUP_USE_UNSAFE_SSL").is_none(), true);
37+
38+
download_to_path_with_backend(Backend::Curl, &from_url, &target_path, false, None)
39+
.expect("Test download failed");
40+
41+
assert_eq!(file_contents(&target_path), "12345");
42+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#![cfg(feature = "curl-backend")]
2+
3+
use download::*;
4+
5+
mod support;
6+
use crate::support::{file_contents, serve_file, tmp_dir};
7+
8+
/// There are two separate files because this crate caches reqwest handles
9+
/// and all tests in one file use either the safe or the unsafe handle
10+
11+
#[test]
12+
fn downloading_with_bad_certificate_unsafely() {
13+
let tmpdir = tmp_dir();
14+
let target_path = tmpdir.path().join("downloaded");
15+
16+
let addr = serve_file(b"12345".to_vec(), true);
17+
let from_url = format!("https://{}", addr).parse().unwrap();
18+
19+
std::env::set_var("RUSTUP_USE_UNSAFE_SSL", "1");
20+
21+
assert_eq!(std::env::var_os("RUSTUP_USE_UNSAFE_SSL").is_some(), true);
22+
23+
download_to_path_with_backend(Backend::Curl, &from_url, &target_path, false, None)
24+
.expect("Test download failed");
25+
26+
assert_eq!(file_contents(&target_path), "12345");
27+
}

src/download/tests/download-reqwest-resume.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ fn callback_gets_all_data_as_if_the_download_happened_all_at_once() {
3434
let target_path = tmpdir.path().join("downloaded");
3535
write_file(&target_path, "123");
3636

37-
let addr = serve_file(b"xxx45".to_vec());
37+
let addr = serve_file(b"xxx45".to_vec(), false);
3838

3939
let from_url = format!("http://{}", addr).parse().unwrap();
4040

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#![cfg(feature = "reqwest-backend")]
2+
3+
use download::*;
4+
5+
mod support;
6+
use crate::support::{file_contents, serve_file, tmp_dir};
7+
8+
/// There are two separate files because this crate caches reqwest handles
9+
/// and all tests in one file use either the safe or the unsafe handle
10+
11+
#[test]
12+
fn downloading_with_no_certificate() {
13+
let tmpdir = tmp_dir();
14+
let target_path = tmpdir.path().join("downloaded");
15+
16+
let addr = serve_file(b"12345".to_vec(), false);
17+
let from_url = format!("http://{}", addr).parse().unwrap();
18+
19+
download_to_path_with_backend(Backend::Reqwest, &from_url, &target_path, false, None)
20+
.expect("Test download failed");
21+
22+
assert_eq!(file_contents(&target_path), "12345");
23+
}
24+
25+
#[test]
26+
#[should_panic]
27+
fn downloading_with_bad_certificate() {
28+
let tmpdir = tmp_dir();
29+
let target_path = tmpdir.path().join("downloaded");
30+
31+
let addr = serve_file(b"12345".to_vec(), true);
32+
let from_url = format!("https://{}", addr).parse().unwrap();
33+
34+
std::env::remove_var("RUSTUP_USE_UNSAFE_SSL");
35+
36+
assert_eq!(std::env::var_os("RUSTUP_USE_UNSAFE_SSL").is_none(), true);
37+
38+
download_to_path_with_backend(Backend::Reqwest, &from_url, &target_path, false, None)
39+
.expect("Test download failed");
40+
41+
assert_eq!(file_contents(&target_path), "12345");
42+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#![cfg(feature = "reqwest-backend")]
2+
3+
use download::*;
4+
5+
mod support;
6+
use crate::support::{file_contents, serve_file, tmp_dir};
7+
8+
/// There are two separate files because this crate caches reqwest handles
9+
/// and all tests in one file use either the safe or the unsafe handle
10+
11+
#[test]
12+
fn downloading_with_bad_certificate_unsafely() {
13+
let tmpdir = tmp_dir();
14+
let target_path = tmpdir.path().join("downloaded");
15+
16+
let addr = serve_file(b"12345".to_vec(), true);
17+
let from_url = format!("https://{}", addr).parse().unwrap();
18+
19+
std::env::set_var("RUSTUP_USE_UNSAFE_SSL", "1");
20+
21+
assert_eq!(std::env::var_os("RUSTUP_USE_UNSAFE_SSL").is_some(), true);
22+
23+
download_to_path_with_backend(Backend::Reqwest, &from_url, &target_path, false, None)
24+
.expect("Test download failed");
25+
26+
assert_eq!(file_contents(&target_path), "12345");
27+
}

src/download/tests/support/cert.p12

2.35 KB
Binary file not shown.

src/download/tests/support/mod.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
extern crate futures;
2-
extern crate hyper;
3-
extern crate tempdir;
4-
51
use std::fs::{self, File};
62
use std::io::{self, Read};
73
use std::net::SocketAddr;
84
use std::path::Path;
95

10-
use self::futures::sync::oneshot;
11-
use self::tempdir::TempDir;
6+
use futures::sync::oneshot;
7+
use tempdir::TempDir;
8+
9+
mod tls_proxy;
10+
use tls_proxy::proxy;
1211

1312
pub fn tmp_dir() -> TempDir {
1413
TempDir::new("rustup-download-test-").expect("creating tempdir for test")
@@ -23,6 +22,7 @@ pub fn file_contents(path: &Path) -> String {
2322
result
2423
}
2524

25+
#[allow(dead_code)]
2626
pub fn write_file(path: &Path, contents: &str) {
2727
let mut file = fs::OpenOptions::new()
2828
.write(true)
@@ -36,11 +36,11 @@ pub fn write_file(path: &Path, contents: &str) {
3636
file.sync_data().expect("writing test data");
3737
}
3838

39-
pub fn serve_file(contents: Vec<u8>) -> SocketAddr {
40-
use self::futures::Future;
39+
pub fn serve_file(contents: Vec<u8>, use_ssl: bool) -> SocketAddr {
40+
use futures::Future;
4141
use std::thread;
4242

43-
let addr = ([127, 0, 0, 1], 0).into();
43+
let addr = ([0, 0, 0, 0], 0).into();
4444
let (addr_tx, addr_rx) = oneshot::channel();
4545

4646
thread::spawn(move || {
@@ -57,8 +57,14 @@ pub fn serve_file(contents: Vec<u8>) -> SocketAddr {
5757
addr_tx.send(addr).unwrap();
5858
hyper::rt::run(server.map_err(|e| panic!(e)));
5959
});
60+
6061
let addr = addr_rx.wait().unwrap();
61-
addr
62+
63+
if use_ssl {
64+
proxy(addr)
65+
} else {
66+
addr
67+
}
6268
}
6369

6470
fn serve_contents(

0 commit comments

Comments
 (0)