Update 'rustls' to 0.20.

Also updates 'tokio-rustls' to a compatible version.

Additionally depends on 'rustls-pemfile' which includes functionality
that was previously part of 'rustls' itself.
This commit is contained in:
Sergio Benitez 2022-02-22 14:01:25 -08:00
parent 502b11c177
commit fda05bddd2
7 changed files with 55 additions and 59 deletions

View File

@ -16,7 +16,7 @@ edition = "2018"
[features]
default = []
tls = ["rustls", "tokio-rustls"]
tls = ["rustls", "tokio-rustls", "rustls-pemfile"]
mtls = ["tls", "x509-parser"]
private-cookies = ["cookie/private", "cookie/key-expansion"]
serde = ["uncased/with-serde-alloc", "serde_"]
@ -28,8 +28,9 @@ percent-encoding = "2"
http = "0.2"
time = { version = "0.3", features = ["formatting", "macros"] }
indexmap = { version = "1.5.2", features = ["std"] }
rustls = { version = "0.19", optional = true }
tokio-rustls = { version = "0.22.0", optional = true }
rustls = { version = "0.20", optional = true }
tokio-rustls = { version = "0.23.0", optional = true }
rustls-pemfile = { version = "0.3", optional = true }
tokio = { version = "1.6.1", features = ["net", "sync", "time"] }
log = "0.4"
ref-cast = "1.0"

View File

