1#![forbid(unsafe_code)]
13
14use std::path::Path;
15
16use cgn_core::{Error, Result};
17use tonic::transport::{Certificate, ClientTlsConfig, Identity, ServerTlsConfig};
18
19pub fn load_identity(cert_path: &Path, key_path: &Path) -> Result<Identity> {
21 let cert = std::fs::read(cert_path)
22 .map_err(|e| Error::Tls(format!("read {}: {e}", cert_path.display())))?;
23 let key = std::fs::read(key_path)
24 .map_err(|e| Error::Tls(format!("read {}: {e}", key_path.display())))?;
25 Ok(Identity::from_pem(cert, key))
26}
27
28pub fn server_tls(ca_path: &Path, cert_path: &Path, key_path: &Path) -> Result<ServerTlsConfig> {
33 let identity = load_identity(cert_path, key_path)?;
34 let ca = std::fs::read(ca_path)
35 .map_err(|e| Error::Tls(format!("read {}: {e}", ca_path.display())))?;
36 Ok(ServerTlsConfig::new()
37 .identity(identity)
38 .client_ca_root(Certificate::from_pem(ca)))
39}
40
41pub fn client_tls(
43 ca_path: &Path,
44 cert_path: &Path,
45 key_path: &Path,
46 domain: impl Into<String>,
47) -> Result<ClientTlsConfig> {
48 let identity = load_identity(cert_path, key_path)?;
49 let ca = std::fs::read(ca_path)
50 .map_err(|e| Error::Tls(format!("read {}: {e}", ca_path.display())))?;
51 Ok(ClientTlsConfig::new()
52 .domain_name(domain)
53 .ca_certificate(Certificate::from_pem(ca))
54 .identity(identity))
55}
56
57pub fn generate_dev_pki(common_name: &str, subject_alt_names: Vec<String>) -> Result<DevPki> {
63 use rcgen::{CertificateParams, IsCa, KeyUsagePurpose};
64
65 let mut ca_params = CertificateParams::new(vec!["cognitora-dev-ca".into()])
66 .map_err(|e| Error::Tls(format!("ca params: {e}")))?;
67 ca_params.is_ca = IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
68 ca_params
69 .distinguished_name
70 .push(rcgen::DnType::CommonName, "Cognitora Dev CA");
71 ca_params.key_usages = vec![
72 KeyUsagePurpose::KeyCertSign,
73 KeyUsagePurpose::CrlSign,
74 KeyUsagePurpose::DigitalSignature,
75 ];
76 let ca_key = rcgen::KeyPair::generate().map_err(|e| Error::Tls(format!("ca keypair: {e}")))?;
77 let ca_cert = ca_params
78 .self_signed(&ca_key)
79 .map_err(|e| Error::Tls(format!("ca self-sign: {e}")))?;
80
81 let mut leaf_params = CertificateParams::new(subject_alt_names)
82 .map_err(|e| Error::Tls(format!("leaf params: {e}")))?;
83 leaf_params
84 .distinguished_name
85 .push(rcgen::DnType::CommonName, common_name);
86 let leaf_key =
87 rcgen::KeyPair::generate().map_err(|e| Error::Tls(format!("leaf keypair: {e}")))?;
88 let leaf_cert = leaf_params
89 .signed_by(&leaf_key, &ca_cert, &ca_key)
90 .map_err(|e| Error::Tls(format!("leaf sign: {e}")))?;
91
92 Ok(DevPki {
93 ca_cert_pem: ca_cert.pem(),
94 ca_key_pem: ca_key.serialize_pem(),
95 leaf_cert_pem: leaf_cert.pem(),
96 leaf_key_pem: leaf_key.serialize_pem(),
97 })
98}
99
100#[derive(Debug, Clone)]
102pub struct DevPki {
103 pub ca_cert_pem: String,
104 pub ca_key_pem: String,
105 pub leaf_cert_pem: String,
106 pub leaf_key_pem: String,
107}