use std::collections::HashSet;
use pem::{EncodeConfig, LineEnding, Pem};
const CERTIFICATE_TAG: &str = "CERTIFICATE";
pub(crate) fn collect_host_cas() -> Option<Vec<u8>> {
let result = rustls_native_certs::load_native_certs();
let error_count = result.errors.len();
let mut seen: HashSet<Vec<u8>> = HashSet::with_capacity(result.certs.len());
let mut pems: Vec<Pem> = Vec::with_capacity(result.certs.len());
for cert in result.certs {
let der = cert.as_ref().to_vec();
if seen.insert(der.clone()) {
pems.push(Pem::new(CERTIFICATE_TAG, der));
}
}
tracing::info!(
imported = pems.len(),
errors = error_count,
"collected host CAs for guest trust store"
);
if pems.is_empty() {
return None;
}
let encoded =
pem::encode_many_config(&pems, EncodeConfig::new().set_line_ending(LineEnding::LF));
Some(encoded.into_bytes())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn collect_host_cas_returns_parseable_bundle() {
let Some(bundle) = collect_host_cas() else {
eprintln!("host has no trusted CAs; skipping roundtrip check");
return;
};
let parsed = pem::parse_many(&bundle).expect("bundle parses");
assert!(!parsed.is_empty(), "bundle contains at least one cert");
for p in &parsed {
assert_eq!(p.tag(), CERTIFICATE_TAG);
assert!(!p.contents().is_empty(), "cert body is non-empty");
}
let mut seen = HashSet::new();
for p in &parsed {
assert!(
seen.insert(p.contents().to_vec()),
"bundle contains a duplicated cert"
);
}
}
}