Skip to content

Commit 4ef827b

Browse files
committed
fix: ssl: ensure certs are packaged in the binary - fixes #18
1 parent 4faf27c commit 4ef827b

File tree

4 files changed

+117
-46
lines changed

4 files changed

+117
-46
lines changed

src/lib/bs.rs

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ extern crate serde_derive;
2121

2222
#[macro_use]
2323
extern crate serde_json;
24+
extern crate tempdir;
2425

2526
pub mod config;
2627
pub mod from_file;
@@ -33,5 +34,6 @@ pub mod proxy_utils;
3334
pub mod replacer;
3435
pub mod rewrites;
3536
pub mod setup;
37+
pub mod ssl;
3638
pub mod with_body;
3739
pub mod without_body;

src/lib/config.rs

+15
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ pub enum ProgramStartError {
3636
ConfigCliError(ConfigError),
3737
InvalidArgs(Error),
3838
FromFile(FromFileError),
39+
BindHttp(std::io::Error),
40+
BindHttps(std::io::Error),
41+
SslFailed,
42+
SslTempDir,
43+
SslTempDirClose,
3944
}
4045

4146
impl std::fmt::Display for ProgramStartError {
@@ -58,6 +63,16 @@ impl std::fmt::Display for ProgramStartError {
5863
ProgramStartError::ConfigFileRead => write!(f, "config file content could not be read"),
5964
ProgramStartError::FromFile(e) => write!(f, "{}", e),
6065
ProgramStartError::InvalidArgs(e) => write!(f, "{}", e),
66+
ProgramStartError::SslFailed => write!(f, "could not create self-signed ssl certs"),
67+
ProgramStartError::SslTempDir => write!(
68+
f,
69+
"could not create the temp dir to hold self-signed ssl certs"
70+
),
71+
ProgramStartError::SslTempDirClose => write!(f, "could not clean up the temp dir"),
72+
ProgramStartError::BindHttp(e) => write!(f, "could not bind over http, reason: {}", e),
73+
ProgramStartError::BindHttps(e) => {
74+
write!(f, "could not bind over https, reason: {}", e)
75+
}
6176
}
6277
}
6378
}

src/lib/ssl.rs

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
use config::ProgramStartError;
2+
use openssl::ssl::{SslAcceptor, SslAcceptorBuilder, SslFiletype, SslMethod};
3+
use std::fs::File;
4+
use std::io::{Error, Write};
5+
use std::path::PathBuf;
6+
use tempdir::TempDir;
7+
8+
const TMP_DIR_NAME: &'static str = "config-gen";
9+
10+
const TMP_KEY: &'static [u8] = include_bytes!("../key.pem");
11+
const TMP_KEY_NAME: &'static str = "key.pem";
12+
13+
const TMP_CERT: &'static [u8] = include_bytes!("../cert.pem");
14+
const TMP_CERT_NAME: &'static str = "cert.pem";
15+
16+
///
17+
/// Create an SslAcceptorBuilder by using self-signed
18+
/// certificates that exist inside this binary
19+
///
20+
/// This is acceptable since this is a development only
21+
/// tool and nothing this runs should be anywhere near anything
22+
/// that's shared, or in production.
23+
///
24+
pub fn builder() -> Result<SslAcceptorBuilder, ProgramStartError> {
25+
let (key_path, cert_path, tmp_dir) = ssl_paths().map_err(|_e| ProgramStartError::SslTempDir)?;
26+
27+
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls())
28+
.map_err(|_e| ProgramStartError::SslFailed)?;
29+
30+
builder
31+
.set_private_key_file(key_path, SslFiletype::PEM)
32+
.map_err(|_e| ProgramStartError::SslFailed)?;
33+
34+
builder
35+
.set_certificate_chain_file(cert_path)
36+
.map_err(|_e| ProgramStartError::SslFailed)?;
37+
38+
tmp_dir
39+
.close()
40+
.map_err(|_e| ProgramStartError::SslTempDirClose)?;
41+
42+
Ok(builder)
43+
}
44+
45+
#[test]
46+
fn test_ssl_builder() {
47+
builder().unwrap();
48+
}
49+
50+
///
51+
/// Takes the self-signed bundled key & cert
52+
/// and places them in a temporary directory so that they
53+
/// can be used by openSSL
54+
///
55+
/// # Examples
56+
///
57+
/// ```
58+
/// use bs::ssl::*;
59+
/// let (key_path, cert_path, tmp_dir) = ssl_paths().unwrap();
60+
/// println!("key={:?}, cert={:?}", key_path, cert_path);
61+
/// tmp_dir.close().unwrap();
62+
/// ```
63+
///
64+
pub fn ssl_paths() -> Result<(PathBuf, PathBuf, TempDir), Error> {
65+
let tmp_dir = TempDir::new(TMP_DIR_NAME)?;
66+
let key_path = tmp_dir.path().join(TMP_KEY_NAME);
67+
let cert_path = tmp_dir.path().join(TMP_CERT_NAME);
68+
69+
let mut key_file = File::create(&key_path)?;
70+
key_file.write_all(TMP_KEY)?;
71+
key_file.sync_all()?;
72+
73+
let mut cert_file = File::create(&cert_path)?;
74+
cert_file.write_all(TMP_CERT)?;
75+
cert_file.sync_all()?;
76+
77+
Ok((key_path, cert_path, tmp_dir))
78+
}
79+
80+
#[test]
81+
fn test_ssl_paths() {
82+
let (_file_key, _file_cert, tmp_dir) = ssl_paths().unwrap();
83+
assert_eq!(tmp_dir.path().exists(), true);
84+
}

