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}