Merge pull request #1665 from yourowncrypto/rustls

Support pem TLS certificates
This commit is contained in:
hashmap
2018-10-08 12:46:44 +02:00
committed by GitHub
9 changed files with 201 additions and 91 deletions
+2 -2
View File
@@ -19,11 +19,11 @@ use http::uri::{InvalidUri, Uri};
use hyper::header::{ACCEPT, AUTHORIZATION, USER_AGENT};
use hyper::rt::{Future, Stream};
use hyper::{Body, Client, Request};
use hyper_tls;
use serde::{Deserialize, Serialize};
use serde_json;
use futures::future::{err, ok, Either};
use hyper_rustls;
use tokio::runtime::Runtime;
use rest::{Error, ErrorKind};
@@ -186,7 +186,7 @@ where
}
fn send_request_async(req: Request<Body>) -> Box<Future<Item = String, Error = Error> + Send> {
let https = hyper_tls::HttpsConnector::new(1).unwrap();
let https = hyper_rustls::HttpsConnector::new(1);
let client = Client::builder().build::<_, Body>(https);
Box::new(
client
+4 -3
View File
@@ -24,7 +24,6 @@ extern crate failure;
#[macro_use]
extern crate failure_derive;
extern crate hyper;
extern crate hyper_tls;
#[macro_use]
extern crate lazy_static;
extern crate regex;
@@ -36,10 +35,12 @@ extern crate serde_json;
extern crate slog;
extern crate futures;
extern crate http;
extern crate native_tls;
extern crate hyper_rustls;
extern crate rustls;
extern crate tokio;
extern crate tokio_core;
extern crate tokio_tls;
extern crate tokio_rustls;
extern crate tokio_tcp;
pub mod auth;
pub mod client;
+65 -44
View File
@@ -22,17 +22,17 @@ use failure::{Backtrace, Context, Fail, ResultExt};
use futures::sync::oneshot;
use futures::Stream;
use hyper::rt::Future;
use hyper::server::conn::Http;
use hyper::{rt, Body, Request, Server};
use native_tls::{Identity, TlsAcceptor};
use router::{Handler, HandlerObj, ResponseFuture, Router};
use rustls;
use rustls::internal::pemfile;
use std::fmt::{self, Display};
use std::fs::File;
use std::io::Read;
use std::net::SocketAddr;
use std::sync::Arc;
use std::{io, thread};
use tokio::net::TcpListener;
use tokio_tls;
use tokio_rustls::ServerConfigExt;
use tokio_tcp;
use util::LOGGER;
/// Errors that can be returned by an ApiEndpoint implementation.
@@ -93,23 +93,55 @@ impl From<Context<ErrorKind>> for Error {
/// TLS config
pub struct TLSConfig {
pub pkcs_bytes: Vec<u8>,
pub pass: String,
certificate: String,
private_key: String,
}
impl TLSConfig {
pub fn new(pass: String, file: String) -> Result<TLSConfig, Error> {
let mut f = File::open(&file).context(ErrorKind::Internal(format!(
"can't open TLS certifiacte file {}",
file
pub fn new(certificate: String, private_key: String) -> TLSConfig {
TLSConfig {
certificate,
private_key,
}
}
fn load_certs(&self) -> Result<Vec<rustls::Certificate>, Error> {
let certfile = File::open(&self.certificate).context(ErrorKind::Internal(format!(
"failed to open file {}",
self.certificate
)))?;
let mut pkcs_bytes = Vec::new();
f.read_to_end(&mut pkcs_bytes)
.context(ErrorKind::Internal(format!(
"can't read TLS certifiacte file {}",
file
)))?;
Ok(TLSConfig { pkcs_bytes, pass })
let mut reader = io::BufReader::new(certfile);
pemfile::certs(&mut reader)
.map_err(|_| ErrorKind::Internal("failed to load certificate".to_string()).into())
}
fn load_private_key(&self) -> Result<rustls::PrivateKey, Error> {
let keyfile = File::open(&self.private_key).context(ErrorKind::Internal(format!(
"failed to open file {}",
self.private_key
)))?;
let mut reader = io::BufReader::new(keyfile);
let keys = pemfile::pkcs8_private_keys(&mut reader)
.map_err(|_| ErrorKind::Internal("failed to load private key".to_string()))?;
if keys.len() != 1 {
return Err(ErrorKind::Internal(
"expected a single private key".to_string(),
))?;
}
Ok(keys[0].clone())
}
pub fn build_server_config(&self) -> Result<Arc<rustls::ServerConfig>, Error> {
let certs = self.load_certs()?;
let key = self.load_private_key()?;
let mut cfg = rustls::ServerConfig::new(rustls::NoClientAuth::new());
cfg.set_single_cert(certs, key)
.context(ErrorKind::Internal(
"set single certificate failed".to_string(),
))?;
Ok(Arc::new(cfg))
}
}
@@ -180,37 +212,26 @@ impl ApiServer {
"Can't start HTTPS API server, it's running already".to_string(),
))?;
}
let tls_conf = conf.build_server_config()?;
thread::Builder::new()
.name("apis".to_string())
.spawn(move || {
let cert = Identity::from_pkcs12(conf.pkcs_bytes.as_slice(), &conf.pass).unwrap();
let tls_cx = TlsAcceptor::builder(cert).build().unwrap();
let tls_cx = tokio_tls::TlsAcceptor::from(tls_cx);
let srv = TcpListener::bind(&addr).expect("Error binding local port");
// Use lower lever hyper API to be able to intercept client connection
let server = Http::new()
.serve_incoming(
srv.incoming().and_then(move |socket| {
tls_cx
.accept(socket)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))
}),
router,
).then(|res| match res {
Ok(conn) => Ok(Some(conn)),
let listener = tokio_tcp::TcpListener::bind(&addr).expect("failed to bind");
let tls = listener
.incoming()
.and_then(move |s| tls_conf.accept_async(s))
.then(|r| match r {
Ok(x) => Ok::<_, io::Error>(Some(x)),
Err(e) => {
eprintln!("Error: {}", e);
Ok(None)
eprintln!("accept_async failed");
Err(e)
}
}).for_each(|conn_opt| {
if let Some(conn) = conn_opt {
rt::spawn(
conn.and_then(|c| c.map_err(|e| panic!("Hyper error {}", e)))
.map_err(|e| eprintln!("Connection error {}", e)),
);
}
Ok(())
});
}).filter_map(|x| x);
let server = Server::builder(tls)
.serve(router)
.map_err(|e| eprintln!("HTTP API server error: {}", e));
rt::run(server);
}).map_err(|_| ErrorKind::Internal("failed to spawn API thread".to_string()).into())