pub fn system_roots() -> Vec<Vec<u8>> {
imp::roots()
}
#[cfg(windows)]
mod imp {
use core::ffi::c_void;
#[repr(C)]
struct CertContext {
encoding_type: u32,
cert_encoded: *const u8,
cert_encoded_len: u32,
cert_info: *mut c_void,
store: *mut c_void,
}
#[link(name = "crypt32")]
extern "system" {
fn CertOpenSystemStoreW(prov: usize, subsystem: *const u16) -> *mut c_void;
fn CertEnumCertificatesInStore(store: *mut c_void, prev: *const CertContext) -> *const CertContext;
fn CertCloseStore(store: *mut c_void, flags: u32) -> i32;
}
const X509_ASN_ENCODING: u32 = 1;
pub(super) fn roots() -> Vec<Vec<u8>> {
let name: Vec<u16> = "ROOT".encode_utf16().chain(Some(0)).collect();
let store = unsafe { CertOpenSystemStoreW(0, name.as_ptr()) };
if store.is_null() {
return Vec::new();
}
let mut out = Vec::new();
let mut ctx: *const CertContext = std::ptr::null();
loop {
ctx = unsafe { CertEnumCertificatesInStore(store, ctx) };
if ctx.is_null() {
break;
}
let der = unsafe {
let c = &*ctx;
if c.encoding_type & X509_ASN_ENCODING == 0 || c.cert_encoded.is_null() {
None
} else {
Some(std::slice::from_raw_parts(c.cert_encoded, c.cert_encoded_len as usize).to_vec())
}
};
if let Some(d) = der {
out.push(d);
}
}
unsafe { CertCloseStore(store, 0) };
out
}
}
#[cfg(not(windows))]
mod imp {
pub(super) fn roots() -> Vec<Vec<u8>> {
Vec::new()
}
}
#[cfg(test)]
mod tests {
#[cfg(windows)]
#[test]
fn windows_root_store_has_certificates() {
let roots = super::system_roots();
assert!(roots.len() > 5, "{} roots", roots.len());
assert!(roots.iter().all(|d| d.first() == Some(&0x30)), "DER SEQUENCE");
}
#[cfg(not(windows))]
#[test]
fn other_systems_use_bundles() {
assert!(super::system_roots().is_empty());
}
}