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