use rcgen::{
generate_simple_self_signed, CertificateParams, CertificateSigningRequestParams, KeyPair,
};
use super::error::{Result, SignError};
pub fn generate_csr(subject_alt_names: &[String]) -> Result<(String, String)> {
let names: Vec<String> = if subject_alt_names.is_empty() {
vec!["localhost".to_string()]
} else {
subject_alt_names.to_vec()
};
let key_pair = KeyPair::generate()
.map_err(|e| SignError::CertificateError(format!("Failed to generate key pair: {}", e)))?;
let private_key_pem = key_pair.serialize_pem();
let cert_params = CertificateParams::new(names).map_err(|e| {
SignError::CertificateError(format!("Failed to create certificate params: {}", e))
})?;
let csr = cert_params
.serialize_request(&key_pair)
.map_err(|e| SignError::CertificateError(format!("Failed to serialize CSR: {}", e)))?;
let csr_pem = csr
.pem()
.map_err(|e| SignError::CertificateError(format!("Failed to get CSR PEM: {}", e)))?
.to_string();
Ok((csr_pem, private_key_pem))
}
pub fn sign_csr(csr_pem: &str, domain: &str) -> Result<String> {
let ca_cert = generate_simple_self_signed(vec![domain.to_string()]).map_err(|e| {
SignError::CertificateError(format!("Failed to generate CA certificate: {}", e))
})?;
let csr_params = CertificateSigningRequestParams::from_pem(csr_pem)
.map_err(|e| SignError::CertificateError(format!("Failed to parse CSR PEM: {}", e)))?;
let signed_cert = csr_params
.signed_by(&ca_cert.cert, &ca_cert.key_pair)
.map_err(|e| SignError::CertificateError(format!("Failed to sign CSR: {}", e)))?;
Ok(signed_cert.pem())
}
pub fn create_self_signed_certificate(subject_alt_names: &[String]) -> Result<(String, String)> {
let names: Vec<String> = if subject_alt_names.is_empty() {
vec!["localhost".to_string()]
} else {
subject_alt_names.to_vec()
};
let cert = generate_simple_self_signed(names).map_err(|e| {
SignError::CertificateError(format!("Failed to generate self-signed certificate: {}", e))
})?;
Ok((cert.cert.pem(), cert.key_pair.serialize_pem()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_generate_csr() {
let sans = vec!["example.com".to_string(), "localhost".to_string()];
let (csr_pem, key_pem) = generate_csr(&sans).unwrap();
assert!(csr_pem.contains("BEGIN CERTIFICATE REQUEST"));
assert!(key_pem.contains("BEGIN PRIVATE KEY"));
}
#[test]
fn test_sign_csr() {
let sans = vec!["example.com".to_string()];
let (csr_pem, _key_pem) = generate_csr(&sans).unwrap();
let signed = sign_csr(&csr_pem, "example.com").unwrap();
assert!(signed.contains("BEGIN CERTIFICATE"));
}
#[test]
fn test_create_self_signed_certificate() {
let sans = vec!["localhost".to_string()];
let (cert_pem, key_pem) = create_self_signed_certificate(&sans).unwrap();
assert!(cert_pem.contains("BEGIN CERTIFICATE"));
assert!(key_pem.contains("BEGIN PRIVATE KEY"));
}
#[test]
fn test_generate_csr_empty_sans() {
let (csr_pem, _) = generate_csr(&[]).unwrap();
assert!(csr_pem.contains("BEGIN CERTIFICATE REQUEST"));
}
}