feat(server): make TlsIdentityCtx accept PEM files (#623)

This is in general more convenient than DER files.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
Marc-Andre Lureau 2024-12-17 19:50:39 +04:00 committed by GitHub
parent 114098b673
commit 9198284263
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -5,23 +5,43 @@ 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<CertificateDer<'static>>,
pub priv_key: PrivateKeyDer<'static>,
pub pub_key: Vec<u8>,
}
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<Self> {
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)
} else {
certs(&mut BufReader::new(File::open(cert_path)?))
}
.collect::<Result<_, _>>()
.context(format!("reading server cert `{cert_path:?}`"))?;
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 +51,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 +61,7 @@ impl TlsIdentityCtx {
pub fn make_acceptor(&self) -> anyhow::Result<TlsAcceptor> {
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)