crypt32: Moved CertAddCertificateContextToStore to cert.c.
[wine.git] / dlls / crypt32 / cert.c
blob2c96419b108cecd6f4c42696bfb9ea91277aaea0
1 /*
2 * Copyright 2004-2006 Juan Lang
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.
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.
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
20 #include <assert.h>
21 #include <stdarg.h>
23 #define NONAMELESSUNION
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wincrypt.h"
27 #include "winnls.h"
28 #include "rpc.h"
29 #include "wine/debug.h"
30 #include "wine/unicode.h"
31 #include "crypt32_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
35 /* Internal version of CertGetCertificateContextProperty that gets properties
36 * directly from the context (or the context it's linked to, depending on its
37 * type.) Doesn't handle special-case properties, since they are handled by
38 * CertGetCertificateContextProperty, and are particular to the store in which
39 * the property exists (which is separate from the context.)
41 static BOOL CertContext_GetProperty(void *context, DWORD dwPropId,
42 void *pvData, DWORD *pcbData);
44 /* Internal version of CertSetCertificateContextProperty that sets properties
45 * directly on the context (or the context it's linked to, depending on its
46 * type.) Doesn't handle special cases, since they're handled by
47 * CertSetCertificateContextProperty anyway.
49 static BOOL CertContext_SetProperty(void *context, DWORD dwPropId,
50 DWORD dwFlags, const void *pvData);
52 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
53 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
54 DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
56 PCCERT_CONTEXT cert = CertCreateCertificateContext(dwCertEncodingType,
57 pbCertEncoded, cbCertEncoded);
58 BOOL ret;
60 TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore, dwCertEncodingType,
61 pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
63 if (cert)
65 ret = CertAddCertificateContextToStore(hCertStore, cert,
66 dwAddDisposition, ppCertContext);
67 CertFreeCertificateContext(cert);
69 else
70 ret = FALSE;
71 return ret;
74 BOOL WINAPI CertAddEncodedCertificateToSystemStoreA(LPCSTR pszCertStoreName,
75 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
77 HCERTSTORE store;
78 BOOL ret = FALSE;
80 TRACE("(%s, %p, %d)\n", debugstr_a(pszCertStoreName), pbCertEncoded,
81 cbCertEncoded);
83 store = CertOpenSystemStoreA(0, pszCertStoreName);
84 if (store)
86 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
87 pbCertEncoded, cbCertEncoded, CERT_STORE_ADD_USE_EXISTING, NULL);
88 CertCloseStore(store, 0);
90 return ret;
93 BOOL WINAPI CertAddEncodedCertificateToSystemStoreW(LPCWSTR pszCertStoreName,
94 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
96 HCERTSTORE store;
97 BOOL ret = FALSE;
99 TRACE("(%s, %p, %d)\n", debugstr_w(pszCertStoreName), pbCertEncoded,
100 cbCertEncoded);
102 store = CertOpenSystemStoreW(0, pszCertStoreName);
103 if (store)
105 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
106 pbCertEncoded, cbCertEncoded, CERT_STORE_ADD_USE_EXISTING, NULL);
107 CertCloseStore(store, 0);
109 return ret;
112 static void Cert_free(context_t *context)
114 cert_t *cert = (cert_t*)context;
116 CryptMemFree(cert->ctx.pbCertEncoded);
117 LocalFree(cert->ctx.pCertInfo);
120 static const context_vtbl_t cert_vtbl = {
121 Cert_free
124 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
125 PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
126 PCCERT_CONTEXT *ppStoreContext)
128 WINECRYPT_CERTSTORE *store = hCertStore;
129 BOOL ret = TRUE;
130 PCCERT_CONTEXT toAdd = NULL, existing = NULL;
132 TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCertContext,
133 dwAddDisposition, ppStoreContext);
135 switch (dwAddDisposition)
137 case CERT_STORE_ADD_ALWAYS:
138 break;
139 case CERT_STORE_ADD_NEW:
140 case CERT_STORE_ADD_REPLACE_EXISTING:
141 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
142 case CERT_STORE_ADD_USE_EXISTING:
143 case CERT_STORE_ADD_NEWER:
144 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES:
146 BYTE hashToAdd[20];
147 DWORD size = sizeof(hashToAdd);
149 ret = CertGetCertificateContextProperty(pCertContext, CERT_HASH_PROP_ID,
150 hashToAdd, &size);
151 if (ret)
153 CRYPT_HASH_BLOB blob = { sizeof(hashToAdd), hashToAdd };
155 existing = CertFindCertificateInStore(hCertStore,
156 pCertContext->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, &blob,
157 NULL);
159 break;
161 default:
162 FIXME("Unimplemented add disposition %d\n", dwAddDisposition);
163 SetLastError(E_INVALIDARG);
164 ret = FALSE;
167 switch (dwAddDisposition)
169 case CERT_STORE_ADD_ALWAYS:
170 toAdd = CertDuplicateCertificateContext(pCertContext);
171 break;
172 case CERT_STORE_ADD_NEW:
173 if (existing)
175 TRACE("found matching certificate, not adding\n");
176 SetLastError(CRYPT_E_EXISTS);
177 ret = FALSE;
179 else
180 toAdd = CertDuplicateCertificateContext(pCertContext);
181 break;
182 case CERT_STORE_ADD_REPLACE_EXISTING:
183 toAdd = CertDuplicateCertificateContext(pCertContext);
184 break;
185 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
186 toAdd = CertDuplicateCertificateContext(pCertContext);
187 if (existing)
188 Context_CopyProperties(toAdd, existing);
189 break;
190 case CERT_STORE_ADD_USE_EXISTING:
191 if (existing)
193 Context_CopyProperties(existing, pCertContext);
194 if (ppStoreContext)
195 *ppStoreContext = CertDuplicateCertificateContext(existing);
197 else
198 toAdd = CertDuplicateCertificateContext(pCertContext);
199 break;
200 case CERT_STORE_ADD_NEWER:
201 if (existing)
203 if (CompareFileTime(&existing->pCertInfo->NotBefore,
204 &pCertContext->pCertInfo->NotBefore) >= 0)
206 TRACE("existing certificate is newer, not adding\n");
207 SetLastError(CRYPT_E_EXISTS);
208 ret = FALSE;
210 else
211 toAdd = CertDuplicateCertificateContext(pCertContext);
213 else
214 toAdd = CertDuplicateCertificateContext(pCertContext);
215 break;
216 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES:
217 if (existing)
219 if (CompareFileTime(&existing->pCertInfo->NotBefore,
220 &pCertContext->pCertInfo->NotBefore) >= 0)
222 TRACE("existing certificate is newer, not adding\n");
223 SetLastError(CRYPT_E_EXISTS);
224 ret = FALSE;
226 else
228 toAdd = CertDuplicateCertificateContext(pCertContext);
229 Context_CopyProperties(toAdd, existing);
232 else
233 toAdd = CertDuplicateCertificateContext(pCertContext);
234 break;
237 if (toAdd)
239 if (store)
240 ret = store->vtbl->certs.addContext(store, (void *)toAdd,
241 (void *)existing, (const void **)ppStoreContext);
242 else if (ppStoreContext)
243 *ppStoreContext = CertDuplicateCertificateContext(toAdd);
244 CertFreeCertificateContext(toAdd);
246 CertFreeCertificateContext(existing);
248 TRACE("returning %d\n", ret);
249 return ret;
252 BOOL WINAPI CertAddCertificateLinkToStore(HCERTSTORE hCertStore,
253 PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
254 PCCERT_CONTEXT *ppCertContext)
256 static int calls;
257 WINECRYPT_CERTSTORE *store = (WINECRYPT_CERTSTORE*)hCertStore;
259 if (!(calls++))
260 FIXME("(%p, %p, %08x, %p): semi-stub\n", hCertStore, pCertContext,
261 dwAddDisposition, ppCertContext);
262 if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
263 return FALSE;
264 if (store->type == StoreTypeCollection)
266 SetLastError(E_INVALIDARG);
267 return FALSE;
269 return CertAddCertificateContextToStore(hCertStore, pCertContext,
270 dwAddDisposition, ppCertContext);
273 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
274 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
276 PCERT_CONTEXT cert = NULL;
277 BOOL ret;
278 PCERT_INFO certInfo = NULL;
279 DWORD size = 0;
281 TRACE("(%08x, %p, %d)\n", dwCertEncodingType, pbCertEncoded,
282 cbCertEncoded);
284 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
286 SetLastError(E_INVALIDARG);
287 return NULL;
290 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT_TO_BE_SIGNED,
291 pbCertEncoded, cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL,
292 &certInfo, &size);
293 if (ret)
295 BYTE *data = NULL;
297 cert = Context_CreateDataContext(sizeof(CERT_CONTEXT), &cert_vtbl);
298 if (!cert)
299 goto end;
300 data = CryptMemAlloc(cbCertEncoded);
301 if (!data)
303 CertFreeCertificateContext(cert);
304 cert = NULL;
305 goto end;
307 memcpy(data, pbCertEncoded, cbCertEncoded);
308 cert->dwCertEncodingType = dwCertEncodingType;
309 cert->pbCertEncoded = data;
310 cert->cbCertEncoded = cbCertEncoded;
311 cert->pCertInfo = certInfo;
312 cert->hCertStore = &empty_store;
315 end:
316 return cert;
319 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(PCCERT_CONTEXT pCertContext)
321 TRACE("(%p)\n", pCertContext);
323 if (!pCertContext)
324 return NULL;
326 Context_AddRef(&cert_from_ptr(pCertContext)->base);
327 return pCertContext;
330 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
332 BOOL ret = TRUE;
334 TRACE("(%p)\n", pCertContext);
336 if (pCertContext)
337 ret = Context_Release(&cert_from_ptr(pCertContext)->base);
338 return ret;
341 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
342 DWORD dwPropId)
344 CONTEXT_PROPERTY_LIST *properties = Context_GetProperties(pCertContext);
345 DWORD ret;
347 TRACE("(%p, %d)\n", pCertContext, dwPropId);
349 if (properties)
350 ret = ContextPropertyList_EnumPropIDs(properties, dwPropId);
351 else
352 ret = 0;
353 return ret;
356 static BOOL CertContext_GetHashProp(void *context, DWORD dwPropId,
357 ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
358 DWORD *pcbData)
360 BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
361 pcbData);
362 if (ret && pvData)
364 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
366 ret = CertContext_SetProperty(context, dwPropId, 0, &blob);
368 return ret;
371 static BOOL CertContext_CopyParam(void *pvData, DWORD *pcbData, const void *pb,
372 DWORD cb)
374 BOOL ret = TRUE;
376 if (!pvData)
377 *pcbData = cb;
378 else if (*pcbData < cb)
380 SetLastError(ERROR_MORE_DATA);
381 *pcbData = cb;
382 ret = FALSE;
384 else
386 memcpy(pvData, pb, cb);
387 *pcbData = cb;
389 return ret;
392 static BOOL CertContext_GetProperty(void *context, DWORD dwPropId,
393 void *pvData, DWORD *pcbData)
395 PCCERT_CONTEXT pCertContext = context;
396 CONTEXT_PROPERTY_LIST *properties = Context_GetProperties(context);
397 BOOL ret;
398 CRYPT_DATA_BLOB blob;
400 TRACE("(%p, %d, %p, %p)\n", context, dwPropId, pvData, pcbData);
402 if (properties)
403 ret = ContextPropertyList_FindProperty(properties, dwPropId, &blob);
404 else
405 ret = FALSE;
406 if (ret)
407 ret = CertContext_CopyParam(pvData, pcbData, blob.pbData, blob.cbData);
408 else
410 /* Implicit properties */
411 switch (dwPropId)
413 case CERT_SHA1_HASH_PROP_ID:
414 ret = CertContext_GetHashProp(context, dwPropId, CALG_SHA1,
415 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData,
416 pcbData);
417 break;
418 case CERT_MD5_HASH_PROP_ID:
419 ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
420 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData,
421 pcbData);
422 break;
423 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
424 ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
425 pCertContext->pCertInfo->Subject.pbData,
426 pCertContext->pCertInfo->Subject.cbData,
427 pvData, pcbData);
428 break;
429 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
430 ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
431 pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
432 pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
433 pvData, pcbData);
434 break;
435 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
436 ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
437 pCertContext->pCertInfo->SerialNumber.pbData,
438 pCertContext->pCertInfo->SerialNumber.cbData,
439 pvData, pcbData);
440 break;
441 case CERT_SIGNATURE_HASH_PROP_ID:
442 ret = CryptHashToBeSigned(0, pCertContext->dwCertEncodingType,
443 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData,
444 pcbData);
445 if (ret && pvData)
447 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
449 ret = CertContext_SetProperty(context, dwPropId, 0, &blob);
451 break;
452 case CERT_KEY_IDENTIFIER_PROP_ID:
454 PCERT_EXTENSION ext = CertFindExtension(
455 szOID_SUBJECT_KEY_IDENTIFIER, pCertContext->pCertInfo->cExtension,
456 pCertContext->pCertInfo->rgExtension);
458 if (ext)
460 CRYPT_DATA_BLOB value;
461 DWORD size = sizeof(value);
463 ret = CryptDecodeObjectEx(X509_ASN_ENCODING,
464 szOID_SUBJECT_KEY_IDENTIFIER, ext->Value.pbData,
465 ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &value,
466 &size);
467 if (ret)
469 ret = CertContext_CopyParam(pvData, pcbData, value.pbData,
470 value.cbData);
471 CertContext_SetProperty(context, dwPropId, 0, &value);
474 else
475 SetLastError(ERROR_INVALID_DATA);
476 break;
478 default:
479 SetLastError(CRYPT_E_NOT_FOUND);
482 TRACE("returning %d\n", ret);
483 return ret;
486 void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info)
488 DWORD i, containerLen, provNameLen;
489 LPBYTE data = (LPBYTE)info + sizeof(CRYPT_KEY_PROV_INFO);
491 info->pwszContainerName = (LPWSTR)data;
492 containerLen = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
493 data += containerLen;
495 info->pwszProvName = (LPWSTR)data;
496 provNameLen = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
497 data += provNameLen;
499 info->rgProvParam = (PCRYPT_KEY_PROV_PARAM)data;
500 data += info->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
502 for (i = 0; i < info->cProvParam; i++)
504 info->rgProvParam[i].pbData = data;
505 data += info->rgProvParam[i].cbData;
509 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
510 DWORD dwPropId, void *pvData, DWORD *pcbData)
512 BOOL ret;
514 TRACE("(%p, %d, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
516 switch (dwPropId)
518 case 0:
519 case CERT_CERT_PROP_ID:
520 case CERT_CRL_PROP_ID:
521 case CERT_CTL_PROP_ID:
522 SetLastError(E_INVALIDARG);
523 ret = FALSE;
524 break;
525 case CERT_ACCESS_STATE_PROP_ID:
526 if (pCertContext->hCertStore)
527 ret = CertGetStoreProperty(pCertContext->hCertStore, dwPropId,
528 pvData, pcbData);
529 else
531 DWORD state = 0;
533 ret = CertContext_CopyParam(pvData, pcbData, &state, sizeof(state));
535 break;
536 case CERT_KEY_PROV_HANDLE_PROP_ID:
538 CERT_KEY_CONTEXT keyContext;
539 DWORD size = sizeof(keyContext);
541 ret = CertContext_GetProperty((void *)pCertContext,
542 CERT_KEY_CONTEXT_PROP_ID, &keyContext, &size);
543 if (ret)
544 ret = CertContext_CopyParam(pvData, pcbData, &keyContext.hCryptProv,
545 sizeof(keyContext.hCryptProv));
546 break;
548 case CERT_KEY_PROV_INFO_PROP_ID:
549 ret = CertContext_GetProperty((void *)pCertContext, dwPropId, pvData,
550 pcbData);
551 if (ret && pvData)
552 CRYPT_FixKeyProvInfoPointers(pvData);
553 break;
554 default:
555 ret = CertContext_GetProperty((void *)pCertContext, dwPropId, pvData,
556 pcbData);
559 TRACE("returning %d\n", ret);
560 return ret;
563 /* Copies key provider info from from into to, where to is assumed to be a
564 * contiguous buffer of memory large enough for from and all its associated
565 * data, but whose pointers are uninitialized.
566 * Upon return, to contains a contiguous copy of from, packed in the following
567 * order:
568 * - CRYPT_KEY_PROV_INFO
569 * - pwszContainerName
570 * - pwszProvName
571 * - rgProvParam[0]...
573 static void CRYPT_CopyKeyProvInfo(PCRYPT_KEY_PROV_INFO to,
574 const CRYPT_KEY_PROV_INFO *from)
576 DWORD i;
577 LPBYTE nextData = (LPBYTE)to + sizeof(CRYPT_KEY_PROV_INFO);
579 if (from->pwszContainerName)
581 to->pwszContainerName = (LPWSTR)nextData;
582 lstrcpyW(to->pwszContainerName, from->pwszContainerName);
583 nextData += (lstrlenW(from->pwszContainerName) + 1) * sizeof(WCHAR);
585 else
586 to->pwszContainerName = NULL;
587 if (from->pwszProvName)
589 to->pwszProvName = (LPWSTR)nextData;
590 lstrcpyW(to->pwszProvName, from->pwszProvName);
591 nextData += (lstrlenW(from->pwszProvName) + 1) * sizeof(WCHAR);
593 else
594 to->pwszProvName = NULL;
595 to->dwProvType = from->dwProvType;
596 to->dwFlags = from->dwFlags;
597 to->cProvParam = from->cProvParam;
598 to->rgProvParam = (PCRYPT_KEY_PROV_PARAM)nextData;
599 nextData += to->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
600 to->dwKeySpec = from->dwKeySpec;
601 for (i = 0; i < to->cProvParam; i++)
603 memcpy(&to->rgProvParam[i], &from->rgProvParam[i],
604 sizeof(CRYPT_KEY_PROV_PARAM));
605 to->rgProvParam[i].pbData = nextData;
606 memcpy(to->rgProvParam[i].pbData, from->rgProvParam[i].pbData,
607 from->rgProvParam[i].cbData);
608 nextData += from->rgProvParam[i].cbData;
612 static BOOL CertContext_SetKeyProvInfoProperty(CONTEXT_PROPERTY_LIST *properties,
613 const CRYPT_KEY_PROV_INFO *info)
615 BOOL ret;
616 LPBYTE buf = NULL;
617 DWORD size = sizeof(CRYPT_KEY_PROV_INFO), i, containerSize, provNameSize;
619 if (info->pwszContainerName)
620 containerSize = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
621 else
622 containerSize = 0;
623 if (info->pwszProvName)
624 provNameSize = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
625 else
626 provNameSize = 0;
627 size += containerSize + provNameSize;
628 for (i = 0; i < info->cProvParam; i++)
629 size += sizeof(CRYPT_KEY_PROV_PARAM) + info->rgProvParam[i].cbData;
630 buf = CryptMemAlloc(size);
631 if (buf)
633 CRYPT_CopyKeyProvInfo((PCRYPT_KEY_PROV_INFO)buf, info);
634 ret = ContextPropertyList_SetProperty(properties,
635 CERT_KEY_PROV_INFO_PROP_ID, buf, size);
636 CryptMemFree(buf);
638 else
639 ret = FALSE;
640 return ret;
643 static BOOL CertContext_SetProperty(void *context, DWORD dwPropId,
644 DWORD dwFlags, const void *pvData)
646 CONTEXT_PROPERTY_LIST *properties = Context_GetProperties(context);
647 BOOL ret;
649 TRACE("(%p, %d, %08x, %p)\n", context, dwPropId, dwFlags, pvData);
651 if (!properties)
652 ret = FALSE;
653 else
655 switch (dwPropId)
657 case CERT_AUTO_ENROLL_PROP_ID:
658 case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */
659 case CERT_DESCRIPTION_PROP_ID:
660 case CERT_FRIENDLY_NAME_PROP_ID:
661 case CERT_HASH_PROP_ID:
662 case CERT_KEY_IDENTIFIER_PROP_ID:
663 case CERT_MD5_HASH_PROP_ID:
664 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
665 case CERT_PUBKEY_ALG_PARA_PROP_ID:
666 case CERT_PVK_FILE_PROP_ID:
667 case CERT_SIGNATURE_HASH_PROP_ID:
668 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
669 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
670 case CERT_EXTENDED_ERROR_INFO_PROP_ID:
671 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
672 case CERT_ENROLLMENT_PROP_ID:
673 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
674 case CERT_RENEWAL_PROP_ID:
676 if (pvData)
678 const CRYPT_DATA_BLOB *blob = pvData;
680 ret = ContextPropertyList_SetProperty(properties, dwPropId,
681 blob->pbData, blob->cbData);
683 else
685 ContextPropertyList_RemoveProperty(properties, dwPropId);
686 ret = TRUE;
688 break;
690 case CERT_DATE_STAMP_PROP_ID:
691 if (pvData)
692 ret = ContextPropertyList_SetProperty(properties, dwPropId,
693 pvData, sizeof(FILETIME));
694 else
696 ContextPropertyList_RemoveProperty(properties, dwPropId);
697 ret = TRUE;
699 break;
700 case CERT_KEY_CONTEXT_PROP_ID:
702 if (pvData)
704 const CERT_KEY_CONTEXT *keyContext = pvData;
706 if (keyContext->cbSize != sizeof(CERT_KEY_CONTEXT))
708 SetLastError(E_INVALIDARG);
709 ret = FALSE;
711 else
712 ret = ContextPropertyList_SetProperty(properties, dwPropId,
713 (const BYTE *)keyContext, keyContext->cbSize);
715 else
717 ContextPropertyList_RemoveProperty(properties, dwPropId);
718 ret = TRUE;
720 break;
722 case CERT_KEY_PROV_INFO_PROP_ID:
723 if (pvData)
724 ret = CertContext_SetKeyProvInfoProperty(properties, pvData);
725 else
727 ContextPropertyList_RemoveProperty(properties, dwPropId);
728 ret = TRUE;
730 break;
731 case CERT_KEY_PROV_HANDLE_PROP_ID:
733 CERT_KEY_CONTEXT keyContext;
734 DWORD size = sizeof(keyContext);
736 ret = CertContext_GetProperty(context, CERT_KEY_CONTEXT_PROP_ID,
737 &keyContext, &size);
738 if (ret)
740 if (!(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
741 CryptReleaseContext(keyContext.hCryptProv, 0);
743 keyContext.cbSize = sizeof(keyContext);
744 if (pvData)
745 keyContext.hCryptProv = *(const HCRYPTPROV *)pvData;
746 else
748 keyContext.hCryptProv = 0;
749 keyContext.dwKeySpec = AT_SIGNATURE;
751 ret = CertContext_SetProperty(context, CERT_KEY_CONTEXT_PROP_ID,
752 0, &keyContext);
753 break;
755 default:
756 FIXME("%d: stub\n", dwPropId);
757 ret = FALSE;
760 TRACE("returning %d\n", ret);
761 return ret;
764 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
765 DWORD dwPropId, DWORD dwFlags, const void *pvData)
767 BOOL ret;
769 TRACE("(%p, %d, %08x, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
771 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
772 * crashes on most of these, I'll be safer.
774 switch (dwPropId)
776 case 0:
777 case CERT_ACCESS_STATE_PROP_ID:
778 case CERT_CERT_PROP_ID:
779 case CERT_CRL_PROP_ID:
780 case CERT_CTL_PROP_ID:
781 SetLastError(E_INVALIDARG);
782 return FALSE;
784 ret = CertContext_SetProperty((void *)pCertContext, dwPropId, dwFlags,
785 pvData);
786 TRACE("returning %d\n", ret);
787 return ret;
790 /* Acquires the private key using the key provider info, retrieving info from
791 * the certificate if info is NULL. The acquired provider is returned in
792 * *phCryptProv, and the key spec for the provider is returned in *pdwKeySpec.
794 static BOOL CRYPT_AcquirePrivateKeyFromProvInfo(PCCERT_CONTEXT pCert,
795 PCRYPT_KEY_PROV_INFO info, HCRYPTPROV *phCryptProv, DWORD *pdwKeySpec)
797 DWORD size = 0;
798 BOOL allocated = FALSE, ret = TRUE;
800 if (!info)
802 ret = CertGetCertificateContextProperty(pCert,
803 CERT_KEY_PROV_INFO_PROP_ID, 0, &size);
804 if (ret)
806 info = HeapAlloc(GetProcessHeap(), 0, size);
807 if (info)
809 ret = CertGetCertificateContextProperty(pCert,
810 CERT_KEY_PROV_INFO_PROP_ID, info, &size);
811 allocated = TRUE;
813 else
815 SetLastError(ERROR_OUTOFMEMORY);
816 ret = FALSE;
819 else
820 SetLastError(CRYPT_E_NO_KEY_PROPERTY);
822 if (ret)
824 ret = CryptAcquireContextW(phCryptProv, info->pwszContainerName,
825 info->pwszProvName, info->dwProvType, 0);
826 if (ret)
828 DWORD i;
830 for (i = 0; i < info->cProvParam; i++)
832 CryptSetProvParam(*phCryptProv,
833 info->rgProvParam[i].dwParam, info->rgProvParam[i].pbData,
834 info->rgProvParam[i].dwFlags);
836 *pdwKeySpec = info->dwKeySpec;
838 else
839 SetLastError(CRYPT_E_NO_KEY_PROPERTY);
841 if (allocated)
842 HeapFree(GetProcessHeap(), 0, info);
843 return ret;
846 BOOL WINAPI CryptAcquireCertificatePrivateKey(PCCERT_CONTEXT pCert,
847 DWORD dwFlags, void *pvReserved, HCRYPTPROV_OR_NCRYPT_KEY_HANDLE *phCryptProv,
848 DWORD *pdwKeySpec, BOOL *pfCallerFreeProv)
850 BOOL ret = FALSE, cache = FALSE;
851 PCRYPT_KEY_PROV_INFO info = NULL;
852 CERT_KEY_CONTEXT keyContext;
853 DWORD size;
855 TRACE("(%p, %08x, %p, %p, %p, %p)\n", pCert, dwFlags, pvReserved,
856 phCryptProv, pdwKeySpec, pfCallerFreeProv);
858 if (dwFlags & CRYPT_ACQUIRE_USE_PROV_INFO_FLAG)
860 DWORD size = 0;
862 ret = CertGetCertificateContextProperty(pCert,
863 CERT_KEY_PROV_INFO_PROP_ID, 0, &size);
864 if (ret)
866 info = HeapAlloc(GetProcessHeap(), 0, size);
867 ret = CertGetCertificateContextProperty(pCert,
868 CERT_KEY_PROV_INFO_PROP_ID, info, &size);
869 if (ret)
870 cache = info->dwFlags & CERT_SET_KEY_CONTEXT_PROP_ID;
873 else if (dwFlags & CRYPT_ACQUIRE_CACHE_FLAG)
874 cache = TRUE;
875 *phCryptProv = 0;
876 if (cache)
878 size = sizeof(keyContext);
879 ret = CertGetCertificateContextProperty(pCert, CERT_KEY_CONTEXT_PROP_ID,
880 &keyContext, &size);
881 if (ret)
883 *phCryptProv = keyContext.hCryptProv;
884 if (pdwKeySpec)
885 *pdwKeySpec = keyContext.dwKeySpec;
886 if (pfCallerFreeProv)
887 *pfCallerFreeProv = !cache;
890 if (!*phCryptProv)
892 ret = CRYPT_AcquirePrivateKeyFromProvInfo(pCert, info,
893 &keyContext.hCryptProv, &keyContext.dwKeySpec);
894 if (ret)
896 *phCryptProv = keyContext.hCryptProv;
897 if (pdwKeySpec)
898 *pdwKeySpec = keyContext.dwKeySpec;
899 if (cache)
901 keyContext.cbSize = sizeof(keyContext);
902 if (CertSetCertificateContextProperty(pCert,
903 CERT_KEY_CONTEXT_PROP_ID, 0, &keyContext))
905 if (pfCallerFreeProv)
906 *pfCallerFreeProv = FALSE;
909 else
911 if (pfCallerFreeProv)
912 *pfCallerFreeProv = TRUE;
916 HeapFree(GetProcessHeap(), 0, info);
917 return ret;
920 static BOOL key_prov_info_matches_cert(PCCERT_CONTEXT pCert,
921 const CRYPT_KEY_PROV_INFO *keyProvInfo)
923 HCRYPTPROV csp;
924 BOOL matches = FALSE;
926 if (CryptAcquireContextW(&csp, keyProvInfo->pwszContainerName,
927 keyProvInfo->pwszProvName, keyProvInfo->dwProvType, keyProvInfo->dwFlags))
929 DWORD size;
931 /* Need to sign something to verify the sig. What to sign? Why not
932 * the certificate itself?
934 if (CryptSignAndEncodeCertificate(csp, AT_SIGNATURE,
935 pCert->dwCertEncodingType, X509_CERT_TO_BE_SIGNED, pCert->pCertInfo,
936 &pCert->pCertInfo->SignatureAlgorithm, NULL, NULL, &size))
938 BYTE *certEncoded = CryptMemAlloc(size);
940 if (certEncoded)
942 if (CryptSignAndEncodeCertificate(csp, AT_SIGNATURE,
943 pCert->dwCertEncodingType, X509_CERT_TO_BE_SIGNED,
944 pCert->pCertInfo, &pCert->pCertInfo->SignatureAlgorithm,
945 NULL, certEncoded, &size))
947 if (size == pCert->cbCertEncoded &&
948 !memcmp(certEncoded, pCert->pbCertEncoded, size))
949 matches = TRUE;
951 CryptMemFree(certEncoded);
954 CryptReleaseContext(csp, 0);
956 return matches;
959 static BOOL container_matches_cert(PCCERT_CONTEXT pCert, LPCSTR container,
960 CRYPT_KEY_PROV_INFO *keyProvInfo)
962 CRYPT_KEY_PROV_INFO copy;
963 WCHAR containerW[MAX_PATH];
964 BOOL matches = FALSE;
966 MultiByteToWideChar(CP_ACP, 0, container, -1,
967 containerW, sizeof(containerW) / sizeof(containerW[0]));
968 /* We make a copy of the CRYPT_KEY_PROV_INFO because the caller expects
969 * keyProvInfo->pwszContainerName to be NULL or a heap-allocated container
970 * name.
972 copy = *keyProvInfo;
973 copy.pwszContainerName = containerW;
974 matches = key_prov_info_matches_cert(pCert, &copy);
975 if (matches)
977 keyProvInfo->pwszContainerName =
978 CryptMemAlloc((strlenW(containerW) + 1) * sizeof(WCHAR));
979 if (keyProvInfo->pwszContainerName)
981 strcpyW(keyProvInfo->pwszContainerName, containerW);
982 keyProvInfo->dwKeySpec = AT_SIGNATURE;
984 else
985 matches = FALSE;
987 return matches;
990 /* Searches the provider named keyProvInfo.pwszProvName for a container whose
991 * private key matches pCert's public key. Upon success, updates keyProvInfo
992 * with the matching container's info (free keyProvInfo.pwszContainerName upon
993 * success.)
994 * Returns TRUE if found, FALSE if not.
996 static BOOL find_key_prov_info_in_provider(PCCERT_CONTEXT pCert,
997 CRYPT_KEY_PROV_INFO *keyProvInfo)
999 HCRYPTPROV defProvider;
1000 BOOL ret, found = FALSE;
1001 char containerA[MAX_PATH];
1003 assert(keyProvInfo->pwszContainerName == NULL);
1004 if ((ret = CryptAcquireContextW(&defProvider, NULL,
1005 keyProvInfo->pwszProvName, keyProvInfo->dwProvType,
1006 keyProvInfo->dwFlags | CRYPT_VERIFYCONTEXT)))
1008 DWORD enumFlags = keyProvInfo->dwFlags | CRYPT_FIRST;
1010 while (ret && !found)
1012 DWORD size = sizeof(containerA);
1014 ret = CryptGetProvParam(defProvider, PP_ENUMCONTAINERS,
1015 (BYTE *)containerA, &size, enumFlags);
1016 if (ret)
1017 found = container_matches_cert(pCert, containerA, keyProvInfo);
1018 if (enumFlags & CRYPT_FIRST)
1020 enumFlags &= ~CRYPT_FIRST;
1021 enumFlags |= CRYPT_NEXT;
1024 CryptReleaseContext(defProvider, 0);
1026 return found;
1029 static BOOL find_matching_provider(PCCERT_CONTEXT pCert, DWORD dwFlags)
1031 BOOL found = FALSE, ret = TRUE;
1032 DWORD index = 0, cbProvName = 0;
1033 CRYPT_KEY_PROV_INFO keyProvInfo;
1035 TRACE("(%p, %08x)\n", pCert, dwFlags);
1037 memset(&keyProvInfo, 0, sizeof(keyProvInfo));
1038 while (ret && !found)
1040 DWORD size = 0;
1042 ret = CryptEnumProvidersW(index, NULL, 0, &keyProvInfo.dwProvType,
1043 NULL, &size);
1044 if (ret)
1046 if (size <= cbProvName)
1047 ret = CryptEnumProvidersW(index, NULL, 0,
1048 &keyProvInfo.dwProvType, keyProvInfo.pwszProvName, &size);
1049 else
1051 CryptMemFree(keyProvInfo.pwszProvName);
1052 keyProvInfo.pwszProvName = CryptMemAlloc(size);
1053 if (keyProvInfo.pwszProvName)
1055 cbProvName = size;
1056 ret = CryptEnumProvidersW(index, NULL, 0,
1057 &keyProvInfo.dwProvType, keyProvInfo.pwszProvName, &size);
1058 if (ret)
1060 if (dwFlags & CRYPT_FIND_SILENT_KEYSET_FLAG)
1061 keyProvInfo.dwFlags |= CRYPT_SILENT;
1062 if (dwFlags & CRYPT_FIND_USER_KEYSET_FLAG ||
1063 !(dwFlags & (CRYPT_FIND_USER_KEYSET_FLAG |
1064 CRYPT_FIND_MACHINE_KEYSET_FLAG)))
1066 keyProvInfo.dwFlags |= CRYPT_USER_KEYSET;
1067 found = find_key_prov_info_in_provider(pCert,
1068 &keyProvInfo);
1070 if (!found)
1072 if (dwFlags & CRYPT_FIND_MACHINE_KEYSET_FLAG ||
1073 !(dwFlags & (CRYPT_FIND_USER_KEYSET_FLAG |
1074 CRYPT_FIND_MACHINE_KEYSET_FLAG)))
1076 keyProvInfo.dwFlags &= ~CRYPT_USER_KEYSET;
1077 keyProvInfo.dwFlags |= CRYPT_MACHINE_KEYSET;
1078 found = find_key_prov_info_in_provider(pCert,
1079 &keyProvInfo);
1084 else
1085 ret = FALSE;
1087 index++;
1090 if (found)
1091 CertSetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID,
1092 0, &keyProvInfo);
1093 CryptMemFree(keyProvInfo.pwszProvName);
1094 CryptMemFree(keyProvInfo.pwszContainerName);
1095 return found;
1098 static BOOL cert_prov_info_matches_cert(PCCERT_CONTEXT pCert)
1100 BOOL matches = FALSE;
1101 DWORD size;
1103 if (CertGetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID,
1104 NULL, &size))
1106 CRYPT_KEY_PROV_INFO *keyProvInfo = CryptMemAlloc(size);
1108 if (keyProvInfo)
1110 if (CertGetCertificateContextProperty(pCert,
1111 CERT_KEY_PROV_INFO_PROP_ID, keyProvInfo, &size))
1112 matches = key_prov_info_matches_cert(pCert, keyProvInfo);
1113 CryptMemFree(keyProvInfo);
1116 return matches;
1119 BOOL WINAPI CryptFindCertificateKeyProvInfo(PCCERT_CONTEXT pCert,
1120 DWORD dwFlags, void *pvReserved)
1122 BOOL matches = FALSE;
1124 TRACE("(%p, %08x, %p)\n", pCert, dwFlags, pvReserved);
1126 matches = cert_prov_info_matches_cert(pCert);
1127 if (!matches)
1128 matches = find_matching_provider(pCert, dwFlags);
1129 return matches;
1132 BOOL WINAPI CertCompareCertificate(DWORD dwCertEncodingType,
1133 PCERT_INFO pCertId1, PCERT_INFO pCertId2)
1135 BOOL ret;
1137 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertId1, pCertId2);
1139 ret = CertCompareCertificateName(dwCertEncodingType, &pCertId1->Issuer,
1140 &pCertId2->Issuer) && CertCompareIntegerBlob(&pCertId1->SerialNumber,
1141 &pCertId2->SerialNumber);
1142 TRACE("returning %d\n", ret);
1143 return ret;
1146 BOOL WINAPI CertCompareCertificateName(DWORD dwCertEncodingType,
1147 PCERT_NAME_BLOB pCertName1, PCERT_NAME_BLOB pCertName2)
1149 BOOL ret;
1151 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertName1, pCertName2);
1153 if (pCertName1->cbData == pCertName2->cbData)
1155 if (pCertName1->cbData)
1156 ret = !memcmp(pCertName1->pbData, pCertName2->pbData,
1157 pCertName1->cbData);
1158 else
1159 ret = TRUE;
1161 else
1162 ret = FALSE;
1163 TRACE("returning %d\n", ret);
1164 return ret;
1167 /* Returns the number of significant bytes in pInt, where a byte is
1168 * insignificant if it's a leading 0 for positive numbers or a leading 0xff
1169 * for negative numbers. pInt is assumed to be little-endian.
1171 static DWORD CRYPT_significantBytes(const CRYPT_INTEGER_BLOB *pInt)
1173 DWORD ret = pInt->cbData;
1175 while (ret > 1)
1177 if (pInt->pbData[ret - 2] <= 0x7f && pInt->pbData[ret - 1] == 0)
1178 ret--;
1179 else if (pInt->pbData[ret - 2] >= 0x80 && pInt->pbData[ret - 1] == 0xff)
1180 ret--;
1181 else
1182 break;
1184 return ret;
1187 BOOL WINAPI CertCompareIntegerBlob(PCRYPT_INTEGER_BLOB pInt1,
1188 PCRYPT_INTEGER_BLOB pInt2)
1190 BOOL ret;
1191 DWORD cb1, cb2;
1193 TRACE("(%p, %p)\n", pInt1, pInt2);
1195 cb1 = CRYPT_significantBytes(pInt1);
1196 cb2 = CRYPT_significantBytes(pInt2);
1197 if (cb1 == cb2)
1199 if (cb1)
1200 ret = !memcmp(pInt1->pbData, pInt2->pbData, cb1);
1201 else
1202 ret = TRUE;
1204 else
1205 ret = FALSE;
1206 TRACE("returning %d\n", ret);
1207 return ret;
1210 BOOL WINAPI CertComparePublicKeyInfo(DWORD dwCertEncodingType,
1211 PCERT_PUBLIC_KEY_INFO pPublicKey1, PCERT_PUBLIC_KEY_INFO pPublicKey2)
1213 BOOL ret;
1215 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pPublicKey1, pPublicKey2);
1217 switch (GET_CERT_ENCODING_TYPE(dwCertEncodingType))
1219 case 0: /* Seems to mean "raw binary bits" */
1220 if (pPublicKey1->PublicKey.cbData == pPublicKey2->PublicKey.cbData &&
1221 pPublicKey1->PublicKey.cUnusedBits == pPublicKey2->PublicKey.cUnusedBits)
1223 if (pPublicKey2->PublicKey.cbData)
1224 ret = !memcmp(pPublicKey1->PublicKey.pbData,
1225 pPublicKey2->PublicKey.pbData, pPublicKey1->PublicKey.cbData);
1226 else
1227 ret = TRUE;
1229 else
1230 ret = FALSE;
1231 break;
1232 default:
1233 WARN("Unknown encoding type %08x\n", dwCertEncodingType);
1234 /* FALLTHROUGH */
1235 case X509_ASN_ENCODING:
1237 BLOBHEADER *pblob1, *pblob2;
1238 DWORD length;
1239 ret = FALSE;
1240 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1241 pPublicKey1->PublicKey.pbData, pPublicKey1->PublicKey.cbData,
1242 0, NULL, &length))
1244 pblob1 = CryptMemAlloc(length);
1245 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1246 pPublicKey1->PublicKey.pbData, pPublicKey1->PublicKey.cbData,
1247 0, pblob1, &length))
1249 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1250 pPublicKey2->PublicKey.pbData, pPublicKey2->PublicKey.cbData,
1251 0, NULL, &length))
1253 pblob2 = CryptMemAlloc(length);
1254 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1255 pPublicKey2->PublicKey.pbData, pPublicKey2->PublicKey.cbData,
1256 0, pblob2, &length))
1258 /* The RSAPUBKEY structure directly follows the BLOBHEADER */
1259 RSAPUBKEY *pk1 = (LPVOID)(pblob1 + 1),
1260 *pk2 = (LPVOID)(pblob2 + 1);
1261 ret = (pk1->bitlen == pk2->bitlen) && (pk1->pubexp == pk2->pubexp)
1262 && !memcmp(pk1 + 1, pk2 + 1, pk1->bitlen/8);
1264 CryptMemFree(pblob2);
1267 CryptMemFree(pblob1);
1270 break;
1273 return ret;
1276 DWORD WINAPI CertGetPublicKeyLength(DWORD dwCertEncodingType,
1277 PCERT_PUBLIC_KEY_INFO pPublicKey)
1279 DWORD len = 0;
1281 TRACE("(%08x, %p)\n", dwCertEncodingType, pPublicKey);
1283 if (GET_CERT_ENCODING_TYPE(dwCertEncodingType) != X509_ASN_ENCODING)
1285 SetLastError(ERROR_FILE_NOT_FOUND);
1286 return 0;
1288 if (pPublicKey->Algorithm.pszObjId &&
1289 !strcmp(pPublicKey->Algorithm.pszObjId, szOID_RSA_DH))
1291 FIXME("unimplemented for DH public keys\n");
1292 SetLastError(CRYPT_E_ASN1_BADTAG);
1294 else
1296 DWORD size;
1297 PBYTE buf;
1298 BOOL ret = CryptDecodeObjectEx(dwCertEncodingType,
1299 RSA_CSP_PUBLICKEYBLOB, pPublicKey->PublicKey.pbData,
1300 pPublicKey->PublicKey.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf,
1301 &size);
1303 if (ret)
1305 RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
1307 len = rsaPubKey->bitlen;
1308 LocalFree(buf);
1311 return len;
1314 typedef BOOL (*CertCompareFunc)(PCCERT_CONTEXT pCertContext, DWORD dwType,
1315 DWORD dwFlags, const void *pvPara);
1317 static BOOL compare_cert_by_md5_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
1318 DWORD dwFlags, const void *pvPara)
1320 BOOL ret;
1321 BYTE hash[16];
1322 DWORD size = sizeof(hash);
1324 ret = CertGetCertificateContextProperty(pCertContext,
1325 CERT_MD5_HASH_PROP_ID, hash, &size);
1326 if (ret)
1328 const CRYPT_HASH_BLOB *pHash = pvPara;
1330 if (size == pHash->cbData)
1331 ret = !memcmp(pHash->pbData, hash, size);
1332 else
1333 ret = FALSE;
1335 return ret;
1338 static BOOL compare_cert_by_sha1_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
1339 DWORD dwFlags, const void *pvPara)
1341 BOOL ret;
1342 BYTE hash[20];
1343 DWORD size = sizeof(hash);
1345 ret = CertGetCertificateContextProperty(pCertContext,
1346 CERT_SHA1_HASH_PROP_ID, hash, &size);
1347 if (ret)
1349 const CRYPT_HASH_BLOB *pHash = pvPara;
1351 if (size == pHash->cbData)
1352 ret = !memcmp(pHash->pbData, hash, size);
1353 else
1354 ret = FALSE;
1356 return ret;
1359 static BOOL compare_cert_by_name(PCCERT_CONTEXT pCertContext, DWORD dwType,
1360 DWORD dwFlags, const void *pvPara)
1362 CERT_NAME_BLOB *blob = (CERT_NAME_BLOB *)pvPara, *toCompare;
1363 BOOL ret;
1365 if (dwType & CERT_INFO_SUBJECT_FLAG)
1366 toCompare = &pCertContext->pCertInfo->Subject;
1367 else
1368 toCompare = &pCertContext->pCertInfo->Issuer;
1369 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1370 toCompare, blob);
1371 return ret;
1374 static BOOL compare_cert_by_public_key(PCCERT_CONTEXT pCertContext,
1375 DWORD dwType, DWORD dwFlags, const void *pvPara)
1377 CERT_PUBLIC_KEY_INFO *publicKey = (CERT_PUBLIC_KEY_INFO *)pvPara;
1378 BOOL ret;
1380 ret = CertComparePublicKeyInfo(pCertContext->dwCertEncodingType,
1381 &pCertContext->pCertInfo->SubjectPublicKeyInfo, publicKey);
1382 return ret;
1385 static BOOL compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext,
1386 DWORD dwType, DWORD dwFlags, const void *pvPara)
1388 CERT_INFO *pCertInfo = (CERT_INFO *)pvPara;
1389 BOOL ret;
1391 /* Matching serial number and subject match.. */
1392 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1393 &pCertContext->pCertInfo->Subject, &pCertInfo->Issuer);
1394 if (ret)
1395 ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
1396 &pCertInfo->SerialNumber);
1397 else
1399 /* failing that, if the serial number and issuer match, we match */
1400 ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
1401 &pCertInfo->SerialNumber);
1402 if (ret)
1403 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1404 &pCertContext->pCertInfo->Issuer, &pCertInfo->Issuer);
1406 TRACE("returning %d\n", ret);
1407 return ret;
1410 static BOOL compare_cert_by_cert_id(PCCERT_CONTEXT pCertContext, DWORD dwType,
1411 DWORD dwFlags, const void *pvPara)
1413 CERT_ID *id = (CERT_ID *)pvPara;
1414 BOOL ret;
1416 switch (id->dwIdChoice)
1418 case CERT_ID_ISSUER_SERIAL_NUMBER:
1419 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1420 &pCertContext->pCertInfo->Issuer, &id->u.IssuerSerialNumber.Issuer);
1421 if (ret)
1422 ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
1423 &id->u.IssuerSerialNumber.SerialNumber);
1424 break;
1425 case CERT_ID_SHA1_HASH:
1426 ret = compare_cert_by_sha1_hash(pCertContext, dwType, dwFlags,
1427 &id->u.HashId);
1428 break;
1429 case CERT_ID_KEY_IDENTIFIER:
1431 DWORD size = 0;
1433 ret = CertGetCertificateContextProperty(pCertContext,
1434 CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
1435 if (ret && size == id->u.KeyId.cbData)
1437 LPBYTE buf = CryptMemAlloc(size);
1439 if (buf)
1441 CertGetCertificateContextProperty(pCertContext,
1442 CERT_KEY_IDENTIFIER_PROP_ID, buf, &size);
1443 ret = !memcmp(buf, id->u.KeyId.pbData, size);
1444 CryptMemFree(buf);
1447 else
1448 ret = FALSE;
1449 break;
1451 default:
1452 ret = FALSE;
1453 break;
1455 return ret;
1458 static BOOL compare_existing_cert(PCCERT_CONTEXT pCertContext, DWORD dwType,
1459 DWORD dwFlags, const void *pvPara)
1461 PCCERT_CONTEXT toCompare = pvPara;
1462 return CertCompareCertificate(pCertContext->dwCertEncodingType,
1463 pCertContext->pCertInfo, toCompare->pCertInfo);
1466 static BOOL compare_cert_by_signature_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
1467 DWORD dwFlags, const void *pvPara)
1469 const CRYPT_HASH_BLOB *hash = pvPara;
1470 DWORD size = 0;
1471 BOOL ret;
1473 ret = CertGetCertificateContextProperty(pCertContext,
1474 CERT_SIGNATURE_HASH_PROP_ID, NULL, &size);
1475 if (ret && size == hash->cbData)
1477 LPBYTE buf = CryptMemAlloc(size);
1479 if (buf)
1481 CertGetCertificateContextProperty(pCertContext,
1482 CERT_SIGNATURE_HASH_PROP_ID, buf, &size);
1483 ret = !memcmp(buf, hash->pbData, size);
1484 CryptMemFree(buf);
1487 else
1488 ret = FALSE;
1489 return ret;
1492 static inline PCCERT_CONTEXT cert_compare_certs_in_store(HCERTSTORE store,
1493 PCCERT_CONTEXT prev, CertCompareFunc compare, DWORD dwType, DWORD dwFlags,
1494 const void *pvPara)
1496 BOOL matches = FALSE;
1497 PCCERT_CONTEXT ret;
1499 ret = prev;
1500 do {
1501 ret = CertEnumCertificatesInStore(store, ret);
1502 if (ret)
1503 matches = compare(ret, dwType, dwFlags, pvPara);
1504 } while (ret != NULL && !matches);
1505 return ret;
1508 typedef PCCERT_CONTEXT (*CertFindFunc)(HCERTSTORE store, DWORD dwType,
1509 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev);
1511 static PCCERT_CONTEXT find_cert_any(HCERTSTORE store, DWORD dwType,
1512 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1514 return CertEnumCertificatesInStore(store, prev);
1517 static PCCERT_CONTEXT find_cert_by_issuer(HCERTSTORE store, DWORD dwType,
1518 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1520 BOOL ret;
1521 PCCERT_CONTEXT found = NULL, subject = pvPara;
1522 PCERT_EXTENSION ext;
1523 DWORD size;
1525 if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER,
1526 subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
1528 CERT_AUTHORITY_KEY_ID_INFO *info;
1530 ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
1531 X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData,
1532 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1533 &info, &size);
1534 if (ret)
1536 CERT_ID id;
1538 if (info->CertIssuer.cbData && info->CertSerialNumber.cbData)
1540 id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
1541 memcpy(&id.u.IssuerSerialNumber.Issuer, &info->CertIssuer,
1542 sizeof(CERT_NAME_BLOB));
1543 memcpy(&id.u.IssuerSerialNumber.SerialNumber,
1544 &info->CertSerialNumber, sizeof(CRYPT_INTEGER_BLOB));
1546 else if (info->KeyId.cbData)
1548 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
1549 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
1551 else
1552 ret = FALSE;
1553 if (ret)
1554 found = cert_compare_certs_in_store(store, prev,
1555 compare_cert_by_cert_id, dwType, dwFlags, &id);
1556 LocalFree(info);
1559 else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2,
1560 subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
1562 CERT_AUTHORITY_KEY_ID2_INFO *info;
1564 ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
1565 X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData,
1566 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1567 &info, &size);
1568 if (ret)
1570 CERT_ID id;
1572 if (info->AuthorityCertIssuer.cAltEntry &&
1573 info->AuthorityCertSerialNumber.cbData)
1575 PCERT_ALT_NAME_ENTRY directoryName = NULL;
1576 DWORD i;
1578 for (i = 0; !directoryName &&
1579 i < info->AuthorityCertIssuer.cAltEntry; i++)
1580 if (info->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice
1581 == CERT_ALT_NAME_DIRECTORY_NAME)
1582 directoryName =
1583 &info->AuthorityCertIssuer.rgAltEntry[i];
1584 if (directoryName)
1586 id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
1587 memcpy(&id.u.IssuerSerialNumber.Issuer,
1588 &directoryName->u.DirectoryName, sizeof(CERT_NAME_BLOB));
1589 memcpy(&id.u.IssuerSerialNumber.SerialNumber,
1590 &info->AuthorityCertSerialNumber,
1591 sizeof(CRYPT_INTEGER_BLOB));
1593 else
1595 FIXME("no supported name type in authority key id2\n");
1596 ret = FALSE;
1599 else if (info->KeyId.cbData)
1601 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
1602 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
1604 else
1605 ret = FALSE;
1606 if (ret)
1607 found = cert_compare_certs_in_store(store, prev,
1608 compare_cert_by_cert_id, dwType, dwFlags, &id);
1609 LocalFree(info);
1612 else
1613 found = cert_compare_certs_in_store(store, prev,
1614 compare_cert_by_name, CERT_COMPARE_NAME | CERT_COMPARE_SUBJECT_CERT,
1615 dwFlags, &subject->pCertInfo->Issuer);
1616 return found;
1619 static BOOL compare_cert_by_name_str(PCCERT_CONTEXT pCertContext,
1620 DWORD dwType, DWORD dwFlags, const void *pvPara)
1622 PCERT_NAME_BLOB name;
1623 DWORD len;
1624 BOOL ret = FALSE;
1626 if (dwType & CERT_INFO_SUBJECT_FLAG)
1627 name = &pCertContext->pCertInfo->Subject;
1628 else
1629 name = &pCertContext->pCertInfo->Issuer;
1630 len = CertNameToStrW(pCertContext->dwCertEncodingType, name,
1631 CERT_SIMPLE_NAME_STR, NULL, 0);
1632 if (len)
1634 LPWSTR str = CryptMemAlloc(len * sizeof(WCHAR));
1636 if (str)
1638 LPWSTR ptr;
1640 CertNameToStrW(pCertContext->dwCertEncodingType, name,
1641 CERT_SIMPLE_NAME_STR, str, len);
1642 for (ptr = str; *ptr; ptr++)
1643 *ptr = tolowerW(*ptr);
1644 if (strstrW(str, pvPara))
1645 ret = TRUE;
1646 CryptMemFree(str);
1649 return ret;
1652 static PCCERT_CONTEXT find_cert_by_name_str_a(HCERTSTORE store, DWORD dwType,
1653 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1655 PCCERT_CONTEXT found = NULL;
1657 TRACE("%s\n", debugstr_a(pvPara));
1659 if (pvPara)
1661 int len = MultiByteToWideChar(CP_ACP, 0, pvPara, -1, NULL, 0);
1662 LPWSTR str = CryptMemAlloc(len * sizeof(WCHAR));
1664 if (str)
1666 LPWSTR ptr;
1668 MultiByteToWideChar(CP_ACP, 0, pvPara, -1, str, len);
1669 for (ptr = str; *ptr; ptr++)
1670 *ptr = tolowerW(*ptr);
1671 found = cert_compare_certs_in_store(store, prev,
1672 compare_cert_by_name_str, dwType, dwFlags, str);
1673 CryptMemFree(str);
1676 else
1677 found = find_cert_any(store, dwType, dwFlags, NULL, prev);
1678 return found;
1681 static PCCERT_CONTEXT find_cert_by_name_str_w(HCERTSTORE store, DWORD dwType,
1682 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1684 PCCERT_CONTEXT found = NULL;
1686 TRACE("%s\n", debugstr_w(pvPara));
1688 if (pvPara)
1690 DWORD len = strlenW(pvPara);
1691 LPWSTR str = CryptMemAlloc((len + 1) * sizeof(WCHAR));
1693 if (str)
1695 LPCWSTR src;
1696 LPWSTR dst;
1698 for (src = pvPara, dst = str; *src; src++, dst++)
1699 *dst = tolowerW(*src);
1700 *dst = 0;
1701 found = cert_compare_certs_in_store(store, prev,
1702 compare_cert_by_name_str, dwType, dwFlags, str);
1703 CryptMemFree(str);
1706 else
1707 found = find_cert_any(store, dwType, dwFlags, NULL, prev);
1708 return found;
1711 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
1712 DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType, const void *pvPara,
1713 PCCERT_CONTEXT pPrevCertContext)
1715 PCCERT_CONTEXT ret;
1716 CertFindFunc find = NULL;
1717 CertCompareFunc compare = NULL;
1719 TRACE("(%p, %08x, %08x, %08x, %p, %p)\n", hCertStore, dwCertEncodingType,
1720 dwFlags, dwType, pvPara, pPrevCertContext);
1722 switch (dwType >> CERT_COMPARE_SHIFT)
1724 case CERT_COMPARE_ANY:
1725 find = find_cert_any;
1726 break;
1727 case CERT_COMPARE_MD5_HASH:
1728 compare = compare_cert_by_md5_hash;
1729 break;
1730 case CERT_COMPARE_SHA1_HASH:
1731 compare = compare_cert_by_sha1_hash;
1732 break;
1733 case CERT_COMPARE_NAME:
1734 compare = compare_cert_by_name;
1735 break;
1736 case CERT_COMPARE_PUBLIC_KEY:
1737 compare = compare_cert_by_public_key;
1738 break;
1739 case CERT_COMPARE_NAME_STR_A:
1740 find = find_cert_by_name_str_a;
1741 break;
1742 case CERT_COMPARE_NAME_STR_W:
1743 find = find_cert_by_name_str_w;
1744 break;
1745 case CERT_COMPARE_SUBJECT_CERT:
1746 compare = compare_cert_by_subject_cert;
1747 break;
1748 case CERT_COMPARE_CERT_ID:
1749 compare = compare_cert_by_cert_id;
1750 break;
1751 case CERT_COMPARE_ISSUER_OF:
1752 find = find_cert_by_issuer;
1753 break;
1754 case CERT_COMPARE_EXISTING:
1755 compare = compare_existing_cert;
1756 break;
1757 case CERT_COMPARE_SIGNATURE_HASH:
1758 compare = compare_cert_by_signature_hash;
1759 break;
1760 default:
1761 FIXME("find type %08x unimplemented\n", dwType);
1764 if (find)
1765 ret = find(hCertStore, dwFlags, dwType, pvPara, pPrevCertContext);
1766 else if (compare)
1767 ret = cert_compare_certs_in_store(hCertStore, pPrevCertContext,
1768 compare, dwType, dwFlags, pvPara);
1769 else
1770 ret = NULL;
1771 if (!ret)
1772 SetLastError(CRYPT_E_NOT_FOUND);
1773 TRACE("returning %p\n", ret);
1774 return ret;
1777 PCCERT_CONTEXT WINAPI CertGetSubjectCertificateFromStore(HCERTSTORE hCertStore,
1778 DWORD dwCertEncodingType, PCERT_INFO pCertId)
1780 TRACE("(%p, %08x, %p)\n", hCertStore, dwCertEncodingType, pCertId);
1782 if (!pCertId)
1784 SetLastError(E_INVALIDARG);
1785 return NULL;
1787 return CertFindCertificateInStore(hCertStore, dwCertEncodingType, 0,
1788 CERT_FIND_SUBJECT_CERT, pCertId, NULL);
1791 BOOL WINAPI CertVerifySubjectCertificateContext(PCCERT_CONTEXT pSubject,
1792 PCCERT_CONTEXT pIssuer, DWORD *pdwFlags)
1794 static const DWORD supportedFlags = CERT_STORE_REVOCATION_FLAG |
1795 CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG;
1797 if (*pdwFlags & ~supportedFlags)
1799 SetLastError(E_INVALIDARG);
1800 return FALSE;
1802 if (*pdwFlags & CERT_STORE_REVOCATION_FLAG)
1804 DWORD flags = 0;
1805 PCCRL_CONTEXT crl = CertGetCRLFromStore(pSubject->hCertStore, pSubject,
1806 NULL, &flags);
1808 /* FIXME: what if the CRL has expired? */
1809 if (crl)
1811 if (CertVerifyCRLRevocation(pSubject->dwCertEncodingType,
1812 pSubject->pCertInfo, 1, (PCRL_INFO *)&crl->pCrlInfo))
1813 *pdwFlags &= CERT_STORE_REVOCATION_FLAG;
1815 else
1816 *pdwFlags |= CERT_STORE_NO_CRL_FLAG;
1818 if (*pdwFlags & CERT_STORE_TIME_VALIDITY_FLAG)
1820 if (0 == CertVerifyTimeValidity(NULL, pSubject->pCertInfo))
1821 *pdwFlags &= ~CERT_STORE_TIME_VALIDITY_FLAG;
1823 if (*pdwFlags & CERT_STORE_SIGNATURE_FLAG)
1825 if (CryptVerifyCertificateSignatureEx(0, pSubject->dwCertEncodingType,
1826 CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)pSubject,
1827 CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)pIssuer, 0, NULL))
1828 *pdwFlags &= ~CERT_STORE_SIGNATURE_FLAG;
1830 return TRUE;
1833 PCCERT_CONTEXT WINAPI CertGetIssuerCertificateFromStore(HCERTSTORE hCertStore,
1834 PCCERT_CONTEXT pSubjectContext, PCCERT_CONTEXT pPrevIssuerContext,
1835 DWORD *pdwFlags)
1837 PCCERT_CONTEXT ret;
1839 TRACE("(%p, %p, %p, %08x)\n", hCertStore, pSubjectContext,
1840 pPrevIssuerContext, *pdwFlags);
1842 if (!pSubjectContext)
1844 SetLastError(E_INVALIDARG);
1845 return NULL;
1848 ret = CertFindCertificateInStore(hCertStore,
1849 pSubjectContext->dwCertEncodingType, 0, CERT_FIND_ISSUER_OF,
1850 pSubjectContext, pPrevIssuerContext);
1851 if (ret)
1853 if (!CertVerifySubjectCertificateContext(pSubjectContext, ret,
1854 pdwFlags))
1856 CertFreeCertificateContext(ret);
1857 ret = NULL;
1860 TRACE("returning %p\n", ret);
1861 return ret;
1864 typedef struct _OLD_CERT_REVOCATION_STATUS {
1865 DWORD cbSize;
1866 DWORD dwIndex;
1867 DWORD dwError;
1868 DWORD dwReason;
1869 } OLD_CERT_REVOCATION_STATUS;
1871 typedef BOOL (WINAPI *CertVerifyRevocationFunc)(DWORD, DWORD, DWORD,
1872 void **, DWORD, PCERT_REVOCATION_PARA, PCERT_REVOCATION_STATUS);
1874 BOOL WINAPI CertVerifyRevocation(DWORD dwEncodingType, DWORD dwRevType,
1875 DWORD cContext, PVOID rgpvContext[], DWORD dwFlags,
1876 PCERT_REVOCATION_PARA pRevPara, PCERT_REVOCATION_STATUS pRevStatus)
1878 BOOL ret;
1880 TRACE("(%08x, %d, %d, %p, %08x, %p, %p)\n", dwEncodingType, dwRevType,
1881 cContext, rgpvContext, dwFlags, pRevPara, pRevStatus);
1883 if (pRevStatus->cbSize != sizeof(OLD_CERT_REVOCATION_STATUS) &&
1884 pRevStatus->cbSize != sizeof(CERT_REVOCATION_STATUS))
1886 SetLastError(E_INVALIDARG);
1887 return FALSE;
1889 if (cContext)
1891 static HCRYPTOIDFUNCSET set = NULL;
1892 DWORD size;
1894 if (!set)
1895 set = CryptInitOIDFunctionSet(CRYPT_OID_VERIFY_REVOCATION_FUNC, 0);
1896 ret = CryptGetDefaultOIDDllList(set, dwEncodingType, NULL, &size);
1897 if (ret)
1899 if (size == 1)
1901 /* empty list */
1902 SetLastError(CRYPT_E_NO_REVOCATION_DLL);
1903 ret = FALSE;
1905 else
1907 LPWSTR dllList = CryptMemAlloc(size * sizeof(WCHAR)), ptr;
1909 if (dllList)
1911 ret = CryptGetDefaultOIDDllList(set, dwEncodingType,
1912 dllList, &size);
1913 if (ret)
1915 for (ptr = dllList; ret && *ptr;
1916 ptr += lstrlenW(ptr) + 1)
1918 CertVerifyRevocationFunc func;
1919 HCRYPTOIDFUNCADDR hFunc;
1921 ret = CryptGetDefaultOIDFunctionAddress(set,
1922 dwEncodingType, ptr, 0, (void **)&func, &hFunc);
1923 if (ret)
1925 ret = func(dwEncodingType, dwRevType, cContext,
1926 rgpvContext, dwFlags, pRevPara, pRevStatus);
1927 CryptFreeOIDFunctionAddress(hFunc, 0);
1931 CryptMemFree(dllList);
1933 else
1935 SetLastError(ERROR_OUTOFMEMORY);
1936 ret = FALSE;
1941 else
1942 ret = TRUE;
1943 return ret;
1946 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
1947 CRYPT_ATTRIBUTE rgAttr[])
1949 PCRYPT_ATTRIBUTE ret = NULL;
1950 DWORD i;
1952 TRACE("%s %d %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
1954 if (!cAttr)
1955 return NULL;
1956 if (!pszObjId)
1958 SetLastError(ERROR_INVALID_PARAMETER);
1959 return NULL;
1962 for (i = 0; !ret && i < cAttr; i++)
1963 if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
1964 ret = &rgAttr[i];
1965 return ret;
1968 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
1969 CERT_EXTENSION rgExtensions[])
1971 PCERT_EXTENSION ret = NULL;
1972 DWORD i;
1974 TRACE("%s %d %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
1976 if (!cExtensions)
1977 return NULL;
1978 if (!pszObjId)
1980 SetLastError(ERROR_INVALID_PARAMETER);
1981 return NULL;
1984 for (i = 0; !ret && i < cExtensions; i++)
1985 if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
1986 rgExtensions[i].pszObjId))
1987 ret = &rgExtensions[i];
1988 return ret;
1991 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
1993 PCERT_RDN_ATTR ret = NULL;
1994 DWORD i, j;
1996 TRACE("%s %p\n", debugstr_a(pszObjId), pName);
1998 if (!pszObjId)
2000 SetLastError(ERROR_INVALID_PARAMETER);
2001 return NULL;
2004 for (i = 0; !ret && i < pName->cRDN; i++)
2005 for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
2006 if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
2007 pName->rgRDN[i].rgRDNAttr[j].pszObjId))
2008 ret = &pName->rgRDN[i].rgRDNAttr[j];
2009 return ret;
2012 static BOOL find_matching_rdn_attr(DWORD dwFlags, const CERT_NAME_INFO *name,
2013 const CERT_RDN_ATTR *attr)
2015 DWORD i, j;
2016 BOOL match = FALSE;
2018 for (i = 0; !match && i < name->cRDN; i++)
2020 for (j = 0; j < name->rgRDN[i].cRDNAttr; j++)
2022 if (!strcmp(name->rgRDN[i].rgRDNAttr[j].pszObjId,
2023 attr->pszObjId) &&
2024 name->rgRDN[i].rgRDNAttr[j].dwValueType ==
2025 attr->dwValueType)
2027 if (dwFlags & CERT_UNICODE_IS_RDN_ATTRS_FLAG)
2029 LPCWSTR nameStr =
2030 (LPCWSTR)name->rgRDN[i].rgRDNAttr[j].Value.pbData;
2031 LPCWSTR attrStr = (LPCWSTR)attr->Value.pbData;
2033 if (attr->Value.cbData !=
2034 name->rgRDN[i].rgRDNAttr[j].Value.cbData)
2035 match = FALSE;
2036 else if (dwFlags & CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG)
2037 match = !strncmpiW(nameStr, attrStr,
2038 attr->Value.cbData / sizeof(WCHAR));
2039 else
2040 match = !strncmpW(nameStr, attrStr,
2041 attr->Value.cbData / sizeof(WCHAR));
2042 TRACE("%s : %s => %d\n",
2043 debugstr_wn(nameStr, attr->Value.cbData / sizeof(WCHAR)),
2044 debugstr_wn(attrStr, attr->Value.cbData / sizeof(WCHAR)),
2045 match);
2047 else
2049 LPCSTR nameStr =
2050 (LPCSTR)name->rgRDN[i].rgRDNAttr[j].Value.pbData;
2051 LPCSTR attrStr = (LPCSTR)attr->Value.pbData;
2053 if (attr->Value.cbData !=
2054 name->rgRDN[i].rgRDNAttr[j].Value.cbData)
2055 match = FALSE;
2056 else if (dwFlags & CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG)
2057 match = !strncasecmp(nameStr, attrStr,
2058 attr->Value.cbData);
2059 else
2060 match = !strncmp(nameStr, attrStr, attr->Value.cbData);
2061 TRACE("%s : %s => %d\n",
2062 debugstr_an(nameStr, attr->Value.cbData),
2063 debugstr_an(attrStr, attr->Value.cbData), match);
2068 return match;
2071 BOOL WINAPI CertIsRDNAttrsInCertificateName(DWORD dwCertEncodingType,
2072 DWORD dwFlags, PCERT_NAME_BLOB pCertName, PCERT_RDN pRDN)
2074 CERT_NAME_INFO *name;
2075 LPCSTR type;
2076 DWORD size;
2077 BOOL ret;
2079 TRACE("(%08x, %08x, %p, %p)\n", dwCertEncodingType, dwFlags, pCertName,
2080 pRDN);
2082 type = dwFlags & CERT_UNICODE_IS_RDN_ATTRS_FLAG ? X509_UNICODE_NAME :
2083 X509_NAME;
2084 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, type, pCertName->pbData,
2085 pCertName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &name, &size)))
2087 DWORD i;
2089 for (i = 0; ret && i < pRDN->cRDNAttr; i++)
2090 ret = find_matching_rdn_attr(dwFlags, name, &pRDN->rgRDNAttr[i]);
2091 if (!ret)
2092 SetLastError(CRYPT_E_NO_MATCH);
2093 LocalFree(name);
2095 return ret;
2098 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
2099 PCERT_INFO pCertInfo)
2101 FILETIME fileTime;
2102 LONG ret;
2104 if (!pTimeToVerify)
2106 GetSystemTimeAsFileTime(&fileTime);
2107 pTimeToVerify = &fileTime;
2109 if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
2111 ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
2112 if (ret < 0)
2113 ret = 0;
2115 return ret;
2118 BOOL WINAPI CertVerifyValidityNesting(PCERT_INFO pSubjectInfo,
2119 PCERT_INFO pIssuerInfo)
2121 TRACE("(%p, %p)\n", pSubjectInfo, pIssuerInfo);
2123 return CertVerifyTimeValidity(&pSubjectInfo->NotBefore, pIssuerInfo) == 0
2124 && CertVerifyTimeValidity(&pSubjectInfo->NotAfter, pIssuerInfo) == 0;
2127 BOOL WINAPI CryptHashCertificate(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
2128 DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
2129 DWORD *pcbComputedHash)
2131 BOOL ret = TRUE;
2132 HCRYPTHASH hHash = 0;
2134 TRACE("(%08lx, %d, %08x, %p, %d, %p, %p)\n", hCryptProv, Algid, dwFlags,
2135 pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
2137 if (!hCryptProv)
2138 hCryptProv = CRYPT_GetDefaultProvider();
2139 if (!Algid)
2140 Algid = CALG_SHA1;
2141 if (ret)
2143 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
2144 if (ret)
2146 ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
2147 if (ret)
2148 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
2149 pcbComputedHash, 0);
2150 CryptDestroyHash(hHash);
2153 return ret;
2156 BOOL WINAPI CryptHashPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
2157 DWORD dwFlags, DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo,
2158 BYTE *pbComputedHash, DWORD *pcbComputedHash)
2160 BOOL ret = TRUE;
2161 HCRYPTHASH hHash = 0;
2163 TRACE("(%08lx, %d, %08x, %d, %p, %p, %p)\n", hCryptProv, Algid, dwFlags,
2164 dwCertEncodingType, pInfo, pbComputedHash, pcbComputedHash);
2166 if (!hCryptProv)
2167 hCryptProv = CRYPT_GetDefaultProvider();
2168 if (!Algid)
2169 Algid = CALG_MD5;
2170 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
2172 SetLastError(ERROR_FILE_NOT_FOUND);
2173 return FALSE;
2175 if (ret)
2177 BYTE *buf;
2178 DWORD size = 0;
2180 ret = CRYPT_AsnEncodePubKeyInfoNoNull(dwCertEncodingType,
2181 X509_PUBLIC_KEY_INFO, pInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
2182 (LPBYTE)&buf, &size);
2183 if (ret)
2185 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
2186 if (ret)
2188 ret = CryptHashData(hHash, buf, size, 0);
2189 if (ret)
2190 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
2191 pcbComputedHash, 0);
2192 CryptDestroyHash(hHash);
2194 LocalFree(buf);
2197 return ret;
2200 BOOL WINAPI CryptHashToBeSigned(HCRYPTPROV_LEGACY hCryptProv,
2201 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
2202 BYTE *pbComputedHash, DWORD *pcbComputedHash)
2204 BOOL ret;
2205 CERT_SIGNED_CONTENT_INFO *info;
2206 DWORD size;
2208 TRACE("(%08lx, %08x, %p, %d, %p, %d)\n", hCryptProv, dwCertEncodingType,
2209 pbEncoded, cbEncoded, pbComputedHash, *pcbComputedHash);
2211 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
2212 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size);
2213 if (ret)
2215 PCCRYPT_OID_INFO oidInfo;
2216 HCRYPTHASH hHash;
2218 if (!hCryptProv)
2219 hCryptProv = CRYPT_GetDefaultProvider();
2220 oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2221 info->SignatureAlgorithm.pszObjId, 0);
2222 if (!oidInfo)
2224 SetLastError(NTE_BAD_ALGID);
2225 ret = FALSE;
2227 else
2229 ret = CryptCreateHash(hCryptProv, oidInfo->u.Algid, 0, 0, &hHash);
2230 if (ret)
2232 ret = CryptHashData(hHash, info->ToBeSigned.pbData,
2233 info->ToBeSigned.cbData, 0);
2234 if (ret)
2235 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
2236 pcbComputedHash, 0);
2237 CryptDestroyHash(hHash);
2240 LocalFree(info);
2242 return ret;
2245 BOOL WINAPI CryptSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
2246 DWORD dwKeySpec, DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned,
2247 DWORD cbEncodedToBeSigned, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
2248 const void *pvHashAuxInfo, BYTE *pbSignature, DWORD *pcbSignature)
2250 BOOL ret;
2251 PCCRYPT_OID_INFO info;
2252 HCRYPTHASH hHash;
2254 TRACE("(%08lx, %d, %d, %p, %d, %p, %p, %p, %p)\n", hCryptProv,
2255 dwKeySpec, dwCertEncodingType, pbEncodedToBeSigned, cbEncodedToBeSigned,
2256 pSignatureAlgorithm, pvHashAuxInfo, pbSignature, pcbSignature);
2258 info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2259 pSignatureAlgorithm->pszObjId, 0);
2260 if (!info)
2262 SetLastError(NTE_BAD_ALGID);
2263 return FALSE;
2265 if (info->dwGroupId == CRYPT_HASH_ALG_OID_GROUP_ID)
2267 if (!hCryptProv)
2268 hCryptProv = CRYPT_GetDefaultProvider();
2269 ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
2270 if (ret)
2272 ret = CryptHashData(hHash, pbEncodedToBeSigned,
2273 cbEncodedToBeSigned, 0);
2274 if (ret)
2275 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbSignature,
2276 pcbSignature, 0);
2277 CryptDestroyHash(hHash);
2280 else
2282 if (!hCryptProv)
2284 SetLastError(ERROR_INVALID_PARAMETER);
2285 ret = FALSE;
2287 else
2289 ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
2290 if (ret)
2292 ret = CryptHashData(hHash, pbEncodedToBeSigned,
2293 cbEncodedToBeSigned, 0);
2294 if (ret)
2295 ret = CryptSignHashW(hHash, dwKeySpec, NULL, 0, pbSignature,
2296 pcbSignature);
2297 CryptDestroyHash(hHash);
2301 return ret;
2304 BOOL WINAPI CryptSignAndEncodeCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
2305 DWORD dwKeySpec, DWORD dwCertEncodingType, LPCSTR lpszStructType,
2306 const void *pvStructInfo, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
2307 const void *pvHashAuxInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
2309 BOOL ret;
2310 DWORD encodedSize, hashSize;
2312 TRACE("(%08lx, %d, %d, %s, %p, %p, %p, %p, %p)\n", hCryptProv, dwKeySpec,
2313 dwCertEncodingType, debugstr_a(lpszStructType), pvStructInfo,
2314 pSignatureAlgorithm, pvHashAuxInfo, pbEncoded, pcbEncoded);
2316 ret = CryptEncodeObject(dwCertEncodingType, lpszStructType, pvStructInfo,
2317 NULL, &encodedSize);
2318 if (ret)
2320 PBYTE encoded = CryptMemAlloc(encodedSize);
2322 if (encoded)
2324 ret = CryptEncodeObject(dwCertEncodingType, lpszStructType,
2325 pvStructInfo, encoded, &encodedSize);
2326 if (ret)
2328 ret = CryptSignCertificate(hCryptProv, dwKeySpec,
2329 dwCertEncodingType, encoded, encodedSize, pSignatureAlgorithm,
2330 pvHashAuxInfo, NULL, &hashSize);
2331 if (ret)
2333 PBYTE hash = CryptMemAlloc(hashSize);
2335 if (hash)
2337 ret = CryptSignCertificate(hCryptProv, dwKeySpec,
2338 dwCertEncodingType, encoded, encodedSize,
2339 pSignatureAlgorithm, pvHashAuxInfo, hash, &hashSize);
2340 if (ret)
2342 CERT_SIGNED_CONTENT_INFO info = { { 0 } };
2344 info.ToBeSigned.cbData = encodedSize;
2345 info.ToBeSigned.pbData = encoded;
2346 info.SignatureAlgorithm = *pSignatureAlgorithm;
2347 info.Signature.cbData = hashSize;
2348 info.Signature.pbData = hash;
2349 info.Signature.cUnusedBits = 0;
2350 ret = CryptEncodeObject(dwCertEncodingType,
2351 X509_CERT, &info, pbEncoded, pcbEncoded);
2353 CryptMemFree(hash);
2357 CryptMemFree(encoded);
2360 return ret;
2363 BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV_LEGACY hCryptProv,
2364 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
2365 PCERT_PUBLIC_KEY_INFO pPublicKey)
2367 CRYPT_DATA_BLOB blob = { cbEncoded, (BYTE *)pbEncoded };
2369 return CryptVerifyCertificateSignatureEx(hCryptProv, dwCertEncodingType,
2370 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &blob,
2371 CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
2374 static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv,
2375 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pubKeyInfo,
2376 const CERT_SIGNED_CONTENT_INFO *signedCert)
2378 BOOL ret;
2379 HCRYPTKEY key;
2380 PCCRYPT_OID_INFO info;
2381 ALG_ID pubKeyID, hashID;
2383 info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2384 signedCert->SignatureAlgorithm.pszObjId, 0);
2385 if (!info || info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID)
2387 SetLastError(NTE_BAD_ALGID);
2388 return FALSE;
2390 hashID = info->u.Algid;
2391 if (info->ExtraInfo.cbData >= sizeof(ALG_ID))
2392 pubKeyID = *(ALG_ID *)info->ExtraInfo.pbData;
2393 else
2394 pubKeyID = hashID;
2395 /* Load the default provider if necessary */
2396 if (!hCryptProv)
2397 hCryptProv = CRYPT_GetDefaultProvider();
2398 ret = CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType,
2399 pubKeyInfo, pubKeyID, 0, NULL, &key);
2400 if (ret)
2402 HCRYPTHASH hash;
2404 ret = CryptCreateHash(hCryptProv, hashID, 0, 0, &hash);
2405 if (ret)
2407 ret = CryptHashData(hash, signedCert->ToBeSigned.pbData,
2408 signedCert->ToBeSigned.cbData, 0);
2409 if (ret)
2410 ret = CryptVerifySignatureW(hash, signedCert->Signature.pbData,
2411 signedCert->Signature.cbData, key, NULL, 0);
2412 CryptDestroyHash(hash);
2414 CryptDestroyKey(key);
2416 return ret;
2419 BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV_LEGACY hCryptProv,
2420 DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
2421 DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
2423 BOOL ret = TRUE;
2424 CRYPT_DATA_BLOB subjectBlob;
2426 TRACE("(%08lx, %d, %d, %p, %d, %p, %08x, %p)\n", hCryptProv,
2427 dwCertEncodingType, dwSubjectType, pvSubject, dwIssuerType, pvIssuer,
2428 dwFlags, pvReserved);
2430 switch (dwSubjectType)
2432 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB:
2434 PCRYPT_DATA_BLOB blob = pvSubject;
2436 subjectBlob.pbData = blob->pbData;
2437 subjectBlob.cbData = blob->cbData;
2438 break;
2440 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT:
2442 PCERT_CONTEXT context = pvSubject;
2444 subjectBlob.pbData = context->pbCertEncoded;
2445 subjectBlob.cbData = context->cbCertEncoded;
2446 break;
2448 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL:
2450 PCRL_CONTEXT context = pvSubject;
2452 subjectBlob.pbData = context->pbCrlEncoded;
2453 subjectBlob.cbData = context->cbCrlEncoded;
2454 break;
2456 default:
2457 SetLastError(E_INVALIDARG);
2458 ret = FALSE;
2461 if (ret)
2463 PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
2464 DWORD size = 0;
2466 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
2467 subjectBlob.pbData, subjectBlob.cbData,
2468 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
2469 &signedCert, &size);
2470 if (ret)
2472 switch (dwIssuerType)
2474 case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY:
2475 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
2476 dwCertEncodingType, pvIssuer,
2477 signedCert);
2478 break;
2479 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT:
2480 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
2481 dwCertEncodingType,
2482 &((PCCERT_CONTEXT)pvIssuer)->pCertInfo->SubjectPublicKeyInfo,
2483 signedCert);
2484 break;
2485 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN:
2486 FIXME("CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: stub\n");
2487 ret = FALSE;
2488 break;
2489 case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL:
2490 if (pvIssuer)
2492 SetLastError(E_INVALIDARG);
2493 ret = FALSE;
2495 else
2497 FIXME("unimplemented for NULL signer\n");
2498 SetLastError(E_INVALIDARG);
2499 ret = FALSE;
2501 break;
2502 default:
2503 SetLastError(E_INVALIDARG);
2504 ret = FALSE;
2506 LocalFree(signedCert);
2509 return ret;
2512 BOOL WINAPI CertGetIntendedKeyUsage(DWORD dwCertEncodingType,
2513 PCERT_INFO pCertInfo, BYTE *pbKeyUsage, DWORD cbKeyUsage)
2515 PCERT_EXTENSION ext;
2516 BOOL ret = FALSE;
2518 TRACE("(%08x, %p, %p, %d)\n", dwCertEncodingType, pCertInfo, pbKeyUsage,
2519 cbKeyUsage);
2521 ext = CertFindExtension(szOID_KEY_USAGE, pCertInfo->cExtension,
2522 pCertInfo->rgExtension);
2523 if (ext)
2525 CRYPT_BIT_BLOB usage;
2526 DWORD size = sizeof(usage);
2528 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS,
2529 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL,
2530 &usage, &size);
2531 if (ret)
2533 if (cbKeyUsage < usage.cbData)
2534 ret = FALSE;
2535 else
2537 memcpy(pbKeyUsage, usage.pbData, usage.cbData);
2538 if (cbKeyUsage > usage.cbData)
2539 memset(pbKeyUsage + usage.cbData, 0,
2540 cbKeyUsage - usage.cbData);
2544 else
2545 SetLastError(0);
2546 return ret;
2549 BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags,
2550 PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage)
2552 PCERT_ENHKEY_USAGE usage = NULL;
2553 DWORD bytesNeeded;
2554 BOOL ret = TRUE;
2556 if (!pCertContext || !pcbUsage)
2558 SetLastError(ERROR_INVALID_PARAMETER);
2559 return FALSE;
2562 TRACE("(%p, %08x, %p, %d)\n", pCertContext, dwFlags, pUsage, *pcbUsage);
2564 if (!(dwFlags & CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG))
2566 DWORD propSize = 0;
2568 if (CertGetCertificateContextProperty(pCertContext,
2569 CERT_ENHKEY_USAGE_PROP_ID, NULL, &propSize))
2571 LPBYTE buf = CryptMemAlloc(propSize);
2573 if (buf)
2575 if (CertGetCertificateContextProperty(pCertContext,
2576 CERT_ENHKEY_USAGE_PROP_ID, buf, &propSize))
2578 ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
2579 X509_ENHANCED_KEY_USAGE, buf, propSize,
2580 CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
2582 CryptMemFree(buf);
2586 if (!usage && !(dwFlags & CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG))
2588 PCERT_EXTENSION ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
2589 pCertContext->pCertInfo->cExtension,
2590 pCertContext->pCertInfo->rgExtension);
2592 if (ext)
2594 ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
2595 X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
2596 CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
2599 if (!usage)
2601 /* If a particular location is specified, this should fail. Otherwise
2602 * it should succeed with an empty usage. (This is true on Win2k and
2603 * later, which we emulate.)
2605 if (dwFlags)
2607 SetLastError(CRYPT_E_NOT_FOUND);
2608 ret = FALSE;
2610 else
2611 bytesNeeded = sizeof(CERT_ENHKEY_USAGE);
2614 if (ret)
2616 if (!pUsage)
2617 *pcbUsage = bytesNeeded;
2618 else if (*pcbUsage < bytesNeeded)
2620 SetLastError(ERROR_MORE_DATA);
2621 *pcbUsage = bytesNeeded;
2622 ret = FALSE;
2624 else
2626 *pcbUsage = bytesNeeded;
2627 if (usage)
2629 DWORD i;
2630 LPSTR nextOID = (LPSTR)((LPBYTE)pUsage +
2631 sizeof(CERT_ENHKEY_USAGE) +
2632 usage->cUsageIdentifier * sizeof(LPSTR));
2634 pUsage->cUsageIdentifier = usage->cUsageIdentifier;
2635 pUsage->rgpszUsageIdentifier = (LPSTR *)((LPBYTE)pUsage +
2636 sizeof(CERT_ENHKEY_USAGE));
2637 for (i = 0; i < usage->cUsageIdentifier; i++)
2639 pUsage->rgpszUsageIdentifier[i] = nextOID;
2640 strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
2641 nextOID += strlen(nextOID) + 1;
2644 else
2645 pUsage->cUsageIdentifier = 0;
2648 if (usage)
2649 LocalFree(usage);
2650 TRACE("returning %d\n", ret);
2651 return ret;
2654 BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext,
2655 PCERT_ENHKEY_USAGE pUsage)
2657 BOOL ret;
2659 TRACE("(%p, %p)\n", pCertContext, pUsage);
2661 if (pUsage)
2663 CRYPT_DATA_BLOB blob = { 0, NULL };
2665 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
2666 pUsage, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData, &blob.cbData);
2667 if (ret)
2669 ret = CertSetCertificateContextProperty(pCertContext,
2670 CERT_ENHKEY_USAGE_PROP_ID, 0, &blob);
2671 LocalFree(blob.pbData);
2674 else
2675 ret = CertSetCertificateContextProperty(pCertContext,
2676 CERT_ENHKEY_USAGE_PROP_ID, 0, NULL);
2677 return ret;
2680 BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
2681 LPCSTR pszUsageIdentifier)
2683 BOOL ret;
2684 DWORD size;
2686 TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
2688 if (CertGetEnhancedKeyUsage(pCertContext,
2689 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size))
2691 PCERT_ENHKEY_USAGE usage = CryptMemAlloc(size);
2693 if (usage)
2695 ret = CertGetEnhancedKeyUsage(pCertContext,
2696 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size);
2697 if (ret)
2699 DWORD i;
2700 BOOL exists = FALSE;
2702 /* Make sure usage doesn't already exist */
2703 for (i = 0; !exists && i < usage->cUsageIdentifier; i++)
2705 if (!strcmp(usage->rgpszUsageIdentifier[i],
2706 pszUsageIdentifier))
2707 exists = TRUE;
2709 if (!exists)
2711 PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size +
2712 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
2714 if (newUsage)
2716 LPSTR nextOID;
2718 newUsage->rgpszUsageIdentifier = (LPSTR *)
2719 ((LPBYTE)newUsage + sizeof(CERT_ENHKEY_USAGE));
2720 nextOID = (LPSTR)((LPBYTE)newUsage->rgpszUsageIdentifier
2721 + (usage->cUsageIdentifier + 1) * sizeof(LPSTR));
2722 for (i = 0; i < usage->cUsageIdentifier; i++)
2724 newUsage->rgpszUsageIdentifier[i] = nextOID;
2725 strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
2726 nextOID += strlen(nextOID) + 1;
2728 newUsage->rgpszUsageIdentifier[i] = nextOID;
2729 strcpy(nextOID, pszUsageIdentifier);
2730 newUsage->cUsageIdentifier = i + 1;
2731 ret = CertSetEnhancedKeyUsage(pCertContext, newUsage);
2732 CryptMemFree(newUsage);
2734 else
2735 ret = FALSE;
2738 CryptMemFree(usage);
2740 else
2741 ret = FALSE;
2743 else
2745 PCERT_ENHKEY_USAGE usage = CryptMemAlloc(sizeof(CERT_ENHKEY_USAGE) +
2746 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
2748 if (usage)
2750 usage->rgpszUsageIdentifier =
2751 (LPSTR *)((LPBYTE)usage + sizeof(CERT_ENHKEY_USAGE));
2752 usage->rgpszUsageIdentifier[0] = (LPSTR)((LPBYTE)usage +
2753 sizeof(CERT_ENHKEY_USAGE) + sizeof(LPSTR));
2754 strcpy(usage->rgpszUsageIdentifier[0], pszUsageIdentifier);
2755 usage->cUsageIdentifier = 1;
2756 ret = CertSetEnhancedKeyUsage(pCertContext, usage);
2757 CryptMemFree(usage);
2759 else
2760 ret = FALSE;
2762 return ret;
2765 BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
2766 LPCSTR pszUsageIdentifier)
2768 BOOL ret;
2769 DWORD size;
2770 CERT_ENHKEY_USAGE usage;
2772 TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
2774 size = sizeof(usage);
2775 ret = CertGetEnhancedKeyUsage(pCertContext,
2776 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, &usage, &size);
2777 if (!ret && GetLastError() == ERROR_MORE_DATA)
2779 PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
2781 if (pUsage)
2783 ret = CertGetEnhancedKeyUsage(pCertContext,
2784 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
2785 if (ret)
2787 if (pUsage->cUsageIdentifier)
2789 DWORD i;
2790 BOOL found = FALSE;
2792 for (i = 0; i < pUsage->cUsageIdentifier; i++)
2794 if (!strcmp(pUsage->rgpszUsageIdentifier[i],
2795 pszUsageIdentifier))
2796 found = TRUE;
2797 if (found && i < pUsage->cUsageIdentifier - 1)
2798 pUsage->rgpszUsageIdentifier[i] =
2799 pUsage->rgpszUsageIdentifier[i + 1];
2801 pUsage->cUsageIdentifier--;
2802 /* Remove the usage if it's empty */
2803 if (pUsage->cUsageIdentifier)
2804 ret = CertSetEnhancedKeyUsage(pCertContext, pUsage);
2805 else
2806 ret = CertSetEnhancedKeyUsage(pCertContext, NULL);
2809 CryptMemFree(pUsage);
2811 else
2812 ret = FALSE;
2814 else
2816 /* it fit in an empty usage, therefore there's nothing to remove */
2817 ret = TRUE;
2819 return ret;
2822 struct BitField
2824 DWORD cIndexes;
2825 DWORD *indexes;
2828 #define BITS_PER_DWORD (sizeof(DWORD) * 8)
2830 static void CRYPT_SetBitInField(struct BitField *field, DWORD bit)
2832 DWORD indexIndex = bit / BITS_PER_DWORD;
2834 if (indexIndex + 1 > field->cIndexes)
2836 if (field->cIndexes)
2837 field->indexes = CryptMemRealloc(field->indexes,
2838 (indexIndex + 1) * sizeof(DWORD));
2839 else
2840 field->indexes = CryptMemAlloc(sizeof(DWORD));
2841 if (field->indexes)
2843 field->indexes[indexIndex] = 0;
2844 field->cIndexes = indexIndex + 1;
2847 if (field->indexes)
2848 field->indexes[indexIndex] |= 1 << (bit % BITS_PER_DWORD);
2851 static BOOL CRYPT_IsBitInFieldSet(const struct BitField *field, DWORD bit)
2853 BOOL set = FALSE;
2854 DWORD indexIndex = bit / BITS_PER_DWORD;
2856 assert(field->cIndexes);
2857 set = field->indexes[indexIndex] & (1 << (bit % BITS_PER_DWORD));
2858 return set;
2861 BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts,
2862 int *cNumOIDs, LPSTR *rghOIDs, DWORD *pcbOIDs)
2864 BOOL ret = TRUE;
2865 DWORD i, cbOIDs = 0;
2866 BOOL allUsagesValid = TRUE;
2867 CERT_ENHKEY_USAGE validUsages = { 0, NULL };
2869 TRACE("(%d, %p, %d, %p, %d)\n", cCerts, rghCerts, *cNumOIDs,
2870 rghOIDs, *pcbOIDs);
2872 for (i = 0; i < cCerts; i++)
2874 CERT_ENHKEY_USAGE usage;
2875 DWORD size = sizeof(usage);
2877 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, &usage, &size);
2878 /* Success is deliberately ignored: it implies all usages are valid */
2879 if (!ret && GetLastError() == ERROR_MORE_DATA)
2881 PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
2883 allUsagesValid = FALSE;
2884 if (pUsage)
2886 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, pUsage, &size);
2887 if (ret)
2889 if (!validUsages.cUsageIdentifier)
2891 DWORD j;
2893 cbOIDs = pUsage->cUsageIdentifier * sizeof(LPSTR);
2894 validUsages.cUsageIdentifier = pUsage->cUsageIdentifier;
2895 for (j = 0; j < validUsages.cUsageIdentifier; j++)
2896 cbOIDs += lstrlenA(pUsage->rgpszUsageIdentifier[j])
2897 + 1;
2898 validUsages.rgpszUsageIdentifier =
2899 CryptMemAlloc(cbOIDs);
2900 if (validUsages.rgpszUsageIdentifier)
2902 LPSTR nextOID = (LPSTR)
2903 ((LPBYTE)validUsages.rgpszUsageIdentifier +
2904 validUsages.cUsageIdentifier * sizeof(LPSTR));
2906 for (j = 0; j < validUsages.cUsageIdentifier; j++)
2908 validUsages.rgpszUsageIdentifier[j] = nextOID;
2909 lstrcpyA(validUsages.rgpszUsageIdentifier[j],
2910 pUsage->rgpszUsageIdentifier[j]);
2911 nextOID += lstrlenA(nextOID) + 1;
2915 else
2917 struct BitField validIndexes = { 0, NULL };
2918 DWORD j, k, numRemoved = 0;
2920 /* Merge: build a bitmap of all the indexes of
2921 * validUsages.rgpszUsageIdentifier that are in pUsage.
2923 for (j = 0; j < pUsage->cUsageIdentifier; j++)
2925 for (k = 0; k < validUsages.cUsageIdentifier; k++)
2927 if (!strcmp(pUsage->rgpszUsageIdentifier[j],
2928 validUsages.rgpszUsageIdentifier[k]))
2930 CRYPT_SetBitInField(&validIndexes, k);
2931 break;
2935 /* Merge by removing from validUsages those that are
2936 * not in the bitmap.
2938 for (j = 0; j < validUsages.cUsageIdentifier; j++)
2940 if (!CRYPT_IsBitInFieldSet(&validIndexes, j))
2942 if (j < validUsages.cUsageIdentifier - 1)
2944 memmove(&validUsages.rgpszUsageIdentifier[j],
2945 &validUsages.rgpszUsageIdentifier[j +
2946 numRemoved + 1],
2947 (validUsages.cUsageIdentifier - numRemoved
2948 - j - 1) * sizeof(LPSTR));
2949 cbOIDs -= lstrlenA(
2950 validUsages.rgpszUsageIdentifier[j]) + 1 +
2951 sizeof(LPSTR);
2952 validUsages.cUsageIdentifier--;
2953 numRemoved++;
2955 else
2956 validUsages.cUsageIdentifier--;
2959 CryptMemFree(validIndexes.indexes);
2962 CryptMemFree(pUsage);
2966 ret = TRUE;
2967 if (allUsagesValid)
2969 *cNumOIDs = -1;
2970 *pcbOIDs = 0;
2972 else
2974 *cNumOIDs = validUsages.cUsageIdentifier;
2975 if (!rghOIDs)
2976 *pcbOIDs = cbOIDs;
2977 else if (*pcbOIDs < cbOIDs)
2979 *pcbOIDs = cbOIDs;
2980 SetLastError(ERROR_MORE_DATA);
2981 ret = FALSE;
2983 else
2985 LPSTR nextOID = (LPSTR)((LPBYTE)rghOIDs +
2986 validUsages.cUsageIdentifier * sizeof(LPSTR));
2988 *pcbOIDs = cbOIDs;
2989 for (i = 0; i < validUsages.cUsageIdentifier; i++)
2991 rghOIDs[i] = nextOID;
2992 lstrcpyA(nextOID, validUsages.rgpszUsageIdentifier[i]);
2993 nextOID += lstrlenA(nextOID) + 1;
2997 CryptMemFree(validUsages.rgpszUsageIdentifier);
2998 TRACE("cNumOIDs: %d\n", *cNumOIDs);
2999 TRACE("returning %d\n", ret);
3000 return ret;
3003 /* Sets the CERT_KEY_PROV_INFO_PROP_ID property of context from pInfo, or, if
3004 * pInfo is NULL, from the attributes of hProv.
3006 static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context,
3007 const CRYPT_KEY_PROV_INFO *pInfo, HCRYPTPROV hProv)
3009 CRYPT_KEY_PROV_INFO info = { 0 };
3010 BOOL ret;
3012 if (!pInfo)
3014 DWORD size;
3015 int len;
3017 ret = CryptGetProvParam(hProv, PP_CONTAINER, NULL, &size, 0);
3018 if (ret)
3020 LPSTR szContainer = CryptMemAlloc(size);
3022 if (szContainer)
3024 ret = CryptGetProvParam(hProv, PP_CONTAINER,
3025 (BYTE *)szContainer, &size, 0);
3026 if (ret)
3028 len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
3029 NULL, 0);
3030 if (len)
3032 info.pwszContainerName = CryptMemAlloc(len *
3033 sizeof(WCHAR));
3034 MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
3035 info.pwszContainerName, len);
3038 CryptMemFree(szContainer);
3041 ret = CryptGetProvParam(hProv, PP_NAME, NULL, &size, 0);
3042 if (ret)
3044 LPSTR szProvider = CryptMemAlloc(size);
3046 if (szProvider)
3048 ret = CryptGetProvParam(hProv, PP_NAME, (BYTE *)szProvider,
3049 &size, 0);
3050 if (ret)
3052 len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
3053 NULL, 0);
3054 if (len)
3056 info.pwszProvName = CryptMemAlloc(len *
3057 sizeof(WCHAR));
3058 MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
3059 info.pwszProvName, len);
3062 CryptMemFree(szProvider);
3065 size = sizeof(info.dwKeySpec);
3066 /* in case no CRYPT_KEY_PROV_INFO given,
3067 * we always use AT_SIGNATURE key spec
3069 info.dwKeySpec = AT_SIGNATURE;
3070 size = sizeof(info.dwProvType);
3071 ret = CryptGetProvParam(hProv, PP_PROVTYPE, (LPBYTE)&info.dwProvType,
3072 &size, 0);
3073 if (!ret)
3074 info.dwProvType = PROV_RSA_FULL;
3075 pInfo = &info;
3078 CertSetCertificateContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID,
3079 0, pInfo);
3081 if (pInfo == &info)
3083 CryptMemFree(info.pwszContainerName);
3084 CryptMemFree(info.pwszProvName);
3088 /* Creates a signed certificate context from the unsigned, encoded certificate
3089 * in blob, using the crypto provider hProv and the signature algorithm sigAlgo.
3091 static PCCERT_CONTEXT CRYPT_CreateSignedCert(const CRYPT_DER_BLOB *blob,
3092 HCRYPTPROV hProv, DWORD dwKeySpec, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo)
3094 PCCERT_CONTEXT context = NULL;
3095 BOOL ret;
3096 DWORD sigSize = 0;
3098 ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
3099 blob->pbData, blob->cbData, sigAlgo, NULL, NULL, &sigSize);
3100 if (ret)
3102 LPBYTE sig = CryptMemAlloc(sigSize);
3104 ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
3105 blob->pbData, blob->cbData, sigAlgo, NULL, sig, &sigSize);
3106 if (ret)
3108 CERT_SIGNED_CONTENT_INFO signedInfo;
3109 BYTE *encodedSignedCert = NULL;
3110 DWORD encodedSignedCertSize = 0;
3112 signedInfo.ToBeSigned.cbData = blob->cbData;
3113 signedInfo.ToBeSigned.pbData = blob->pbData;
3114 signedInfo.SignatureAlgorithm = *sigAlgo;
3115 signedInfo.Signature.cbData = sigSize;
3116 signedInfo.Signature.pbData = sig;
3117 signedInfo.Signature.cUnusedBits = 0;
3118 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT,
3119 &signedInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
3120 &encodedSignedCert, &encodedSignedCertSize);
3121 if (ret)
3123 context = CertCreateCertificateContext(X509_ASN_ENCODING,
3124 encodedSignedCert, encodedSignedCertSize);
3125 LocalFree(encodedSignedCert);
3128 CryptMemFree(sig);
3130 return context;
3133 /* Copies data from the parameters into info, where:
3134 * pSerialNumber: The serial number. Must not be NULL.
3135 * pSubjectIssuerBlob: Specifies both the subject and issuer for info.
3136 * Must not be NULL
3137 * pSignatureAlgorithm: Optional.
3138 * pStartTime: The starting time of the certificate. If NULL, the current
3139 * system time is used.
3140 * pEndTime: The ending time of the certificate. If NULL, one year past the
3141 * starting time is used.
3142 * pubKey: The public key of the certificate. Must not be NULL.
3143 * pExtensions: Extensions to be included with the certificate. Optional.
3145 static void CRYPT_MakeCertInfo(PCERT_INFO info, const CRYPT_DATA_BLOB *pSerialNumber,
3146 const CERT_NAME_BLOB *pSubjectIssuerBlob,
3147 const CRYPT_ALGORITHM_IDENTIFIER *pSignatureAlgorithm, const SYSTEMTIME *pStartTime,
3148 const SYSTEMTIME *pEndTime, const CERT_PUBLIC_KEY_INFO *pubKey,
3149 const CERT_EXTENSIONS *pExtensions)
3151 static CHAR oid[] = szOID_RSA_SHA1RSA;
3153 assert(info);
3154 assert(pSerialNumber);
3155 assert(pSubjectIssuerBlob);
3156 assert(pubKey);
3158 if (pExtensions && pExtensions->cExtension)
3159 info->dwVersion = CERT_V3;
3160 else
3161 info->dwVersion = CERT_V1;
3162 info->SerialNumber.cbData = pSerialNumber->cbData;
3163 info->SerialNumber.pbData = pSerialNumber->pbData;
3164 if (pSignatureAlgorithm)
3165 info->SignatureAlgorithm = *pSignatureAlgorithm;
3166 else
3168 info->SignatureAlgorithm.pszObjId = oid;
3169 info->SignatureAlgorithm.Parameters.cbData = 0;
3170 info->SignatureAlgorithm.Parameters.pbData = NULL;
3172 info->Issuer.cbData = pSubjectIssuerBlob->cbData;
3173 info->Issuer.pbData = pSubjectIssuerBlob->pbData;
3174 if (pStartTime)
3175 SystemTimeToFileTime(pStartTime, &info->NotBefore);
3176 else
3177 GetSystemTimeAsFileTime(&info->NotBefore);
3178 if (pEndTime)
3179 SystemTimeToFileTime(pEndTime, &info->NotAfter);
3180 else
3182 SYSTEMTIME endTime;
3184 if (FileTimeToSystemTime(&info->NotBefore, &endTime))
3186 endTime.wYear++;
3187 SystemTimeToFileTime(&endTime, &info->NotAfter);
3190 info->Subject.cbData = pSubjectIssuerBlob->cbData;
3191 info->Subject.pbData = pSubjectIssuerBlob->pbData;
3192 info->SubjectPublicKeyInfo = *pubKey;
3193 if (pExtensions)
3195 info->cExtension = pExtensions->cExtension;
3196 info->rgExtension = pExtensions->rgExtension;
3198 else
3200 info->cExtension = 0;
3201 info->rgExtension = NULL;
3205 typedef RPC_STATUS (RPC_ENTRY *UuidCreateFunc)(UUID *);
3206 typedef RPC_STATUS (RPC_ENTRY *UuidToStringFunc)(UUID *, unsigned char **);
3207 typedef RPC_STATUS (RPC_ENTRY *RpcStringFreeFunc)(unsigned char **);
3209 static HCRYPTPROV CRYPT_CreateKeyProv(void)
3211 HCRYPTPROV hProv = 0;
3212 HMODULE rpcrt = LoadLibraryA("rpcrt4");
3214 if (rpcrt)
3216 UuidCreateFunc uuidCreate = (UuidCreateFunc)GetProcAddress(rpcrt,
3217 "UuidCreate");
3218 UuidToStringFunc uuidToString = (UuidToStringFunc)GetProcAddress(rpcrt,
3219 "UuidToStringA");
3220 RpcStringFreeFunc rpcStringFree = (RpcStringFreeFunc)GetProcAddress(
3221 rpcrt, "RpcStringFreeA");
3223 if (uuidCreate && uuidToString && rpcStringFree)
3225 UUID uuid;
3226 RPC_STATUS status = uuidCreate(&uuid);
3228 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY)
3230 unsigned char *uuidStr;
3232 status = uuidToString(&uuid, &uuidStr);
3233 if (status == RPC_S_OK)
3235 BOOL ret = CryptAcquireContextA(&hProv, (LPCSTR)uuidStr,
3236 MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_NEWKEYSET);
3238 if (ret)
3240 HCRYPTKEY key;
3242 ret = CryptGenKey(hProv, AT_SIGNATURE, 0, &key);
3243 if (ret)
3244 CryptDestroyKey(key);
3246 rpcStringFree(&uuidStr);
3250 FreeLibrary(rpcrt);
3252 return hProv;
3255 PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hProv,
3256 PCERT_NAME_BLOB pSubjectIssuerBlob, DWORD dwFlags,
3257 PCRYPT_KEY_PROV_INFO pKeyProvInfo,
3258 PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime,
3259 PSYSTEMTIME pEndTime, PCERT_EXTENSIONS pExtensions)
3261 PCCERT_CONTEXT context = NULL;
3262 BOOL ret, releaseContext = FALSE;
3263 PCERT_PUBLIC_KEY_INFO pubKey = NULL;
3264 DWORD pubKeySize = 0, dwKeySpec;
3266 TRACE("(%08lx, %p, %08x, %p, %p, %p, %p, %p)\n", hProv,
3267 pSubjectIssuerBlob, dwFlags, pKeyProvInfo, pSignatureAlgorithm, pStartTime,
3268 pExtensions, pExtensions);
3270 if(!pSubjectIssuerBlob)
3272 SetLastError(ERROR_INVALID_PARAMETER);
3273 return NULL;
3276 dwKeySpec = pKeyProvInfo ? pKeyProvInfo->dwKeySpec : AT_SIGNATURE;
3277 if (!hProv)
3279 if (!pKeyProvInfo)
3281 hProv = CRYPT_CreateKeyProv();
3282 releaseContext = TRUE;
3284 else if (pKeyProvInfo->dwFlags & CERT_SET_KEY_PROV_HANDLE_PROP_ID)
3286 SetLastError(NTE_BAD_FLAGS);
3287 return NULL;
3289 else
3291 HCRYPTKEY hKey = 0;
3292 /* acquire the context using the given information*/
3293 ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
3294 pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
3295 pKeyProvInfo->dwFlags);
3296 if (!ret)
3298 if(GetLastError() != NTE_BAD_KEYSET)
3299 return NULL;
3300 /* create the key set */
3301 ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
3302 pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
3303 pKeyProvInfo->dwFlags|CRYPT_NEWKEYSET);
3304 if (!ret)
3305 return NULL;
3307 /* check if the key is here */
3308 ret = CryptGetUserKey(hProv,dwKeySpec,&hKey);
3309 if(!ret)
3311 if (NTE_NO_KEY == GetLastError())
3312 { /* generate the key */
3313 ret = CryptGenKey(hProv,dwKeySpec,0,&hKey);
3315 if (!ret)
3317 CryptReleaseContext(hProv,0);
3318 SetLastError(NTE_BAD_KEYSET);
3319 return NULL;
3322 CryptDestroyKey(hKey);
3323 releaseContext = TRUE;
3327 ret = CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING, NULL,
3328 &pubKeySize);
3329 if (!ret)
3330 goto end;
3331 pubKey = CryptMemAlloc(pubKeySize);
3332 if (pubKey)
3334 ret = CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING,
3335 pubKey, &pubKeySize);
3336 if (ret)
3338 CERT_INFO info = { 0 };
3339 CRYPT_DER_BLOB blob = { 0, NULL };
3340 BYTE serial[16];
3341 CRYPT_DATA_BLOB serialBlob = { sizeof(serial), serial };
3343 CryptGenRandom(hProv, sizeof(serial), serial);
3344 CRYPT_MakeCertInfo(&info, &serialBlob, pSubjectIssuerBlob,
3345 pSignatureAlgorithm, pStartTime, pEndTime, pubKey, pExtensions);
3346 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
3347 &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData,
3348 &blob.cbData);
3349 if (ret)
3351 if (!(dwFlags & CERT_CREATE_SELFSIGN_NO_SIGN))
3352 context = CRYPT_CreateSignedCert(&blob, hProv,dwKeySpec,
3353 &info.SignatureAlgorithm);
3354 else
3355 context = CertCreateCertificateContext(X509_ASN_ENCODING,
3356 blob.pbData, blob.cbData);
3357 if (context && !(dwFlags & CERT_CREATE_SELFSIGN_NO_KEY_INFO))
3358 CertContext_SetKeyProvInfo(context, pKeyProvInfo, hProv);
3359 LocalFree(blob.pbData);
3362 CryptMemFree(pubKey);
3364 end:
3365 if (releaseContext)
3366 CryptReleaseContext(hProv, 0);
3367 return context;
3370 BOOL WINAPI CertVerifyCTLUsage(DWORD dwEncodingType, DWORD dwSubjectType,
3371 void *pvSubject, PCTL_USAGE pSubjectUsage, DWORD dwFlags,
3372 PCTL_VERIFY_USAGE_PARA pVerifyUsagePara,
3373 PCTL_VERIFY_USAGE_STATUS pVerifyUsageStatus)
3375 FIXME("(0x%x, %d, %p, %p, 0x%x, %p, %p): stub\n", dwEncodingType,
3376 dwSubjectType, pvSubject, pSubjectUsage, dwFlags, pVerifyUsagePara,
3377 pVerifyUsageStatus);
3378 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3379 return FALSE;
3382 const void * WINAPI CertCreateContext(DWORD dwContextType, DWORD dwEncodingType,
3383 const BYTE *pbEncoded, DWORD cbEncoded,
3384 DWORD dwFlags, PCERT_CREATE_CONTEXT_PARA pCreatePara)
3386 TRACE("(0x%x, 0x%x, %p, %d, 0x%08x, %p)\n", dwContextType, dwEncodingType,
3387 pbEncoded, cbEncoded, dwFlags, pCreatePara);
3389 if (dwFlags)
3391 FIXME("dwFlags 0x%08x not handled\n", dwFlags);
3392 return NULL;
3394 if (pCreatePara)
3396 FIXME("pCreatePara not handled\n");
3397 return NULL;
3400 switch (dwContextType)
3402 case CERT_STORE_CERTIFICATE_CONTEXT:
3403 return CertCreateCertificateContext(dwEncodingType, pbEncoded, cbEncoded);
3404 case CERT_STORE_CRL_CONTEXT:
3405 return CertCreateCRLContext(dwEncodingType, pbEncoded, cbEncoded);
3406 case CERT_STORE_CTL_CONTEXT:
3407 return CertCreateCTLContext(dwEncodingType, pbEncoded, cbEncoded);
3408 default:
3409 WARN("unknown context type: 0x%x\n", dwContextType);
3410 return NULL;