use anyhow::{Context, Result}; use rcgen::{CertificateParams, DistinguishedName, DnType, KeyPair, SanType}; use std::net::IpAddr; use std::path::Path; pub fn issue_node_cert( node_id: &str, hostname: &str, ip: &str, ca_cert_path: Option<&str>, ca_key_path: Option<&str>, ) -> Result<(String, String)> { let mut dns_names = Vec::new(); if !node_id.trim().is_empty() { dns_names.push(node_id.to_string()); } if !hostname.trim().is_empty() && hostname != node_id { dns_names.push(hostname.to_string()); } if dns_names.is_empty() { dns_names.push("photoncloud-node".to_string()); } let mut params = CertificateParams::new(dns_names).context("failed to create certificate params")?; let mut distinguished_name = DistinguishedName::new(); if !node_id.trim().is_empty() { distinguished_name.push(DnType::CommonName, node_id); } params.distinguished_name = distinguished_name; if let Ok(ip_addr) = ip.parse::() { params.subject_alt_names.push(SanType::IpAddress(ip_addr)); } let key_pair = KeyPair::generate().context("failed to generate TLS key pair")?; if let (Some(ca_cert_path), Some(ca_key_path)) = (ca_cert_path, ca_key_path) { let ca_cert_pem = std::fs::read_to_string(Path::new(ca_cert_path)) .with_context(|| format!("failed to read CA cert from {}", ca_cert_path))?; let ca_key_pem = std::fs::read_to_string(Path::new(ca_key_path)) .with_context(|| format!("failed to read CA key from {}", ca_key_path))?; let ca_key_pair = KeyPair::from_pem(&ca_key_pem).context("failed to parse CA key pair from PEM")?; let ca_params = CertificateParams::from_ca_cert_pem(&ca_cert_pem) .context("failed to parse CA certificate")?; let ca_cert = ca_params .self_signed(&ca_key_pair) .context("failed to build CA certificate for signing")?; let cert = params .signed_by(&key_pair, &ca_cert, &ca_key_pair) .context("failed to sign node certificate")?; let cert_pem = cert.pem(); let key_pem = key_pair.serialize_pem(); return Ok((cert_pem, key_pem)); } let cert = params .self_signed(&key_pair) .context("failed to self-sign node certificate")?; let cert_pem = cert.pem(); let key_pem = key_pair.serialize_pem(); Ok((cert_pem, key_pem)) }