Synchronize with trunk r58606.
[reactos.git] / dll / win32 / crypt32 / cert.c
1 /*
2 * Copyright 2004-2006 Juan Lang
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 *
18 */
19
20 #define WIN32_NO_STATUS
21 #define _INC_WINDOWS
22 #define COM_NO_WINDOWS_H
23
24 #include <assert.h>
25 #include <stdarg.h>
26
27 #define NONAMELESSUNION
28 #include <windef.h>
29 #include <winbase.h>
30 #include <wincrypt.h>
31 //#include "winnls.h"
32 #include <rpc.h>
33 #include <wine/debug.h>
34 #include <wine/unicode.h>
35 #include "crypt32_private.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
38
39 /* Internal version of CertGetCertificateContextProperty that gets properties
40 * directly from the context (or the context it's linked to, depending on its
41 * type.) Doesn't handle special-case properties, since they are handled by
42 * CertGetCertificateContextProperty, and are particular to the store in which
43 * the property exists (which is separate from the context.)
44 */
45 static BOOL CertContext_GetProperty(void *context, DWORD dwPropId,
46 void *pvData, DWORD *pcbData);
47
48 /* Internal version of CertSetCertificateContextProperty that sets properties
49 * directly on the context (or the context it's linked to, depending on its
50 * type.) Doesn't handle special cases, since they're handled by
51 * CertSetCertificateContextProperty anyway.
52 */
53 static BOOL CertContext_SetProperty(void *context, DWORD dwPropId,
54 DWORD dwFlags, const void *pvData);
55
56 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
57 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
58 DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
59 {
60 PCCERT_CONTEXT cert = CertCreateCertificateContext(dwCertEncodingType,
61 pbCertEncoded, cbCertEncoded);
62 BOOL ret;
63
64 TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore, dwCertEncodingType,
65 pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
66
67 if (cert)
68 {
69 ret = CertAddCertificateContextToStore(hCertStore, cert,
70 dwAddDisposition, ppCertContext);
71 CertFreeCertificateContext(cert);
72 }
73 else
74 ret = FALSE;
75 return ret;
76 }
77
78 BOOL WINAPI CertAddEncodedCertificateToSystemStoreA(LPCSTR pszCertStoreName,
79 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
80 {
81 HCERTSTORE store;
82 BOOL ret = FALSE;
83
84 TRACE("(%s, %p, %d)\n", debugstr_a(pszCertStoreName), pbCertEncoded,
85 cbCertEncoded);
86
87 store = CertOpenSystemStoreA(0, pszCertStoreName);
88 if (store)
89 {
90 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
91 pbCertEncoded, cbCertEncoded, CERT_STORE_ADD_USE_EXISTING, NULL);
92 CertCloseStore(store, 0);
93 }
94 return ret;
95 }
96
97 BOOL WINAPI CertAddEncodedCertificateToSystemStoreW(LPCWSTR pszCertStoreName,
98 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
99 {
100 HCERTSTORE store;
101 BOOL ret = FALSE;
102
103 TRACE("(%s, %p, %d)\n", debugstr_w(pszCertStoreName), pbCertEncoded,
104 cbCertEncoded);
105
106 store = CertOpenSystemStoreW(0, pszCertStoreName);
107 if (store)
108 {
109 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
110 pbCertEncoded, cbCertEncoded, CERT_STORE_ADD_USE_EXISTING, NULL);
111 CertCloseStore(store, 0);
112 }
113 return ret;
114 }
115
116 BOOL WINAPI CertAddCertificateLinkToStore(HCERTSTORE hCertStore,
117 PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
118 PCCERT_CONTEXT *ppCertContext)
119 {
120 static int calls;
121 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
122
123 if (!(calls++))
124 FIXME("(%p, %p, %08x, %p): semi-stub\n", hCertStore, pCertContext,
125 dwAddDisposition, ppCertContext);
126 if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
127 return FALSE;
128 if (store->type == StoreTypeCollection)
129 {
130 SetLastError(E_INVALIDARG);
131 return FALSE;
132 }
133 return CertAddCertificateContextToStore(hCertStore, pCertContext,
134 dwAddDisposition, ppCertContext);
135 }
136
137 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
138 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
139 {
140 PCERT_CONTEXT cert = NULL;
141 BOOL ret;
142 PCERT_INFO certInfo = NULL;
143 DWORD size = 0;
144
145 TRACE("(%08x, %p, %d)\n", dwCertEncodingType, pbCertEncoded,
146 cbCertEncoded);
147
148 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
149 {
150 SetLastError(E_INVALIDARG);
151 return NULL;
152 }
153
154 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT_TO_BE_SIGNED,
155 pbCertEncoded, cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL,
156 &certInfo, &size);
157 if (ret)
158 {
159 BYTE *data = NULL;
160
161 cert = Context_CreateDataContext(sizeof(CERT_CONTEXT));
162 if (!cert)
163 goto end;
164 data = CryptMemAlloc(cbCertEncoded);
165 if (!data)
166 {
167 CertFreeCertificateContext(cert);
168 cert = NULL;
169 goto end;
170 }
171 memcpy(data, pbCertEncoded, cbCertEncoded);
172 cert->dwCertEncodingType = dwCertEncodingType;
173 cert->pbCertEncoded = data;
174 cert->cbCertEncoded = cbCertEncoded;
175 cert->pCertInfo = certInfo;
176 cert->hCertStore = 0;
177 }
178
179 end:
180 return cert;
181 }
182
183 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
184 PCCERT_CONTEXT pCertContext)
185 {
186 TRACE("(%p)\n", pCertContext);
187
188 if (!pCertContext)
189 return NULL;
190
191 Context_AddRef((void *)pCertContext, sizeof(CERT_CONTEXT));
192 return pCertContext;
193 }
194
195 static void CertDataContext_Free(void *context)
196 {
197 PCERT_CONTEXT certContext = context;
198
199 CryptMemFree(certContext->pbCertEncoded);
200 LocalFree(certContext->pCertInfo);
201 }
202
203 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
204 {
205 BOOL ret = TRUE;
206
207 TRACE("(%p)\n", pCertContext);
208
209 if (pCertContext)
210 ret = Context_Release((void *)pCertContext, sizeof(CERT_CONTEXT),
211 CertDataContext_Free);
212 return ret;
213 }
214
215 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
216 DWORD dwPropId)
217 {
218 PCONTEXT_PROPERTY_LIST properties = Context_GetProperties(
219 pCertContext, sizeof(CERT_CONTEXT));
220 DWORD ret;
221
222 TRACE("(%p, %d)\n", pCertContext, dwPropId);
223
224 if (properties)
225 ret = ContextPropertyList_EnumPropIDs(properties, dwPropId);
226 else
227 ret = 0;
228 return ret;
229 }
230
231 static BOOL CertContext_GetHashProp(void *context, DWORD dwPropId,
232 ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
233 DWORD *pcbData)
234 {
235 BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
236 pcbData);
237 if (ret && pvData)
238 {
239 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
240
241 ret = CertContext_SetProperty(context, dwPropId, 0, &blob);
242 }
243 return ret;
244 }
245
246 static BOOL CertContext_CopyParam(void *pvData, DWORD *pcbData, const void *pb,
247 DWORD cb)
248 {
249 BOOL ret = TRUE;
250
251 if (!pvData)
252 *pcbData = cb;
253 else if (*pcbData < cb)
254 {
255 SetLastError(ERROR_MORE_DATA);
256 *pcbData = cb;
257 ret = FALSE;
258 }
259 else
260 {
261 memcpy(pvData, pb, cb);
262 *pcbData = cb;
263 }
264 return ret;
265 }
266
267 static BOOL CertContext_GetProperty(void *context, DWORD dwPropId,
268 void *pvData, DWORD *pcbData)
269 {
270 PCCERT_CONTEXT pCertContext = context;
271 PCONTEXT_PROPERTY_LIST properties =
272 Context_GetProperties(context, sizeof(CERT_CONTEXT));
273 BOOL ret;
274 CRYPT_DATA_BLOB blob;
275
276 TRACE("(%p, %d, %p, %p)\n", context, dwPropId, pvData, pcbData);
277
278 if (properties)
279 ret = ContextPropertyList_FindProperty(properties, dwPropId, &blob);
280 else
281 ret = FALSE;
282 if (ret)
283 ret = CertContext_CopyParam(pvData, pcbData, blob.pbData, blob.cbData);
284 else
285 {
286 /* Implicit properties */
287 switch (dwPropId)
288 {
289 case CERT_SHA1_HASH_PROP_ID:
290 ret = CertContext_GetHashProp(context, dwPropId, CALG_SHA1,
291 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData,
292 pcbData);
293 break;
294 case CERT_MD5_HASH_PROP_ID:
295 ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
296 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData,
297 pcbData);
298 break;
299 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
300 ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
301 pCertContext->pCertInfo->Subject.pbData,
302 pCertContext->pCertInfo->Subject.cbData,
303 pvData, pcbData);
304 break;
305 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
306 ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
307 pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
308 pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
309 pvData, pcbData);
310 break;
311 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
312 ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
313 pCertContext->pCertInfo->SerialNumber.pbData,
314 pCertContext->pCertInfo->SerialNumber.cbData,
315 pvData, pcbData);
316 break;
317 case CERT_SIGNATURE_HASH_PROP_ID:
318 ret = CryptHashToBeSigned(0, pCertContext->dwCertEncodingType,
319 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData,
320 pcbData);
321 if (ret && pvData)
322 {
323 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
324
325 ret = CertContext_SetProperty(context, dwPropId, 0, &blob);
326 }
327 break;
328 case CERT_KEY_IDENTIFIER_PROP_ID:
329 {
330 PCERT_EXTENSION ext = CertFindExtension(
331 szOID_SUBJECT_KEY_IDENTIFIER, pCertContext->pCertInfo->cExtension,
332 pCertContext->pCertInfo->rgExtension);
333
334 if (ext)
335 {
336 CRYPT_DATA_BLOB value;
337 DWORD size = sizeof(value);
338
339 ret = CryptDecodeObjectEx(X509_ASN_ENCODING,
340 szOID_SUBJECT_KEY_IDENTIFIER, ext->Value.pbData,
341 ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &value,
342 &size);
343 if (ret)
344 {
345 ret = CertContext_CopyParam(pvData, pcbData, value.pbData,
346 value.cbData);
347 CertContext_SetProperty(context, dwPropId, 0, &value);
348 }
349 }
350 else
351 SetLastError(ERROR_INVALID_DATA);
352 break;
353 }
354 default:
355 SetLastError(CRYPT_E_NOT_FOUND);
356 }
357 }
358 TRACE("returning %d\n", ret);
359 return ret;
360 }
361
362 void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info)
363 {
364 DWORD i, containerLen, provNameLen;
365 LPBYTE data = (LPBYTE)info + sizeof(CRYPT_KEY_PROV_INFO);
366
367 info->pwszContainerName = (LPWSTR)data;
368 containerLen = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
369 data += containerLen;
370
371 info->pwszProvName = (LPWSTR)data;
372 provNameLen = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
373 data += provNameLen;
374
375 info->rgProvParam = (PCRYPT_KEY_PROV_PARAM)data;
376 data += info->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
377
378 for (i = 0; i < info->cProvParam; i++)
379 {
380 info->rgProvParam[i].pbData = data;
381 data += info->rgProvParam[i].cbData;
382 }
383 }
384
385 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
386 DWORD dwPropId, void *pvData, DWORD *pcbData)
387 {
388 BOOL ret;
389
390 TRACE("(%p, %d, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
391
392 switch (dwPropId)
393 {
394 case 0:
395 case CERT_CERT_PROP_ID:
396 case CERT_CRL_PROP_ID:
397 case CERT_CTL_PROP_ID:
398 SetLastError(E_INVALIDARG);
399 ret = FALSE;
400 break;
401 case CERT_ACCESS_STATE_PROP_ID:
402 if (pCertContext->hCertStore)
403 ret = CertGetStoreProperty(pCertContext->hCertStore, dwPropId,
404 pvData, pcbData);
405 else
406 {
407 DWORD state = 0;
408
409 ret = CertContext_CopyParam(pvData, pcbData, &state, sizeof(state));
410 }
411 break;
412 case CERT_KEY_PROV_HANDLE_PROP_ID:
413 {
414 CERT_KEY_CONTEXT keyContext;
415 DWORD size = sizeof(keyContext);
416
417 ret = CertContext_GetProperty((void *)pCertContext,
418 CERT_KEY_CONTEXT_PROP_ID, &keyContext, &size);
419 if (ret)
420 ret = CertContext_CopyParam(pvData, pcbData, &keyContext.hCryptProv,
421 sizeof(keyContext.hCryptProv));
422 break;
423 }
424 case CERT_KEY_PROV_INFO_PROP_ID:
425 ret = CertContext_GetProperty((void *)pCertContext, dwPropId, pvData,
426 pcbData);
427 if (ret && pvData)
428 CRYPT_FixKeyProvInfoPointers(pvData);
429 break;
430 default:
431 ret = CertContext_GetProperty((void *)pCertContext, dwPropId, pvData,
432 pcbData);
433 }
434
435 TRACE("returning %d\n", ret);
436 return ret;
437 }
438
439 /* Copies key provider info from from into to, where to is assumed to be a
440 * contiguous buffer of memory large enough for from and all its associated
441 * data, but whose pointers are uninitialized.
442 * Upon return, to contains a contiguous copy of from, packed in the following
443 * order:
444 * - CRYPT_KEY_PROV_INFO
445 * - pwszContainerName
446 * - pwszProvName
447 * - rgProvParam[0]...
448 */
449 static void CRYPT_CopyKeyProvInfo(PCRYPT_KEY_PROV_INFO to,
450 const CRYPT_KEY_PROV_INFO *from)
451 {
452 DWORD i;
453 LPBYTE nextData = (LPBYTE)to + sizeof(CRYPT_KEY_PROV_INFO);
454
455 if (from->pwszContainerName)
456 {
457 to->pwszContainerName = (LPWSTR)nextData;
458 lstrcpyW(to->pwszContainerName, from->pwszContainerName);
459 nextData += (lstrlenW(from->pwszContainerName) + 1) * sizeof(WCHAR);
460 }
461 else
462 to->pwszContainerName = NULL;
463 if (from->pwszProvName)
464 {
465 to->pwszProvName = (LPWSTR)nextData;
466 lstrcpyW(to->pwszProvName, from->pwszProvName);
467 nextData += (lstrlenW(from->pwszProvName) + 1) * sizeof(WCHAR);
468 }
469 else
470 to->pwszProvName = NULL;
471 to->dwProvType = from->dwProvType;
472 to->dwFlags = from->dwFlags;
473 to->cProvParam = from->cProvParam;
474 to->rgProvParam = (PCRYPT_KEY_PROV_PARAM)nextData;
475 nextData += to->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
476 to->dwKeySpec = from->dwKeySpec;
477 for (i = 0; i < to->cProvParam; i++)
478 {
479 memcpy(&to->rgProvParam[i], &from->rgProvParam[i],
480 sizeof(CRYPT_KEY_PROV_PARAM));
481 to->rgProvParam[i].pbData = nextData;
482 memcpy(to->rgProvParam[i].pbData, from->rgProvParam[i].pbData,
483 from->rgProvParam[i].cbData);
484 nextData += from->rgProvParam[i].cbData;
485 }
486 }
487
488 static BOOL CertContext_SetKeyProvInfoProperty(PCONTEXT_PROPERTY_LIST properties,
489 const CRYPT_KEY_PROV_INFO *info)
490 {
491 BOOL ret;
492 LPBYTE buf = NULL;
493 DWORD size = sizeof(CRYPT_KEY_PROV_INFO), i, containerSize, provNameSize;
494
495 if (info->pwszContainerName)
496 containerSize = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
497 else
498 containerSize = 0;
499 if (info->pwszProvName)
500 provNameSize = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
501 else
502 provNameSize = 0;
503 size += containerSize + provNameSize;
504 for (i = 0; i < info->cProvParam; i++)
505 size += sizeof(CRYPT_KEY_PROV_PARAM) + info->rgProvParam[i].cbData;
506 buf = CryptMemAlloc(size);
507 if (buf)
508 {
509 CRYPT_CopyKeyProvInfo((PCRYPT_KEY_PROV_INFO)buf, info);
510 ret = ContextPropertyList_SetProperty(properties,
511 CERT_KEY_PROV_INFO_PROP_ID, buf, size);
512 CryptMemFree(buf);
513 }
514 else
515 ret = FALSE;
516 return ret;
517 }
518
519 static BOOL CertContext_SetProperty(void *context, DWORD dwPropId,
520 DWORD dwFlags, const void *pvData)
521 {
522 PCONTEXT_PROPERTY_LIST properties =
523 Context_GetProperties(context, sizeof(CERT_CONTEXT));
524 BOOL ret;
525
526 TRACE("(%p, %d, %08x, %p)\n", context, dwPropId, dwFlags, pvData);
527
528 if (!properties)
529 ret = FALSE;
530 else
531 {
532 switch (dwPropId)
533 {
534 case CERT_AUTO_ENROLL_PROP_ID:
535 case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */
536 case CERT_DESCRIPTION_PROP_ID:
537 case CERT_FRIENDLY_NAME_PROP_ID:
538 case CERT_HASH_PROP_ID:
539 case CERT_KEY_IDENTIFIER_PROP_ID:
540 case CERT_MD5_HASH_PROP_ID:
541 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
542 case CERT_PUBKEY_ALG_PARA_PROP_ID:
543 case CERT_PVK_FILE_PROP_ID:
544 case CERT_SIGNATURE_HASH_PROP_ID:
545 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
546 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
547 case CERT_EXTENDED_ERROR_INFO_PROP_ID:
548 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
549 case CERT_ENROLLMENT_PROP_ID:
550 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
551 case CERT_RENEWAL_PROP_ID:
552 {
553 if (pvData)
554 {
555 const CRYPT_DATA_BLOB *blob = pvData;
556
557 ret = ContextPropertyList_SetProperty(properties, dwPropId,
558 blob->pbData, blob->cbData);
559 }
560 else
561 {
562 ContextPropertyList_RemoveProperty(properties, dwPropId);
563 ret = TRUE;
564 }
565 break;
566 }
567 case CERT_DATE_STAMP_PROP_ID:
568 if (pvData)
569 ret = ContextPropertyList_SetProperty(properties, dwPropId,
570 pvData, sizeof(FILETIME));
571 else
572 {
573 ContextPropertyList_RemoveProperty(properties, dwPropId);
574 ret = TRUE;
575 }
576 break;
577 case CERT_KEY_CONTEXT_PROP_ID:
578 {
579 if (pvData)
580 {
581 const CERT_KEY_CONTEXT *keyContext = pvData;
582
583 if (keyContext->cbSize != sizeof(CERT_KEY_CONTEXT))
584 {
585 SetLastError(E_INVALIDARG);
586 ret = FALSE;
587 }
588 else
589 ret = ContextPropertyList_SetProperty(properties, dwPropId,
590 (const BYTE *)keyContext, keyContext->cbSize);
591 }
592 else
593 {
594 ContextPropertyList_RemoveProperty(properties, dwPropId);
595 ret = TRUE;
596 }
597 break;
598 }
599 case CERT_KEY_PROV_INFO_PROP_ID:
600 if (pvData)
601 ret = CertContext_SetKeyProvInfoProperty(properties, pvData);
602 else
603 {
604 ContextPropertyList_RemoveProperty(properties, dwPropId);
605 ret = TRUE;
606 }
607 break;
608 case CERT_KEY_PROV_HANDLE_PROP_ID:
609 {
610 CERT_KEY_CONTEXT keyContext;
611 DWORD size = sizeof(keyContext);
612
613 ret = CertContext_GetProperty(context, CERT_KEY_CONTEXT_PROP_ID,
614 &keyContext, &size);
615 if (ret)
616 {
617 if (!(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
618 CryptReleaseContext(keyContext.hCryptProv, 0);
619 }
620 keyContext.cbSize = sizeof(keyContext);
621 if (pvData)
622 keyContext.hCryptProv = *(const HCRYPTPROV *)pvData;
623 else
624 {
625 keyContext.hCryptProv = 0;
626 keyContext.dwKeySpec = AT_SIGNATURE;
627 }
628 ret = CertContext_SetProperty(context, CERT_KEY_CONTEXT_PROP_ID,
629 0, &keyContext);
630 break;
631 }
632 default:
633 FIXME("%d: stub\n", dwPropId);
634 ret = FALSE;
635 }
636 }
637 TRACE("returning %d\n", ret);
638 return ret;
639 }
640
641 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
642 DWORD dwPropId, DWORD dwFlags, const void *pvData)
643 {
644 BOOL ret;
645
646 TRACE("(%p, %d, %08x, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
647
648 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
649 * crashes on most of these, I'll be safer.
650 */
651 switch (dwPropId)
652 {
653 case 0:
654 case CERT_ACCESS_STATE_PROP_ID:
655 case CERT_CERT_PROP_ID:
656 case CERT_CRL_PROP_ID:
657 case CERT_CTL_PROP_ID:
658 SetLastError(E_INVALIDARG);
659 return FALSE;
660 }
661 ret = CertContext_SetProperty((void *)pCertContext, dwPropId, dwFlags,
662 pvData);
663 TRACE("returning %d\n", ret);
664 return ret;
665 }
666
667 /* Acquires the private key using the key provider info, retrieving info from
668 * the certificate if info is NULL. The acquired provider is returned in
669 * *phCryptProv, and the key spec for the provider is returned in *pdwKeySpec.
670 */
671 static BOOL CRYPT_AcquirePrivateKeyFromProvInfo(PCCERT_CONTEXT pCert,
672 PCRYPT_KEY_PROV_INFO info, HCRYPTPROV *phCryptProv, DWORD *pdwKeySpec)
673 {
674 DWORD size = 0;
675 BOOL allocated = FALSE, ret = TRUE;
676
677 if (!info)
678 {
679 ret = CertGetCertificateContextProperty(pCert,
680 CERT_KEY_PROV_INFO_PROP_ID, 0, &size);
681 if (ret)
682 {
683 info = HeapAlloc(GetProcessHeap(), 0, size);
684 if (info)
685 {
686 ret = CertGetCertificateContextProperty(pCert,
687 CERT_KEY_PROV_INFO_PROP_ID, info, &size);
688 allocated = TRUE;
689 }
690 else
691 {
692 SetLastError(ERROR_OUTOFMEMORY);
693 ret = FALSE;
694 }
695 }
696 else
697 SetLastError(CRYPT_E_NO_KEY_PROPERTY);
698 }
699 if (ret)
700 {
701 ret = CryptAcquireContextW(phCryptProv, info->pwszContainerName,
702 info->pwszProvName, info->dwProvType, 0);
703 if (ret)
704 {
705 DWORD i;
706
707 for (i = 0; i < info->cProvParam; i++)
708 {
709 CryptSetProvParam(*phCryptProv,
710 info->rgProvParam[i].dwParam, info->rgProvParam[i].pbData,
711 info->rgProvParam[i].dwFlags);
712 }
713 *pdwKeySpec = info->dwKeySpec;
714 }
715 else
716 SetLastError(CRYPT_E_NO_KEY_PROPERTY);
717 }
718 if (allocated)
719 HeapFree(GetProcessHeap(), 0, info);
720 return ret;
721 }
722
723 BOOL WINAPI CryptAcquireCertificatePrivateKey(PCCERT_CONTEXT pCert,
724 DWORD dwFlags, void *pvReserved, HCRYPTPROV_OR_NCRYPT_KEY_HANDLE *phCryptProv,
725 DWORD *pdwKeySpec, BOOL *pfCallerFreeProv)
726 {
727 BOOL ret = FALSE, cache = FALSE;
728 PCRYPT_KEY_PROV_INFO info = NULL;
729 CERT_KEY_CONTEXT keyContext;
730 DWORD size;
731
732 TRACE("(%p, %08x, %p, %p, %p, %p)\n", pCert, dwFlags, pvReserved,
733 phCryptProv, pdwKeySpec, pfCallerFreeProv);
734
735 if (dwFlags & CRYPT_ACQUIRE_USE_PROV_INFO_FLAG)
736 {
737 DWORD size = 0;
738
739 ret = CertGetCertificateContextProperty(pCert,
740 CERT_KEY_PROV_INFO_PROP_ID, 0, &size);
741 if (ret)
742 {
743 info = HeapAlloc(GetProcessHeap(), 0, size);
744 ret = CertGetCertificateContextProperty(pCert,
745 CERT_KEY_PROV_INFO_PROP_ID, info, &size);
746 if (ret)
747 cache = info->dwFlags & CERT_SET_KEY_CONTEXT_PROP_ID;
748 }
749 }
750 else if (dwFlags & CRYPT_ACQUIRE_CACHE_FLAG)
751 cache = TRUE;
752 *phCryptProv = 0;
753 if (cache)
754 {
755 size = sizeof(keyContext);
756 ret = CertGetCertificateContextProperty(pCert, CERT_KEY_CONTEXT_PROP_ID,
757 &keyContext, &size);
758 if (ret)
759 {
760 *phCryptProv = keyContext.hCryptProv;
761 if (pdwKeySpec)
762 *pdwKeySpec = keyContext.dwKeySpec;
763 if (pfCallerFreeProv)
764 *pfCallerFreeProv = !cache;
765 }
766 }
767 if (!*phCryptProv)
768 {
769 ret = CRYPT_AcquirePrivateKeyFromProvInfo(pCert, info,
770 &keyContext.hCryptProv, &keyContext.dwKeySpec);
771 if (ret)
772 {
773 *phCryptProv = keyContext.hCryptProv;
774 if (pdwKeySpec)
775 *pdwKeySpec = keyContext.dwKeySpec;
776 if (cache)
777 {
778 keyContext.cbSize = sizeof(keyContext);
779 if (CertSetCertificateContextProperty(pCert,
780 CERT_KEY_CONTEXT_PROP_ID, 0, &keyContext))
781 {
782 if (pfCallerFreeProv)
783 *pfCallerFreeProv = FALSE;
784 }
785 }
786 else
787 {
788 if (pfCallerFreeProv)
789 *pfCallerFreeProv = TRUE;
790 }
791 }
792 }
793 HeapFree(GetProcessHeap(), 0, info);
794 return ret;
795 }
796
797 static BOOL key_prov_info_matches_cert(PCCERT_CONTEXT pCert,
798 const CRYPT_KEY_PROV_INFO *keyProvInfo)
799 {
800 HCRYPTPROV csp;
801 BOOL matches = FALSE;
802
803 if (CryptAcquireContextW(&csp, keyProvInfo->pwszContainerName,
804 keyProvInfo->pwszProvName, keyProvInfo->dwProvType, keyProvInfo->dwFlags))
805 {
806 DWORD size;
807
808 /* Need to sign something to verify the sig. What to sign? Why not
809 * the certificate itself?
810 */
811 if (CryptSignAndEncodeCertificate(csp, AT_SIGNATURE,
812 pCert->dwCertEncodingType, X509_CERT_TO_BE_SIGNED, pCert->pCertInfo,
813 &pCert->pCertInfo->SignatureAlgorithm, NULL, NULL, &size))
814 {
815 BYTE *certEncoded = CryptMemAlloc(size);
816
817 if (certEncoded)
818 {
819 if (CryptSignAndEncodeCertificate(csp, AT_SIGNATURE,
820 pCert->dwCertEncodingType, X509_CERT_TO_BE_SIGNED,
821 pCert->pCertInfo, &pCert->pCertInfo->SignatureAlgorithm,
822 NULL, certEncoded, &size))
823 {
824 if (size == pCert->cbCertEncoded &&
825 !memcmp(certEncoded, pCert->pbCertEncoded, size))
826 matches = TRUE;
827 }
828 CryptMemFree(certEncoded);
829 }
830 }
831 CryptReleaseContext(csp, 0);
832 }
833 return matches;
834 }
835
836 static BOOL container_matches_cert(PCCERT_CONTEXT pCert, LPCSTR container,
837 CRYPT_KEY_PROV_INFO *keyProvInfo)
838 {
839 CRYPT_KEY_PROV_INFO copy;
840 WCHAR containerW[MAX_PATH];
841 BOOL matches = FALSE;
842
843 MultiByteToWideChar(CP_ACP, 0, container, -1,
844 containerW, sizeof(containerW) / sizeof(containerW[0]));
845 /* We make a copy of the CRYPT_KEY_PROV_INFO because the caller expects
846 * keyProvInfo->pwszContainerName to be NULL or a heap-allocated container
847 * name.
848 */
849 memcpy(&copy, keyProvInfo, sizeof(copy));
850 copy.pwszContainerName = containerW;
851 matches = key_prov_info_matches_cert(pCert, &copy);
852 if (matches)
853 {
854 keyProvInfo->pwszContainerName =
855 CryptMemAlloc((strlenW(containerW) + 1) * sizeof(WCHAR));
856 if (keyProvInfo->pwszContainerName)
857 {
858 strcpyW(keyProvInfo->pwszContainerName, containerW);
859 keyProvInfo->dwKeySpec = AT_SIGNATURE;
860 }
861 else
862 matches = FALSE;
863 }
864 return matches;
865 }
866
867 /* Searches the provider named keyProvInfo.pwszProvName for a container whose
868 * private key matches pCert's public key. Upon success, updates keyProvInfo
869 * with the matching container's info (free keyProvInfo.pwszContainerName upon
870 * success.)
871 * Returns TRUE if found, FALSE if not.
872 */
873 static BOOL find_key_prov_info_in_provider(PCCERT_CONTEXT pCert,
874 CRYPT_KEY_PROV_INFO *keyProvInfo)
875 {
876 HCRYPTPROV defProvider;
877 BOOL ret, found = FALSE;
878 char containerA[MAX_PATH];
879
880 assert(keyProvInfo->pwszContainerName == NULL);
881 if ((ret = CryptAcquireContextW(&defProvider, NULL,
882 keyProvInfo->pwszProvName, keyProvInfo->dwProvType,
883 keyProvInfo->dwFlags | CRYPT_VERIFYCONTEXT)))
884 {
885 DWORD enumFlags = keyProvInfo->dwFlags | CRYPT_FIRST;
886
887 while (ret && !found)
888 {
889 DWORD size = sizeof(containerA);
890
891 ret = CryptGetProvParam(defProvider, PP_ENUMCONTAINERS,
892 (BYTE *)containerA, &size, enumFlags);
893 if (ret)
894 found = container_matches_cert(pCert, containerA, keyProvInfo);
895 if (enumFlags & CRYPT_FIRST)
896 {
897 enumFlags &= ~CRYPT_FIRST;
898 enumFlags |= CRYPT_NEXT;
899 }
900 }
901 CryptReleaseContext(defProvider, 0);
902 }
903 return found;
904 }
905
906 static BOOL find_matching_provider(PCCERT_CONTEXT pCert, DWORD dwFlags)
907 {
908 BOOL found = FALSE, ret = TRUE;
909 DWORD index = 0, cbProvName = 0;
910 CRYPT_KEY_PROV_INFO keyProvInfo;
911
912 TRACE("(%p, %08x)\n", pCert, dwFlags);
913
914 memset(&keyProvInfo, 0, sizeof(keyProvInfo));
915 while (ret && !found)
916 {
917 DWORD size = 0;
918
919 ret = CryptEnumProvidersW(index, NULL, 0, &keyProvInfo.dwProvType,
920 NULL, &size);
921 if (ret)
922 {
923 if (size <= cbProvName)
924 ret = CryptEnumProvidersW(index, NULL, 0,
925 &keyProvInfo.dwProvType, keyProvInfo.pwszProvName, &size);
926 else
927 {
928 CryptMemFree(keyProvInfo.pwszProvName);
929 keyProvInfo.pwszProvName = CryptMemAlloc(size);
930 if (keyProvInfo.pwszProvName)
931 {
932 cbProvName = size;
933 ret = CryptEnumProvidersW(index, NULL, 0,
934 &keyProvInfo.dwProvType, keyProvInfo.pwszProvName, &size);
935 if (ret)
936 {
937 if (dwFlags & CRYPT_FIND_SILENT_KEYSET_FLAG)
938 keyProvInfo.dwFlags |= CRYPT_SILENT;
939 if (dwFlags & CRYPT_FIND_USER_KEYSET_FLAG ||
940 !(dwFlags & (CRYPT_FIND_USER_KEYSET_FLAG |
941 CRYPT_FIND_MACHINE_KEYSET_FLAG)))
942 {
943 keyProvInfo.dwFlags |= CRYPT_USER_KEYSET;
944 found = find_key_prov_info_in_provider(pCert,
945 &keyProvInfo);
946 }
947 if (!found)
948 {
949 if (dwFlags & CRYPT_FIND_MACHINE_KEYSET_FLAG ||
950 !(dwFlags & (CRYPT_FIND_USER_KEYSET_FLAG |
951 CRYPT_FIND_MACHINE_KEYSET_FLAG)))
952 {
953 keyProvInfo.dwFlags &= ~CRYPT_USER_KEYSET;
954 keyProvInfo.dwFlags |= CRYPT_MACHINE_KEYSET;
955 found = find_key_prov_info_in_provider(pCert,
956 &keyProvInfo);
957 }
958 }
959 }
960 }
961 else
962 ret = FALSE;
963 }
964 index++;
965 }
966 }
967 if (found)
968 CertSetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID,
969 0, &keyProvInfo);
970 CryptMemFree(keyProvInfo.pwszProvName);
971 CryptMemFree(keyProvInfo.pwszContainerName);
972 return found;
973 }
974
975 static BOOL cert_prov_info_matches_cert(PCCERT_CONTEXT pCert)
976 {
977 BOOL matches = FALSE;
978 DWORD size;
979
980 if (CertGetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID,
981 NULL, &size))
982 {
983 CRYPT_KEY_PROV_INFO *keyProvInfo = CryptMemAlloc(size);
984
985 if (keyProvInfo)
986 {
987 if (CertGetCertificateContextProperty(pCert,
988 CERT_KEY_PROV_INFO_PROP_ID, keyProvInfo, &size))
989 matches = key_prov_info_matches_cert(pCert, keyProvInfo);
990 CryptMemFree(keyProvInfo);
991 }
992 }
993 return matches;
994 }
995
996 BOOL WINAPI CryptFindCertificateKeyProvInfo(PCCERT_CONTEXT pCert,
997 DWORD dwFlags, void *pvReserved)
998 {
999 BOOL matches = FALSE;
1000
1001 TRACE("(%p, %08x, %p)\n", pCert, dwFlags, pvReserved);
1002
1003 matches = cert_prov_info_matches_cert(pCert);
1004 if (!matches)
1005 matches = find_matching_provider(pCert, dwFlags);
1006 return matches;
1007 }
1008
1009 BOOL WINAPI CertCompareCertificate(DWORD dwCertEncodingType,
1010 PCERT_INFO pCertId1, PCERT_INFO pCertId2)
1011 {
1012 BOOL ret;
1013
1014 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertId1, pCertId2);
1015
1016 ret = CertCompareCertificateName(dwCertEncodingType, &pCertId1->Issuer,
1017 &pCertId2->Issuer) && CertCompareIntegerBlob(&pCertId1->SerialNumber,
1018 &pCertId2->SerialNumber);
1019 TRACE("returning %d\n", ret);
1020 return ret;
1021 }
1022
1023 BOOL WINAPI CertCompareCertificateName(DWORD dwCertEncodingType,
1024 PCERT_NAME_BLOB pCertName1, PCERT_NAME_BLOB pCertName2)
1025 {
1026 BOOL ret;
1027
1028 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertName1, pCertName2);
1029
1030 if (pCertName1->cbData == pCertName2->cbData)
1031 {
1032 if (pCertName1->cbData)
1033 ret = !memcmp(pCertName1->pbData, pCertName2->pbData,
1034 pCertName1->cbData);
1035 else
1036 ret = TRUE;
1037 }
1038 else
1039 ret = FALSE;
1040 TRACE("returning %d\n", ret);
1041 return ret;
1042 }
1043
1044 /* Returns the number of significant bytes in pInt, where a byte is
1045 * insignificant if it's a leading 0 for positive numbers or a leading 0xff
1046 * for negative numbers. pInt is assumed to be little-endian.
1047 */
1048 static DWORD CRYPT_significantBytes(const CRYPT_INTEGER_BLOB *pInt)
1049 {
1050 DWORD ret = pInt->cbData;
1051
1052 while (ret > 1)
1053 {
1054 if (pInt->pbData[ret - 2] <= 0x7f && pInt->pbData[ret - 1] == 0)
1055 ret--;
1056 else if (pInt->pbData[ret - 2] >= 0x80 && pInt->pbData[ret - 1] == 0xff)
1057 ret--;
1058 else
1059 break;
1060 }
1061 return ret;
1062 }
1063
1064 BOOL WINAPI CertCompareIntegerBlob(PCRYPT_INTEGER_BLOB pInt1,
1065 PCRYPT_INTEGER_BLOB pInt2)
1066 {
1067 BOOL ret;
1068 DWORD cb1, cb2;
1069
1070 TRACE("(%p, %p)\n", pInt1, pInt2);
1071
1072 cb1 = CRYPT_significantBytes(pInt1);
1073 cb2 = CRYPT_significantBytes(pInt2);
1074 if (cb1 == cb2)
1075 {
1076 if (cb1)
1077 ret = !memcmp(pInt1->pbData, pInt2->pbData, cb1);
1078 else
1079 ret = TRUE;
1080 }
1081 else
1082 ret = FALSE;
1083 TRACE("returning %d\n", ret);
1084 return ret;
1085 }
1086
1087 BOOL WINAPI CertComparePublicKeyInfo(DWORD dwCertEncodingType,
1088 PCERT_PUBLIC_KEY_INFO pPublicKey1, PCERT_PUBLIC_KEY_INFO pPublicKey2)
1089 {
1090 BOOL ret;
1091
1092 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pPublicKey1, pPublicKey2);
1093
1094 switch (GET_CERT_ENCODING_TYPE(dwCertEncodingType))
1095 {
1096 case 0: /* Seems to mean "raw binary bits" */
1097 if (pPublicKey1->PublicKey.cbData == pPublicKey2->PublicKey.cbData &&
1098 pPublicKey1->PublicKey.cUnusedBits == pPublicKey2->PublicKey.cUnusedBits)
1099 {
1100 if (pPublicKey2->PublicKey.cbData)
1101 ret = !memcmp(pPublicKey1->PublicKey.pbData,
1102 pPublicKey2->PublicKey.pbData, pPublicKey1->PublicKey.cbData);
1103 else
1104 ret = TRUE;
1105 }
1106 else
1107 ret = FALSE;
1108 break;
1109 default:
1110 WARN("Unknown encoding type %08x\n", dwCertEncodingType);
1111 /* FALLTHROUGH */
1112 case X509_ASN_ENCODING:
1113 {
1114 BLOBHEADER *pblob1, *pblob2;
1115 DWORD length;
1116 ret = FALSE;
1117 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1118 pPublicKey1->PublicKey.pbData, pPublicKey1->PublicKey.cbData,
1119 0, NULL, &length))
1120 {
1121 pblob1 = CryptMemAlloc(length);
1122 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1123 pPublicKey1->PublicKey.pbData, pPublicKey1->PublicKey.cbData,
1124 0, pblob1, &length))
1125 {
1126 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1127 pPublicKey2->PublicKey.pbData, pPublicKey2->PublicKey.cbData,
1128 0, NULL, &length))
1129 {
1130 pblob2 = CryptMemAlloc(length);
1131 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1132 pPublicKey2->PublicKey.pbData, pPublicKey2->PublicKey.cbData,
1133 0, pblob2, &length))
1134 {
1135 /* The RSAPUBKEY structure directly follows the BLOBHEADER */
1136 RSAPUBKEY *pk1 = (LPVOID)(pblob1 + 1),
1137 *pk2 = (LPVOID)(pblob2 + 1);
1138 ret = (pk1->bitlen == pk2->bitlen) && (pk1->pubexp == pk2->pubexp)
1139 && !memcmp(pk1 + 1, pk2 + 1, pk1->bitlen/8);
1140 }
1141 CryptMemFree(pblob2);
1142 }
1143 }
1144 CryptMemFree(pblob1);
1145 }
1146
1147 break;
1148 }
1149 }
1150 return ret;
1151 }
1152
1153 DWORD WINAPI CertGetPublicKeyLength(DWORD dwCertEncodingType,
1154 PCERT_PUBLIC_KEY_INFO pPublicKey)
1155 {
1156 DWORD len = 0;
1157
1158 TRACE("(%08x, %p)\n", dwCertEncodingType, pPublicKey);
1159
1160 if (GET_CERT_ENCODING_TYPE(dwCertEncodingType) != X509_ASN_ENCODING)
1161 {
1162 SetLastError(ERROR_FILE_NOT_FOUND);
1163 return 0;
1164 }
1165 if (pPublicKey->Algorithm.pszObjId &&
1166 !strcmp(pPublicKey->Algorithm.pszObjId, szOID_RSA_DH))
1167 {
1168 FIXME("unimplemented for DH public keys\n");
1169 SetLastError(CRYPT_E_ASN1_BADTAG);
1170 }
1171 else
1172 {
1173 DWORD size;
1174 PBYTE buf;
1175 BOOL ret = CryptDecodeObjectEx(dwCertEncodingType,
1176 RSA_CSP_PUBLICKEYBLOB, pPublicKey->PublicKey.pbData,
1177 pPublicKey->PublicKey.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf,
1178 &size);
1179
1180 if (ret)
1181 {
1182 RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
1183
1184 len = rsaPubKey->bitlen;
1185 LocalFree(buf);
1186 }
1187 }
1188 return len;
1189 }
1190
1191 typedef BOOL (*CertCompareFunc)(PCCERT_CONTEXT pCertContext, DWORD dwType,
1192 DWORD dwFlags, const void *pvPara);
1193
1194 static BOOL compare_cert_by_md5_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
1195 DWORD dwFlags, const void *pvPara)
1196 {
1197 BOOL ret;
1198 BYTE hash[16];
1199 DWORD size = sizeof(hash);
1200
1201 ret = CertGetCertificateContextProperty(pCertContext,
1202 CERT_MD5_HASH_PROP_ID, hash, &size);
1203 if (ret)
1204 {
1205 const CRYPT_HASH_BLOB *pHash = pvPara;
1206
1207 if (size == pHash->cbData)
1208 ret = !memcmp(pHash->pbData, hash, size);
1209 else
1210 ret = FALSE;
1211 }
1212 return ret;
1213 }
1214
1215 static BOOL compare_cert_by_sha1_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
1216 DWORD dwFlags, const void *pvPara)
1217 {
1218 BOOL ret;
1219 BYTE hash[20];
1220 DWORD size = sizeof(hash);
1221
1222 ret = CertGetCertificateContextProperty(pCertContext,
1223 CERT_SHA1_HASH_PROP_ID, hash, &size);
1224 if (ret)
1225 {
1226 const CRYPT_HASH_BLOB *pHash = pvPara;
1227
1228 if (size == pHash->cbData)
1229 ret = !memcmp(pHash->pbData, hash, size);
1230 else
1231 ret = FALSE;
1232 }
1233 return ret;
1234 }
1235
1236 static BOOL compare_cert_by_name(PCCERT_CONTEXT pCertContext, DWORD dwType,
1237 DWORD dwFlags, const void *pvPara)
1238 {
1239 CERT_NAME_BLOB *blob = (CERT_NAME_BLOB *)pvPara, *toCompare;
1240 BOOL ret;
1241
1242 if (dwType & CERT_INFO_SUBJECT_FLAG)
1243 toCompare = &pCertContext->pCertInfo->Subject;
1244 else
1245 toCompare = &pCertContext->pCertInfo->Issuer;
1246 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1247 toCompare, blob);
1248 return ret;
1249 }
1250
1251 static BOOL compare_cert_by_public_key(PCCERT_CONTEXT pCertContext,
1252 DWORD dwType, DWORD dwFlags, const void *pvPara)
1253 {
1254 CERT_PUBLIC_KEY_INFO *publicKey = (CERT_PUBLIC_KEY_INFO *)pvPara;
1255 BOOL ret;
1256
1257 ret = CertComparePublicKeyInfo(pCertContext->dwCertEncodingType,
1258 &pCertContext->pCertInfo->SubjectPublicKeyInfo, publicKey);
1259 return ret;
1260 }
1261
1262 static BOOL compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext,
1263 DWORD dwType, DWORD dwFlags, const void *pvPara)
1264 {
1265 CERT_INFO *pCertInfo = (CERT_INFO *)pvPara;
1266 BOOL ret;
1267
1268 /* Matching serial number and subject match.. */
1269 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1270 &pCertContext->pCertInfo->Subject, &pCertInfo->Issuer);
1271 if (ret)
1272 ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
1273 &pCertInfo->SerialNumber);
1274 else
1275 {
1276 /* failing that, if the serial number and issuer match, we match */
1277 ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
1278 &pCertInfo->SerialNumber);
1279 if (ret)
1280 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1281 &pCertContext->pCertInfo->Issuer, &pCertInfo->Issuer);
1282 }
1283 TRACE("returning %d\n", ret);
1284 return ret;
1285 }
1286
1287 static BOOL compare_cert_by_cert_id(PCCERT_CONTEXT pCertContext, DWORD dwType,
1288 DWORD dwFlags, const void *pvPara)
1289 {
1290 CERT_ID *id = (CERT_ID *)pvPara;
1291 BOOL ret;
1292
1293 switch (id->dwIdChoice)
1294 {
1295 case CERT_ID_ISSUER_SERIAL_NUMBER:
1296 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1297 &pCertContext->pCertInfo->Issuer, &id->u.IssuerSerialNumber.Issuer);
1298 if (ret)
1299 ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
1300 &id->u.IssuerSerialNumber.SerialNumber);
1301 break;
1302 case CERT_ID_SHA1_HASH:
1303 ret = compare_cert_by_sha1_hash(pCertContext, dwType, dwFlags,
1304 &id->u.HashId);
1305 break;
1306 case CERT_ID_KEY_IDENTIFIER:
1307 {
1308 DWORD size = 0;
1309
1310 ret = CertGetCertificateContextProperty(pCertContext,
1311 CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
1312 if (ret && size == id->u.KeyId.cbData)
1313 {
1314 LPBYTE buf = CryptMemAlloc(size);
1315
1316 if (buf)
1317 {
1318 CertGetCertificateContextProperty(pCertContext,
1319 CERT_KEY_IDENTIFIER_PROP_ID, buf, &size);
1320 ret = !memcmp(buf, id->u.KeyId.pbData, size);
1321 CryptMemFree(buf);
1322 }
1323 }
1324 else
1325 ret = FALSE;
1326 break;
1327 }
1328 default:
1329 ret = FALSE;
1330 break;
1331 }
1332 return ret;
1333 }
1334
1335 static BOOL compare_existing_cert(PCCERT_CONTEXT pCertContext, DWORD dwType,
1336 DWORD dwFlags, const void *pvPara)
1337 {
1338 PCCERT_CONTEXT toCompare = pvPara;
1339 return CertCompareCertificate(pCertContext->dwCertEncodingType,
1340 pCertContext->pCertInfo, toCompare->pCertInfo);
1341 }
1342
1343 static BOOL compare_cert_by_signature_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
1344 DWORD dwFlags, const void *pvPara)
1345 {
1346 const CRYPT_HASH_BLOB *hash = pvPara;
1347 DWORD size = 0;
1348 BOOL ret;
1349
1350 ret = CertGetCertificateContextProperty(pCertContext,
1351 CERT_SIGNATURE_HASH_PROP_ID, NULL, &size);
1352 if (ret && size == hash->cbData)
1353 {
1354 LPBYTE buf = CryptMemAlloc(size);
1355
1356 if (buf)
1357 {
1358 CertGetCertificateContextProperty(pCertContext,
1359 CERT_SIGNATURE_HASH_PROP_ID, buf, &size);
1360 ret = !memcmp(buf, hash->pbData, size);
1361 CryptMemFree(buf);
1362 }
1363 }
1364 else
1365 ret = FALSE;
1366 return ret;
1367 }
1368
1369 static inline PCCERT_CONTEXT cert_compare_certs_in_store(HCERTSTORE store,
1370 PCCERT_CONTEXT prev, CertCompareFunc compare, DWORD dwType, DWORD dwFlags,
1371 const void *pvPara)
1372 {
1373 BOOL matches = FALSE;
1374 PCCERT_CONTEXT ret;
1375
1376 ret = prev;
1377 do {
1378 ret = CertEnumCertificatesInStore(store, ret);
1379 if (ret)
1380 matches = compare(ret, dwType, dwFlags, pvPara);
1381 } while (ret != NULL && !matches);
1382 return ret;
1383 }
1384
1385 typedef PCCERT_CONTEXT (*CertFindFunc)(HCERTSTORE store, DWORD dwType,
1386 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev);
1387
1388 static PCCERT_CONTEXT find_cert_any(HCERTSTORE store, DWORD dwType,
1389 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1390 {
1391 return CertEnumCertificatesInStore(store, prev);
1392 }
1393
1394 static PCCERT_CONTEXT find_cert_by_issuer(HCERTSTORE store, DWORD dwType,
1395 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1396 {
1397 BOOL ret;
1398 PCCERT_CONTEXT found = NULL, subject = pvPara;
1399 PCERT_EXTENSION ext;
1400 DWORD size;
1401
1402 if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER,
1403 subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
1404 {
1405 CERT_AUTHORITY_KEY_ID_INFO *info;
1406
1407 ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
1408 X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData,
1409 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1410 &info, &size);
1411 if (ret)
1412 {
1413 CERT_ID id;
1414
1415 if (info->CertIssuer.cbData && info->CertSerialNumber.cbData)
1416 {
1417 id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
1418 memcpy(&id.u.IssuerSerialNumber.Issuer, &info->CertIssuer,
1419 sizeof(CERT_NAME_BLOB));
1420 memcpy(&id.u.IssuerSerialNumber.SerialNumber,
1421 &info->CertSerialNumber, sizeof(CRYPT_INTEGER_BLOB));
1422 }
1423 else if (info->KeyId.cbData)
1424 {
1425 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
1426 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
1427 }
1428 else
1429 ret = FALSE;
1430 if (ret)
1431 found = cert_compare_certs_in_store(store, prev,
1432 compare_cert_by_cert_id, dwType, dwFlags, &id);
1433 LocalFree(info);
1434 }
1435 }
1436 else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2,
1437 subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
1438 {
1439 CERT_AUTHORITY_KEY_ID2_INFO *info;
1440
1441 ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
1442 X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData,
1443 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1444 &info, &size);
1445 if (ret)
1446 {
1447 CERT_ID id;
1448
1449 if (info->AuthorityCertIssuer.cAltEntry &&
1450 info->AuthorityCertSerialNumber.cbData)
1451 {
1452 PCERT_ALT_NAME_ENTRY directoryName = NULL;
1453 DWORD i;
1454
1455 for (i = 0; !directoryName &&
1456 i < info->AuthorityCertIssuer.cAltEntry; i++)
1457 if (info->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice
1458 == CERT_ALT_NAME_DIRECTORY_NAME)
1459 directoryName =
1460 &info->AuthorityCertIssuer.rgAltEntry[i];
1461 if (directoryName)
1462 {
1463 id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
1464 memcpy(&id.u.IssuerSerialNumber.Issuer,
1465 &directoryName->u.DirectoryName, sizeof(CERT_NAME_BLOB));
1466 memcpy(&id.u.IssuerSerialNumber.SerialNumber,
1467 &info->AuthorityCertSerialNumber,
1468 sizeof(CRYPT_INTEGER_BLOB));
1469 }
1470 else
1471 {
1472 FIXME("no supported name type in authority key id2\n");
1473 ret = FALSE;
1474 }
1475 }
1476 else if (info->KeyId.cbData)
1477 {
1478 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
1479 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
1480 }
1481 else
1482 ret = FALSE;
1483 if (ret)
1484 found = cert_compare_certs_in_store(store, prev,
1485 compare_cert_by_cert_id, dwType, dwFlags, &id);
1486 LocalFree(info);
1487 }
1488 }
1489 else
1490 found = cert_compare_certs_in_store(store, prev,
1491 compare_cert_by_name, CERT_COMPARE_NAME | CERT_COMPARE_SUBJECT_CERT,
1492 dwFlags, &subject->pCertInfo->Issuer);
1493 return found;
1494 }
1495
1496 static BOOL compare_cert_by_name_str(PCCERT_CONTEXT pCertContext,
1497 DWORD dwType, DWORD dwFlags, const void *pvPara)
1498 {
1499 PCERT_NAME_BLOB name;
1500 DWORD len;
1501 BOOL ret = FALSE;
1502
1503 if (dwType & CERT_INFO_SUBJECT_FLAG)
1504 name = &pCertContext->pCertInfo->Subject;
1505 else
1506 name = &pCertContext->pCertInfo->Issuer;
1507 len = CertNameToStrW(pCertContext->dwCertEncodingType, name,
1508 CERT_SIMPLE_NAME_STR, NULL, 0);
1509 if (len)
1510 {
1511 LPWSTR str = CryptMemAlloc(len * sizeof(WCHAR));
1512
1513 if (str)
1514 {
1515 LPWSTR ptr;
1516
1517 CertNameToStrW(pCertContext->dwCertEncodingType, name,
1518 CERT_SIMPLE_NAME_STR, str, len);
1519 for (ptr = str; *ptr; ptr++)
1520 *ptr = tolowerW(*ptr);
1521 if (strstrW(str, pvPara))
1522 ret = TRUE;
1523 CryptMemFree(str);
1524 }
1525 }
1526 return ret;
1527 }
1528
1529 static PCCERT_CONTEXT find_cert_by_name_str_a(HCERTSTORE store, DWORD dwType,
1530 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1531 {
1532 PCCERT_CONTEXT found = NULL;
1533
1534 TRACE("%s\n", debugstr_a(pvPara));
1535
1536 if (pvPara)
1537 {
1538 int len = MultiByteToWideChar(CP_ACP, 0, pvPara, -1, NULL, 0);
1539 LPWSTR str = CryptMemAlloc(len * sizeof(WCHAR));
1540
1541 if (str)
1542 {
1543 LPWSTR ptr;
1544
1545 MultiByteToWideChar(CP_ACP, 0, pvPara, -1, str, len);
1546 for (ptr = str; *ptr; ptr++)
1547 *ptr = tolowerW(*ptr);
1548 found = cert_compare_certs_in_store(store, prev,
1549 compare_cert_by_name_str, dwType, dwFlags, str);
1550 CryptMemFree(str);
1551 }
1552 }
1553 else
1554 found = find_cert_any(store, dwType, dwFlags, NULL, prev);
1555 return found;
1556 }
1557
1558 static PCCERT_CONTEXT find_cert_by_name_str_w(HCERTSTORE store, DWORD dwType,
1559 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1560 {
1561 PCCERT_CONTEXT found = NULL;
1562
1563 TRACE("%s\n", debugstr_w(pvPara));
1564
1565 if (pvPara)
1566 {
1567 DWORD len = strlenW(pvPara);
1568 LPWSTR str = CryptMemAlloc((len + 1) * sizeof(WCHAR));
1569
1570 if (str)
1571 {
1572 LPCWSTR src;
1573 LPWSTR dst;
1574
1575 for (src = pvPara, dst = str; *src; src++, dst++)
1576 *dst = tolowerW(*src);
1577 *dst = 0;
1578 found = cert_compare_certs_in_store(store, prev,
1579 compare_cert_by_name_str, dwType, dwFlags, str);
1580 CryptMemFree(str);
1581 }
1582 }
1583 else
1584 found = find_cert_any(store, dwType, dwFlags, NULL, prev);
1585 return found;
1586 }
1587
1588 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
1589 DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType, const void *pvPara,
1590 PCCERT_CONTEXT pPrevCertContext)
1591 {
1592 PCCERT_CONTEXT ret;
1593 CertFindFunc find = NULL;
1594 CertCompareFunc compare = NULL;
1595
1596 TRACE("(%p, %08x, %08x, %08x, %p, %p)\n", hCertStore, dwCertEncodingType,
1597 dwFlags, dwType, pvPara, pPrevCertContext);
1598
1599 switch (dwType >> CERT_COMPARE_SHIFT)
1600 {
1601 case CERT_COMPARE_ANY:
1602 find = find_cert_any;
1603 break;
1604 case CERT_COMPARE_MD5_HASH:
1605 compare = compare_cert_by_md5_hash;
1606 break;
1607 case CERT_COMPARE_SHA1_HASH:
1608 compare = compare_cert_by_sha1_hash;
1609 break;
1610 case CERT_COMPARE_NAME:
1611 compare = compare_cert_by_name;
1612 break;
1613 case CERT_COMPARE_PUBLIC_KEY:
1614 compare = compare_cert_by_public_key;
1615 break;
1616 case CERT_COMPARE_NAME_STR_A:
1617 find = find_cert_by_name_str_a;
1618 break;
1619 case CERT_COMPARE_NAME_STR_W:
1620 find = find_cert_by_name_str_w;
1621 break;
1622 case CERT_COMPARE_SUBJECT_CERT:
1623 compare = compare_cert_by_subject_cert;
1624 break;
1625 case CERT_COMPARE_CERT_ID:
1626 compare = compare_cert_by_cert_id;
1627 break;
1628 case CERT_COMPARE_ISSUER_OF:
1629 find = find_cert_by_issuer;
1630 break;
1631 case CERT_COMPARE_EXISTING:
1632 compare = compare_existing_cert;
1633 break;
1634 case CERT_COMPARE_SIGNATURE_HASH:
1635 compare = compare_cert_by_signature_hash;
1636 break;
1637 default:
1638 FIXME("find type %08x unimplemented\n", dwType);
1639 }
1640
1641 if (find)
1642 ret = find(hCertStore, dwFlags, dwType, pvPara, pPrevCertContext);
1643 else if (compare)
1644 ret = cert_compare_certs_in_store(hCertStore, pPrevCertContext,
1645 compare, dwType, dwFlags, pvPara);
1646 else
1647 ret = NULL;
1648 if (!ret)
1649 SetLastError(CRYPT_E_NOT_FOUND);
1650 TRACE("returning %p\n", ret);
1651 return ret;
1652 }
1653
1654 PCCERT_CONTEXT WINAPI CertGetSubjectCertificateFromStore(HCERTSTORE hCertStore,
1655 DWORD dwCertEncodingType, PCERT_INFO pCertId)
1656 {
1657 TRACE("(%p, %08x, %p)\n", hCertStore, dwCertEncodingType, pCertId);
1658
1659 if (!pCertId)
1660 {
1661 SetLastError(E_INVALIDARG);
1662 return NULL;
1663 }
1664 return CertFindCertificateInStore(hCertStore, dwCertEncodingType, 0,
1665 CERT_FIND_SUBJECT_CERT, pCertId, NULL);
1666 }
1667
1668 BOOL WINAPI CertVerifySubjectCertificateContext(PCCERT_CONTEXT pSubject,
1669 PCCERT_CONTEXT pIssuer, DWORD *pdwFlags)
1670 {
1671 static const DWORD supportedFlags = CERT_STORE_REVOCATION_FLAG |
1672 CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG;
1673
1674 if (*pdwFlags & ~supportedFlags)
1675 {
1676 SetLastError(E_INVALIDARG);
1677 return FALSE;
1678 }
1679 if (*pdwFlags & CERT_STORE_REVOCATION_FLAG)
1680 {
1681 DWORD flags = 0;
1682 PCCRL_CONTEXT crl = CertGetCRLFromStore(pSubject->hCertStore, pSubject,
1683 NULL, &flags);
1684
1685 /* FIXME: what if the CRL has expired? */
1686 if (crl)
1687 {
1688 if (CertVerifyCRLRevocation(pSubject->dwCertEncodingType,
1689 pSubject->pCertInfo, 1, (PCRL_INFO *)&crl->pCrlInfo))
1690 *pdwFlags &= CERT_STORE_REVOCATION_FLAG;
1691 }
1692 else
1693 *pdwFlags |= CERT_STORE_NO_CRL_FLAG;
1694 }
1695 if (*pdwFlags & CERT_STORE_TIME_VALIDITY_FLAG)
1696 {
1697 if (0 == CertVerifyTimeValidity(NULL, pSubject->pCertInfo))
1698 *pdwFlags &= ~CERT_STORE_TIME_VALIDITY_FLAG;
1699 }
1700 if (*pdwFlags & CERT_STORE_SIGNATURE_FLAG)
1701 {
1702 if (CryptVerifyCertificateSignatureEx(0, pSubject->dwCertEncodingType,
1703 CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)pSubject,
1704 CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)pIssuer, 0, NULL))
1705 *pdwFlags &= ~CERT_STORE_SIGNATURE_FLAG;
1706 }
1707 return TRUE;
1708 }
1709
1710 PCCERT_CONTEXT WINAPI CertGetIssuerCertificateFromStore(HCERTSTORE hCertStore,
1711 PCCERT_CONTEXT pSubjectContext, PCCERT_CONTEXT pPrevIssuerContext,
1712 DWORD *pdwFlags)
1713 {
1714 PCCERT_CONTEXT ret;
1715
1716 TRACE("(%p, %p, %p, %08x)\n", hCertStore, pSubjectContext,
1717 pPrevIssuerContext, *pdwFlags);
1718
1719 if (!pSubjectContext)
1720 {
1721 SetLastError(E_INVALIDARG);
1722 return NULL;
1723 }
1724
1725 ret = CertFindCertificateInStore(hCertStore,
1726 pSubjectContext->dwCertEncodingType, 0, CERT_FIND_ISSUER_OF,
1727 pSubjectContext, pPrevIssuerContext);
1728 if (ret)
1729 {
1730 if (!CertVerifySubjectCertificateContext(pSubjectContext, ret,
1731 pdwFlags))
1732 {
1733 CertFreeCertificateContext(ret);
1734 ret = NULL;
1735 }
1736 }
1737 TRACE("returning %p\n", ret);
1738 return ret;
1739 }
1740
1741 typedef struct _OLD_CERT_REVOCATION_STATUS {
1742 DWORD cbSize;
1743 DWORD dwIndex;
1744 DWORD dwError;
1745 DWORD dwReason;
1746 } OLD_CERT_REVOCATION_STATUS, *POLD_CERT_REVOCATION_STATUS;
1747
1748 typedef BOOL (WINAPI *CertVerifyRevocationFunc)(DWORD, DWORD, DWORD,
1749 void **, DWORD, PCERT_REVOCATION_PARA, PCERT_REVOCATION_STATUS);
1750
1751 BOOL WINAPI CertVerifyRevocation(DWORD dwEncodingType, DWORD dwRevType,
1752 DWORD cContext, PVOID rgpvContext[], DWORD dwFlags,
1753 PCERT_REVOCATION_PARA pRevPara, PCERT_REVOCATION_STATUS pRevStatus)
1754 {
1755 BOOL ret;
1756
1757 TRACE("(%08x, %d, %d, %p, %08x, %p, %p)\n", dwEncodingType, dwRevType,
1758 cContext, rgpvContext, dwFlags, pRevPara, pRevStatus);
1759
1760 if (pRevStatus->cbSize != sizeof(OLD_CERT_REVOCATION_STATUS) &&
1761 pRevStatus->cbSize != sizeof(CERT_REVOCATION_STATUS))
1762 {
1763 SetLastError(E_INVALIDARG);
1764 return FALSE;
1765 }
1766 if (cContext)
1767 {
1768 static HCRYPTOIDFUNCSET set = NULL;
1769 DWORD size;
1770
1771 if (!set)
1772 set = CryptInitOIDFunctionSet(CRYPT_OID_VERIFY_REVOCATION_FUNC, 0);
1773 ret = CryptGetDefaultOIDDllList(set, dwEncodingType, NULL, &size);
1774 if (ret)
1775 {
1776 if (size == 1)
1777 {
1778 /* empty list */
1779 SetLastError(CRYPT_E_NO_REVOCATION_DLL);
1780 ret = FALSE;
1781 }
1782 else
1783 {
1784 LPWSTR dllList = CryptMemAlloc(size * sizeof(WCHAR)), ptr;
1785
1786 if (dllList)
1787 {
1788 ret = CryptGetDefaultOIDDllList(set, dwEncodingType,
1789 dllList, &size);
1790 if (ret)
1791 {
1792 for (ptr = dllList; ret && *ptr;
1793 ptr += lstrlenW(ptr) + 1)
1794 {
1795 CertVerifyRevocationFunc func;
1796 HCRYPTOIDFUNCADDR hFunc;
1797
1798 ret = CryptGetDefaultOIDFunctionAddress(set,
1799 dwEncodingType, ptr, 0, (void **)&func, &hFunc);
1800 if (ret)
1801 {
1802 ret = func(dwEncodingType, dwRevType, cContext,
1803 rgpvContext, dwFlags, pRevPara, pRevStatus);
1804 CryptFreeOIDFunctionAddress(hFunc, 0);
1805 }
1806 }
1807 }
1808 CryptMemFree(dllList);
1809 }
1810 else
1811 {
1812 SetLastError(ERROR_OUTOFMEMORY);
1813 ret = FALSE;
1814 }
1815 }
1816 }
1817 }
1818 else
1819 ret = TRUE;
1820 return ret;
1821 }
1822
1823 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
1824 CRYPT_ATTRIBUTE rgAttr[])
1825 {
1826 PCRYPT_ATTRIBUTE ret = NULL;
1827 DWORD i;
1828
1829 TRACE("%s %d %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
1830
1831 if (!cAttr)
1832 return NULL;
1833 if (!pszObjId)
1834 {
1835 SetLastError(ERROR_INVALID_PARAMETER);
1836 return NULL;
1837 }
1838
1839 for (i = 0; !ret && i < cAttr; i++)
1840 if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
1841 ret = &rgAttr[i];
1842 return ret;
1843 }
1844
1845 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
1846 CERT_EXTENSION rgExtensions[])
1847 {
1848 PCERT_EXTENSION ret = NULL;
1849 DWORD i;
1850
1851 TRACE("%s %d %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
1852
1853 if (!cExtensions)
1854 return NULL;
1855 if (!pszObjId)
1856 {
1857 SetLastError(ERROR_INVALID_PARAMETER);
1858 return NULL;
1859 }
1860
1861 for (i = 0; !ret && i < cExtensions; i++)
1862 if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
1863 rgExtensions[i].pszObjId))
1864 ret = &rgExtensions[i];
1865 return ret;
1866 }
1867
1868 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
1869 {
1870 PCERT_RDN_ATTR ret = NULL;
1871 DWORD i, j;
1872
1873 TRACE("%s %p\n", debugstr_a(pszObjId), pName);
1874
1875 if (!pszObjId)
1876 {
1877 SetLastError(ERROR_INVALID_PARAMETER);
1878 return NULL;
1879 }
1880
1881 for (i = 0; !ret && i < pName->cRDN; i++)
1882 for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
1883 if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
1884 pName->rgRDN[i].rgRDNAttr[j].pszObjId))
1885 ret = &pName->rgRDN[i].rgRDNAttr[j];
1886 return ret;
1887 }
1888
1889 static BOOL find_matching_rdn_attr(DWORD dwFlags, const CERT_NAME_INFO *name,
1890 const CERT_RDN_ATTR *attr)
1891 {
1892 DWORD i, j;
1893 BOOL match = FALSE;
1894
1895 for (i = 0; !match && i < name->cRDN; i++)
1896 {
1897 for (j = 0; j < name->rgRDN[i].cRDNAttr; j++)
1898 {
1899 if (!strcmp(name->rgRDN[i].rgRDNAttr[j].pszObjId,
1900 attr->pszObjId) &&
1901 name->rgRDN[i].rgRDNAttr[j].dwValueType ==
1902 attr->dwValueType)
1903 {
1904 if (dwFlags & CERT_UNICODE_IS_RDN_ATTRS_FLAG)
1905 {
1906 LPCWSTR nameStr =
1907 (LPCWSTR)name->rgRDN[i].rgRDNAttr[j].Value.pbData;
1908 LPCWSTR attrStr = (LPCWSTR)attr->Value.pbData;
1909
1910 if (attr->Value.cbData !=
1911 name->rgRDN[i].rgRDNAttr[j].Value.cbData)
1912 match = FALSE;
1913 else if (dwFlags & CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG)
1914 match = !strncmpiW(nameStr, attrStr,
1915 attr->Value.cbData / sizeof(WCHAR));
1916 else
1917 match = !strncmpW(nameStr, attrStr,
1918 attr->Value.cbData / sizeof(WCHAR));
1919 TRACE("%s : %s => %d\n",
1920 debugstr_wn(nameStr, attr->Value.cbData / sizeof(WCHAR)),
1921 debugstr_wn(attrStr, attr->Value.cbData / sizeof(WCHAR)),
1922 match);
1923 }
1924 else
1925 {
1926 LPCSTR nameStr =
1927 (LPCSTR)name->rgRDN[i].rgRDNAttr[j].Value.pbData;
1928 LPCSTR attrStr = (LPCSTR)attr->Value.pbData;
1929
1930 if (attr->Value.cbData !=
1931 name->rgRDN[i].rgRDNAttr[j].Value.cbData)
1932 match = FALSE;
1933 else if (dwFlags & CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG)
1934 match = !strncasecmp(nameStr, attrStr,
1935 attr->Value.cbData);
1936 else
1937 match = !strncmp(nameStr, attrStr, attr->Value.cbData);
1938 TRACE("%s : %s => %d\n",
1939 debugstr_an(nameStr, attr->Value.cbData),
1940 debugstr_an(attrStr, attr->Value.cbData), match);
1941 }
1942 }
1943 }
1944 }
1945 return match;
1946 }
1947
1948 BOOL WINAPI CertIsRDNAttrsInCertificateName(DWORD dwCertEncodingType,
1949 DWORD dwFlags, PCERT_NAME_BLOB pCertName, PCERT_RDN pRDN)
1950 {
1951 CERT_NAME_INFO *name;
1952 LPCSTR type;
1953 DWORD size;
1954 BOOL ret;
1955
1956 TRACE("(%08x, %08x, %p, %p)\n", dwCertEncodingType, dwFlags, pCertName,
1957 pRDN);
1958
1959 type = dwFlags & CERT_UNICODE_IS_RDN_ATTRS_FLAG ? X509_UNICODE_NAME :
1960 X509_NAME;
1961 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, type, pCertName->pbData,
1962 pCertName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &name, &size)))
1963 {
1964 DWORD i;
1965
1966 for (i = 0; ret && i < pRDN->cRDNAttr; i++)
1967 ret = find_matching_rdn_attr(dwFlags, name, &pRDN->rgRDNAttr[i]);
1968 if (!ret)
1969 SetLastError(CRYPT_E_NO_MATCH);
1970 LocalFree(name);
1971 }
1972 return ret;
1973 }
1974
1975 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
1976 PCERT_INFO pCertInfo)
1977 {
1978 FILETIME fileTime;
1979 LONG ret;
1980
1981 if (!pTimeToVerify)
1982 {
1983 GetSystemTimeAsFileTime(&fileTime);
1984 pTimeToVerify = &fileTime;
1985 }
1986 if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
1987 {
1988 ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
1989 if (ret < 0)
1990 ret = 0;
1991 }
1992 return ret;
1993 }
1994
1995 BOOL WINAPI CertVerifyValidityNesting(PCERT_INFO pSubjectInfo,
1996 PCERT_INFO pIssuerInfo)
1997 {
1998 TRACE("(%p, %p)\n", pSubjectInfo, pIssuerInfo);
1999
2000 return CertVerifyTimeValidity(&pSubjectInfo->NotBefore, pIssuerInfo) == 0
2001 && CertVerifyTimeValidity(&pSubjectInfo->NotAfter, pIssuerInfo) == 0;
2002 }
2003
2004 BOOL WINAPI CryptHashCertificate(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
2005 DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
2006 DWORD *pcbComputedHash)
2007 {
2008 BOOL ret = TRUE;
2009 HCRYPTHASH hHash = 0;
2010
2011 TRACE("(%08lx, %d, %08x, %p, %d, %p, %p)\n", hCryptProv, Algid, dwFlags,
2012 pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
2013
2014 if (!hCryptProv)
2015 hCryptProv = CRYPT_GetDefaultProvider();
2016 if (!Algid)
2017 Algid = CALG_SHA1;
2018 if (ret)
2019 {
2020 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
2021 if (ret)
2022 {
2023 ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
2024 if (ret)
2025 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
2026 pcbComputedHash, 0);
2027 CryptDestroyHash(hHash);
2028 }
2029 }
2030 return ret;
2031 }
2032
2033 BOOL WINAPI CryptHashPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
2034 DWORD dwFlags, DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo,
2035 BYTE *pbComputedHash, DWORD *pcbComputedHash)
2036 {
2037 BOOL ret = TRUE;
2038 HCRYPTHASH hHash = 0;
2039
2040 TRACE("(%08lx, %d, %08x, %d, %p, %p, %p)\n", hCryptProv, Algid, dwFlags,
2041 dwCertEncodingType, pInfo, pbComputedHash, pcbComputedHash);
2042
2043 if (!hCryptProv)
2044 hCryptProv = CRYPT_GetDefaultProvider();
2045 if (!Algid)
2046 Algid = CALG_MD5;
2047 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
2048 {
2049 SetLastError(ERROR_FILE_NOT_FOUND);
2050 return FALSE;
2051 }
2052 if (ret)
2053 {
2054 BYTE *buf;
2055 DWORD size = 0;
2056
2057 ret = CRYPT_AsnEncodePubKeyInfoNoNull(dwCertEncodingType,
2058 X509_PUBLIC_KEY_INFO, pInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
2059 (LPBYTE)&buf, &size);
2060 if (ret)
2061 {
2062 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
2063 if (ret)
2064 {
2065 ret = CryptHashData(hHash, buf, size, 0);
2066 if (ret)
2067 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
2068 pcbComputedHash, 0);
2069 CryptDestroyHash(hHash);
2070 }
2071 LocalFree(buf);
2072 }
2073 }
2074 return ret;
2075 }
2076
2077 BOOL WINAPI CryptHashToBeSigned(HCRYPTPROV_LEGACY hCryptProv,
2078 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
2079 BYTE *pbComputedHash, DWORD *pcbComputedHash)
2080 {
2081 BOOL ret;
2082 CERT_SIGNED_CONTENT_INFO *info;
2083 DWORD size;
2084
2085 TRACE("(%08lx, %08x, %p, %d, %p, %d)\n", hCryptProv, dwCertEncodingType,
2086 pbEncoded, cbEncoded, pbComputedHash, *pcbComputedHash);
2087
2088 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
2089 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size);
2090 if (ret)
2091 {
2092 PCCRYPT_OID_INFO oidInfo;
2093 HCRYPTHASH hHash;
2094
2095 if (!hCryptProv)
2096 hCryptProv = CRYPT_GetDefaultProvider();
2097 oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2098 info->SignatureAlgorithm.pszObjId, 0);
2099 if (!oidInfo)
2100 {
2101 SetLastError(NTE_BAD_ALGID);
2102 ret = FALSE;
2103 }
2104 else
2105 {
2106 ret = CryptCreateHash(hCryptProv, oidInfo->u.Algid, 0, 0, &hHash);
2107 if (ret)
2108 {
2109 ret = CryptHashData(hHash, info->ToBeSigned.pbData,
2110 info->ToBeSigned.cbData, 0);
2111 if (ret)
2112 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
2113 pcbComputedHash, 0);
2114 CryptDestroyHash(hHash);
2115 }
2116 }
2117 LocalFree(info);
2118 }
2119 return ret;
2120 }
2121
2122 BOOL WINAPI CryptSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
2123 DWORD dwKeySpec, DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned,
2124 DWORD cbEncodedToBeSigned, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
2125 const void *pvHashAuxInfo, BYTE *pbSignature, DWORD *pcbSignature)
2126 {
2127 BOOL ret;
2128 PCCRYPT_OID_INFO info;
2129 HCRYPTHASH hHash;
2130
2131 TRACE("(%08lx, %d, %d, %p, %d, %p, %p, %p, %p)\n", hCryptProv,
2132 dwKeySpec, dwCertEncodingType, pbEncodedToBeSigned, cbEncodedToBeSigned,
2133 pSignatureAlgorithm, pvHashAuxInfo, pbSignature, pcbSignature);
2134
2135 info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2136 pSignatureAlgorithm->pszObjId, 0);
2137 if (!info)
2138 {
2139 SetLastError(NTE_BAD_ALGID);
2140 return FALSE;
2141 }
2142 if (info->dwGroupId == CRYPT_HASH_ALG_OID_GROUP_ID)
2143 {
2144 if (!hCryptProv)
2145 hCryptProv = CRYPT_GetDefaultProvider();
2146 ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
2147 if (ret)
2148 {
2149 ret = CryptHashData(hHash, pbEncodedToBeSigned,
2150 cbEncodedToBeSigned, 0);
2151 if (ret)
2152 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbSignature,
2153 pcbSignature, 0);
2154 CryptDestroyHash(hHash);
2155 }
2156 }
2157 else
2158 {
2159 if (!hCryptProv)
2160 {
2161 SetLastError(ERROR_INVALID_PARAMETER);
2162 ret = FALSE;
2163 }
2164 else
2165 {
2166 ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
2167 if (ret)
2168 {
2169 ret = CryptHashData(hHash, pbEncodedToBeSigned,
2170 cbEncodedToBeSigned, 0);
2171 if (ret)
2172 ret = CryptSignHashW(hHash, dwKeySpec, NULL, 0, pbSignature,
2173 pcbSignature);
2174 CryptDestroyHash(hHash);
2175 }
2176 }
2177 }
2178 return ret;
2179 }
2180
2181 BOOL WINAPI CryptSignAndEncodeCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
2182 DWORD dwKeySpec, DWORD dwCertEncodingType, LPCSTR lpszStructType,
2183 const void *pvStructInfo, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
2184 const void *pvHashAuxInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
2185 {
2186 BOOL ret;
2187 DWORD encodedSize, hashSize;
2188
2189 TRACE("(%08lx, %d, %d, %s, %p, %p, %p, %p, %p)\n", hCryptProv, dwKeySpec,
2190 dwCertEncodingType, debugstr_a(lpszStructType), pvStructInfo,
2191 pSignatureAlgorithm, pvHashAuxInfo, pbEncoded, pcbEncoded);
2192
2193 ret = CryptEncodeObject(dwCertEncodingType, lpszStructType, pvStructInfo,
2194 NULL, &encodedSize);
2195 if (ret)
2196 {
2197 PBYTE encoded = CryptMemAlloc(encodedSize);
2198
2199 if (encoded)
2200 {
2201 ret = CryptEncodeObject(dwCertEncodingType, lpszStructType,
2202 pvStructInfo, encoded, &encodedSize);
2203 if (ret)
2204 {
2205 ret = CryptSignCertificate(hCryptProv, dwKeySpec,
2206 dwCertEncodingType, encoded, encodedSize, pSignatureAlgorithm,
2207 pvHashAuxInfo, NULL, &hashSize);
2208 if (ret)
2209 {
2210 PBYTE hash = CryptMemAlloc(hashSize);
2211
2212 if (hash)
2213 {
2214 ret = CryptSignCertificate(hCryptProv, dwKeySpec,
2215 dwCertEncodingType, encoded, encodedSize,
2216 pSignatureAlgorithm, pvHashAuxInfo, hash, &hashSize);
2217 if (ret)
2218 {
2219 CERT_SIGNED_CONTENT_INFO info = { { 0 } };
2220
2221 info.ToBeSigned.cbData = encodedSize;
2222 info.ToBeSigned.pbData = encoded;
2223 memcpy(&info.SignatureAlgorithm,
2224 pSignatureAlgorithm,
2225 sizeof(info.SignatureAlgorithm));
2226 info.Signature.cbData = hashSize;
2227 info.Signature.pbData = hash;
2228 info.Signature.cUnusedBits = 0;
2229 ret = CryptEncodeObject(dwCertEncodingType,
2230 X509_CERT, &info, pbEncoded, pcbEncoded);
2231 }
2232 CryptMemFree(hash);
2233 }
2234 }
2235 }
2236 CryptMemFree(encoded);
2237 }
2238 }
2239 return ret;
2240 }
2241
2242 BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV_LEGACY hCryptProv,
2243 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
2244 PCERT_PUBLIC_KEY_INFO pPublicKey)
2245 {
2246 return CryptVerifyCertificateSignatureEx(hCryptProv, dwCertEncodingType,
2247 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, (void *)pbEncoded,
2248 CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
2249 }
2250
2251 static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv,
2252 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pubKeyInfo,
2253 const CERT_SIGNED_CONTENT_INFO *signedCert)
2254 {
2255 BOOL ret;
2256 HCRYPTKEY key;
2257 PCCRYPT_OID_INFO info;
2258 ALG_ID pubKeyID, hashID;
2259
2260 info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2261 signedCert->SignatureAlgorithm.pszObjId, 0);
2262 if (!info || info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID)
2263 {
2264 SetLastError(NTE_BAD_ALGID);
2265 return FALSE;
2266 }
2267 hashID = info->u.Algid;
2268 if (info->ExtraInfo.cbData >= sizeof(ALG_ID))
2269 pubKeyID = *(ALG_ID *)info->ExtraInfo.pbData;
2270 else
2271 pubKeyID = hashID;
2272 /* Load the default provider if necessary */
2273 if (!hCryptProv)
2274 hCryptProv = CRYPT_GetDefaultProvider();
2275 ret = CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType,
2276 pubKeyInfo, pubKeyID, 0, NULL, &key);
2277 if (ret)
2278 {
2279 HCRYPTHASH hash;
2280
2281 ret = CryptCreateHash(hCryptProv, hashID, 0, 0, &hash);
2282 if (ret)
2283 {
2284 ret = CryptHashData(hash, signedCert->ToBeSigned.pbData,
2285 signedCert->ToBeSigned.cbData, 0);
2286 if (ret)
2287 ret = CryptVerifySignatureW(hash, signedCert->Signature.pbData,
2288 signedCert->Signature.cbData, key, NULL, 0);
2289 CryptDestroyHash(hash);
2290 }
2291 CryptDestroyKey(key);
2292 }
2293 return ret;
2294 }
2295
2296 BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV_LEGACY hCryptProv,
2297 DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
2298 DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
2299 {
2300 BOOL ret = TRUE;
2301 CRYPT_DATA_BLOB subjectBlob;
2302
2303 TRACE("(%08lx, %d, %d, %p, %d, %p, %08x, %p)\n", hCryptProv,
2304 dwCertEncodingType, dwSubjectType, pvSubject, dwIssuerType, pvIssuer,
2305 dwFlags, pvReserved);
2306
2307 switch (dwSubjectType)
2308 {
2309 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB:
2310 {
2311 PCRYPT_DATA_BLOB blob = pvSubject;
2312
2313 subjectBlob.pbData = blob->pbData;
2314 subjectBlob.cbData = blob->cbData;
2315 break;
2316 }
2317 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT:
2318 {
2319 PCERT_CONTEXT context = pvSubject;
2320
2321 subjectBlob.pbData = context->pbCertEncoded;
2322 subjectBlob.cbData = context->cbCertEncoded;
2323 break;
2324 }
2325 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL:
2326 {
2327 PCRL_CONTEXT context = pvSubject;
2328
2329 subjectBlob.pbData = context->pbCrlEncoded;
2330 subjectBlob.cbData = context->cbCrlEncoded;
2331 break;
2332 }
2333 default:
2334 SetLastError(E_INVALIDARG);
2335 ret = FALSE;
2336 }
2337
2338 if (ret)
2339 {
2340 PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
2341 DWORD size = 0;
2342
2343 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
2344 subjectBlob.pbData, subjectBlob.cbData,
2345 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
2346 &signedCert, &size);
2347 if (ret)
2348 {
2349 switch (dwIssuerType)
2350 {
2351 case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY:
2352 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
2353 dwCertEncodingType, pvIssuer,
2354 signedCert);
2355 break;
2356 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT:
2357 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
2358 dwCertEncodingType,
2359 &((PCCERT_CONTEXT)pvIssuer)->pCertInfo->SubjectPublicKeyInfo,
2360 signedCert);
2361 break;
2362 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN:
2363 FIXME("CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: stub\n");
2364 ret = FALSE;
2365 break;
2366 case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL:
2367 if (pvIssuer)
2368 {
2369 SetLastError(E_INVALIDARG);
2370 ret = FALSE;
2371 }
2372 else
2373 {
2374 FIXME("unimplemented for NULL signer\n");
2375 SetLastError(E_INVALIDARG);
2376 ret = FALSE;
2377 }
2378 break;
2379 default:
2380 SetLastError(E_INVALIDARG);
2381 ret = FALSE;
2382 }
2383 LocalFree(signedCert);
2384 }
2385 }
2386 return ret;
2387 }
2388
2389 BOOL WINAPI CertGetIntendedKeyUsage(DWORD dwCertEncodingType,
2390 PCERT_INFO pCertInfo, BYTE *pbKeyUsage, DWORD cbKeyUsage)
2391 {
2392 PCERT_EXTENSION ext;
2393 BOOL ret = FALSE;
2394
2395 TRACE("(%08x, %p, %p, %d)\n", dwCertEncodingType, pCertInfo, pbKeyUsage,
2396 cbKeyUsage);
2397
2398 ext = CertFindExtension(szOID_KEY_USAGE, pCertInfo->cExtension,
2399 pCertInfo->rgExtension);
2400 if (ext)
2401 {
2402 CRYPT_BIT_BLOB usage;
2403 DWORD size = sizeof(usage);
2404
2405 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS,
2406 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL,
2407 &usage, &size);
2408 if (ret)
2409 {
2410 if (cbKeyUsage < usage.cbData)
2411 ret = FALSE;
2412 else
2413 {
2414 memcpy(pbKeyUsage, usage.pbData, usage.cbData);
2415 if (cbKeyUsage > usage.cbData)
2416 memset(pbKeyUsage + usage.cbData, 0,
2417 cbKeyUsage - usage.cbData);
2418 }
2419 }
2420 }
2421 else
2422 SetLastError(0);
2423 return ret;
2424 }
2425
2426 BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags,
2427 PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage)
2428 {
2429 PCERT_ENHKEY_USAGE usage = NULL;
2430 DWORD bytesNeeded;
2431 BOOL ret = TRUE;
2432
2433 if (!pCertContext || !pcbUsage)
2434 {
2435 SetLastError(ERROR_INVALID_PARAMETER);
2436 return FALSE;
2437 }
2438
2439 TRACE("(%p, %08x, %p, %d)\n", pCertContext, dwFlags, pUsage, *pcbUsage);
2440
2441 if (!(dwFlags & CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG))
2442 {
2443 DWORD propSize = 0;
2444
2445 if (CertGetCertificateContextProperty(pCertContext,
2446 CERT_ENHKEY_USAGE_PROP_ID, NULL, &propSize))
2447 {
2448 LPBYTE buf = CryptMemAlloc(propSize);
2449
2450 if (buf)
2451 {
2452 if (CertGetCertificateContextProperty(pCertContext,
2453 CERT_ENHKEY_USAGE_PROP_ID, buf, &propSize))
2454 {
2455 ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
2456 X509_ENHANCED_KEY_USAGE, buf, propSize,
2457 CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
2458 }
2459 CryptMemFree(buf);
2460 }
2461 }
2462 }
2463 if (!usage && !(dwFlags & CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG))
2464 {
2465 PCERT_EXTENSION ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
2466 pCertContext->pCertInfo->cExtension,
2467 pCertContext->pCertInfo->rgExtension);
2468
2469 if (ext)
2470 {
2471 ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
2472 X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
2473 CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
2474 }
2475 }
2476 if (!usage)
2477 {
2478 /* If a particular location is specified, this should fail. Otherwise
2479 * it should succeed with an empty usage. (This is true on Win2k and
2480 * later, which we emulate.)
2481 */
2482 if (dwFlags)
2483 {
2484 SetLastError(CRYPT_E_NOT_FOUND);
2485 ret = FALSE;
2486 }
2487 else
2488 bytesNeeded = sizeof(CERT_ENHKEY_USAGE);
2489 }
2490
2491 if (ret)
2492 {
2493 if (!pUsage)
2494 *pcbUsage = bytesNeeded;
2495 else if (*pcbUsage < bytesNeeded)
2496 {
2497 SetLastError(ERROR_MORE_DATA);
2498 *pcbUsage = bytesNeeded;
2499 ret = FALSE;
2500 }
2501 else
2502 {
2503 *pcbUsage = bytesNeeded;
2504 if (usage)
2505 {
2506 DWORD i;
2507 LPSTR nextOID = (LPSTR)((LPBYTE)pUsage +
2508 sizeof(CERT_ENHKEY_USAGE) +
2509 usage->cUsageIdentifier * sizeof(LPSTR));
2510
2511 pUsage->cUsageIdentifier = usage->cUsageIdentifier;
2512 pUsage->rgpszUsageIdentifier = (LPSTR *)((LPBYTE)pUsage +
2513 sizeof(CERT_ENHKEY_USAGE));
2514 for (i = 0; i < usage->cUsageIdentifier; i++)
2515 {
2516 pUsage->rgpszUsageIdentifier[i] = nextOID;
2517 strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
2518 nextOID += strlen(nextOID) + 1;
2519 }
2520 }
2521 else
2522 pUsage->cUsageIdentifier = 0;
2523 }
2524 }
2525 if (usage)
2526 LocalFree(usage);
2527 TRACE("returning %d\n", ret);
2528 return ret;
2529 }
2530
2531 BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext,
2532 PCERT_ENHKEY_USAGE pUsage)
2533 {
2534 BOOL ret;
2535
2536 TRACE("(%p, %p)\n", pCertContext, pUsage);
2537
2538 if (pUsage)
2539 {
2540 CRYPT_DATA_BLOB blob = { 0, NULL };
2541
2542 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
2543 pUsage, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData, &blob.cbData);
2544 if (ret)
2545 {
2546 ret = CertSetCertificateContextProperty(pCertContext,
2547 CERT_ENHKEY_USAGE_PROP_ID, 0, &blob);
2548 LocalFree(blob.pbData);
2549 }
2550 }
2551 else
2552 ret = CertSetCertificateContextProperty(pCertContext,
2553 CERT_ENHKEY_USAGE_PROP_ID, 0, NULL);
2554 return ret;
2555 }
2556
2557 BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
2558 LPCSTR pszUsageIdentifier)
2559 {
2560 BOOL ret;
2561 DWORD size;
2562
2563 TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
2564
2565 if (CertGetEnhancedKeyUsage(pCertContext,
2566 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size))
2567 {
2568 PCERT_ENHKEY_USAGE usage = CryptMemAlloc(size);
2569
2570 if (usage)
2571 {
2572 ret = CertGetEnhancedKeyUsage(pCertContext,
2573 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size);
2574 if (ret)
2575 {
2576 DWORD i;
2577 BOOL exists = FALSE;
2578
2579 /* Make sure usage doesn't already exist */
2580 for (i = 0; !exists && i < usage->cUsageIdentifier; i++)
2581 {
2582 if (!strcmp(usage->rgpszUsageIdentifier[i],
2583 pszUsageIdentifier))
2584 exists = TRUE;
2585 }
2586 if (!exists)
2587 {
2588 PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size +
2589 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
2590
2591 if (newUsage)
2592 {
2593 LPSTR nextOID;
2594
2595 newUsage->rgpszUsageIdentifier = (LPSTR *)
2596 ((LPBYTE)newUsage + sizeof(CERT_ENHKEY_USAGE));
2597 nextOID = (LPSTR)((LPBYTE)newUsage->rgpszUsageIdentifier
2598 + (usage->cUsageIdentifier + 1) * sizeof(LPSTR));
2599 for (i = 0; i < usage->cUsageIdentifier; i++)
2600 {
2601 newUsage->rgpszUsageIdentifier[i] = nextOID;
2602 strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
2603 nextOID += strlen(nextOID) + 1;
2604 }
2605 newUsage->rgpszUsageIdentifier[i] = nextOID;
2606 strcpy(nextOID, pszUsageIdentifier);
2607 newUsage->cUsageIdentifier = i + 1;
2608 ret = CertSetEnhancedKeyUsage(pCertContext, newUsage);
2609 CryptMemFree(newUsage);
2610 }
2611 else
2612 ret = FALSE;
2613 }
2614 }
2615 CryptMemFree(usage);
2616 }
2617 else
2618 ret = FALSE;
2619 }
2620 else
2621 {
2622 PCERT_ENHKEY_USAGE usage = CryptMemAlloc(sizeof(CERT_ENHKEY_USAGE) +
2623 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
2624
2625 if (usage)
2626 {
2627 usage->rgpszUsageIdentifier =
2628 (LPSTR *)((LPBYTE)usage + sizeof(CERT_ENHKEY_USAGE));
2629 usage->rgpszUsageIdentifier[0] = (LPSTR)((LPBYTE)usage +
2630 sizeof(CERT_ENHKEY_USAGE) + sizeof(LPSTR));
2631 strcpy(usage->rgpszUsageIdentifier[0], pszUsageIdentifier);
2632 usage->cUsageIdentifier = 1;
2633 ret = CertSetEnhancedKeyUsage(pCertContext, usage);
2634 CryptMemFree(usage);
2635 }
2636 else
2637 ret = FALSE;
2638 }
2639 return ret;
2640 }
2641
2642 BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
2643 LPCSTR pszUsageIdentifier)
2644 {
2645 BOOL ret;
2646 DWORD size;
2647 CERT_ENHKEY_USAGE usage;
2648
2649 TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
2650
2651 size = sizeof(usage);
2652 ret = CertGetEnhancedKeyUsage(pCertContext,
2653 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, &usage, &size);
2654 if (!ret && GetLastError() == ERROR_MORE_DATA)
2655 {
2656 PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
2657
2658 if (pUsage)
2659 {
2660 ret = CertGetEnhancedKeyUsage(pCertContext,
2661 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
2662 if (ret)
2663 {
2664 if (pUsage->cUsageIdentifier)
2665 {
2666 DWORD i;
2667 BOOL found = FALSE;
2668
2669 for (i = 0; i < pUsage->cUsageIdentifier; i++)
2670 {
2671 if (!strcmp(pUsage->rgpszUsageIdentifier[i],
2672 pszUsageIdentifier))
2673 found = TRUE;
2674 if (found && i < pUsage->cUsageIdentifier - 1)
2675 pUsage->rgpszUsageIdentifier[i] =
2676 pUsage->rgpszUsageIdentifier[i + 1];
2677 }
2678 pUsage->cUsageIdentifier--;
2679 /* Remove the usage if it's empty */
2680 if (pUsage->cUsageIdentifier)
2681 ret = CertSetEnhancedKeyUsage(pCertContext, pUsage);
2682 else
2683 ret = CertSetEnhancedKeyUsage(pCertContext, NULL);
2684 }
2685 }
2686 CryptMemFree(pUsage);
2687 }
2688 else
2689 ret = FALSE;
2690 }
2691 else
2692 {
2693 /* it fit in an empty usage, therefore there's nothing to remove */
2694 ret = TRUE;
2695 }
2696 return ret;
2697 }
2698
2699 struct BitField
2700 {
2701 DWORD cIndexes;
2702 DWORD *indexes;
2703 };
2704
2705 #define BITS_PER_DWORD (sizeof(DWORD) * 8)
2706
2707 static void CRYPT_SetBitInField(struct BitField *field, DWORD bit)
2708 {
2709 DWORD indexIndex = bit / BITS_PER_DWORD;
2710
2711 if (indexIndex + 1 > field->cIndexes)
2712 {
2713 if (field->cIndexes)
2714 field->indexes = CryptMemRealloc(field->indexes,
2715 (indexIndex + 1) * sizeof(DWORD));
2716 else
2717 field->indexes = CryptMemAlloc(sizeof(DWORD));
2718 if (field->indexes)
2719 {
2720 field->indexes[indexIndex] = 0;
2721 field->cIndexes = indexIndex + 1;
2722 }
2723 }
2724 if (field->indexes)
2725 field->indexes[indexIndex] |= 1 << (bit % BITS_PER_DWORD);
2726 }
2727
2728 static BOOL CRYPT_IsBitInFieldSet(const struct BitField *field, DWORD bit)
2729 {
2730 BOOL set = FALSE;
2731 DWORD indexIndex = bit / BITS_PER_DWORD;
2732
2733 assert(field->cIndexes);
2734 set = field->indexes[indexIndex] & (1 << (bit % BITS_PER_DWORD));
2735 return set;
2736 }
2737
2738 BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts,
2739 int *cNumOIDs, LPSTR *rghOIDs, DWORD *pcbOIDs)
2740 {
2741 BOOL ret = TRUE;
2742 DWORD i, cbOIDs = 0;
2743 BOOL allUsagesValid = TRUE;
2744 CERT_ENHKEY_USAGE validUsages = { 0, NULL };
2745
2746 TRACE("(%d, %p, %d, %p, %d)\n", cCerts, rghCerts, *cNumOIDs,
2747 rghOIDs, *pcbOIDs);
2748
2749 for (i = 0; i < cCerts; i++)
2750 {
2751 CERT_ENHKEY_USAGE usage;
2752 DWORD size = sizeof(usage);
2753
2754 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, &usage, &size);
2755 /* Success is deliberately ignored: it implies all usages are valid */
2756 if (!ret && GetLastError() == ERROR_MORE_DATA)
2757 {
2758 PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
2759
2760 allUsagesValid = FALSE;
2761 if (pUsage)
2762 {
2763 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, pUsage, &size);
2764 if (ret)
2765 {
2766 if (!validUsages.cUsageIdentifier)
2767 {
2768 DWORD j;
2769
2770 cbOIDs = pUsage->cUsageIdentifier * sizeof(LPSTR);
2771 validUsages.cUsageIdentifier = pUsage->cUsageIdentifier;
2772 for (j = 0; j < validUsages.cUsageIdentifier; j++)
2773 cbOIDs += lstrlenA(pUsage->rgpszUsageIdentifier[j])
2774 + 1;
2775 validUsages.rgpszUsageIdentifier =
2776 CryptMemAlloc(cbOIDs);
2777 if (validUsages.rgpszUsageIdentifier)
2778 {
2779 LPSTR nextOID = (LPSTR)
2780 ((LPBYTE)validUsages.rgpszUsageIdentifier +
2781 validUsages.cUsageIdentifier * sizeof(LPSTR));
2782
2783 for (j = 0; j < validUsages.cUsageIdentifier; j++)
2784 {
2785 validUsages.rgpszUsageIdentifier[j] = nextOID;
2786 lstrcpyA(validUsages.rgpszUsageIdentifier[j],
2787 pUsage->rgpszUsageIdentifier[j]);
2788 nextOID += lstrlenA(nextOID) + 1;
2789 }
2790 }
2791 }
2792 else
2793 {
2794 struct BitField validIndexes = { 0, NULL };
2795 DWORD j, k, numRemoved = 0;
2796
2797 /* Merge: build a bitmap of all the indexes of
2798 * validUsages.rgpszUsageIdentifier that are in pUsage.
2799 */
2800 for (j = 0; j < pUsage->cUsageIdentifier; j++)
2801 {
2802 for (k = 0; k < validUsages.cUsageIdentifier; k++)
2803 {
2804 if (!strcmp(pUsage->rgpszUsageIdentifier[j],
2805 validUsages.rgpszUsageIdentifier[k]))
2806 {
2807 CRYPT_SetBitInField(&validIndexes, k);
2808 break;
2809 }
2810 }
2811 }
2812 /* Merge by removing from validUsages those that are
2813 * not in the bitmap.
2814 */
2815 for (j = 0; j < validUsages.cUsageIdentifier; j++)
2816 {
2817 if (!CRYPT_IsBitInFieldSet(&validIndexes, j))
2818 {
2819 if (j < validUsages.cUsageIdentifier - 1)
2820 {
2821 memmove(&validUsages.rgpszUsageIdentifier[j],
2822 &validUsages.rgpszUsageIdentifier[j +
2823 numRemoved + 1],
2824 (validUsages.cUsageIdentifier - numRemoved
2825 - j - 1) * sizeof(LPSTR));
2826 cbOIDs -= lstrlenA(
2827 validUsages.rgpszUsageIdentifier[j]) + 1 +
2828 sizeof(LPSTR);
2829 validUsages.cUsageIdentifier--;
2830 numRemoved++;
2831 }
2832 else
2833 validUsages.cUsageIdentifier--;
2834 }
2835 }
2836 CryptMemFree(validIndexes.indexes);
2837 }
2838 }
2839 CryptMemFree(pUsage);
2840 }
2841 }
2842 }
2843 ret = TRUE;
2844 if (allUsagesValid)
2845 {
2846 *cNumOIDs = -1;
2847 *pcbOIDs = 0;
2848 }
2849 else
2850 {
2851 *cNumOIDs = validUsages.cUsageIdentifier;
2852 if (!rghOIDs)
2853 *pcbOIDs = cbOIDs;
2854 else if (*pcbOIDs < cbOIDs)
2855 {
2856 *pcbOIDs = cbOIDs;
2857 SetLastError(ERROR_MORE_DATA);
2858 ret = FALSE;
2859 }
2860 else
2861 {
2862 LPSTR nextOID = (LPSTR)((LPBYTE)rghOIDs +
2863 validUsages.cUsageIdentifier * sizeof(LPSTR));
2864
2865 *pcbOIDs = cbOIDs;
2866 for (i = 0; i < validUsages.cUsageIdentifier; i++)
2867 {
2868 rghOIDs[i] = nextOID;
2869 lstrcpyA(nextOID, validUsages.rgpszUsageIdentifier[i]);
2870 nextOID += lstrlenA(nextOID) + 1;
2871 }
2872 }
2873 }
2874 CryptMemFree(validUsages.rgpszUsageIdentifier);
2875 TRACE("cNumOIDs: %d\n", *cNumOIDs);
2876 TRACE("returning %d\n", ret);
2877 return ret;
2878 }
2879
2880 /* Sets the CERT_KEY_PROV_INFO_PROP_ID property of context from pInfo, or, if
2881 * pInfo is NULL, from the attributes of hProv.
2882 */
2883 static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context,
2884 const CRYPT_KEY_PROV_INFO *pInfo, HCRYPTPROV hProv)
2885 {
2886 CRYPT_KEY_PROV_INFO info = { 0 };
2887 BOOL ret;
2888
2889 if (!pInfo)
2890 {
2891 DWORD size;
2892 int len;
2893
2894 ret = CryptGetProvParam(hProv, PP_CONTAINER, NULL, &size, 0);
2895 if (ret)
2896 {
2897 LPSTR szContainer = CryptMemAlloc(size);
2898
2899 if (szContainer)
2900 {
2901 ret = CryptGetProvParam(hProv, PP_CONTAINER,
2902 (BYTE *)szContainer, &size, 0);
2903 if (ret)
2904 {
2905 len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
2906 NULL, 0);
2907 if (len)
2908 {
2909 info.pwszContainerName = CryptMemAlloc(len *
2910 sizeof(WCHAR));
2911 MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
2912 info.pwszContainerName, len);
2913 }
2914 }
2915 CryptMemFree(szContainer);
2916 }
2917 }
2918 ret = CryptGetProvParam(hProv, PP_NAME, NULL, &size, 0);
2919 if (ret)
2920 {
2921 LPSTR szProvider = CryptMemAlloc(size);
2922
2923 if (szProvider)
2924 {
2925 ret = CryptGetProvParam(hProv, PP_NAME, (BYTE *)szProvider,
2926 &size, 0);
2927 if (ret)
2928 {
2929 len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
2930 NULL, 0);
2931 if (len)
2932 {
2933 info.pwszProvName = CryptMemAlloc(len *
2934 sizeof(WCHAR));
2935 MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
2936 info.pwszProvName, len);
2937 }
2938 }
2939 CryptMemFree(szProvider);
2940 }
2941 }
2942 size = sizeof(info.dwKeySpec);
2943 /* in case no CRYPT_KEY_PROV_INFO given,
2944 * we always use AT_SIGNATURE key spec
2945 */
2946 info.dwKeySpec = AT_SIGNATURE;
2947 size = sizeof(info.dwProvType);
2948 ret = CryptGetProvParam(hProv, PP_PROVTYPE, (LPBYTE)&info.dwProvType,
2949 &size, 0);
2950 if (!ret)
2951 info.dwProvType = PROV_RSA_FULL;
2952 pInfo = &info;
2953 }
2954
2955 CertSetCertificateContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID,
2956 0, pInfo);
2957
2958 if (pInfo == &info)
2959 {
2960 CryptMemFree(info.pwszContainerName);
2961 CryptMemFree(info.pwszProvName);
2962 }
2963 }
2964
2965 /* Creates a signed certificate context from the unsigned, encoded certificate
2966 * in blob, using the crypto provider hProv and the signature algorithm sigAlgo.
2967 */
2968 static PCCERT_CONTEXT CRYPT_CreateSignedCert(const CRYPT_DER_BLOB *blob,
2969 HCRYPTPROV hProv, DWORD dwKeySpec, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo)
2970 {
2971 PCCERT_CONTEXT context = NULL;
2972 BOOL ret;
2973 DWORD sigSize = 0;
2974
2975 ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
2976 blob->pbData, blob->cbData, sigAlgo, NULL, NULL, &sigSize);
2977 if (ret)
2978 {
2979 LPBYTE sig = CryptMemAlloc(sigSize);
2980
2981 ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
2982 blob->pbData, blob->cbData, sigAlgo, NULL, sig, &sigSize);
2983 if (ret)
2984 {
2985 CERT_SIGNED_CONTENT_INFO signedInfo;
2986 BYTE *encodedSignedCert = NULL;
2987 DWORD encodedSignedCertSize = 0;
2988
2989 signedInfo.ToBeSigned.cbData = blob->cbData;
2990 signedInfo.ToBeSigned.pbData = blob->pbData;
2991 memcpy(&signedInfo.SignatureAlgorithm, sigAlgo,
2992 sizeof(signedInfo.SignatureAlgorithm));
2993 signedInfo.Signature.cbData = sigSize;
2994 signedInfo.Signature.pbData = sig;
2995 signedInfo.Signature.cUnusedBits = 0;
2996 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT,
2997 &signedInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
2998 &encodedSignedCert, &encodedSignedCertSize);
2999 if (ret)
3000 {
3001 context = CertCreateCertificateContext(X509_ASN_ENCODING,
3002 encodedSignedCert, encodedSignedCertSize);
3003 LocalFree(encodedSignedCert);
3004 }
3005 }
3006 CryptMemFree(sig);
3007 }
3008 return context;
3009 }
3010
3011 /* Copies data from the parameters into info, where:
3012 * pSerialNumber: The serial number. Must not be NULL.
3013 * pSubjectIssuerBlob: Specifies both the subject and issuer for info.
3014 * Must not be NULL
3015 * pSignatureAlgorithm: Optional.
3016 * pStartTime: The starting time of the certificate. If NULL, the current
3017 * system time is used.
3018 * pEndTime: The ending time of the certificate. If NULL, one year past the
3019 * starting time is used.
3020 * pubKey: The public key of the certificate. Must not be NULL.
3021 * pExtensions: Extensions to be included with the certificate. Optional.
3022 */
3023 static void CRYPT_MakeCertInfo(PCERT_INFO info, const CRYPT_DATA_BLOB *pSerialNumber,
3024 const CERT_NAME_BLOB *pSubjectIssuerBlob,
3025 const CRYPT_ALGORITHM_IDENTIFIER *pSignatureAlgorithm, const SYSTEMTIME *pStartTime,
3026 const SYSTEMTIME *pEndTime, const CERT_PUBLIC_KEY_INFO *pubKey,
3027 const CERT_EXTENSIONS *pExtensions)
3028 {
3029 static CHAR oid[] = szOID_RSA_SHA1RSA;
3030
3031 assert(info);
3032 assert(pSerialNumber);
3033 assert(pSubjectIssuerBlob);
3034 assert(pubKey);
3035
3036 if (pExtensions && pExtensions->cExtension)
3037 info->dwVersion = CERT_V3;
3038 else
3039 info->dwVersion = CERT_V1;
3040 info->SerialNumber.cbData = pSerialNumber->cbData;
3041 info->SerialNumber.pbData = pSerialNumber->pbData;
3042 if (pSignatureAlgorithm)
3043 memcpy(&info->SignatureAlgorithm, pSignatureAlgorithm,
3044 sizeof(info->SignatureAlgorithm));
3045 else
3046 {
3047 info->SignatureAlgorithm.pszObjId = oid;
3048 info->SignatureAlgorithm.Parameters.cbData = 0;
3049 info->SignatureAlgorithm.Parameters.pbData = NULL;
3050 }
3051 info->Issuer.cbData = pSubjectIssuerBlob->cbData;
3052 info->Issuer.pbData = pSubjectIssuerBlob->pbData;
3053 if (pStartTime)
3054 SystemTimeToFileTime(pStartTime, &info->NotBefore);
3055 else
3056 GetSystemTimeAsFileTime(&info->NotBefore);
3057 if (pEndTime)
3058 SystemTimeToFileTime(pEndTime, &info->NotAfter);
3059 else
3060 {
3061 SYSTEMTIME endTime;
3062
3063 if (FileTimeToSystemTime(&info->NotBefore, &endTime))
3064 {
3065 endTime.wYear++;
3066 SystemTimeToFileTime(&endTime, &info->NotAfter);
3067 }
3068 }
3069 info->Subject.cbData = pSubjectIssuerBlob->cbData;
3070 info->Subject.pbData = pSubjectIssuerBlob->pbData;
3071 memcpy(&info->SubjectPublicKeyInfo, pubKey,
3072 sizeof(info->SubjectPublicKeyInfo));
3073 if (pExtensions)
3074 {
3075 info->cExtension = pExtensions->cExtension;
3076 info->rgExtension = pExtensions->rgExtension;
3077 }
3078 else
3079 {
3080 info->cExtension = 0;
3081 info->rgExtension = NULL;
3082 }
3083 }
3084
3085 typedef RPC_STATUS (RPC_ENTRY *UuidCreateFunc)(UUID *);
3086 typedef RPC_STATUS (RPC_ENTRY *UuidToStringFunc)(UUID *, unsigned char **);
3087 typedef RPC_STATUS (RPC_ENTRY *RpcStringFreeFunc)(unsigned char **);
3088
3089 static HCRYPTPROV CRYPT_CreateKeyProv(void)
3090 {
3091 HCRYPTPROV hProv = 0;
3092 HMODULE rpcrt = LoadLibraryA("rpcrt4");
3093
3094 if (rpcrt)
3095 {
3096 UuidCreateFunc uuidCreate = (UuidCreateFunc)GetProcAddress(rpcrt,
3097 "UuidCreate");
3098 UuidToStringFunc uuidToString = (UuidToStringFunc)GetProcAddress(rpcrt,
3099 "UuidToStringA");
3100 RpcStringFreeFunc rpcStringFree = (RpcStringFreeFunc)GetProcAddress(
3101 rpcrt, "RpcStringFreeA");
3102
3103 if (uuidCreate && uuidToString && rpcStringFree)
3104 {
3105 UUID uuid;
3106 RPC_STATUS status = uuidCreate(&uuid);
3107
3108 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY)
3109 {
3110 unsigned char *uuidStr;
3111
3112 status = uuidToString(&uuid, &uuidStr);
3113 if (status == RPC_S_OK)
3114 {
3115 BOOL ret = CryptAcquireContextA(&hProv, (LPCSTR)uuidStr,
3116 MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_NEWKEYSET);
3117
3118 if (ret)
3119 {
3120 HCRYPTKEY key;
3121
3122 ret = CryptGenKey(hProv, AT_SIGNATURE, 0, &key);
3123 if (ret)
3124 CryptDestroyKey(key);
3125 }
3126 rpcStringFree(&uuidStr);
3127 }
3128 }
3129 }
3130 FreeLibrary(rpcrt);
3131 }
3132 return hProv;
3133 }
3134
3135 PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hProv,
3136 PCERT_NAME_BLOB pSubjectIssuerBlob, DWORD dwFlags,
3137 PCRYPT_KEY_PROV_INFO pKeyProvInfo,
3138 PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime,
3139 PSYSTEMTIME pEndTime, PCERT_EXTENSIONS pExtensions)
3140 {
3141 PCCERT_CONTEXT context = NULL;
3142 BOOL ret, releaseContext = FALSE;
3143 PCERT_PUBLIC_KEY_INFO pubKey = NULL;
3144 DWORD pubKeySize = 0,dwKeySpec = AT_SIGNATURE;
3145
3146 TRACE("(%08lx, %p, %08x, %p, %p, %p, %p, %p)\n", hProv,
3147 pSubjectIssuerBlob, dwFlags, pKeyProvInfo, pSignatureAlgorithm, pStartTime,
3148 pExtensions, pExtensions);
3149
3150 if(!pSubjectIssuerBlob)
3151 {
3152 SetLastError(ERROR_INVALID_PARAMETER);
3153 return NULL;
3154 }
3155
3156 if (!hProv)
3157 {
3158 if (!pKeyProvInfo)
3159 {
3160 hProv = CRYPT_CreateKeyProv();
3161 releaseContext = TRUE;
3162 }
3163 else if (pKeyProvInfo->dwFlags & CERT_SET_KEY_PROV_HANDLE_PROP_ID)
3164 {
3165 SetLastError(NTE_BAD_FLAGS);
3166 return NULL;
3167 }
3168 else
3169 {
3170 HCRYPTKEY hKey = 0;
3171 /* acquire the context using the given information*/
3172 ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
3173 pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
3174 pKeyProvInfo->dwFlags);
3175 if (!ret)
3176 {
3177 if(GetLastError() != NTE_BAD_KEYSET)
3178 return NULL;
3179 /* create the key set */
3180 ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
3181 pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
3182 pKeyProvInfo->dwFlags|CRYPT_NEWKEYSET);
3183 if (!ret)
3184 return NULL;
3185 }
3186 dwKeySpec = pKeyProvInfo->dwKeySpec;
3187 /* check if the key is here */
3188 ret = CryptGetUserKey(hProv,dwKeySpec,&hKey);
3189 if(!ret)
3190 {
3191 if (NTE_NO_KEY == GetLastError())
3192 { /* generate the key */
3193 ret = CryptGenKey(hProv,dwKeySpec,0,&hKey);
3194 }
3195 if (!ret)
3196 {
3197 CryptReleaseContext(hProv,0);
3198 SetLastError(NTE_BAD_KEYSET);
3199 return NULL;
3200 }
3201 }
3202 CryptDestroyKey(hKey);
3203 releaseContext = TRUE;
3204 }
3205 }
3206 else if (pKeyProvInfo)
3207 {
3208 SetLastError(ERROR_INVALID_PARAMETER);
3209 return NULL;
3210 }
3211
3212 CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING, NULL,
3213 &pubKeySize);
3214 pubKey = CryptMemAlloc(pubKeySize);
3215 if (pubKey)
3216 {
3217 ret = CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING,
3218 pubKey, &pubKeySize);
3219 if (ret)
3220 {
3221 CERT_INFO info = { 0 };
3222 CRYPT_DER_BLOB blob = { 0, NULL };
3223 BYTE serial[16];
3224 CRYPT_DATA_BLOB serialBlob = { sizeof(serial), serial };
3225
3226 CryptGenRandom(hProv, sizeof(serial), serial);
3227 CRYPT_MakeCertInfo(&info, &serialBlob, pSubjectIssuerBlob,
3228 pSignatureAlgorithm, pStartTime, pEndTime, pubKey, pExtensions);
3229 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
3230 &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData,
3231 &blob.cbData);
3232 if (ret)
3233 {
3234 if (!(dwFlags & CERT_CREATE_SELFSIGN_NO_SIGN))
3235 context = CRYPT_CreateSignedCert(&blob, hProv,dwKeySpec,
3236 &info.SignatureAlgorithm);
3237 else
3238 context = CertCreateCertificateContext(X509_ASN_ENCODING,
3239 blob.pbData, blob.cbData);
3240 if (context && !(dwFlags & CERT_CREATE_SELFSIGN_NO_KEY_INFO))
3241 CertContext_SetKeyProvInfo(context, pKeyProvInfo, hProv);
3242 LocalFree(blob.pbData);
3243 }
3244 }
3245 CryptMemFree(pubKey);
3246 }
3247 if (releaseContext)
3248 CryptReleaseContext(hProv, 0);
3249 return context;
3250 }
3251
3252 BOOL WINAPI CertVerifyCTLUsage(DWORD dwEncodingType, DWORD dwSubjectType,
3253 void *pvSubject, PCTL_USAGE pSubjectUsage, DWORD dwFlags,
3254 PCTL_VERIFY_USAGE_PARA pVerifyUsagePara,
3255 PCTL_VERIFY_USAGE_STATUS pVerifyUsageStatus)
3256 {
3257 FIXME("(0x%x, %d, %p, %p, 0x%x, %p, %p): stub\n", dwEncodingType,
3258 dwSubjectType, pvSubject, pSubjectUsage, dwFlags, pVerifyUsagePara,
3259 pVerifyUsageStatus);
3260 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3261 return FALSE;
3262 }
3263
3264 const void * WINAPI CertCreateContext(DWORD dwContextType, DWORD dwEncodingType,
3265 const BYTE *pbEncoded, DWORD cbEncoded,
3266 DWORD dwFlags, PCERT_CREATE_CONTEXT_PARA pCreatePara)
3267 {
3268 TRACE("(0x%x, 0x%x, %p, %d, 0x%08x, %p)\n", dwContextType, dwEncodingType,
3269 pbEncoded, cbEncoded, dwFlags, pCreatePara);
3270
3271 if (dwFlags)
3272 {
3273 FIXME("dwFlags 0x%08x not handled\n", dwFlags);
3274 return NULL;
3275 }
3276 if (pCreatePara)
3277 {
3278 FIXME("pCreatePara not handled\n");
3279 return NULL;
3280 }
3281
3282 switch (dwContextType)
3283 {
3284 case CERT_STORE_CERTIFICATE_CONTEXT:
3285 return CertCreateCertificateContext(dwEncodingType, pbEncoded, cbEncoded);
3286 case CERT_STORE_CRL_CONTEXT:
3287 return CertCreateCRLContext(dwEncodingType, pbEncoded, cbEncoded);
3288 case CERT_STORE_CTL_CONTEXT:
3289 return CertCreateCTLContext(dwEncodingType, pbEncoded, cbEncoded);
3290 default:
3291 WARN("unknown context type: 0x%x\n", dwContextType);
3292 return NULL;
3293 }
3294 }