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