Skip to content

Commit

Permalink
Skip proxies with MITM root certificates by setting RUSTUP_USE_UNSAFE…
Browse files Browse the repository at this point in the history
…_SSL environment variable
  • Loading branch information
orthoxerox committed Feb 3, 2019
1 parent b697df1 commit 1e6c852
Show file tree
Hide file tree
Showing 14 changed files with 252 additions and 16 deletions.
14 changes: 14 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,12 @@ Command | Description
- `RUSTUP_UPDATE_ROOT` (default `https://static.rust-lang.org/rustup`)
Sets the root URL for downloading self-updates.

- `RUSTUP_USE_UNSAFE_SSL` (default: none)
If set, rustup will not validate the SSL certificate when downloading
files. This parameter should be used only in exceptional circumstances
when youre computer is behind a corporate proxy that injects its own
certificates into HTTPS connections.

## Other installation methods

The primary installation method, as described at
Expand Down
12 changes: 10 additions & 2 deletions rustup-init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -385,13 +385,21 @@ downloader() {
else
_dld='curl or wget' # to be used in error message of need_cmd
fi

if [ -n "$RUSTUP_USE_UNSAFE_SSL" ]; then
_curl_unsafe = "--insecure"
_wget_unsafe = "--no-check-certificate"
else
_curl_unsafe = ""
_wget_unsafe = ""
fi

if [ "$1" = --check ]; then
need_cmd "$_dld"
elif [ "$_dld" = curl ]; then
curl -sSfL "$1" -o "$2"
curl -sSfL "$_curl_unsafe" "$1" -o "$2"
elif [ "$_dld" = wget ]; then
wget "$1" -O "$2"
wget "$1" "$_wget_unsafe" -O "$2"
else
err "Unknown downloader" # should not reach here
fi
Expand Down
3 changes: 3 additions & 0 deletions src/download/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,6 @@ reqwest = { version = "0.9", optional = true }
futures = "0.1"
hyper = "0.12"
tempdir = "0.3.4"
tokio = "0.1.11"
tokio-tls = "0.2.1"
native-tls = "0.2.1"
16 changes: 14 additions & 2 deletions src/download/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ extern crate lazy_static;
#[cfg(feature = "reqwest-backend")]
extern crate reqwest;

use std::env;
use std::path::Path;
use url::Url;

Expand Down Expand Up @@ -128,6 +129,10 @@ pub fn download_to_path_with_backend(
})
}

fn use_unsafe_ssl() -> bool {
env::var_os("RUSTUP_USE_UNSAFE_SSL").is_some()
}

