use std::time::Duration;
#[derive(Debug, Clone)]
pub struct CertProfile {
pub validity: Duration,
pub client_auth: bool,
pub server_auth: bool,
pub max_cn_bytes: usize,
}
impl Default for CertProfile {
fn default() -> Self {
Self {
validity: Duration::from_secs(7 * 24 * 60 * 60),
client_auth: true,
server_auth: false,
max_cn_bytes: 128,
}
}
}
impl CertProfile {
pub fn client_auth_for_days(days: u64) -> Self {
Self { validity: Duration::from_secs(days * 86_400), ..Self::default() }
}
pub fn validate_cn(&self, cn: &str) -> Result<(), String> {
if cn.is_empty() {
return Err("CN must not be empty".into());
}
if cn.as_bytes().len() > self.max_cn_bytes {
return Err(format!("CN exceeds {} bytes", self.max_cn_bytes));
}
if cn.chars().any(|c| c.is_control()) {
return Err("CN contains control characters".into());
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn validate_cn_rejects_empty_oversize_and_control_chars() {
let p = CertProfile::default();
assert!(p.validate_cn("gateway-001").is_ok());
assert!(p.validate_cn("").is_err());
let huge = "x".repeat(p.max_cn_bytes + 1);
assert!(p.validate_cn(&huge).is_err());
assert!(p.validate_cn("bad\x07cn").is_err());
}
}