1 //! Bindings to Certificate Trust Lists (CTL) in winapi.
2 
3 #![allow(dead_code)]
4 
5 use std::io;
6 use std::mem;
7 use std::ptr;
8 use winapi::shared::minwindef as winapi;
9 use winapi::shared::ntdef;
10 use winapi::um::wincrypt;
11 
12 use crate::cert_context::CertContext;
13 use crate::Inner;
14 
15 lazy_static! {
16 	static ref szOID_OIWSEC_sha1: Vec<u8> =
17 		wincrypt::szOID_OIWSEC_sha1.bytes().chain(Some(0)).collect();
18 }
19 
20 /// Wrapped `PCCTL_CONTEXT` which represents a certificate trust list to
21 /// Windows.
22 pub struct CtlContext(wincrypt::PCCTL_CONTEXT);
23 
24 unsafe impl Send for CtlContext {}
25 unsafe impl Sync for CtlContext {}
26 
27 impl Drop for CtlContext {
drop(&mut self)28     fn drop(&mut self) {
29         unsafe {
30             wincrypt::CertFreeCTLContext(self.0);
31         }
32     }
33 }
34 
35 impl Inner<wincrypt::PCCTL_CONTEXT> for CtlContext {
from_inner(t: wincrypt::PCCTL_CONTEXT) -> CtlContext36     unsafe fn from_inner(t: wincrypt::PCCTL_CONTEXT) -> CtlContext {
37         CtlContext(t)
38     }
39 
as_inner(&self) -> wincrypt::PCCTL_CONTEXT40     fn as_inner(&self) -> wincrypt::PCCTL_CONTEXT {
41         self.0
42     }
43 
get_mut(&mut self) -> &mut wincrypt::PCCTL_CONTEXT44     fn get_mut(&mut self) -> &mut wincrypt::PCCTL_CONTEXT {
45         &mut self.0
46     }
47 }
48 
49 impl CtlContext {
50     /// Returns a builder reader to create an encoded `CtlContext`.
builder() -> Builder51     pub fn builder() -> Builder {
52         Builder {
53             certificates: vec![],
54             usages: vec![],
55         }
56     }
57 }
58 
59 /// Used to build an encoded `CtlContext` which can be added to a `Memory` store
60 /// to get back the actual `CtlContext`.
61 pub struct Builder {
62     certificates: Vec<CertContext>,
63     usages: Vec<Vec<u8>>,
64 }
65 
66 impl Builder {
67     /// Adds a certificate to be passed to `CryptMsgEncodeAndSignCTL` later on.
certificate(&mut self, cert: CertContext) -> &mut Builder68     pub fn certificate(&mut self, cert: CertContext) -> &mut Builder {
69         self.certificates.push(cert);
70         self
71     }
72 
73     /// Adds a usage string to be passed in the `SubjectUsage` field to
74     /// `CryptMsgEncodeAndSignCTL` later on.
usage(&mut self, usage: &str) -> &mut Builder75     pub fn usage(&mut self, usage: &str) -> &mut Builder {
76         let mut usage = usage.as_bytes().to_owned();
77         usage.push(0);
78         self.usages.push(usage);
79         self
80     }
81 
82     /// Calls `CryptMsgEncodeAndSignCTL` to encode this list of certificates
83     /// into a CTL.
84     ///
85     /// This can later be passed to `Memory::add_encoded_ctl`.
encode_and_sign(&self) -> io::Result<Vec<u8>>86     pub fn encode_and_sign(&self) -> io::Result<Vec<u8>> {
87         unsafe {
88             let encoding = wincrypt::X509_ASN_ENCODING | wincrypt::PKCS_7_ASN_ENCODING;
89 
90             let mut usages = self.usages.iter().map(|u| u.as_ptr()).collect::<Vec<_>>();
91             let mut entry_data = vec![];
92             let mut entries = vec![];
93             for certificate in &self.certificates {
94                 let data = cert_entry(certificate)?;
95                 entries.push(*(data.as_ptr() as *const wincrypt::CTL_ENTRY));
96                 entry_data.push(data);
97             }
98 
99             let mut ctl_info: wincrypt::CTL_INFO = mem::zeroed();
100             ctl_info.dwVersion = wincrypt::CTL_V1;
101             ctl_info.SubjectUsage.cUsageIdentifier = usages.len() as winapi::DWORD;
102             ctl_info.SubjectUsage.rgpszUsageIdentifier = usages.as_mut_ptr() as *mut ntdef::LPSTR;
103             ctl_info.SubjectAlgorithm.pszObjId = szOID_OIWSEC_sha1.as_ptr() as ntdef::LPSTR;
104             ctl_info.cCTLEntry = entries.len() as winapi::DWORD;
105             ctl_info.rgCTLEntry = entries.as_mut_ptr();
106 
107             let mut sign_info: wincrypt::CMSG_SIGNED_ENCODE_INFO = mem::zeroed();
108             sign_info.cbSize = mem::size_of_val(&sign_info) as winapi::DWORD;
109             let mut encoded_certs = self.certificates
110                 .iter()
111                 .map(|c| {
112                     wincrypt::CERT_BLOB {
113                         cbData: (*c.as_inner()).cbCertEncoded,
114                         pbData: (*c.as_inner()).pbCertEncoded,
115                     }
116                 })
117                 .collect::<Vec<_>>();
118             sign_info.rgCertEncoded = encoded_certs.as_mut_ptr();
119             sign_info.cCertEncoded = encoded_certs.len() as winapi::DWORD;
120 
121             let flags = wincrypt::CMSG_ENCODE_SORTED_CTL_FLAG |
122                         wincrypt::CMSG_ENCODE_HASHED_SUBJECT_IDENTIFIER_FLAG;
123 
124             let mut size = 0;
125 
126             let res = wincrypt::CryptMsgEncodeAndSignCTL(encoding,
127                                                          &mut ctl_info,
128                                                          &mut sign_info,
129                                                          flags,
130                                                          ptr::null_mut(),
131                                                          &mut size);
132             if res == winapi::FALSE {
133                 return Err(io::Error::last_os_error())
134             }
135 
136             let mut encoded = vec![0; size as usize];
137 
138             let res = wincrypt::CryptMsgEncodeAndSignCTL(encoding,
139                                                          &mut ctl_info,
140                                                          &mut sign_info,
141                                                          flags,
142                                                          encoded.as_mut_ptr() as *mut winapi::BYTE,
143                                                          &mut size);
144             if res == winapi::FALSE {
145                 return Err(io::Error::last_os_error())
146             }
147 
148             Ok(encoded)
149         }
150     }
151 }
152 
cert_entry(cert: &CertContext) -> io::Result<Vec<u8>>153 fn cert_entry(cert: &CertContext) -> io::Result<Vec<u8>> {
154     // FIXME: Seems to be missing since the winapi 0.3 upgrade?
155     const CTL_ENTRY_FROM_PROP_CHAIN_FLAG: winapi::DWORD = 1;
156 
157     unsafe {
158         let mut size = 0;
159 
160         let res = wincrypt::CertCreateCTLEntryFromCertificateContextProperties(
161 			cert.as_inner(),
162 			0,
163 			ptr::null_mut(),
164 			CTL_ENTRY_FROM_PROP_CHAIN_FLAG,
165 			ptr::null_mut(),
166 			ptr::null_mut(),
167 			&mut size);
168         if res == winapi::FALSE {
169             return Err(io::Error::last_os_error());
170         }
171 
172         let mut entry = vec![0u8; size as usize];
173         let res = wincrypt::CertCreateCTLEntryFromCertificateContextProperties(
174 			cert.as_inner(),
175 			0,
176 			ptr::null_mut(),
177 			CTL_ENTRY_FROM_PROP_CHAIN_FLAG,
178 			ptr::null_mut(),
179 			entry.as_mut_ptr() as wincrypt::PCTL_ENTRY,
180 			&mut size);
181         if res == winapi::FALSE {
182             Err(io::Error::last_os_error())
183         } else {
184             Ok(entry)
185         }
186     }
187 }
188