use base64::engine::general_purpose::STANDARD as base64_engine;
use base64::Engine;
use pki_types::{CertificateDer, PrivateKeyDer};
use rustls_pemfile::{certs, private_key};
use std::io::{self, Cursor};
use std::sync::Arc;
use tokio_rustls::rustls::crypto::ring;
use tokio_rustls::rustls::{ClientConfig, RootCertStore, ServerConfig};
use tokio_rustls::{TlsAcceptor, TlsConnector};
fn install_provider() {
let _ = ring::default_provider().install_default();
}
pub fn from_base64_raw(pem: &str) -> io::Result<Vec<u8>> {
let cert_bytes = base64_engine
.decode(pem)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e.to_string()));
return cert_bytes;
}
pub fn certs_from_base64(cert_base64: &str) -> io::Result<Vec<CertificateDer<'static>>> {
let cert_bytes = from_base64_raw(cert_base64)?;
let mut cursor = Cursor::new(cert_bytes);
certs(&mut cursor).collect()
}
pub fn privkey_from_base64(privkey_base64: &str) -> io::Result<PrivateKeyDer<'static>> {
let key_bytes = from_base64_raw(privkey_base64)?;
let mut cursor = Cursor::new(key_bytes);
private_key(&mut cursor)?
.ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "No private key found"))
}
pub fn tls_connector_from_base64(
ca_cert_base64: &str,
) -> Result<TlsConnector, Box<dyn std::error::Error>> {
install_provider();
let mut root_store = RootCertStore::empty();
let certs = load_certs_from_base64(ca_cert_base64)?;
for cert in certs {
root_store.add(cert)?;
}
let config = ClientConfig::builder()
.with_root_certificates(root_store)
.with_no_client_auth();
Ok(TlsConnector::from(Arc::new(config)))
}
pub fn tls_acceptor_from_base64(
cert_base64: &str,
privkey_base64: &str,
h1: bool,
h2: bool,
) -> Result<TlsAcceptor, Box<dyn std::error::Error + Send + Sync>> {
install_provider();
let certs = load_certs_from_base64(cert_base64)?;
let key = load_keys_from_base64(privkey_base64)?;
let mut server_config = ServerConfig::builder()
.with_no_client_auth()
.with_single_cert(certs, key)?;
let mut protos = Vec::new();
if h2 {
protos.push(b"h2".to_vec());
}
if h1 {
protos.push(b"http/1.1".to_vec());
protos.push(b"http/1.0".to_vec());
}
server_config.alpn_protocols = protos;
let tls_acceptor = TlsAcceptor::from(Arc::new(server_config));
Ok(tls_acceptor)
}
pub fn load_certs_from_base64(cert_base64: &str) -> io::Result<Vec<CertificateDer<'static>>> {
install_provider();
let cert_bytes = from_base64_raw(cert_base64)?;
let mut cursor = Cursor::new(cert_bytes);
certs(&mut cursor).collect()
}
pub fn load_keys_from_base64(privkey_base64: &str) -> io::Result<PrivateKeyDer<'static>> {
install_provider();
let key_bytes = from_base64_raw(privkey_base64)?;
let mut cursor = Cursor::new(key_bytes);
private_key(&mut cursor)?
.ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "No private key found"))
}