use crate::error::ConversionError;
use crate::openssl::ParsedPfx;
use openssl::x509::X509;
pub struct PemFormatter;
impl PemFormatter {
pub fn private_key_to_pem(parsed: &ParsedPfx) -> Result<Vec<u8>, ConversionError> {
let pem_data = parsed
.private_key
.private_key_to_pem_pkcs8()
.map_err(ConversionError::from)?;
if !Self::validate_pem(&pem_data) {
return Err(ConversionError::InvalidFormat(
"Generated private key PEM is invalid".to_string(),
));
}
Ok(pem_data)
}
pub fn certificate_to_pem(parsed: &ParsedPfx) -> Result<Vec<u8>, ConversionError> {
let pem_data = parsed.certificate.to_pem().map_err(ConversionError::from)?;
if !Self::validate_pem(&pem_data) {
return Err(ConversionError::InvalidFormat(
"Generated certificate PEM is invalid".to_string(),
));
}
Ok(pem_data)
}
pub fn cert_to_pem(cert: &X509) -> Result<Vec<u8>, ConversionError> {
let pem_data = cert.to_pem().map_err(ConversionError::from)?;
if !Self::validate_pem(&pem_data) {
return Err(ConversionError::InvalidFormat(
"Generated certificate PEM is invalid".to_string(),
));
}
Ok(pem_data)
}
pub fn chain_to_pem(parsed: &ParsedPfx) -> Result<Vec<u8>, ConversionError> {
let mut chain_pem = Self::certificate_to_pem(parsed)?;
for cert in &parsed.chain {
let cert_pem = Self::cert_to_pem(cert)?;
chain_pem.extend_from_slice(&cert_pem);
}
if !Self::validate_pem(&chain_pem) {
return Err(ConversionError::InvalidFormat(
"Generated certificate chain PEM is invalid".to_string(),
));
}
Ok(chain_pem)
}
pub fn chain_certs_to_pem(parsed: &ParsedPfx) -> Result<Vec<Vec<u8>>, ConversionError> {
parsed.chain.iter().map(Self::cert_to_pem).collect()
}
pub fn combined_to_pem(
parsed: &ParsedPfx,
include_chain: bool,
) -> Result<Vec<u8>, ConversionError> {
let mut combined = Self::private_key_to_pem(parsed)?;
if include_chain && parsed.has_chain() {
let chain_pem = Self::chain_to_pem(parsed)?;
combined.extend_from_slice(&chain_pem);
} else {
let cert_pem = Self::certificate_to_pem(parsed)?;
combined.extend_from_slice(&cert_pem);
}
if !Self::validate_pem(&combined) {
return Err(ConversionError::InvalidFormat(
"Generated combined PEM is invalid".to_string(),
));
}
Ok(combined)
}
pub fn validate_pem(pem_data: &[u8]) -> bool {
let pem_str = match std::str::from_utf8(pem_data) {
Ok(s) => s,
Err(_) => return false,
};
let has_begin = pem_str.contains("-----BEGIN");
let has_end = pem_str.contains("-----END");
if !has_begin || !has_end {
return false;
}
let begin_count = pem_str.matches("-----BEGIN").count();
let end_count = pem_str.matches("-----END").count();
begin_count == end_count && begin_count > 0
}
}