1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-08-07 17:03:01 +03:00

Upgrade rustls

This commit is contained in:
Quentin Gliech
2024-02-02 10:42:03 +01:00
parent d01b8c36a6
commit aeca03a120
11 changed files with 60 additions and 62 deletions

29
Cargo.lock generated
View File

@@ -161,9 +161,9 @@ checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
[[package]]
name = "apalis-core"
version = "0.4.9"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1deb48475efcdece1f23a0553209ee842f264c2a5e9bcc4928bfa6a15a044cde"
checksum = "5dbe998f2a77a65433e3e893f7ffba5b0c4835a9601ccab02aa868d1d3ed71eb"
dependencies = [
"async-stream",
"async-trait",
@@ -184,9 +184,9 @@ dependencies = [
[[package]]
name = "apalis-cron"
version = "0.4.9"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43310b7e0132f9520b09224fb6faafb32eec82a672aa79c09e46b5b488ed505b"
checksum = "9fc57450bd6a857d2370bb5504cf3d7f2a1fb85c7b68bdb7f92f50aac0e26aac"
dependencies = [
"apalis-core",
"async-stream",
@@ -2252,7 +2252,7 @@ dependencies = [
"http 0.2.11",
"hyper",
"rustls 0.22.2",
"rustls-native-certs 0.7.0",
"rustls-native-certs",
"rustls-pki-types",
"tokio",
"tokio-rustls",
@@ -2910,6 +2910,7 @@ dependencies = [
"rand 0.8.5",
"rand_chacha 0.3.1",
"rustls-pemfile 2.0.0",
"rustls-pki-types",
"schemars",
"serde",
"serde_json",
@@ -3053,7 +3054,7 @@ dependencies = [
"once_cell",
"opentelemetry",
"rustls 0.22.2",
"rustls-native-certs 0.6.3",
"rustls-native-certs",
"serde",
"serde_json",
"serde_urlencoded",
@@ -4441,9 +4442,9 @@ checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94"
[[package]]
name = "psl"
version = "2.1.18"
version = "2.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e109d6dd5679c4dce63a1c6bd7b61ed6758368af1ccf0701dfb02c021fbb9d0d"
checksum = "9667155e4837711406c6a5d26be83cdf53932f182d2ce8785529fd2c1a7e9e97"
dependencies = [
"psl-types",
]
@@ -4804,18 +4805,6 @@ dependencies = [
"zeroize",
]
[[package]]
name = "rustls-native-certs"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00"
dependencies = [
"openssl-probe",
"rustls-pemfile 1.0.4",
"schannel",
"security-framework",
]
[[package]]
name = "rustls-native-certs"
version = "0.7.0"

View File

@@ -285,11 +285,8 @@ where
pub fn build_tls_server_config(config: &HttpTlsConfig) -> Result<ServerConfig, anyhow::Error> {
let (key, chain) = config.load()?;
let key = rustls::PrivateKey(key);
let chain = chain.into_iter().map(rustls::Certificate).collect();
let mut config = rustls::ServerConfig::builder()
.with_safe_defaults()
.with_no_client_auth()
.with_single_cert(chain, key)
.context("failed to build TLS server config")?;

View File

@@ -32,6 +32,7 @@ serde_with = { version = "3.4.0", features = ["hex", "chrono"] }
serde_json.workspace = true
pem-rfc7468 = "0.7.0"
rustls-pki-types = "1.1.0"
rustls-pemfile = "2.0.0"
rand.workspace = true
rand_chacha = "0.3.1"

View File

@@ -14,7 +14,7 @@
#![allow(deprecated)]
use std::{borrow::Cow, io::Cursor, ops::Deref};
use std::{borrow::Cow, io::Cursor};
use anyhow::bail;
use async_trait::async_trait;
@@ -22,6 +22,7 @@ use camino::Utf8PathBuf;
use ipnetwork::IpNetwork;
use mas_keystore::PrivateKey;
use rand::Rng;
use rustls_pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
@@ -197,7 +198,9 @@ impl TlsConfig {
/// - a password was provided but the key was not encrypted
/// - decoding the certificate chain as PEM
/// - the certificate chain is empty
pub fn load(&self) -> Result<(Vec<u8>, Vec<Vec<u8>>), anyhow::Error> {
pub fn load(
&self,
) -> Result<(PrivateKeyDer<'static>, Vec<CertificateDer<'static>>), anyhow::Error> {
let password = match &self.password {
Some(PasswordOrFile::Password(password)) => Some(Cow::Borrowed(password.as_str())),
Some(PasswordOrFile::PasswordFile(path)) => {
@@ -230,9 +233,7 @@ impl TlsConfig {
// Re-serialize the key to PKCS#8 DER, so rustls can consume it
let key = key.to_pkcs8_der()?;
// This extracts the Vec out of the Zeroizing by copying it
// XXX: maybe we should keep that zeroizing?
let key = key.deref().clone();
let key = PrivatePkcs8KeyDer::from(key.to_vec()).into();
let certificate_chain_pem = match &self.certificate {
CertificateOrFile::Certificate(pem) => Cow::Borrowed(pem.as_str()),
@@ -240,7 +241,9 @@ impl TlsConfig {
};
let mut certificate_chain_reader = Cursor::new(certificate_chain_pem.as_bytes());
let certificate_chain = rustls_pemfile::certs(&mut certificate_chain_reader)?;
let certificate_chain: Result<Vec<_>, _> =
rustls_pemfile::certs(&mut certificate_chain_reader).collect();
let certificate_chain = certificate_chain?;
if certificate_chain.is_empty() {
bail!("TLS certificate chain is empty (or invalid)")

View File

@@ -30,7 +30,7 @@ pub use self::{
compat_sessions::{CompatSession, CompatSsoLogin},
cursor::{Cursor, NodeCursor},
node::{Node, NodeType},
oauth::{OAuth2Client, OAuth2Consent, OAuth2Session},
oauth::{OAuth2Client, OAuth2Session},
upstream_oauth::{UpstreamOAuth2Link, UpstreamOAuth2Provider},
users::{User, UserEmail},
viewer::{Anonymous, Viewer, ViewerSession},

View File

@@ -23,7 +23,7 @@ hyper-rustls = { version = "0.25.0", features = ["http1", "http2"], default-feat
once_cell = "1.18.0"
opentelemetry.workspace = true
rustls = { version = "0.22.2", optional = true }
rustls-native-certs = { version = "0.6.3", optional = true }
rustls-native-certs = { version = "0.7.0", optional = true }
serde.workspace = true
serde_json.workspace = true
serde_urlencoded = "0.7.1"

View File

@@ -75,15 +75,11 @@ async fn tls_roots() -> Result<rustls::RootCertStore, NativeRootsInitError> {
#[cfg(feature = "webpki-roots")]
#[allow(clippy::unused_async)]
async fn tls_roots() -> Result<rustls::RootCertStore, Infallible> {
let mut roots = rustls::RootCertStore::empty();
roots.add_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.iter().map(|ta| {
rustls::OwnedTrustAnchor::from_subject_spki_name_constraints(
ta.subject,
ta.spki,
ta.name_constraints,
)
}));
Ok(roots)
let root_store = rustls::RootCertStore {
roots: webpki_roots::TLS_SERVER_ROOTS.to_vec(),
};
Ok(root_store)
}
#[cfg(feature = "native-roots")]
@@ -131,7 +127,6 @@ pub enum NativeRootsLoadError {
async fn make_tls_config() -> Result<rustls::ClientConfig, ClientInitError> {
let roots = tls_roots().await?;
let tls_config = rustls::ClientConfig::builder()
.with_safe_defaults()
.with_root_certificates(roots)
.with_no_client_auth();

View File

@@ -24,10 +24,7 @@ use anyhow::Context;
use hyper::{service::service_fn, Request, Response};
use mas_listener::{server::Server, shutdown::ShutdownStream, ConnectionInfo};
use tokio::signal::unix::SignalKind;
use tokio_rustls::rustls::{
server::AllowAnyAnonymousOrAuthenticatedClient, Certificate, PrivateKey, RootCertStore,
ServerConfig,
};
use tokio_rustls::rustls::{server::WebPkiClientVerifier, RootCertStore, ServerConfig};
static CA_CERT_PEM: &[u8] = include_bytes!("./certs/ca.pem");
static SERVER_CERT_PEM: &[u8] = include_bytes!("./certs/server.pem");
@@ -75,27 +72,30 @@ async fn main() -> Result<(), anyhow::Error> {
fn load_tls_config() -> Result<Arc<ServerConfig>, anyhow::Error> {
let mut ca_cert_reader = BufReader::new(CA_CERT_PEM);
let ca_cert = rustls_pemfile::certs(&mut ca_cert_reader).context("Invalid CA certificate")?;
let ca_cert = rustls_pemfile::certs(&mut ca_cert_reader)
.collect::<Result<Vec<_>, _>>()
.context("Invalid CA certificate")?;
let mut ca_cert_store = RootCertStore::empty();
ca_cert_store.add_parsable_certificates(&ca_cert);
ca_cert_store.add_parsable_certificates(ca_cert);
let mut server_cert_reader = BufReader::new(SERVER_CERT_PEM);
let server_cert: Vec<_> = rustls_pemfile::certs(&mut server_cert_reader)
.context("Invalid server certificate")?
.into_iter()
.map(Certificate)
.collect();
.collect::<Result<Vec<_>, _>>()
.context("Invalid server certificate")?;
let mut server_key_reader = BufReader::new(SERVER_KEY_PEM);
let mut server_key = rustls_pemfile::rsa_private_keys(&mut server_key_reader)
let server_key = rustls_pemfile::rsa_private_keys(&mut server_key_reader)
.next()
.context("No RSA private key found")?
.context("Invalid server TLS keys")?;
let server_key = PrivateKey(server_key.pop().context("Missing server TLS key")?);
let client_cert_verifier = Arc::new(AllowAnyAnonymousOrAuthenticatedClient::new(ca_cert_store));
let client_cert_verifier = WebPkiClientVerifier::builder(Arc::new(ca_cert_store))
.allow_unauthenticated()
.build()?;
let mut config = ServerConfig::builder()
.with_safe_defaults()
.with_client_cert_verifier(client_cert_verifier)
.with_single_cert(server_cert, server_key)?;
.with_single_cert(server_cert, server_key.into())?;
config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
Ok(Arc::new(config))

View File

@@ -20,7 +20,10 @@ use std::{
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
use tokio_rustls::{
rustls::{Certificate, ProtocolVersion, ServerConfig, ServerConnection, SupportedCipherSuite},
rustls::{
pki_types::CertificateDer, ProtocolVersion, ServerConfig, ServerConnection,
SupportedCipherSuite,
},
TlsAcceptor,
};
@@ -31,7 +34,7 @@ pub struct TlsStreamInfo {
pub negotiated_cipher_suite: SupportedCipherSuite,
pub sni_hostname: Option<String>,
pub alpn_protocol: Option<Vec<u8>>,
pub peer_certificates: Option<Vec<Certificate>>,
pub peer_certificates: Option<Vec<CertificateDer<'static>>>,
}
impl TlsStreamInfo {
@@ -98,7 +101,13 @@ impl<T> MaybeTlsStream<T> {
let sni_hostname = conn.server_name().map(ToOwned::to_owned);
let alpn_protocol = conn.alpn_protocol().map(ToOwned::to_owned);
let peer_certificates = conn.peer_certificates().map(ToOwned::to_owned);
let peer_certificates = conn.peer_certificates().map(|certs| {
certs
.iter()
.cloned()
.map(CertificateDer::into_owned)
.collect()
});
Some(TlsStreamInfo {
protocol_version,
negotiated_cipher_suite,

View File

@@ -32,6 +32,10 @@ static MAS_USER_AGENT: HeaderValue = HeaderValue::from_static("mas-oidc-client/0
/// Constructs a [`HttpService`] using [hyper] as a backend.
///
/// # Panics
///
/// If the native TLS root certificates fail to load
///
/// [hyper]: https://crates.io/crates/hyper
#[must_use]
pub fn hyper_service() -> HttpService {
@@ -41,8 +45,8 @@ pub fn hyper_service() -> HttpService {
http.enforce_http(false);
let tls_config = rustls::ClientConfig::builder()
.with_safe_defaults()
.with_native_roots()
.expect("Failed to load native TLS")
.with_no_client_auth();
let https = HttpsConnectorBuilder::new()

View File

@@ -13,8 +13,8 @@ workspace = true
[dependencies]
anyhow.workspace = true
apalis-core = { version = "0.4.7", features = ["extensions", "tokio-comp", "storage"] }
apalis-cron = "0.4.7"
apalis-core = { version = "=0.4.7", features = ["extensions", "tokio-comp", "storage"] }
apalis-cron = "=0.4.7"
async-stream = "0.3.5"
async-trait = "0.1.74"
chrono.workspace = true