rustls_helper/
lib.rs

1use rustls::{
2    server::{AllowAnyAuthenticatedClient, NoClientAuth},
3    Certificate, ClientConfig, PrivateKey, RootCertStore, ServerConfig,
4};
5
6/// create `rustls::Certificate` from pem file
7pub fn cert_from_pem(cert: Vec<u8>) -> Result<Vec<Certificate>, std::io::Error> {
8    let cert_list = rustls_pemfile::read_all(&mut cert.as_ref())?
9        .into_iter()
10        .filter_map(|i| match i {
11            rustls_pemfile::Item::X509Certificate(i) => Some(i),
12            _ => None,
13        })
14        .map(Certificate)
15        .collect::<Vec<_>>();
16    if cert_list.len() >= 1 {
17        Ok(cert_list)
18    } else {
19        Err(std::io::Error::new(
20            std::io::ErrorKind::NotFound,
21            "No certififcate found.",
22        ))
23    }
24}
25
26/// create `rustls::PrivateKey` from pem file
27pub fn key_from_pem(key: Vec<u8>) -> Result<PrivateKey, std::io::Error> {
28    let option_key = rustls_pemfile::read_all(&mut key.as_ref())?
29        .into_iter()
30        .find_map(|i| match i {
31            rustls_pemfile::Item::RSAKey(i)
32            | rustls_pemfile::Item::PKCS8Key(i)
33            | rustls_pemfile::Item::ECKey(i) => Some(i),
34            _ => None,
35        })
36        .map(PrivateKey);
37    match option_key {
38        Some(k) => Ok(k),
39        None => Err(std::io::Error::new(
40            std::io::ErrorKind::NotFound,
41            "No private key found.",
42        )),
43    }
44}
45
46/// create `rustls::ServerConfig` from certificate,private key and optional client auth.
47pub fn create_server_config(
48    cert: Vec<Certificate>,
49    key: PrivateKey,
50    ca: Option<Vec<Certificate>>,
51) -> Result<ServerConfig, rustls::Error> {
52    Ok(ServerConfig::builder()
53        .with_safe_defaults()
54        .with_client_cert_verifier(match ca {
55            Some(ca) => AllowAnyAuthenticatedClient::new(root_cert_store(ca)?).boxed(),
56            None => NoClientAuth::boxed(),
57        })
58        .with_single_cert(cert, key)?)
59}
60
61/// create `rustls::ClientConfig` from CA certificate and optional client auth.
62/// Note `cert` and `key` need to be both `Some(...)` to enable client auth.
63pub fn create_client_config(
64    cert: Option<Vec<Certificate>>,
65    key: Option<PrivateKey>,
66    ca: Vec<Certificate>,
67) -> Result<ClientConfig, rustls::Error> {
68    let builder = ClientConfig::builder()
69        .with_safe_defaults()
70        .with_root_certificates(root_cert_store(ca)?);
71    let config = if let (Some(cert), Some(key)) = (cert, key) {
72        builder.with_client_auth_cert(cert, key)?
73    } else {
74        builder.with_no_client_auth()
75    };
76    Ok(config)
77}
78
79fn root_cert_store(cert: Vec<Certificate>) -> Result<RootCertStore, rustls::Error> {
80    let mut roots = rustls::RootCertStore::empty();
81    for cer in cert {
82        roots.add(&cer)?;
83    }
84    Ok(roots)
85}