use anyhow::{anyhow, Result};
use rustls::{
sign::{any_supported_type, CertifiedKey},
Certificate, PrivateKey,
};
use serde::{Deserialize, Serialize};
use std::{
fs::File,
io::BufReader,
path::{Path, PathBuf},
};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct KeyCertPathPair {
pub key_path: PathBuf,
pub cert_path: PathBuf,
}
impl KeyCertPathPair {
pub fn load_certified_key(&self) -> Result<CertifiedKey> {
let certificate = load_certs(&self.cert_path)?;
let private_key = load_private_key(&self.key_path)?;
let private_key = any_supported_type(&private_key)?;
Ok(CertifiedKey::new(certificate, private_key))
}
pub fn parent_paths(&self) -> Vec<PathBuf> {
let key_parent_dir = self
.key_path
.parent()
.expect("Key file should never be filesystem root.");
let certificate_parent_dir = self
.key_path
.parent()
.expect("Key file should never be filesystem root.");
if key_parent_dir == certificate_parent_dir {
vec![key_parent_dir.to_path_buf()]
} else {
vec![
key_parent_dir.to_path_buf(),
certificate_parent_dir.to_path_buf(),
]
}
}
}
pub fn load_certs(filename: &Path) -> Result<Vec<Certificate>> {
let certfile = File::open(filename)?;
let mut reader = BufReader::new(certfile);
let certs = rustls_pemfile::certs(&mut reader)?;
Ok(certs.into_iter().map(rustls::Certificate).collect())
}
pub fn load_private_key(filename: &Path) -> Result<PrivateKey> {
let keyfile = File::open(filename)?;
let mut reader = BufReader::new(keyfile);
let keys = rustls_pemfile::pkcs8_private_keys(&mut reader)?;
if keys.len() != 1 {
return Err(anyhow!("expected a single private key"));
}
Ok(rustls::PrivateKey(keys[0].clone()))
}