tls_helpers/
lib.rs

1use base64::engine::general_purpose::STANDARD as base64_engine;
2use base64::Engine;
3use pki_types::{CertificateDer, PrivateKeyDer};
4use rustls::{Certificate, PrivateKey};
5use rustls_pemfile::{certs, pkcs8_private_keys};
6use std::io::{self, Cursor};
7use std::sync::Arc;
8use tokio_rustls::rustls::ServerConfig;
9use tokio_rustls::rustls::{ClientConfig, RootCertStore};
10use tokio_rustls::{TlsAcceptor, TlsConnector};
11
12pub fn from_base64_raw(pem: &str) -> io::Result<Vec<u8>> {
13    let cert_bytes = base64_engine
14        .decode(pem)
15        .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e.to_string()));
16
17    return cert_bytes;
18}
19
20pub fn certs_from_base64(cert_base64: &str) -> io::Result<Vec<Certificate>> {
21    let cert_bytes = from_base64_raw(cert_base64)?;
22    let mut cursor = Cursor::new(cert_bytes);
23    certs(&mut cursor)
24        .map(|result| result.map(|der| Certificate(der.to_vec())))
25        .collect()
26}
27
28pub fn privkey_from_base64(privkey_base64: &str) -> io::Result<PrivateKey> {
29    let key_bytes = from_base64_raw(privkey_base64)?;
30    let mut cursor = Cursor::new(key_bytes);
31    let keys = pkcs8_private_keys(&mut cursor)
32        .collect::<Result<Vec<_>, _>>()
33        .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Failed to read private keys"))?;
34    let key = keys
35        .into_iter()
36        .next()
37        .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "No private key found"))?;
38    Ok(PrivateKey(key.secret_pkcs8_der().to_vec()))
39}
40
41pub fn tls_connector_from_base64(
42    ca_cert_base64: &str,
43) -> Result<TlsConnector, Box<dyn std::error::Error>> {
44    let mut root_store = RootCertStore::empty();
45    let certs = load_certs_from_base64(ca_cert_base64)?;
46    for cert in certs {
47        root_store.add(cert)?;
48    }
49    let config = ClientConfig::builder()
50        .with_root_certificates(root_store)
51        .with_no_client_auth();
52    Ok(TlsConnector::from(Arc::new(config)))
53}
54
55pub fn tls_acceptor_from_base64(
56    cert_base64: &str,
57    privkey_base64: &str,
58    h1: bool,
59    h2: bool,
60) -> Result<TlsAcceptor, Box<dyn std::error::Error + Send + Sync>> {
61    let certs = load_certs_from_base64(cert_base64)?;
62    let key = load_keys_from_base64(privkey_base64)?;
63
64    let mut server_config = ServerConfig::builder()
65        .with_no_client_auth()
66        .with_single_cert(certs, key)?;
67
68    let mut protos = Vec::new();
69
70    if h2 {
71        protos.push(b"h2".to_vec());
72    }
73
74    if h1 {
75        protos.push(b"http/1.1".to_vec());
76        protos.push(b"http/1.0".to_vec());
77    }
78
79    server_config.alpn_protocols = protos;
80
81    let tls_acceptor = TlsAcceptor::from(Arc::new(server_config));
82
83    Ok(tls_acceptor)
84}
85
86pub fn load_certs_from_base64(cert_base64: &str) -> io::Result<Vec<CertificateDer<'static>>> {
87    let cert_bytes = from_base64_raw(cert_base64)?;
88    let mut cursor = Cursor::new(cert_bytes);
89    certs(&mut cursor).collect()
90}
91
92pub fn load_keys_from_base64(privkey_base64: &str) -> io::Result<PrivateKeyDer<'static>> {
93    let key_bytes = from_base64_raw(privkey_base64)?;
94    let mut cursor = Cursor::new(key_bytes);
95
96    // Try EC keys first
97    let ec_keys = rustls_pemfile::ec_private_keys(&mut cursor)
98        .collect::<Result<Vec<_>, _>>()
99        .map_err(|_| {
100            io::Error::new(io::ErrorKind::InvalidData, "Failed to read EC private keys")
101        })?;
102
103    if let Some(key) = ec_keys.into_iter().next() {
104        return Ok(PrivateKeyDer::from(key));
105    }
106
107    // If no EC keys found, reset cursor and try PKCS8
108    cursor.set_position(0);
109    let pkcs8_keys = pkcs8_private_keys(&mut cursor)
110        .collect::<Result<Vec<_>, _>>()
111        .map_err(|_| {
112            io::Error::new(
113                io::ErrorKind::InvalidData,
114                "Failed to read PKCS8 private keys",
115            )
116        })?;
117
118    pkcs8_keys
119        .into_iter()
120        .next()
121        .map(PrivateKeyDer::from)
122        .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "No private key found"))
123}