#[cfg(test)]
mod tests {
use certificate_manager::certificate::*;
use rustls_pki_types::{pem::PemObject, CertificateDer};
use std::fs::write;
use x509_parser::parse_x509_certificate;
#[test]
fn test_load_from_pem_files_without_passphrase() {
let temp_dir = tempfile::tempdir().expect("Failed to create temp directory");
let cert_path = temp_dir.path().join("cert.pem");
let key_path = temp_dir.path().join("key.pem");
let ca_created =
CertificateAuthority::new(None).expect("Failed to create Certificate Authority");
write(&cert_path, &ca_created.cert.pem()).expect("Failed to write certificate to file");
write(&key_path, &ca_created.key_pair.serialize_pem())
.expect("Failed to write private key to file");
let ca_loaded =
CertificateAuthority::load_from_pem_files(cert_path.clone(), key_path.clone(), None)
.expect("Failed to load Certificate Authority from PEM files");
let (_, parsed_ca_created) = parse_x509_certificate(&ca_created.cert.der())
.expect("Failed to parse PEM from certificate");
let (_, parsed_ca_loaded) = parse_x509_certificate(&ca_loaded.cert.der())
.expect("Failed to parse PEM from certificate");
assert_eq!(
parsed_ca_created, parsed_ca_loaded,
"Loaded certificate does not match the created certificate"
);
assert_eq!(
ca_loaded.key_pair.serialize_pem(),
ca_created.key_pair.serialize_pem(),
"Loaded private key does not match the loaded certificate"
);
temp_dir
.close()
.expect("Failed to clean up temporary directory");
}
#[test]
fn test_load_from_pem_files_with_passphrase() {
let temp_dir = tempfile::tempdir().expect("Failed to create temp directory");
let cert_path = temp_dir.path().join("cert.pem");
let key_path = temp_dir.path().join("key.pem");
let passphrase = Some("passphrase".to_string());
let ca_created =
CertificateAuthority::new(None).expect("Failed to create Certificate Authority");
let private_key = encrypt_private_key(&ca_created.key_pair, &passphrase).unwrap();
write(&cert_path, &ca_created.cert.pem()).expect("Failed to write certificate to file");
write(&key_path, &private_key).expect("Failed to write private key to file");
let ca_loaded = CertificateAuthority::load_from_pem_files(
cert_path.clone(),
key_path.clone(),
passphrase,
)
.expect("Failed to load Certificate Authority from PEM files");
let (_, parsed_ca_created) = parse_x509_certificate(&ca_created.cert.der())
.expect("Failed to parse PEM from certificate");
let (_, parsed_ca_loaded) = parse_x509_certificate(&ca_loaded.cert.der())
.expect("Failed to parse PEM from certificate");
assert_eq!(
parsed_ca_created, parsed_ca_loaded,
"Loaded certificate does not match the created certificate"
);
assert_eq!(
ca_created.key_pair.serialize_pem(),
ca_loaded.key_pair.serialize_pem(),
"Loaded private key does not match the loaded certificate"
);
temp_dir
.close()
.expect("Failed to clean up temporary directory");
}
#[test]
fn test_create_signed_certificate_for_domain() {
let ca = CertificateAuthority::new(None).expect("Failed to create Certificate Authority");
let domain = "example.com";
let cert = ca
.create_signed_certificate_for_domain(domain, None)
.expect("Failed to create signed certificate");
let (_, parsed_cert) =
parse_x509_certificate(&cert.der()).expect("Failed to parse PEM from certificate");
let (_, parsed_ca_cert) =
parse_x509_certificate(&ca.cert.der()).expect("Failed to parse PEM from certificate");
let subject_cn = parsed_cert
.subject()
.iter_common_name()
.next()
.expect("No common name in subject")
.as_str()
.expect("Failed to parse subject common name");
assert_eq!(
subject_cn, domain,
"The subject CN does not match the domain"
);
let issuer_name = parsed_cert.issuer().to_string();
let ca_subject_name = parsed_ca_cert.issuer().to_string();
assert_eq!(
issuer_name, ca_subject_name,
"The issuer does not match the CA's subject name"
);
assert!(
parsed_cert
.verify_signature(Some(&parsed_ca_cert.subject_pki))
.is_ok(),
"Certificate failed verification with CA key"
);
let san_extension = parsed_cert
.subject_alternative_name()
.expect("No SAN extension found")
.unwrap();
assert!(
san_extension
.value
.general_names
.iter()
.any(|name| matches!(name, x509_parser::extensions::GeneralName::DNSName(dns) if *dns == domain)),
"Default SAN does not match the domain"
);
let san_list = vec!["www.example.com".to_string(), "api.example.com".to_string()];
let cert_with_sans = ca
.create_signed_certificate_for_domain(domain, Some(san_list.clone()))
.expect("Failed to create signed certificate with SANs");
let (_, parsed_cert_with_sans) = parse_x509_certificate(&cert_with_sans.der())
.expect("Failed to parse PEM from certificate");
let subject_cn_with_sans = parsed_cert_with_sans
.subject()
.iter_common_name()
.next()
.expect("No common name in subject")
.as_str()
.expect("Failed to parse subject common name");
assert_eq!(
subject_cn_with_sans.to_string(),
domain,
"The subject CN does not match the domain"
);
let issuer_name = parsed_cert_with_sans.issuer().to_string();
let ca_subject_name = parsed_ca_cert.issuer().to_string();
assert_eq!(
issuer_name, ca_subject_name,
"The issuer does not match the CA's subject name"
);
assert!(
parsed_cert_with_sans
.verify_signature(Some(&parsed_ca_cert.subject_pki))
.is_ok(),
"Certificate failed verification with CA key"
);
let san_extension_with_sans = parsed_cert_with_sans
.subject_alternative_name()
.expect("No SAN extension found in certificate with SANs")
.unwrap();
for san in san_list {
assert!(
san_extension_with_sans
.value
.general_names
.iter()
.any(|name| matches!(name, x509_parser::extensions::GeneralName::DNSName(dns) if *dns == san.as_str())),
"SAN {} not found in certificate",
san
);
}
}
#[test]
fn test_spoof_certificate() {
let temp_dir = tempfile::tempdir().expect("Failed to create temp directory");
let cert_path = temp_dir.path().join("cert.pem");
let key_path = temp_dir.path().join("key.pem");
let ca_created = CertificateAuthority::new(Some("CA Spoofed".to_string()))
.expect("Failed to create Certificate Authority");
write(&cert_path, &ca_created.cert.pem()).expect("Failed to write certificate to file");
write(&key_path, &ca_created.key_pair.serialize_pem())
.expect("Failed to write private key to file");
let ca = CertificateAuthority::load_from_pem_files(cert_path, key_path, None)
.expect("Failed to create Certificate Authority");
let ca_to_spoof =
CertificateAuthority::new(None).expect("Failed to create Certificate Authority");
let (_, parsed_ca_cert) =
parse_x509_certificate(&ca.cert.der()).expect("Failed to parse PEM from certificate");
let ca_to_spoof_der = CertificateDer::from_pem_slice(ca_to_spoof.cert.pem().as_bytes())
.expect("Failed to parse PEM from certificate");
let spoofed_cert = ca
.spoof_certificate(ca_to_spoof_der)
.expect("Failed to spoof certificate");
let (_, parsed_spoofed_cert) =
parse_x509_certificate(&spoofed_cert).expect("Failed to parse PEM from certificate");
assert!(
parsed_spoofed_cert
.verify_signature(Some(&parsed_ca_cert.subject_pki))
.is_ok(),
"Certificate failed verification with CA key"
);
}
}