-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #25 from jacob-pro/main
Add an example for how to use `replace_acceptor` to change certificate
- Loading branch information
Showing
6 changed files
with
154 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
use hyper::server::conn::{AddrIncoming, Http}; | ||
use hyper::service::service_fn; | ||
use hyper::{Body, Request, Response}; | ||
use std::convert::Infallible; | ||
use std::sync::atomic::{AtomicU64, Ordering}; | ||
use std::sync::Arc; | ||
|
||
mod tls_config; | ||
use tls_config::{tls_acceptor, tls_acceptor2, Acceptor}; | ||
use tokio::sync::mpsc; | ||
|
||
/// To view the current certificate try: | ||
/// `echo "Q" |openssl s_client -showcerts -connect 127.0.0.1:3000 | grep subject=CN` | ||
/// | ||
/// To change the certificate make a HTTP request: | ||
/// `curl https://127.0.0.1:3000 -k` | ||
#[tokio::main(flavor = "current_thread")] | ||
async fn main() { | ||
let addr = ([127, 0, 0, 1], 3000).into(); | ||
let counter = Arc::new(AtomicU64::new(0)); | ||
|
||
let mut listener = tls_listener::builder(tls_acceptor()) | ||
.max_handshakes(10) | ||
.listen(AddrIncoming::bind(&addr).unwrap()); | ||
|
||
let (tx, mut rx) = mpsc::channel::<Acceptor>(1); | ||
|
||
let http = Http::new(); | ||
loop { | ||
tokio::select! { | ||
conn = listener.accept() => { | ||
match conn.expect("Tls listener stream should be infinite") { | ||
Ok(conn) => { | ||
let http = http.clone(); | ||
let tx = tx.clone(); | ||
let counter = counter.clone(); | ||
tokio::spawn(async move { | ||
let svc = service_fn(move |request| handle_request(tx.clone(), counter.clone(), request)); | ||
if let Err(err) = http.serve_connection(conn, svc).await { | ||
eprintln!("Application error: {}", err); | ||
} | ||
}); | ||
}, | ||
Err(e) => { | ||
eprintln!("Bad connection: {}", e); | ||
} | ||
} | ||
}, | ||
message = rx.recv() => { | ||
// Certificate is loaded on another task; we don't want to block the listener loop | ||
let acceptor = message.expect("Channel should not be closed"); | ||
println!("Rotating certificate..."); | ||
listener.replace_acceptor(acceptor); | ||
} | ||
} | ||
} | ||
} | ||
|
||
async fn handle_request( | ||
change_certificate: mpsc::Sender<Acceptor>, | ||
counter: Arc<AtomicU64>, | ||
_request: Request<Body>, | ||
) -> Result<Response<Body>, Infallible> { | ||
let counter = counter.fetch_add(1, Ordering::Relaxed) + 1; | ||
let new_cert = if counter % 2 == 0 { | ||
tls_acceptor() | ||
} else { | ||
tls_acceptor2() | ||
}; | ||
change_certificate.send(new_cert).await.ok(); | ||
Ok(Response::new(Body::from("Changing certificate..."))) | ||
} |
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,97 @@ | ||
#[cfg(feature = "rustls")] | ||
mod cert { | ||
pub const CERT: &[u8] = include_bytes!("local.cert"); | ||
pub const PKEY: &[u8] = include_bytes!("local.key"); | ||
} | ||
#[cfg(all(feature = "native-tls", not(feature = "rustls")))] | ||
const PFX: &[u8] = include_bytes!("local.pfx"); | ||
|
||
#[cfg(feature = "rustls")] | ||
pub fn tls_acceptor() -> tokio_rustls::TlsAcceptor { | ||
mod config { | ||
use std::sync::Arc; | ||
use tokio_rustls::rustls::{Certificate, PrivateKey, ServerConfig}; | ||
|
||
let key = PrivateKey(cert::PKEY.into()); | ||
let cert = Certificate(cert::CERT.into()); | ||
|
||
Arc::new( | ||
ServerConfig::builder() | ||
.with_safe_defaults() | ||
.with_no_client_auth() | ||
.with_single_cert(vec![cert], key) | ||
.unwrap(), | ||
) | ||
.into() | ||
const CERT: &[u8] = include_bytes!("local.cert"); | ||
const PKEY: &[u8] = include_bytes!("local.key"); | ||
const CERT2: &[u8] = include_bytes!("local2.cert"); | ||
const PKEY2: &[u8] = include_bytes!("local2.key"); | ||
|
||
pub type Acceptor = tokio_rustls::TlsAcceptor; | ||
|
||
fn tls_acceptor_impl(cert_der: &[u8], key_der: &[u8]) -> Acceptor { | ||
let key = PrivateKey(cert_der.into()); | ||
let cert = Certificate(key_der.into()); | ||
Arc::new( | ||
ServerConfig::builder() | ||
.with_safe_defaults() | ||
.with_no_client_auth() | ||
.with_single_cert(vec![cert], key) | ||
.unwrap(), | ||
) | ||
.into() | ||
} | ||
|
||
pub fn tls_acceptor() -> Acceptor { | ||
tls_acceptor_impl(PKEY, CERT) | ||
} | ||
|
||
pub fn tls_acceptor2() -> Acceptor { | ||
tls_acceptor_impl(PKEY2, CERT2) | ||
} | ||
} | ||
|
||
#[cfg(all( | ||
feature = "native-tls", | ||
not(any(feature = "rustls", feature = "openssl")) | ||
))] | ||
pub fn tls_acceptor() -> tokio_native_tls::TlsAcceptor { | ||
mod config { | ||
use tokio_native_tls::native_tls::{Identity, TlsAcceptor}; | ||
|
||
let identity = Identity::from_pkcs12(PFX, "").unwrap(); | ||
TlsAcceptor::builder(identity).build().unwrap().into() | ||
const PFX: &[u8] = include_bytes!("local.pfx"); | ||
const PFX2: &[u8] = include_bytes!("local2.pfx"); | ||
|
||
pub type Acceptor = tokio_native_tls::TlsAcceptor; | ||
|
||
fn tls_acceptor_impl(pfx: &[u8]) -> Acceptor { | ||
let identity = Identity::from_pkcs12(pfx, "").unwrap(); | ||
TlsAcceptor::builder(identity).build().unwrap().into() | ||
} | ||
|
||
pub fn tls_acceptor() -> Acceptor { | ||
tls_acceptor_impl(PFX) | ||
} | ||
|
||
pub fn tls_acceptor2() -> Acceptor { | ||
tls_acceptor_impl(PFX2) | ||
} | ||
} | ||
|
||
#[cfg(all( | ||
feature = "openssl", | ||
not(any(feature = "rustls", feature = "native-tls")) | ||
))] | ||
pub fn tls_acceptor() -> openssl_impl::ssl::SslContext { | ||
mod config { | ||
use openssl_impl::ssl::{SslContext, SslFiletype, SslMethod}; | ||
let mut builder = SslContext::builder(SslMethod::tls_server()).unwrap(); | ||
builder | ||
.set_certificate_file("./examples/tls_config/local.cert", SslFiletype::ASN1) | ||
.unwrap(); | ||
builder | ||
.set_private_key_file("./examples/tls_config/local.key", SslFiletype::ASN1) | ||
.unwrap(); | ||
builder.build() | ||
use std::path::Path; | ||
|
||
pub type Acceptor = openssl_impl::ssl::SslContext; | ||
|
||
fn tls_acceptor_impl<P: AsRef<Path>>(cert_file: P, key_file: P) -> Acceptor { | ||
let mut builder = SslContext::builder(SslMethod::tls_server()).unwrap(); | ||
builder | ||
.set_certificate_file(cert_file, SslFiletype::ASN1) | ||
.unwrap(); | ||
builder | ||
.set_private_key_file(key_file, SslFiletype::ASN1) | ||
.unwrap(); | ||
builder.build() | ||
} | ||
|
||
pub fn tls_acceptor() -> Acceptor { | ||
tls_acceptor_impl( | ||
"./examples/tls_config/local.cert", | ||
"./examples/tls_config/local.key", | ||
) | ||
} | ||
|
||
pub fn tls_acceptor2() -> Acceptor { | ||
tls_acceptor_impl( | ||
"./examples/tls_config/local2.cert", | ||
"./examples/tls_config/local2.key", | ||
) | ||
} | ||
} | ||
|
||
pub use config::*; |