aboutsummaryrefslogtreecommitdiff
path: root/src/libs/dutil/WixToolset.DUtil/certutil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/dutil/WixToolset.DUtil/certutil.cpp')
-rw-r--r--src/libs/dutil/WixToolset.DUtil/certutil.cpp342
1 files changed, 342 insertions, 0 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/certutil.cpp b/src/libs/dutil/WixToolset.DUtil/certutil.cpp
new file mode 100644
index 00000000..69897b9e
--- /dev/null
+++ b/src/libs/dutil/WixToolset.DUtil/certutil.cpp
@@ -0,0 +1,342 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// Exit macros
7#define CertExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_CERTUTIL, x, s, __VA_ARGS__)
8#define CertExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_CERTUTIL, x, s, __VA_ARGS__)
9#define CertExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_CERTUTIL, x, s, __VA_ARGS__)
10#define CertExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_CERTUTIL, x, s, __VA_ARGS__)
11#define CertExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_CERTUTIL, x, s, __VA_ARGS__)
12#define CertExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_CERTUTIL, x, s, __VA_ARGS__)
13#define CertExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_CERTUTIL, p, x, e, s, __VA_ARGS__)
14#define CertExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_CERTUTIL, p, x, s, __VA_ARGS__)
15#define CertExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_CERTUTIL, p, x, e, s, __VA_ARGS__)
16#define CertExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_CERTUTIL, p, x, s, __VA_ARGS__)
17#define CertExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_CERTUTIL, e, x, s, __VA_ARGS__)
18#define CertExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_CERTUTIL, g, x, s, __VA_ARGS__)
19
20/********************************************************************
21CertReadProperty - reads a property from the certificate.
22
23NOTE: call MemFree() on the returned pvValue.
24********************************************************************/
25extern "C" HRESULT DAPI CertReadProperty(
26 __in PCCERT_CONTEXT pCertContext,
27 __in DWORD dwProperty,
28 __deref_out_bound LPVOID* ppvValue,
29 __out_opt DWORD* pcbValue
30 )
31{
32 HRESULT hr = S_OK;
33 LPVOID pv = NULL;
34 DWORD cb = 0;
35
36 if (!::CertGetCertificateContextProperty(pCertContext, dwProperty, NULL, &cb))
37 {
38 CertExitWithLastError(hr, "Failed to get size of certificate property.");
39 }
40
41 pv = MemAlloc(cb, TRUE);
42 CertExitOnNull(pv, hr, E_OUTOFMEMORY, "Failed to allocate memory for certificate property.");
43
44 if (!::CertGetCertificateContextProperty(pCertContext, dwProperty, pv, &cb))
45 {
46 CertExitWithLastError(hr, "Failed to get certificate property.");
47 }
48
49 *ppvValue = pv;
50 pv = NULL;
51
52 if (pcbValue)
53 {
54 *pcbValue = cb;
55 }
56
57LExit:
58 ReleaseMem(pv);
59 return hr;
60}
61
62
63extern "C" HRESULT DAPI CertGetAuthenticodeSigningTimestamp(
64 __in CMSG_SIGNER_INFO* pSignerInfo,
65 __out FILETIME* pftSigningTimestamp
66 )
67{
68 HRESULT hr = S_OK;
69 CRYPT_INTEGER_BLOB* pBlob = NULL;
70 PCMSG_SIGNER_INFO pCounterSignerInfo = NULL;
71 DWORD cbSigningTimestamp = sizeof(FILETIME);
72
73 // Find the countersigner blob. The countersigner in Authenticode contains the time
74 // that signing took place. It's a "countersigner" because the signing time was sent
75 // off to the certificate authority in the sky to return the verified time signed.
76 for (DWORD i = 0; i < pSignerInfo->UnauthAttrs.cAttr; ++i)
77 {
78 if (CSTR_EQUAL == ::CompareStringA(LOCALE_NEUTRAL, 0, szOID_RSA_counterSign, -1, pSignerInfo->UnauthAttrs.rgAttr[i].pszObjId, -1))
79 {
80 pBlob = pSignerInfo->UnauthAttrs.rgAttr[i].rgValue;
81 break;
82 }
83 }
84
85 if (!pBlob)
86 {
87 hr = TRUST_E_FAIL;
88 CertExitOnFailure(hr, "Failed to find countersigner in signer information.");
89 }
90
91 hr = CrypDecodeObject(PKCS7_SIGNER_INFO, pBlob->pbData, pBlob->cbData, 0, reinterpret_cast<LPVOID*>(&pCounterSignerInfo), NULL);
92 CertExitOnFailure(hr, "Failed to decode countersigner information.");
93
94 pBlob = NULL; // reset the blob before searching for the signing time.
95
96 // Find the signing time blob in the countersigner.
97 for (DWORD i = 0; i < pCounterSignerInfo->AuthAttrs.cAttr; ++i)
98 {
99 if (CSTR_EQUAL == ::CompareStringA(LOCALE_NEUTRAL, 0, szOID_RSA_signingTime, -1, pCounterSignerInfo->AuthAttrs.rgAttr[i].pszObjId, -1))
100 {
101 pBlob = pCounterSignerInfo->AuthAttrs.rgAttr[i].rgValue;
102 break;
103 }
104 }
105
106 if (!pBlob)
107 {
108 hr = TRUST_E_FAIL;
109 CertExitOnFailure(hr, "Failed to find signing time in countersigner information.");
110 }
111
112 if (!::CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, szOID_RSA_signingTime, pBlob->pbData, pBlob->cbData, 0, pftSigningTimestamp, &cbSigningTimestamp))
113 {
114 CertExitWithLastError(hr, "Failed to decode countersigner signing timestamp.");
115 }
116
117LExit:
118 ReleaseMem(pCounterSignerInfo);
119
120 return hr;
121}
122
123
124extern "C" HRESULT DAPI GetCryptProvFromCert(
125 __in_opt HWND hwnd,
126 __in PCCERT_CONTEXT pCert,
127 __out HCRYPTPROV *phCryptProv,
128 __out DWORD *pdwKeySpec,
129 __in BOOL *pfDidCryptAcquire,
130 __deref_opt_out LPWSTR *ppwszTmpContainer,
131 __deref_opt_out LPWSTR *ppwszProviderName,
132 __out DWORD *pdwProviderType
133 )
134{
135 HRESULT hr = S_OK;
136 HMODULE hMsSign32 = NULL;
137
138 typedef BOOL (WINAPI *GETCRYPTPROVFROMCERTPTR)(HWND, PCCERT_CONTEXT, HCRYPTPROV*, DWORD*,BOOL*,LPWSTR*,LPWSTR*,DWORD*);
139 GETCRYPTPROVFROMCERTPTR pGetCryptProvFromCert = NULL;
140
141 hr = LoadSystemLibrary(L"MsSign32.dll", &hMsSign32);
142 CertExitOnFailure(hr, "Failed to get handle to MsSign32.dll");
143
144 pGetCryptProvFromCert = (GETCRYPTPROVFROMCERTPTR)::GetProcAddress(hMsSign32, "GetCryptProvFromCert");
145 CertExitOnNullWithLastError(hMsSign32, hr, "Failed to get handle to MsSign32.dll");
146
147 if (!pGetCryptProvFromCert(hwnd,
148 pCert,
149 phCryptProv,
150 pdwKeySpec,
151 pfDidCryptAcquire,
152 ppwszTmpContainer,
153 ppwszProviderName,
154 pdwProviderType))
155 {
156 CertExitWithLastError(hr, "Failed to get CSP from cert.");
157 }
158LExit:
159 return hr;
160}
161
162extern "C" HRESULT DAPI FreeCryptProvFromCert(
163 __in BOOL fAcquired,
164 __in HCRYPTPROV hProv,
165 __in_opt LPWSTR pwszCapiProvider,
166 __in DWORD dwProviderType,
167 __in_opt LPWSTR pwszTmpContainer
168 )
169{
170 HRESULT hr = S_OK;
171 HMODULE hMsSign32 = NULL;
172
173 typedef void (WINAPI *FREECRYPTPROVFROMCERT)(BOOL, HCRYPTPROV, LPWSTR, DWORD, LPWSTR);
174 FREECRYPTPROVFROMCERT pFreeCryptProvFromCert = NULL;
175
176 hr = LoadSystemLibrary(L"MsSign32.dll", &hMsSign32);
177 CertExitOnFailure(hr, "Failed to get handle to MsSign32.dll");
178
179 pFreeCryptProvFromCert = (FREECRYPTPROVFROMCERT)::GetProcAddress(hMsSign32, "FreeCryptProvFromCert");
180 CertExitOnNullWithLastError(hMsSign32, hr, "Failed to get handle to MsSign32.dll");
181
182 pFreeCryptProvFromCert(fAcquired, hProv, pwszCapiProvider, dwProviderType, pwszTmpContainer);
183LExit:
184 return hr;
185}
186
187extern "C" HRESULT DAPI GetProvSecurityDesc(
188 __in HCRYPTPROV hProv,
189 __deref_out SECURITY_DESCRIPTOR** ppSecurity)
190{
191 HRESULT hr = S_OK;
192 ULONG ulSize = 0;
193 SECURITY_DESCRIPTOR* pSecurity = NULL;
194
195 // Get the size of the security descriptor.
196 if (!::CryptGetProvParam(
197 hProv,
198 PP_KEYSET_SEC_DESCR,
199 NULL,
200 &ulSize,
201 DACL_SECURITY_INFORMATION))
202 {
203 CertExitWithLastError(hr, "Error getting security descriptor size for CSP.");
204 }
205
206 // Allocate the memory for the security descriptor.
207 pSecurity = static_cast<SECURITY_DESCRIPTOR *>(MemAlloc(ulSize, TRUE));
208 CertExitOnNullWithLastError(pSecurity, hr, "Error allocating memory for CSP DACL");
209
210 // Get the security descriptor.
211 if (!::CryptGetProvParam(
212 hProv,
213 PP_KEYSET_SEC_DESCR,
214 (BYTE*)pSecurity,
215 &ulSize,
216 DACL_SECURITY_INFORMATION))
217 {
218 MemFree(pSecurity);
219 CertExitWithLastError(hr, "Error getting security descriptor for CSP.");
220 }
221 *ppSecurity = pSecurity;
222
223LExit:
224 return hr;
225}
226
227
228extern "C" HRESULT DAPI SetProvSecurityDesc(
229 __in HCRYPTPROV hProv,
230 __in SECURITY_DESCRIPTOR* pSecurity)
231{
232 HRESULT hr = S_OK;
233
234 // Set the new security descriptor.
235 if (!::CryptSetProvParam(
236 hProv,
237 PP_KEYSET_SEC_DESCR,
238 (BYTE*)pSecurity,
239 DACL_SECURITY_INFORMATION))
240 {
241 CertExitWithLastError(hr, "Error setting security descriptor for CSP.");
242 }
243LExit:
244 return hr;
245}
246
247extern "C" BOOL DAPI CertHasPrivateKey(
248 __in PCCERT_CONTEXT pCertContext,
249 __out_opt DWORD* pdwKeySpec)
250{
251 HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hPrivateKey = NULL;
252 DWORD dwKeySpec = 0;
253 // set CRYPT_ACQUIRE_CACHE_FLAG so that we don't have to release the private key handle
254 BOOL fResult = ::CryptAcquireCertificatePrivateKey(
255 pCertContext,
256 CRYPT_ACQUIRE_SILENT_FLAG | CRYPT_ACQUIRE_CACHE_FLAG,
257 0, //pvReserved
258 &hPrivateKey,
259 &dwKeySpec,
260 NULL
261 );
262 if (pdwKeySpec)
263 {
264 *pdwKeySpec = dwKeySpec;
265 }
266 return fResult;
267}
268
269
270extern "C" HRESULT DAPI CertInstallSingleCertificate(
271 __in HCERTSTORE hStore,
272 __in PCCERT_CONTEXT pCertContext,
273 __in LPCWSTR wzName
274 )
275{
276 HRESULT hr = S_OK;
277 CERT_BLOB blob = { };
278
279 DWORD dwKeySpec = 0;
280
281 HCRYPTPROV hCsp = NULL;
282 LPWSTR pwszTmpContainer = NULL;
283 LPWSTR pwszProviderName = NULL;
284 DWORD dwProviderType = 0;
285 BOOL fAcquired = TRUE;
286
287 SECURITY_DESCRIPTOR* pSecurity = NULL;
288 SECURITY_DESCRIPTOR* pSecurityNew = NULL;
289
290 // Update the friendly name of the certificate to be configured.
291 blob.pbData = (BYTE*)wzName;
292 blob.cbData = (lstrlenW(wzName) + 1) * sizeof(WCHAR); // including terminating null
293
294 if (!::CertSetCertificateContextProperty(pCertContext, CERT_FRIENDLY_NAME_PROP_ID, 0, &blob))
295 {
296 CertExitWithLastError(hr, "Failed to set the friendly name of the certificate: %ls", wzName);
297 }
298
299 if (!::CertAddCertificateContextToStore(hStore, pCertContext, CERT_STORE_ADD_REPLACE_EXISTING, NULL))
300 {
301 CertExitWithLastError(hr, "Failed to add certificate to the store.");
302 }
303
304 // if the certificate has a private key, grant Administrators access
305 if (CertHasPrivateKey(pCertContext, &dwKeySpec))
306 {
307 if (AT_KEYEXCHANGE == dwKeySpec || AT_SIGNATURE == dwKeySpec)
308 {
309 // We added a CSP key
310 hr = GetCryptProvFromCert(NULL, pCertContext, &hCsp, &dwKeySpec, &fAcquired, &pwszTmpContainer, &pwszProviderName, &dwProviderType);
311 CertExitOnFailure(hr, "Failed to get handle to CSP");
312
313 hr = GetProvSecurityDesc(hCsp, &pSecurity);
314 CertExitOnFailure(hr, "Failed to get security descriptor of CSP");
315
316 hr = AclAddAdminToSecurityDescriptor(pSecurity, &pSecurityNew);
317 CertExitOnFailure(hr, "Failed to create new security descriptor");
318
319 hr = SetProvSecurityDesc(hCsp, pSecurityNew);
320 CertExitOnFailure(hr, "Failed to set Admin ACL on CSP");
321 }
322
323 if (CERT_NCRYPT_KEY_SPEC == dwKeySpec)
324 {
325 // We added a CNG key
326 // TODO change ACL on CNG key
327 }
328 }
329LExit:
330 if (hCsp)
331 {
332 FreeCryptProvFromCert(fAcquired, hCsp, NULL, dwProviderType, NULL);
333 }
334
335 ReleaseMem(pSecurity);
336
337 if (pSecurityNew)
338 {
339 AclFreeSecurityDescriptor(pSecurityNew);
340 }
341 return hr;
342}