Skip to content

Instantly share code, notes, and snippets.

@stofte
Last active September 26, 2023 14:20
Show Gist options
  • Save stofte/fb338b847533b762f25d91e4e8db976f to your computer and use it in GitHub Desktop.
Save stofte/fb338b847533b762f25d91e4e8db976f to your computer and use it in GitHub Desktop.
rustc 1.72.0
[package]
name = "rust-cert"
version = "0.1.0"
edition = "2021"
[dependencies]
windows-sys = { version = "0.48", features = [
"Win32_Foundation",
"Win32_Security_Cryptography"] }
use std::ffi::{c_void, OsStr};
use std::os::windows::ffi::OsStrExt;
use std::ptr::null_mut;
use std::io::Write;
use std::fs;
use windows_sys::{
w,
Win32::Security::Cryptography::{
CertCloseStore, CertFindCertificateInStore, CertOpenStore, CryptStringToBinaryW,
CertAddCertificateContextToStore, CertFreeCertificateContext, PFXExportCertStoreEx,
CERT_CLOSE_STORE_CHECK_FLAG, CERT_FIND_HASH, CERT_OPEN_STORE_FLAGS,
CERT_QUERY_ENCODING_TYPE, CERT_STORE_PROV_MEMORY, CERT_STORE_PROV_SYSTEM_W,
CERT_SYSTEM_STORE_CURRENT_USER_ID, CERT_SYSTEM_STORE_LOCATION_SHIFT, CRYPT_INTEGER_BLOB,
CRYPT_STRING_HEXRAW, HCRYPTPROV_LEGACY, PKCS_7_ASN_ENCODING, X509_ASN_ENCODING,
CERT_CONTEXT, CERT_STORE_ADD_USE_EXISTING, EXPORT_PRIVATE_KEYS,
REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY,
},
};
fn main() {
unsafe {
let memory_store = CertOpenStore(
CERT_STORE_PROV_MEMORY,
CERT_QUERY_ENCODING_TYPE::default(),
HCRYPTPROV_LEGACY::default(),
CERT_OPEN_STORE_FLAGS::default(),
std::ptr::null(),
);
let store_name = OsStr::new("My")
.encode_wide()
.chain(Some(0))
.collect::<Vec<_>>();
let user_store = CertOpenStore(
CERT_STORE_PROV_SYSTEM_W,
CERT_QUERY_ENCODING_TYPE::default(),
HCRYPTPROV_LEGACY::default(),
CERT_SYSTEM_STORE_CURRENT_USER_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT,
store_name.as_ptr() as *const c_void,
);
if user_store.is_null() {
println!("user_store is null!");
} else {
println!("user_store obtained!");
}
let cert_thumbprint = w!("72f26338e9a4aefa3d54fe2ab66aaf85ce711805");
let hash_vec = vec![0; 40];
let mut hash_blob = CRYPT_INTEGER_BLOB {
cbData: 40 as u32,
pbData: hash_vec.as_ptr() as _,
};
if CryptStringToBinaryW(
cert_thumbprint,
hash_blob.cbData,
CRYPT_STRING_HEXRAW,
hash_blob.pbData,
&mut hash_blob.cbData,
null_mut(),
null_mut(),
) == 0
{
println!("Failed to write hash thumbprint");
}
let foo_ptr: *const c_void = &hash_blob as *const _ as _;
let cert_context = CertFindCertificateInStore(
user_store,
PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
0,
CERT_FIND_HASH,
foo_ptr,
std::ptr::null_mut(),
);
if cert_context.is_null() {
println!("No certificate was found!");
} else {
println!("Certificate was found!");
}
let foob: *const CERT_CONTEXT = cert_context;
if CertAddCertificateContextToStore(memory_store, foob, CERT_STORE_ADD_USE_EXISTING, null_mut()) == 1 {
println!("Added cert to memory store");
} else {
println!("Failed to add cert to memory store");
}
if CertFreeCertificateContext(foob) == 0 {
println!("Failed to free certificate context");
}
if CertCloseStore(user_store, CERT_CLOSE_STORE_CHECK_FLAG) == 1 {
println!("Closed user_store");
} else {
println!("Could NOT close user_store (due to unfreed resources)");
}
let mut pfx_blob = CRYPT_INTEGER_BLOB {
cbData: 0,
pbData: null_mut(),
};
if PFXExportCertStoreEx(
memory_store,
&mut pfx_blob,
null_mut(),
null_mut(),
EXPORT_PRIVATE_KEYS | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY
) == 1 {
println!("PFX required size: {}", pfx_blob.cbData);
let pfx_vec: Vec<u8> = vec![0; pfx_blob.cbData as usize];
pfx_blob.pbData = pfx_vec.as_ptr() as _;
if PFXExportCertStoreEx(
memory_store,
&mut pfx_blob,
null_mut(),
null_mut(),
EXPORT_PRIVATE_KEYS | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY
) == 1 {
println!("PFX export success");
fs::write("rust-cert.pfx", pfx_vec).unwrap();
} else {
println!("PFX export failed");
}
}
if CertCloseStore(memory_store, CERT_CLOSE_STORE_CHECK_FLAG) == 1 {
println!("Closed memory_store");
} else {
println!("Could NOT close memory_store (due to unfreed resources)");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment