Skip to content

Commit

Permalink
fix: ssl: ensure certs are packaged in the binary - fixes #18
Browse files Browse the repository at this point in the history
  • Loading branch information
shakyShane committed Oct 12, 2018
1 parent 4faf27c commit 4ef827b
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 46 deletions.
2 changes: 2 additions & 0 deletions src/lib/bs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ extern crate serde_derive;

#[macro_use]
extern crate serde_json;
extern crate tempdir;

pub mod config;
pub mod from_file;
Expand All @@ -33,5 +34,6 @@ pub mod proxy_utils;
pub mod replacer;
pub mod rewrites;
pub mod setup;
pub mod ssl;
pub mod with_body;
pub mod without_body;
15 changes: 15 additions & 0 deletions src/lib/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ pub enum ProgramStartError {
ConfigCliError(ConfigError),
InvalidArgs(Error),
FromFile(FromFileError),
BindHttp(std::io::Error),
BindHttps(std::io::Error),
SslFailed,
SslTempDir,
SslTempDirClose,
}

impl std::fmt::Display for ProgramStartError {
Expand All @@ -58,6 +63,16 @@ impl std::fmt::Display for ProgramStartError {
ProgramStartError::ConfigFileRead => write!(f, "config file content could not be read"),
ProgramStartError::FromFile(e) => write!(f, "{}", e),
ProgramStartError::InvalidArgs(e) => write!(f, "{}", e),
ProgramStartError::SslFailed => write!(f, "could not create self-signed ssl certs"),
ProgramStartError::SslTempDir => write!(
f,
"could not create the temp dir to hold self-signed ssl certs"
),
ProgramStartError::SslTempDirClose => write!(f, "could not clean up the temp dir"),
ProgramStartError::BindHttp(e) => write!(f, "could not bind over http, reason: {}", e),
ProgramStartError::BindHttps(e) => {
write!(f, "could not bind over https, reason: {}", e)
}
}
}
}
84 changes: 84 additions & 0 deletions src/lib/ssl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use config::ProgramStartError;
use openssl::ssl::{SslAcceptor, SslAcceptorBuilder, SslFiletype, SslMethod};
use std::fs::File;
use std::io::{Error, Write};
use std::path::PathBuf;
use tempdir::TempDir;

const TMP_DIR_NAME: &'static str = "config-gen";

const TMP_KEY: &'static [u8] = include_bytes!("../key.pem");
const TMP_KEY_NAME: &'static str = "key.pem";

const TMP_CERT: &'static [u8] = include_bytes!("../cert.pem");
const TMP_CERT_NAME: &'static str = "cert.pem";

///
/// Create an SslAcceptorBuilder by using self-signed
/// certificates that exist inside this binary
///
/// This is acceptable since this is a development only
/// tool and nothing this runs should be anywhere near anything
/// that's shared, or in production.
///
pub fn builder() -> Result<SslAcceptorBuilder, ProgramStartError> {
let (key_path, cert_path, tmp_dir) = ssl_paths().map_err(|_e| ProgramStartError::SslTempDir)?;

let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls())
.map_err(|_e| ProgramStartError::SslFailed)?;

builder
.set_private_key_file(key_path, SslFiletype::PEM)
.map_err(|_e| ProgramStartError::SslFailed)?;

builder
.set_certificate_chain_file(cert_path)
.map_err(|_e| ProgramStartError::SslFailed)?;

tmp_dir
.close()
.map_err(|_e| ProgramStartError::SslTempDirClose)?;

Ok(builder)
}

#[test]
fn test_ssl_builder() {
builder().unwrap();
}

///
/// Takes the self-signed bundled key & cert
/// and places them in a temporary directory so that they
/// can be used by openSSL
///
/// # Examples
///
/// ```
/// use bs::ssl::*;
/// let (key_path, cert_path, tmp_dir) = ssl_paths().unwrap();
/// println!("key={:?}, cert={:?}", key_path, cert_path);
/// tmp_dir.close().unwrap();
/// ```
///
pub fn ssl_paths() -> Result<(PathBuf, PathBuf, TempDir), Error> {
let tmp_dir = TempDir::new(TMP_DIR_NAME)?;
let key_path = tmp_dir.path().join(TMP_KEY_NAME);
let cert_path = tmp_dir.path().join(TMP_CERT_NAME);

let mut key_file = File::create(&key_path)?;
key_file.write_all(TMP_KEY)?;
key_file.sync_all()?;

let mut cert_file = File::create(&cert_path)?;
cert_file.write_all(TMP_CERT)?;
cert_file.sync_all()?;

Ok((key_path, cert_path, tmp_dir))
}

#[test]
fn test_ssl_paths() {
let (_file_key, _file_cert, tmp_dir) = ssl_paths().unwrap();
assert_eq!(tmp_dir.path().exists(), true);
}
62 changes: 16 additions & 46 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,20 @@ extern crate mime;
extern crate openssl;
extern crate regex;
extern crate serde_yaml;
extern crate url;
extern crate tempdir;
extern crate url;

use actix_web::{server, App};
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};

use bs::config::{ProgramConfig, ProgramStartError};
use bs::from_file::FromFile;
use bs::options::{ProgramOptions, ProxyScheme};
use bs::setup::{apply_presets, state_and_presets};
use openssl::ssl::SslAcceptorBuilder;
use std::ffi::CString;
use std::env;
use tempdir::TempDir;
use std::fs::File;
use bs::ssl;

fn main() {
match ProgramOptions::from_vec(&mut std::env::args_os()).and_then(run_with_opts) {
Ok(opts) => println!("Running!"),
Ok(..) => { /* Running! */ }
Err(e) => {
eprintln!("{}", e);
std::process::exit(1);
Expand Down Expand Up @@ -92,50 +87,25 @@ fn run_with_opts(opts: ProgramOptions) -> Result<(), ProgramStartError> {
// target URL's scheme
//
let s = match server_opts.scheme {
ProxyScheme::Http => s.bind(&local_addr),
ProxyScheme::Https => s.bind_ssl(&local_addr, get_ssl_builder()),
ProxyScheme::Http => s.bind(&local_addr).map_err(ProgramStartError::BindHttp)?,
ProxyScheme::Https => {
let builder = ssl::builder()?;
s.bind_ssl(&local_addr, builder)
.map_err(ProgramStartError::BindHttps)?
}
};

s.expect("Couldn't start the application")
.shutdown_timeout(0)
.start();
//
// Start the server
//
s.shutdown_timeout(0).start();

//
// Output the proxy URL only
//
println!("{}://{}", server_opts.scheme, local_addr);

let _ = sys.run();

Ok(())
}

///
/// SSL builder
///
/// Todo: allow key/cert options
///
fn get_ssl_builder() -> SslAcceptorBuilder {

use std::fs::File;
use std::io::{self, Write};

let tmp_dir = TempDir::new("example").unwrap();
let file_key = tmp_dir.path().join("key.pem");
let file_cert = tmp_dir.path().join("cert.pem");

let mut tmp_file = File::create(&file_key).unwrap();
tmp_file.write_all(include_bytes!("key.pem")).unwrap();
tmp_file.sync_all().unwrap();

let mut tmp_file2 = File::create(&file_cert).unwrap();
tmp_file2.write_all(include_bytes!("cert.pem")).unwrap();
tmp_file2.sync_all().unwrap();

let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
builder
.set_private_key_file(file_key, SslFiletype::PEM)
.unwrap();
builder.set_certificate_chain_file(file_cert).unwrap();

tmp_dir.close().unwrap();

builder
}

0 comments on commit 4ef827b

Please sign in to comment.