| //! Bindings to Certificate Trust Lists (CTL) in winapi. | 
 |  | 
 | #![allow(dead_code)] | 
 |  | 
 | use std::io; | 
 | use std::mem; | 
 | use std::ptr; | 
 | use winapi::shared::minwindef as winapi; | 
 | use winapi::shared::ntdef; | 
 | use winapi::um::wincrypt; | 
 |  | 
 | use crate::cert_context::CertContext; | 
 | use crate::Inner; | 
 |  | 
 | lazy_static! { | 
 | 	static ref szOID_OIWSEC_sha1: Vec<u8> = | 
 | 		wincrypt::szOID_OIWSEC_sha1.bytes().chain(Some(0)).collect(); | 
 | } | 
 |  | 
 | /// Wrapped `PCCTL_CONTEXT` which represents a certificate trust list to | 
 | /// Windows. | 
 | pub struct CtlContext(wincrypt::PCCTL_CONTEXT); | 
 |  | 
 | unsafe impl Send for CtlContext {} | 
 | unsafe impl Sync for CtlContext {} | 
 |  | 
 | impl Drop for CtlContext { | 
 |     fn drop(&mut self) { | 
 |         unsafe { | 
 |             wincrypt::CertFreeCTLContext(self.0); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | impl Inner<wincrypt::PCCTL_CONTEXT> for CtlContext { | 
 |     unsafe fn from_inner(t: wincrypt::PCCTL_CONTEXT) -> CtlContext { | 
 |         CtlContext(t) | 
 |     } | 
 |  | 
 |     fn as_inner(&self) -> wincrypt::PCCTL_CONTEXT { | 
 |         self.0 | 
 |     } | 
 |  | 
 |     fn get_mut(&mut self) -> &mut wincrypt::PCCTL_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 = wincrypt::X509_ASN_ENCODING | wincrypt::PKCS_7_ASN_ENCODING; | 
 |  | 
 |             let mut usages = self.usages.iter().map(|u| u.as_ptr()).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 wincrypt::CTL_ENTRY)); | 
 |                 entry_data.push(data); | 
 |             } | 
 |  | 
 |             let mut ctl_info: wincrypt::CTL_INFO = mem::zeroed(); | 
 |             ctl_info.dwVersion = wincrypt::CTL_V1; | 
 |             ctl_info.SubjectUsage.cUsageIdentifier = usages.len() as winapi::DWORD; | 
 |             ctl_info.SubjectUsage.rgpszUsageIdentifier = usages.as_mut_ptr() as *mut ntdef::LPSTR; | 
 |             ctl_info.SubjectAlgorithm.pszObjId = szOID_OIWSEC_sha1.as_ptr() as ntdef::LPSTR; | 
 |             ctl_info.cCTLEntry = entries.len() as winapi::DWORD; | 
 |             ctl_info.rgCTLEntry = entries.as_mut_ptr(); | 
 |  | 
 |             let mut sign_info: wincrypt::CMSG_SIGNED_ENCODE_INFO = mem::zeroed(); | 
 |             sign_info.cbSize = mem::size_of_val(&sign_info) as winapi::DWORD; | 
 |             let mut encoded_certs = self.certificates | 
 |                 .iter() | 
 |                 .map(|c| { | 
 |                     wincrypt::CERT_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 winapi::DWORD; | 
 |  | 
 |             let flags = wincrypt::CMSG_ENCODE_SORTED_CTL_FLAG | | 
 |                         wincrypt::CMSG_ENCODE_HASHED_SUBJECT_IDENTIFIER_FLAG; | 
 |  | 
 |             let mut size = 0; | 
 |  | 
 |             let res = wincrypt::CryptMsgEncodeAndSignCTL(encoding, | 
 |                                                          &mut ctl_info, | 
 |                                                          &mut sign_info, | 
 |                                                          flags, | 
 |                                                          ptr::null_mut(), | 
 |                                                          &mut size); | 
 |             if res == winapi::FALSE { | 
 |                 return Err(io::Error::last_os_error()) | 
 |             } | 
 |  | 
 |             let mut encoded = vec![0; size as usize]; | 
 |  | 
 |             let res = wincrypt::CryptMsgEncodeAndSignCTL(encoding, | 
 |                                                          &mut ctl_info, | 
 |                                                          &mut sign_info, | 
 |                                                          flags, | 
 |                                                          encoded.as_mut_ptr() as *mut winapi::BYTE, | 
 |                                                          &mut size); | 
 |             if res == winapi::FALSE { | 
 |                 return Err(io::Error::last_os_error()) | 
 |             } | 
 |  | 
 |             Ok(encoded) | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | fn cert_entry(cert: &CertContext) -> io::Result<Vec<u8>> { | 
 |     // FIXME: Seems to be missing since the winapi 0.3 upgrade? | 
 |     const CTL_ENTRY_FROM_PROP_CHAIN_FLAG: winapi::DWORD = 1; | 
 |  | 
 |     unsafe { | 
 |         let mut size = 0; | 
 |  | 
 |         let res = wincrypt::CertCreateCTLEntryFromCertificateContextProperties( | 
 | 			cert.as_inner(), | 
 | 			0, | 
 | 			ptr::null_mut(), | 
 | 			CTL_ENTRY_FROM_PROP_CHAIN_FLAG, | 
 | 			ptr::null_mut(), | 
 | 			ptr::null_mut(), | 
 | 			&mut size); | 
 |         if res == winapi::FALSE { | 
 |             return Err(io::Error::last_os_error()); | 
 |         } | 
 |  | 
 |         let mut entry = vec![0u8; size as usize]; | 
 |         let res = wincrypt::CertCreateCTLEntryFromCertificateContextProperties( | 
 | 			cert.as_inner(), | 
 | 			0, | 
 | 			ptr::null_mut(), | 
 | 			CTL_ENTRY_FROM_PROP_CHAIN_FLAG, | 
 | 			ptr::null_mut(), | 
 | 			entry.as_mut_ptr() as wincrypt::PCTL_ENTRY, | 
 | 			&mut size); | 
 |         if res == winapi::FALSE { | 
 |             Err(io::Error::last_os_error()) | 
 |         } else { | 
 |             Ok(entry) | 
 |         } | 
 |     } | 
 | } |