@ -54,7 +54,7 @@ pub trait Connection: AsyncRead + AsyncWrite {
///
/// Defaults to an empty vector to indicate that no certificates were
/// presented.
fn peer_certificates(&self) -> Option<Vec<RawCertificate>> { None }
fn peer_certificates(&self) -> Option<&[RawCertificate]> { None }
}
pin_project_lite::pin_project! {

View File

@ -5,7 +5,6 @@ use std::task::{Context, Poll};
use std::net::SocketAddr;
use std::future::Future;
use rustls::{ServerConfig, SupportedCipherSuite};
use tokio_rustls::{TlsAcceptor, Accept, server::TlsStream};
use tokio::net::{TcpListener, TcpStream};
@ -27,7 +26,7 @@ enum State {
pub struct Config<R> {
pub cert_chain: R,
pub private_key: R,
pub ciphersuites: Vec<&'static SupportedCipherSuite>,
pub ciphersuites: Vec<rustls::SupportedCipherSuite>,
pub prefer_server_order: bool,
pub ca_certs: Option<R>,
pub mandatory_mtls: bool,
@ -37,40 +36,38 @@ impl TlsListener {
pub async fn bind<R>(addr: SocketAddr, mut c: Config<R>) -> io::Result<TlsListener>
where R: io::BufRead
{
let cert_chain = load_certs(&mut c.cert_chain).map_err(|e| {
let msg = format!("malformed TLS certificate chain: {}", e);
io::Error::new(e.kind(), msg)
})?;
use rustls::server::{AllowAnyAuthenticatedClient, AllowAnyAnonymousOrAuthenticatedClient};
use rustls::server::{NoClientAuth, ServerSessionMemoryCache, ServerConfig};
let key = load_private_key(&mut c.private_key).map_err(|e| {
let msg = format!("malformed TLS private key: {}", e);
io::Error::new(e.kind(), msg)
})?;
let cert_chain = load_certs(&mut c.cert_chain)
.map_err(|e| io::Error::new(e.kind(), format!("bad TLS cert chain: {}", e)))?;
let key = load_private_key(&mut c.private_key)
.map_err(|e| io::Error::new(e.kind(), format!("bad TLS private key: {}", e)))?;
let client_auth = match c.ca_certs {
Some(ref mut ca_certs) => {
let roots = load_ca_certs(ca_certs).map_err(|e| {
let msg = format!("malformed CA certificate(s): {}", e);
io::Error::new(e.kind(), msg)
})?;
if c.mandatory_mtls {
rustls::AllowAnyAuthenticatedClient::new(roots)
} else {
rustls::AllowAnyAnonymousOrAuthenticatedClient::new(roots)
}
}
None => rustls::NoClientAuth::new(),
Some(ref mut ca_certs) => match load_ca_certs(ca_certs) {
Ok(ca_roots) if c.mandatory_mtls => AllowAnyAuthenticatedClient::new(ca_roots),
Ok(ca_roots) => AllowAnyAnonymousOrAuthenticatedClient::new(ca_roots),
Err(e) => return Err(io::Error::new(e.kind(), format!("bad CA cert(s): {}", e))),
},
None => NoClientAuth::new(),
};
let mut tls_config = ServerConfig::new(client_auth);
let cache = rustls::ServerSessionMemoryCache::new(1024);
tls_config.set_persistence(cache);
tls_config.ticketer = rustls::Ticketer::new();
tls_config.ciphersuites = c.ciphersuites;
let mut tls_config = ServerConfig::builder()
.with_cipher_suites(&c.ciphersuites)
.with_safe_default_kx_groups()
.with_safe_default_protocol_versions()
.map_err(|e| io::Error::new(io::ErrorKind::Other, format!("bad TLS config: {}", e)))?
.with_client_cert_verifier(client_auth)
.with_single_cert(cert_chain, key)
.map_err(|e| io::Error::new(io::ErrorKind::Other, format!("bad TLS config: {}", e)))?;
tls_config.ignore_client_order = c.prefer_server_order;
tls_config.set_single_cert(cert_chain, key).expect("invalid key");
tls_config.set_protocols(&[b"h2".to_vec(), b"http/1.1".to_vec()]);
tls_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
tls_config.session_storage = ServerSessionMemoryCache::new(1024);
tls_config.ticketer = rustls::Ticketer::new()
.map_err(|e| io::Error::new(io::ErrorKind::Other, format!("bad TLS ticketer: {}", e)))?;
let listener = TcpListener::bind(addr).await?;
let acceptor = TlsAcceptor::from(Arc::new(tls_config));
@ -120,9 +117,7 @@ impl Connection for TlsStream<TcpStream> {
self.get_ref().0.peer_address()
}
fn peer_certificates(&self) -> Option<Vec<RawCertificate>> {
use rustls::Session;
self.get_ref().1.get_peer_certificates()
fn peer_certificates(&self) -> Option<&[RawCertificate]> {
self.get_ref().1.peer_certificates()
}
}

View File

@ -1,6 +1,6 @@
use std::io::{self, Cursor, Read};
use rustls::{internal::pemfile, Certificate, PrivateKey, RootCertStore};
use rustls::{Certificate, PrivateKey, RootCertStore};
fn err(message: impl Into<std::borrow::Cow<'static, str>>) -> io::Error {
io::Error::new(io::ErrorKind::Other, message.into())
@ -8,7 +8,8 @@ fn err(message: impl Into<std::borrow::Cow<'static, str>>) -> io::Error {
/// Loads certificates from `reader`.
pub fn load_certs(reader: &mut dyn io::BufRead) -> io::Result<Vec<Certificate>> {
pemfile::certs(reader).map_err(|_| err("invalid certificate"))
let certs = rustls_pemfile::certs(reader).map_err(|_| err("invalid certificate"))?;
Ok(certs.into_iter().map(Certificate).collect())
}
/// Load and decode the private key from `reader`.
@ -19,8 +20,8 @@ pub fn load_private_key(reader: &mut dyn io::BufRead) -> io::Result<PrivateKey>
reader.read_line(&mut first_line)?;
let private_keys_fn = match first_line.trim_end() {
"-----BEGIN RSA PRIVATE KEY-----" => pemfile::rsa_private_keys,
"-----BEGIN PRIVATE KEY-----" => pemfile::pkcs8_private_keys,
"-----BEGIN RSA PRIVATE KEY-----" => rustls_pemfile::rsa_private_keys,
"-----BEGIN PRIVATE KEY-----" => rustls_pemfile::pkcs8_private_keys,
_ => return Err(err("invalid key header"))
};
@ -28,7 +29,7 @@ pub fn load_private_key(reader: &mut dyn io::BufRead) -> io::Result<PrivateKey>
.map_err(|_| err("invalid key file"))
.and_then(|mut keys| match keys.len() {
0 => Err(err("no valid keys found; is the file malformed?")),
1 => Ok(keys.remove(0)),
1 => Ok(PrivateKey(keys.remove(0))),
n => Err(err(format!("expected 1 key, found {}", n))),
})?;
@ -41,9 +42,8 @@ pub fn load_private_key(reader: &mut dyn io::BufRead) -> io::Result<PrivateKey>
/// Load and decode CA certificates from `reader`.
pub fn load_ca_certs(reader: &mut dyn io::BufRead) -> io::Result<RootCertStore> {
let mut roots = rustls::RootCertStore::empty();
let (_, e) = roots.add_pem_file(reader).map_err(|_| err("PEM format error"))?;
if e != 0 {
return Err(err("validity checks failed"));
for cert in load_certs(reader)? {
roots.add(&cert).map_err(|e| err(format!("CA cert error: {}", e)))?;
}
Ok(roots)

View File

@ -630,7 +630,7 @@ mod with_tls_feature {
use crate::http::tls::Config;
use crate::http::tls::rustls::SupportedCipherSuite as RustlsCipher;
use crate::http::tls::rustls::ciphersuite as rustls;
use crate::http::tls::rustls::cipher_suite;
use yansi::Paint;
@ -675,26 +675,26 @@ mod with_tls_feature {
})
}
fn rustls_ciphers(&self) -> impl Iterator<Item = &'static RustlsCipher> + '_ {
fn rustls_ciphers(&self) -> impl Iterator<Item = RustlsCipher> + '_ {
self.ciphers().map(|ciphersuite| match ciphersuite {
CipherSuite::TLS_CHACHA20_POLY1305_SHA256 =>
&rustls::TLS13_CHACHA20_POLY1305_SHA256,
cipher_suite::TLS13_CHACHA20_POLY1305_SHA256,
CipherSuite::TLS_AES_256_GCM_SHA384 =>
&rustls::TLS13_AES_256_GCM_SHA384,
cipher_suite::TLS13_AES_256_GCM_SHA384,
CipherSuite::TLS_AES_128_GCM_SHA256 =>
&rustls::TLS13_AES_128_GCM_SHA256,
cipher_suite::TLS13_AES_128_GCM_SHA256,
CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 =>
&rustls::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
cipher_suite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 =>
&rustls::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
cipher_suite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 =>
&rustls::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 =>
&rustls::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 =>
&rustls::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
cipher_suite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 =>
&rustls::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
cipher_suite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
})
}
}

View File

@ -298,7 +298,7 @@ impl<F: Future, C: Connection> Connection for CancellableIo<F, C> {
self.io.peer_address()
}
fn peer_certificates(&self) -> Option<Vec<RawCertificate>> {
fn peer_certificates(&self) -> Option<&[RawCertificate]> {
self.io.peer_certificates()
}
}

View File

@ -444,7 +444,7 @@ impl Rocket<Orbit> {
let rocket = rocket.clone();
let connection = ConnectionMeta {
remote: conn.peer_address(),
client_certificates: conn.peer_certificates().map(Arc::new),
client_certificates: conn.peer_certificates().map(|certs| Arc::new(certs.to_vec())),
};
async move {