From 9676877ee7625fd334bf9a1176bbc3d33670f83d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 17 Dec 2024 15:48:58 +0400 Subject: [PATCH] feat(server): make TlsIdentityCtx accept PEM files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is in general more convenient than DER files. Signed-off-by: Marc-André Lureau --- crates/ironrdp-server/src/helper.rs | 44 ++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/crates/ironrdp-server/src/helper.rs b/crates/ironrdp-server/src/helper.rs index 7548c2494..a2a677fa2 100644 --- a/crates/ironrdp-server/src/helper.rs +++ b/crates/ironrdp-server/src/helper.rs @@ -5,23 +5,44 @@ use std::sync::Arc; use anyhow::Context; use rustls_pemfile::{certs, pkcs8_private_keys}; -use tokio_rustls::{rustls, TlsAcceptor}; +use tokio_rustls::rustls::pki_types::pem::PemObject; +use tokio_rustls::rustls::pki_types::{CertificateDer, PrivateKeyDer}; +use tokio_rustls::rustls::{self}; +use tokio_rustls::TlsAcceptor; pub struct TlsIdentityCtx { - pub cert: rustls::pki_types::CertificateDer<'static>, - pub priv_key: rustls::pki_types::PrivateKeyDer<'static>, + pub certs: Vec>, + pub priv_key: PrivateKeyDer<'static>, pub pub_key: Vec, } impl TlsIdentityCtx { + /// A constructor to create a `TlsIdentityCtx` from the given certificate and key paths. + /// + /// The file format can be either PEM (if the file extension ends with .pem) or DER. pub fn init_from_paths(cert_path: &Path, key_path: &Path) -> anyhow::Result { - use x509_cert::der::Decode as _; + let certs: Vec<_> = if cert_path.extension().map_or(false, |ext| ext == "pem") { + CertificateDer::pem_file_iter(cert_path) + .context(format!("reading server cert `{cert_path:?}`"))? + .map(|cert| cert.unwrap()) + .collect() + } else { + certs(&mut BufReader::new(File::open(cert_path)?)).collect::>()? + }; - let cert = certs(&mut BufReader::new(File::open(cert_path)?)) - .next() - .context("no certificate")??; + let priv_key = if key_path.extension().map_or(false, |ext| ext == "pem") { + PrivateKeyDer::from_pem_file(key_path).context("reading server key `{key_path:?}`")? + } else { + pkcs8_private_keys(&mut BufReader::new(File::open(key_path)?)) + .next() + .context("no private key")? + .map(PrivateKeyDer::from)? + }; let pub_key = { + use x509_cert::der::Decode as _; + + let cert = certs.first().ok_or_else(|| std::io::Error::other("invalid cert"))?; let cert = x509_cert::Certificate::from_der(&cert).map_err(std::io::Error::other)?; cert.tbs_certificate .subject_public_key_info @@ -31,13 +52,8 @@ impl TlsIdentityCtx { .to_owned() }; - let priv_key = pkcs8_private_keys(&mut BufReader::new(File::open(key_path)?)) - .next() - .context("no private key")? - .map(rustls::pki_types::PrivateKeyDer::from)?; - Ok(Self { - cert, + certs, priv_key, pub_key, }) @@ -46,7 +62,7 @@ impl TlsIdentityCtx { pub fn make_acceptor(&self) -> anyhow::Result { let mut server_config = rustls::ServerConfig::builder() .with_no_client_auth() - .with_single_cert(vec![self.cert.clone()], self.priv_key.clone_key()) + .with_single_cert(self.certs.clone(), self.priv_key.clone_key()) .context("bad certificate/key")?; // This adds support for the SSLKEYLOGFILE env variable (https://wiki.wireshark.org/TLS#using-the-pre-master-secret)