common/
tls.rs

1use std::error::Error;
2use std::fmt::Debug;
3use std::io::BufReader;
4use std::path::PathBuf;
5
6use tokio::fs::File;
7use tokio::io::AsyncReadExt;
8use tokio_rustls::rustls::internal::pemfile;
9use tokio_rustls::rustls::sign::{RSASigningKey, SigningKey};
10use tokio_rustls::rustls::{Certificate, PrivateKey};
11
12pub async fn load_certificate(pem_path: PathBuf) -> Result<Certificate, Box<dyn Error>> {
13    log::debug!("loading certificate from {:?}", pem_path);
14    let content = load_file_content(pem_path).await?;
15    let parsed_result = pemfile::certs(&mut BufReader::new(content.as_slice()));
16    parse_pem_single_element_result(parsed_result)
17}
18
19pub async fn load_private_key(pem_path: PathBuf) -> Result<PrivateKey, Box<dyn Error>> {
20    log::debug!("loading private key from {:?}", pem_path);
21    let content = load_file_content(pem_path).await?;
22    let parsed_result = pemfile::pkcs8_private_keys(&mut BufReader::new(content.as_slice()));
23
24    if let Ok(key) = parse_pem_single_element_result(parsed_result) {
25        return Ok(key);
26    };
27
28    let parsed_result = pemfile::rsa_private_keys(&mut BufReader::new(content.as_slice()));
29    parse_pem_single_element_result(parsed_result)
30}
31
32pub async fn load_signing_key(pem_path: PathBuf) -> Result<Box<dyn SigningKey>, Box<dyn Error>> {
33    let private_key = load_private_key(pem_path).await?;
34    match RSASigningKey::new(&private_key) {
35        Ok(s) => Ok(Box::new(s)),
36        Err(_) => Err("failed to convert private key to signing key".into()),
37    }
38}
39
40fn parse_pem_single_element_result<T: Clone + Debug>(
41    result: Result<Vec<T>, ()>,
42) -> Result<T, Box<dyn Error>> {
43    match result {
44        Ok(vec) => match vec.len() {
45            1 => Ok(vec.get(0).unwrap().clone()),
46            _ => Err(format!("expected a single element, got {:?}", vec).into()),
47        },
48        Err(_) => Err("failed to parse PEM content".into()),
49    }
50}
51
52async fn load_file_content(path: PathBuf) -> Result<Vec<u8>, Box<dyn Error>> {
53    let mut file = File::open(path).await?;
54    let mut content = vec![];
55    file.read_to_end(&mut content).await?;
56    Ok(content)
57}