diff options
Diffstat (limited to 'vendor/schannel/src/ctl_context.rs')
-rw-r--r-- | vendor/schannel/src/ctl_context.rs | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/vendor/schannel/src/ctl_context.rs b/vendor/schannel/src/ctl_context.rs new file mode 100644 index 0000000..f73f45c --- /dev/null +++ b/vendor/schannel/src/ctl_context.rs @@ -0,0 +1,187 @@ +//! Bindings to Certificate Trust Lists (CTL) in winapi. + +#![allow(dead_code)] + +use std::io; +use std::mem; +use std::ptr; + +use windows_sys::Win32::Security::Cryptography; + +use crate::cert_context::CertContext; +use crate::Inner; + +/// Wrapped `PCCTL_CONTEXT` which represents a certificate trust list to +/// Windows. +pub struct CtlContext(*const Cryptography::CTL_CONTEXT); + +unsafe impl Send for CtlContext {} +unsafe impl Sync for CtlContext {} + +impl Drop for CtlContext { + fn drop(&mut self) { + unsafe { + Cryptography::CertFreeCTLContext(self.0); + } + } +} + +impl Inner<*const Cryptography::CTL_CONTEXT> for CtlContext { + unsafe fn from_inner(t: *const Cryptography::CTL_CONTEXT) -> CtlContext { + CtlContext(t) + } + + fn as_inner(&self) -> *const Cryptography::CTL_CONTEXT { + self.0 + } + + fn get_mut(&mut self) -> &mut *const Cryptography::CTL_CONTEXT { + &mut self.0 + } +} + +impl CtlContext { + /// Returns a builder reader to create an encoded `CtlContext`. + pub fn builder() -> Builder { + Builder { + certificates: vec![], + usages: vec![], + } + } +} + +/// Used to build an encoded `CtlContext` which can be added to a `Memory` store +/// to get back the actual `CtlContext`. +pub struct Builder { + certificates: Vec<CertContext>, + usages: Vec<Vec<u8>>, +} + +impl Builder { + /// Adds a certificate to be passed to `CryptMsgEncodeAndSignCTL` later on. + pub fn certificate(&mut self, cert: CertContext) -> &mut Builder { + self.certificates.push(cert); + self + } + + /// Adds a usage string to be passed in the `SubjectUsage` field to + /// `CryptMsgEncodeAndSignCTL` later on. + pub fn usage(&mut self, usage: &str) -> &mut Builder { + let mut usage = usage.as_bytes().to_owned(); + usage.push(0); + self.usages.push(usage); + self + } + + /// Calls `CryptMsgEncodeAndSignCTL` to encode this list of certificates + /// into a CTL. + /// + /// This can later be passed to `Memory::add_encoded_ctl`. + pub fn encode_and_sign(&self) -> io::Result<Vec<u8>> { + unsafe { + let encoding = Cryptography::X509_ASN_ENCODING | Cryptography::PKCS_7_ASN_ENCODING; + + let mut usages = self + .usages + .iter() + .map(|u| u.as_ptr() as _) + .collect::<Vec<_>>(); + let mut entry_data = vec![]; + let mut entries = vec![]; + for certificate in &self.certificates { + let data = cert_entry(certificate)?; + entries.push(*(data.as_ptr() as *const Cryptography::CTL_ENTRY)); + entry_data.push(data); + } + + let mut ctl_info: Cryptography::CTL_INFO = mem::zeroed(); + ctl_info.dwVersion = Cryptography::CTL_V1; + ctl_info.SubjectUsage.cUsageIdentifier = usages.len() as u32; + ctl_info.SubjectUsage.rgpszUsageIdentifier = usages.as_mut_ptr(); + ctl_info.SubjectAlgorithm.pszObjId = Cryptography::szOID_OIWSEC_sha1 as _; + ctl_info.cCTLEntry = entries.len() as u32; + ctl_info.rgCTLEntry = entries.as_mut_ptr(); + + let mut sign_info: Cryptography::CMSG_SIGNED_ENCODE_INFO = mem::zeroed(); + sign_info.cbSize = mem::size_of_val(&sign_info) as u32; + let mut encoded_certs = self + .certificates + .iter() + .map(|c| Cryptography::CRYPT_INTEGER_BLOB { + cbData: (*c.as_inner()).cbCertEncoded, + pbData: (*c.as_inner()).pbCertEncoded, + }) + .collect::<Vec<_>>(); + sign_info.rgCertEncoded = encoded_certs.as_mut_ptr(); + sign_info.cCertEncoded = encoded_certs.len() as u32; + + let flags = Cryptography::CMSG_ENCODE_SORTED_CTL_FLAG + | Cryptography::CMSG_ENCODE_HASHED_SUBJECT_IDENTIFIER_FLAG; + + let mut size = 0; + + let res = Cryptography::CryptMsgEncodeAndSignCTL( + encoding, + &ctl_info, + &sign_info, + flags, + ptr::null_mut(), + &mut size, + ); + if res == 0 { + return Err(io::Error::last_os_error()); + } + + let mut encoded = vec![0; size as usize]; + + let res = Cryptography::CryptMsgEncodeAndSignCTL( + encoding, + &ctl_info, + &sign_info, + flags, + encoded.as_mut_ptr() as *mut u8, + &mut size, + ); + if res == 0 { + return Err(io::Error::last_os_error()); + } + + Ok(encoded) + } + } +} + +fn cert_entry(cert: &CertContext) -> io::Result<Vec<u8>> { + unsafe { + let mut size: u32 = 0; + + let res = Cryptography::CertCreateCTLEntryFromCertificateContextProperties( + cert.as_inner(), + 0, + ptr::null(), + Cryptography::CTL_ENTRY_FROM_PROP_CHAIN_FLAG, + ptr::null_mut(), + ptr::null_mut(), + &mut size, + ); + if res == 0 { + return Err(io::Error::last_os_error()); + } + + let mut entry = vec![0u8; size as usize]; + let res = Cryptography::CertCreateCTLEntryFromCertificateContextProperties( + cert.as_inner(), + 0, + ptr::null(), + Cryptography::CTL_ENTRY_FROM_PROP_CHAIN_FLAG, + ptr::null_mut(), + entry.as_mut_ptr() as *mut Cryptography::CTL_ENTRY, + &mut size, + ); + if res == 0 { + Err(io::Error::last_os_error()) + } else { + Ok(entry) + } + } +} |