/// Download via libcurl; encrypt with the native (or OpenSSl) TLS
/// stack via libcurl
#[cfg(feature = "curl-backend")]
Expand All @@ -136,6 +141,7 @@ pub mod curl {
extern crate curl;

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

handle
.ssl_verify_peer(!use_unsafe_ssl())
.chain_err(|| "failed to configure unsafe SSL mode")?;

{
let cberr = RefCell::new(None);
let mut transfer = handle.transfer();
Expand Down Expand Up @@ -254,6 +264,7 @@ pub mod curl {
pub mod reqwest_be {
extern crate env_proxy;

use super::use_unsafe_ssl;
use super::Event;
use crate::errors::*;
use reqwest::{header, Client, Proxy, Response};
Expand Down Expand Up @@ -302,6 +313,7 @@ pub mod reqwest_be {
.gzip(false)
.proxy(Proxy::custom(env_proxy))
.timeout(Duration::from_secs(30))
.danger_accept_invalid_certs(use_unsafe_ssl())
.build()
};

Expand Down Expand Up @@ -374,7 +386,7 @@ pub mod reqwest_be {
pub mod curl {

use super::Event;
use errors::*;
use crate::errors::*;
use url::Url;

pub fn download(
Expand All @@ -390,7 +402,7 @@ pub mod curl {
pub mod reqwest_be {

use super::Event;
use errors::*;
use crate::errors::*;
use url::Url;

pub fn download(
Expand Down
2 changes: 1 addition & 1 deletion src/download/tests/download-curl-resume.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn callback_gets_all_data_as_if_the_download_happened_all_at_once() {
let target_path = tmpdir.path().join("downloaded");
write_file(&target_path, "123");

let addr = serve_file(b"xxx45".to_vec());
let addr = serve_file(b"xxx45".to_vec(), false);

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

Expand Down
42 changes: 42 additions & 0 deletions src/download/tests/download-curl-safe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#![cfg(feature = "curl-backend")]

use download::*;

mod support;
use crate::support::{file_contents, serve_file, tmp_dir};

/// There are two separate files because this crate caches curl handles
/// and all tests in one file use either the safe or the unsafe handle

#[test]
fn downloading_with_no_certificate() {
let tmpdir = tmp_dir();
let target_path = tmpdir.path().join("downloaded");

let addr = serve_file(b"12345".to_vec(), false);
let from_url = format!("http://{}", addr).parse().unwrap();

download_to_path_with_backend(Backend::Curl, &from_url, &target_path, false, None)
.expect("Test download failed");

assert_eq!(file_contents(&target_path), "12345");
}

#[test]
#[should_panic]
fn downloading_with_bad_certificate() {
let tmpdir = tmp_dir();
let target_path = tmpdir.path().join("downloaded");

let addr = serve_file(b"12345".to_vec(), true);
let from_url = format!("https://{}", addr).parse().unwrap();

std::env::remove_var("RUSTUP_USE_UNSAFE_SSL");

assert_eq!(std::env::var_os("RUSTUP_USE_UNSAFE_SSL").is_none(), true);

download_to_path_with_backend(Backend::Curl, &from_url, &target_path, false, None)
.expect("Test download failed");

assert_eq!(file_contents(&target_path), "12345");
}
27 changes: 27 additions & 0 deletions src/download/tests/download-curl-unsafe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#![cfg(feature = "curl-backend")]

use download::*;

mod support;
use crate::support::{file_contents, serve_file, tmp_dir};

/// There are two separate files because this crate caches reqwest handles
/// and all tests in one file use either the safe or the unsafe handle

#[test]
fn downloading_with_bad_certificate_unsafely() {
let tmpdir = tmp_dir();
let target_path = tmpdir.path().join("downloaded");

let addr = serve_file(b"12345".to_vec(), true);
let from_url = format!("https://{}", addr).parse().unwrap();

std::env::set_var("RUSTUP_USE_UNSAFE_SSL", "1");

assert_eq!(std::env::var_os("RUSTUP_USE_UNSAFE_SSL").is_some(), true);

download_to_path_with_backend(Backend::Curl, &from_url, &target_path, false, None)
.expect("Test download failed");

assert_eq!(file_contents(&target_path), "12345");
}
2 changes: 1 addition & 1 deletion src/download/tests/download-reqwest-resume.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn callback_gets_all_data_as_if_the_download_happened_all_at_once() {
let target_path = tmpdir.path().join("downloaded");
write_file(&target_path, "123");

let addr = serve_file(b"xxx45".to_vec());
let addr = serve_file(b"xxx45".to_vec(), false);

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

Expand Down
42 changes: 42 additions & 0 deletions src/download/tests/download-reqwest-safe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#![cfg(feature = "reqwest-backend")]

use download::*;

mod support;
use crate::support::{file_contents, serve_file, tmp_dir};

/// There are two separate files because this crate caches reqwest handles
/// and all tests in one file use either the safe or the unsafe handle

#[test]
fn downloading_with_no_certificate() {
let tmpdir = tmp_dir();
let target_path = tmpdir.path().join("downloaded");

let addr = serve_file(b"12345".to_vec(), false);
let from_url = format!("http://{}", addr).parse().unwrap();

download_to_path_with_backend(Backend::Reqwest, &from_url, &target_path, false, None)
.expect("Test download failed");

assert_eq!(file_contents(&target_path), "12345");
}

#[test]
#[should_panic]
fn downloading_with_bad_certificate() {
let tmpdir = tmp_dir();
let target_path = tmpdir.path().join("downloaded");

let addr = serve_file(b"12345".to_vec(), true);
let from_url = format!("https://{}", addr).parse().unwrap();

std::env::remove_var("RUSTUP_USE_UNSAFE_SSL");

assert_eq!(std::env::var_os("RUSTUP_USE_UNSAFE_SSL").is_none(), true);

download_to_path_with_backend(Backend::Reqwest, &from_url, &target_path, false, None)
.expect("Test download failed");

assert_eq!(file_contents(&target_path), "12345");
}
27 changes: 27 additions & 0 deletions src/download/tests/download-reqwest-unsafe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#![cfg(feature = "reqwest-backend")]

use download::*;

mod support;
use crate::support::{file_contents, serve_file, tmp_dir};

/// There are two separate files because this crate caches reqwest handles
/// and all tests in one file use either the safe or the unsafe handle

#[test]
fn downloading_with_bad_certificate_unsafely() {
let tmpdir = tmp_dir();
let target_path = tmpdir.path().join("downloaded");

let addr = serve_file(b"12345".to_vec(), true);
let from_url = format!("https://{}", addr).parse().unwrap();

std::env::set_var("RUSTUP_USE_UNSAFE_SSL", "1");

assert_eq!(std::env::var_os("RUSTUP_USE_UNSAFE_SSL").is_some(), true);

download_to_path_with_backend(Backend::Reqwest, &from_url, &target_path, false, None)
.expect("Test download failed");

assert_eq!(file_contents(&target_path), "12345");
}
Binary file added src/download/tests/support/cert.p12
Binary file not shown.
26 changes: 16 additions & 10 deletions src/download/tests/support/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
extern crate futures;
extern crate hyper;
extern crate tempdir;

use std::fs::{self, File};
use std::io::{self, Read};
use std::net::SocketAddr;
use std::path::Path;

use self::futures::sync::oneshot;
use self::tempdir::TempDir;
use futures::sync::oneshot;
use tempdir::TempDir;

mod tls_proxy;
use tls_proxy::proxy;

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

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

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

let addr = ([127, 0, 0, 1], 0).into();
let addr = ([0, 0, 0, 0], 0).into();
let (addr_tx, addr_rx) = oneshot::channel();

thread::spawn(move || {
Expand All @@ -57,8 +57,14 @@ pub fn serve_file(contents: Vec<u8>) -> SocketAddr {
addr_tx.send(addr).unwrap();
hyper::rt::run(server.map_err(|e| panic!(e)));
});

let addr = addr_rx.wait().unwrap();
addr

if use_ssl {
proxy(addr)
} else {
addr
}
}

fn serve_contents(
Expand Down
Loading

0 comments on commit 1e6c852

Please sign in to comment.