src/main.rs

+16-46
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,20 @@ extern crate mime;
1111
extern crate openssl;
1212
extern crate regex;
1313
extern crate serde_yaml;
14-
extern crate url;
1514
extern crate tempdir;
15+
extern crate url;
1616

1717
use actix_web::{server, App};
18-
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
1918

2019
use bs::config::{ProgramConfig, ProgramStartError};
2120
use bs::from_file::FromFile;
2221
use bs::options::{ProgramOptions, ProxyScheme};
2322
use bs::setup::{apply_presets, state_and_presets};
24-
use openssl::ssl::SslAcceptorBuilder;
25-
use std::ffi::CString;
26-
use std::env;
27-
use tempdir::TempDir;
28-
use std::fs::File;
23+
use bs::ssl;
2924

3025
fn main() {
3126
match ProgramOptions::from_vec(&mut std::env::args_os()).and_then(run_with_opts) {
32-
Ok(opts) => println!("Running!"),
27+
Ok(..) => { /* Running! */ }
3328
Err(e) => {
3429
eprintln!("{}", e);
3530
std::process::exit(1);
@@ -92,50 +87,25 @@ fn run_with_opts(opts: ProgramOptions) -> Result<(), ProgramStartError> {
9287
// target URL's scheme
9388
//
9489
let s = match server_opts.scheme {
95-
ProxyScheme::Http => s.bind(&local_addr),
96-
ProxyScheme::Https => s.bind_ssl(&local_addr, get_ssl_builder()),
90+
ProxyScheme::Http => s.bind(&local_addr).map_err(ProgramStartError::BindHttp)?,
91+
ProxyScheme::Https => {
92+
let builder = ssl::builder()?;
93+
s.bind_ssl(&local_addr, builder)
94+
.map_err(ProgramStartError::BindHttps)?
95+
}
9796
};
9897

99-
s.expect("Couldn't start the application")
100-
.shutdown_timeout(0)
101-
.start();
98+
//
99+
// Start the server
100+
//
101+
s.shutdown_timeout(0).start();
102102

103+
//
104+
// Output the proxy URL only
105+
//
103106
println!("{}://{}", server_opts.scheme, local_addr);
104107

105108
let _ = sys.run();
106109

107110
Ok(())
108111
}
109-
110-
///
111-
/// SSL builder
112-
///
113-
/// Todo: allow key/cert options
114-
///
115-
fn get_ssl_builder() -> SslAcceptorBuilder {
116-
117-
use std::fs::File;
118-
use std::io::{self, Write};
119-
120-
let tmp_dir = TempDir::new("example").unwrap();
121-
let file_key = tmp_dir.path().join("key.pem");
122-
let file_cert = tmp_dir.path().join("cert.pem");
123-
124-
let mut tmp_file = File::create(&file_key).unwrap();
125-
tmp_file.write_all(include_bytes!("key.pem")).unwrap();
126-
tmp_file.sync_all().unwrap();
127-
128-
let mut tmp_file2 = File::create(&file_cert).unwrap();
129-
tmp_file2.write_all(include_bytes!("cert.pem")).unwrap();
130-
tmp_file2.sync_all().unwrap();
131-
132-
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
133-
builder
134-
.set_private_key_file(file_key, SslFiletype::PEM)
135-
.unwrap();
136-
builder.set_certificate_chain_file(file_cert).unwrap();
137-
138-
tmp_dir.close().unwrap();
139-
140-
builder
141-
}

0 commit comments

Comments
 (0)