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
23 #define NONAMELESSUNION
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);
60 TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore, dwCertEncodingType,
61 pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
65 ret = CertAddCertificateContextToStore(hCertStore, cert,
66 dwAddDisposition, ppCertContext);
67 CertFreeCertificateContext(cert);
74 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
75 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
77 PCERT_CONTEXT cert = NULL;
79 PCERT_INFO certInfo = NULL;
82 TRACE("(%08x, %p, %d)\n", dwCertEncodingType, pbCertEncoded,
85 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT_TO_BE_SIGNED,
86 pbCertEncoded, cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL,
92 cert = Context_CreateDataContext(sizeof(CERT_CONTEXT));
95 data = CryptMemAlloc(cbCertEncoded);
102 memcpy(data, pbCertEncoded, cbCertEncoded);
103 cert->dwCertEncodingType = dwCertEncodingType;
104 cert->pbCertEncoded = data;
105 cert->cbCertEncoded = cbCertEncoded;
106 cert->pCertInfo = certInfo;
107 cert->hCertStore = 0;
114 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
115 PCCERT_CONTEXT pCertContext)
117 TRACE("(%p)\n", pCertContext);
118 Context_AddRef((void *)pCertContext, sizeof(CERT_CONTEXT));
122 static void CertDataContext_Free(void *context)
124 PCERT_CONTEXT certContext = context;
126 CryptMemFree(certContext->pbCertEncoded);
127 LocalFree(certContext->pCertInfo);
130 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
132 TRACE("(%p)\n", pCertContext);
135 Context_Release((void *)pCertContext, sizeof(CERT_CONTEXT),
136 CertDataContext_Free);
140 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
143 PCONTEXT_PROPERTY_LIST properties = Context_GetProperties(
144 pCertContext, sizeof(CERT_CONTEXT));
147 TRACE("(%p, %d)\n", pCertContext, dwPropId);
150 ret = ContextPropertyList_EnumPropIDs(properties, dwPropId);
156 static BOOL CertContext_GetHashProp(void *context, DWORD dwPropId,
157 ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
160 BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
164 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
166 ret = CertContext_SetProperty(context, dwPropId, 0, &blob);
171 static BOOL CertContext_CopyParam(void *pvData, DWORD *pcbData, const void *pb,
178 else if (*pcbData < cb)
180 SetLastError(ERROR_MORE_DATA);
186 memcpy(pvData, pb, cb);
192 static BOOL CertContext_GetProperty(void *context, DWORD dwPropId,
193 void *pvData, DWORD *pcbData)
195 PCCERT_CONTEXT pCertContext = context;
196 PCONTEXT_PROPERTY_LIST properties =
197 Context_GetProperties(context, sizeof(CERT_CONTEXT));
199 CRYPT_DATA_BLOB blob;
201 TRACE("(%p, %d, %p, %p)\n", context, dwPropId, pvData, pcbData);
204 ret = ContextPropertyList_FindProperty(properties, dwPropId, &blob);
208 ret = CertContext_CopyParam(pvData, pcbData, blob.pbData, blob.cbData);
211 /* Implicit properties */
214 case CERT_SHA1_HASH_PROP_ID:
215 ret = CertContext_GetHashProp(context, dwPropId, CALG_SHA1,
216 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData,
219 case CERT_MD5_HASH_PROP_ID:
220 ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
221 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData,
224 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
225 ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
226 pCertContext->pCertInfo->Subject.pbData,
227 pCertContext->pCertInfo->Subject.cbData,
230 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
231 ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
232 pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
233 pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
236 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
237 ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
238 pCertContext->pCertInfo->SerialNumber.pbData,
239 pCertContext->pCertInfo->SerialNumber.cbData,
242 case CERT_SIGNATURE_HASH_PROP_ID:
243 ret = CryptHashToBeSigned(0, pCertContext->dwCertEncodingType,
244 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData,
248 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
250 ret = CertContext_SetProperty(context, dwPropId, 0, &blob);
253 case CERT_KEY_IDENTIFIER_PROP_ID:
255 PCERT_EXTENSION ext = CertFindExtension(
256 szOID_SUBJECT_KEY_IDENTIFIER, pCertContext->pCertInfo->cExtension,
257 pCertContext->pCertInfo->rgExtension);
261 CRYPT_DATA_BLOB value;
262 DWORD size = sizeof(value);
264 ret = CryptDecodeObjectEx(X509_ASN_ENCODING,
265 szOID_SUBJECT_KEY_IDENTIFIER, ext->Value.pbData,
266 ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &value,
270 ret = CertContext_CopyParam(pvData, pcbData, value.pbData,
272 CertContext_SetProperty(context, dwPropId, 0, &value);
276 SetLastError(ERROR_INVALID_DATA);
280 SetLastError(CRYPT_E_NOT_FOUND);
283 TRACE("returning %d\n", ret);
287 void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info)
289 DWORD i, containerLen, provNameLen;
290 LPBYTE data = (LPBYTE)info + sizeof(CRYPT_KEY_PROV_INFO);
292 info->pwszContainerName = (LPWSTR)data;
293 containerLen = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
294 data += containerLen;
296 info->pwszProvName = (LPWSTR)data;
297 provNameLen = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
300 info->rgProvParam = (PCRYPT_KEY_PROV_PARAM)data;
301 data += info->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
303 for (i = 0; i < info->cProvParam; i++)
305 info->rgProvParam[i].pbData = data;
306 data += info->rgProvParam[i].cbData;
310 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
311 DWORD dwPropId, void *pvData, DWORD *pcbData)
315 TRACE("(%p, %d, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
320 case CERT_CERT_PROP_ID:
321 case CERT_CRL_PROP_ID:
322 case CERT_CTL_PROP_ID:
323 SetLastError(E_INVALIDARG);
326 case CERT_ACCESS_STATE_PROP_ID:
327 if (pCertContext->hCertStore)
328 ret = CertGetStoreProperty(pCertContext->hCertStore, dwPropId,
334 ret = CertContext_CopyParam(pvData, pcbData, &state, sizeof(state));
337 case CERT_KEY_PROV_HANDLE_PROP_ID:
339 CERT_KEY_CONTEXT keyContext;
340 DWORD size = sizeof(keyContext);
342 ret = CertContext_GetProperty((void *)pCertContext,
343 CERT_KEY_CONTEXT_PROP_ID, &keyContext, &size);
345 ret = CertContext_CopyParam(pvData, pcbData, &keyContext.hCryptProv,
346 sizeof(keyContext.hCryptProv));
349 case CERT_KEY_PROV_INFO_PROP_ID:
350 ret = CertContext_GetProperty((void *)pCertContext, dwPropId, pvData,
353 CRYPT_FixKeyProvInfoPointers(pvData);
356 ret = CertContext_GetProperty((void *)pCertContext, dwPropId, pvData,
360 TRACE("returning %d\n", ret);
364 /* Copies key provider info from from into to, where to is assumed to be a
365 * contiguous buffer of memory large enough for from and all its associated
366 * data, but whose pointers are uninitialized.
367 * Upon return, to contains a contiguous copy of from, packed in the following
369 * - CRYPT_KEY_PROV_INFO
370 * - pwszContainerName
372 * - rgProvParam[0]...
374 static void CRYPT_CopyKeyProvInfo(PCRYPT_KEY_PROV_INFO to,
375 const CRYPT_KEY_PROV_INFO *from)
378 LPBYTE nextData = (LPBYTE)to + sizeof(CRYPT_KEY_PROV_INFO);
380 if (from->pwszContainerName)
382 to->pwszContainerName = (LPWSTR)nextData;
383 lstrcpyW(to->pwszContainerName, from->pwszContainerName);
384 nextData += (lstrlenW(from->pwszContainerName) + 1) * sizeof(WCHAR);
387 to->pwszContainerName = NULL;
388 if (from->pwszProvName)
390 to->pwszProvName = (LPWSTR)nextData;
391 lstrcpyW(to->pwszProvName, from->pwszProvName);
392 nextData += (lstrlenW(from->pwszProvName) + 1) * sizeof(WCHAR);
395 to->pwszProvName = NULL;
396 to->dwProvType = from->dwProvType;
397 to->dwFlags = from->dwFlags;
398 to->cProvParam = from->cProvParam;
399 to->rgProvParam = (PCRYPT_KEY_PROV_PARAM)nextData;
400 nextData += to->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
401 to->dwKeySpec = from->dwKeySpec;
402 for (i = 0; i < to->cProvParam; i++)
404 memcpy(&to->rgProvParam[i], &from->rgProvParam[i],
405 sizeof(CRYPT_KEY_PROV_PARAM));
406 to->rgProvParam[i].pbData = nextData;
407 memcpy(to->rgProvParam[i].pbData, from->rgProvParam[i].pbData,
408 from->rgProvParam[i].cbData);
409 nextData += from->rgProvParam[i].cbData;
413 static BOOL CertContext_SetKeyProvInfoProperty(PCONTEXT_PROPERTY_LIST properties,
414 const CRYPT_KEY_PROV_INFO *info)
418 DWORD size = sizeof(CRYPT_KEY_PROV_INFO), i, containerSize, provNameSize;
420 if (info->pwszContainerName)
421 containerSize = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
424 if (info->pwszProvName)
425 provNameSize = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
428 size += containerSize + provNameSize;
429 for (i = 0; i < info->cProvParam; i++)
430 size += sizeof(CRYPT_KEY_PROV_PARAM) + info->rgProvParam[i].cbData;
431 buf = CryptMemAlloc(size);
434 CRYPT_CopyKeyProvInfo((PCRYPT_KEY_PROV_INFO)buf, info);
435 ret = ContextPropertyList_SetProperty(properties,
436 CERT_KEY_PROV_INFO_PROP_ID, buf, size);
444 static BOOL CertContext_SetProperty(void *context, DWORD dwPropId,
445 DWORD dwFlags, const void *pvData)
447 PCONTEXT_PROPERTY_LIST properties =
448 Context_GetProperties(context, sizeof(CERT_CONTEXT));
451 TRACE("(%p, %d, %08x, %p)\n", context, dwPropId, dwFlags, pvData);
459 case CERT_AUTO_ENROLL_PROP_ID:
460 case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */
461 case CERT_DESCRIPTION_PROP_ID:
462 case CERT_FRIENDLY_NAME_PROP_ID:
463 case CERT_HASH_PROP_ID:
464 case CERT_KEY_IDENTIFIER_PROP_ID:
465 case CERT_MD5_HASH_PROP_ID:
466 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
467 case CERT_PUBKEY_ALG_PARA_PROP_ID:
468 case CERT_PVK_FILE_PROP_ID:
469 case CERT_SIGNATURE_HASH_PROP_ID:
470 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
471 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
472 case CERT_EXTENDED_ERROR_INFO_PROP_ID:
473 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
474 case CERT_ENROLLMENT_PROP_ID:
475 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
476 case CERT_RENEWAL_PROP_ID:
480 const CRYPT_DATA_BLOB *blob = pvData;
482 ret = ContextPropertyList_SetProperty(properties, dwPropId,
483 blob->pbData, blob->cbData);
487 ContextPropertyList_RemoveProperty(properties, dwPropId);
492 case CERT_DATE_STAMP_PROP_ID:
494 ret = ContextPropertyList_SetProperty(properties, dwPropId,
495 pvData, sizeof(FILETIME));
498 ContextPropertyList_RemoveProperty(properties, dwPropId);
502 case CERT_KEY_CONTEXT_PROP_ID:
506 const CERT_KEY_CONTEXT *keyContext = pvData;
508 if (keyContext->cbSize != sizeof(CERT_KEY_CONTEXT))
510 SetLastError(E_INVALIDARG);
514 ret = ContextPropertyList_SetProperty(properties, dwPropId,
515 (const BYTE *)keyContext, keyContext->cbSize);
519 ContextPropertyList_RemoveProperty(properties, dwPropId);
524 case CERT_KEY_PROV_INFO_PROP_ID:
526 ret = CertContext_SetKeyProvInfoProperty(properties, pvData);
529 ContextPropertyList_RemoveProperty(properties, dwPropId);
533 case CERT_KEY_PROV_HANDLE_PROP_ID:
535 CERT_KEY_CONTEXT keyContext;
536 DWORD size = sizeof(keyContext);
538 ret = CertContext_GetProperty(context, CERT_KEY_CONTEXT_PROP_ID,
542 if (!(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
543 CryptReleaseContext(keyContext.hCryptProv, 0);
545 keyContext.cbSize = sizeof(keyContext);
547 keyContext.hCryptProv = *(const HCRYPTPROV *)pvData;
550 keyContext.hCryptProv = 0;
551 keyContext.dwKeySpec = AT_SIGNATURE;
553 ret = CertContext_SetProperty(context, CERT_KEY_CONTEXT_PROP_ID,
558 FIXME("%d: stub\n", dwPropId);
562 TRACE("returning %d\n", ret);
566 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
567 DWORD dwPropId, DWORD dwFlags, const void *pvData)
571 TRACE("(%p, %d, %08x, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
573 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
574 * crashes on most of these, I'll be safer.
579 case CERT_ACCESS_STATE_PROP_ID:
580 case CERT_CERT_PROP_ID:
581 case CERT_CRL_PROP_ID:
582 case CERT_CTL_PROP_ID:
583 SetLastError(E_INVALIDARG);
586 ret = CertContext_SetProperty((void *)pCertContext, dwPropId, dwFlags,
588 TRACE("returning %d\n", ret);
592 /* Acquires the private key using the key provider info, retrieving info from
593 * the certificate if info is NULL. The acquired provider is returned in
594 * *phCryptProv, and the key spec for the provider is returned in *pdwKeySpec.
596 static BOOL CRYPT_AcquirePrivateKeyFromProvInfo(PCCERT_CONTEXT pCert,
597 PCRYPT_KEY_PROV_INFO info, HCRYPTPROV *phCryptProv, DWORD *pdwKeySpec)
600 BOOL allocated = FALSE, ret = TRUE;
604 ret = CertGetCertificateContextProperty(pCert,
605 CERT_KEY_PROV_INFO_PROP_ID, 0, &size);
608 info = HeapAlloc(GetProcessHeap(), 0, size);
611 ret = CertGetCertificateContextProperty(pCert,
612 CERT_KEY_PROV_INFO_PROP_ID, info, &size);
617 SetLastError(ERROR_OUTOFMEMORY);
622 SetLastError(CRYPT_E_NO_KEY_PROPERTY);
626 ret = CryptAcquireContextW(phCryptProv, info->pwszContainerName,
627 info->pwszProvName, info->dwProvType, 0);
632 for (i = 0; i < info->cProvParam; i++)
634 CryptSetProvParam(*phCryptProv,
635 info->rgProvParam[i].dwParam, info->rgProvParam[i].pbData,
636 info->rgProvParam[i].dwFlags);
638 *pdwKeySpec = info->dwKeySpec;
641 SetLastError(CRYPT_E_NO_KEY_PROPERTY);
644 HeapFree(GetProcessHeap(), 0, info);
648 BOOL WINAPI CryptAcquireCertificatePrivateKey(PCCERT_CONTEXT pCert,
649 DWORD dwFlags, void *pvReserved, HCRYPTPROV_OR_NCRYPT_KEY_HANDLE *phCryptProv,
650 DWORD *pdwKeySpec, BOOL *pfCallerFreeProv)
652 BOOL ret = FALSE, cache = FALSE;
653 PCRYPT_KEY_PROV_INFO info = NULL;
654 CERT_KEY_CONTEXT keyContext;
657 TRACE("(%p, %08x, %p, %p, %p, %p)\n", pCert, dwFlags, pvReserved,
658 phCryptProv, pdwKeySpec, pfCallerFreeProv);
660 if (dwFlags & CRYPT_ACQUIRE_USE_PROV_INFO_FLAG)
664 ret = CertGetCertificateContextProperty(pCert,
665 CERT_KEY_PROV_INFO_PROP_ID, 0, &size);
668 info = HeapAlloc(GetProcessHeap(), 0, size);
669 ret = CertGetCertificateContextProperty(pCert,
670 CERT_KEY_PROV_INFO_PROP_ID, info, &size);
672 cache = info->dwFlags & CERT_SET_KEY_CONTEXT_PROP_ID;
675 else if (dwFlags & CRYPT_ACQUIRE_CACHE_FLAG)
680 size = sizeof(keyContext);
681 ret = CertGetCertificateContextProperty(pCert, CERT_KEY_CONTEXT_PROP_ID,
685 *phCryptProv = keyContext.hCryptProv;
687 *pdwKeySpec = keyContext.dwKeySpec;
688 if (pfCallerFreeProv)
689 *pfCallerFreeProv = !cache;
694 ret = CRYPT_AcquirePrivateKeyFromProvInfo(pCert, info,
695 &keyContext.hCryptProv, &keyContext.dwKeySpec);
698 *phCryptProv = keyContext.hCryptProv;
700 *pdwKeySpec = keyContext.dwKeySpec;
703 keyContext.cbSize = sizeof(keyContext);
704 if (CertSetCertificateContextProperty(pCert,
705 CERT_KEY_CONTEXT_PROP_ID, 0, &keyContext))
707 if (pfCallerFreeProv)
708 *pfCallerFreeProv = FALSE;
713 if (pfCallerFreeProv)
714 *pfCallerFreeProv = TRUE;
718 HeapFree(GetProcessHeap(), 0, info);
722 static BOOL key_prov_info_matches_cert(PCCERT_CONTEXT pCert,
723 const CRYPT_KEY_PROV_INFO *keyProvInfo)
726 BOOL matches = FALSE;
728 if (CryptAcquireContextW(&csp, keyProvInfo->pwszContainerName,
729 keyProvInfo->pwszProvName, keyProvInfo->dwProvType, keyProvInfo->dwFlags))
733 /* Need to sign something to verify the sig. What to sign? Why not
734 * the certificate itself?
736 if (CryptSignAndEncodeCertificate(csp, AT_SIGNATURE,
737 pCert->dwCertEncodingType, X509_CERT_TO_BE_SIGNED, pCert->pCertInfo,
738 &pCert->pCertInfo->SignatureAlgorithm, NULL, NULL, &size))
740 BYTE *certEncoded = CryptMemAlloc(size);
744 if (CryptSignAndEncodeCertificate(csp, AT_SIGNATURE,
745 pCert->dwCertEncodingType, X509_CERT_TO_BE_SIGNED,
746 pCert->pCertInfo, &pCert->pCertInfo->SignatureAlgorithm,
747 NULL, certEncoded, &size))
749 if (size == pCert->cbCertEncoded &&
750 !memcmp(certEncoded, pCert->pbCertEncoded, size))
753 CryptMemFree(certEncoded);
756 CryptReleaseContext(csp, 0);
761 static BOOL container_matches_cert(PCCERT_CONTEXT pCert, LPCSTR container,
762 CRYPT_KEY_PROV_INFO *keyProvInfo)
764 CRYPT_KEY_PROV_INFO copy;
765 WCHAR containerW[MAX_PATH];
766 BOOL matches = FALSE;
768 MultiByteToWideChar(CP_ACP, 0, container, -1,
769 containerW, sizeof(containerW) / sizeof(containerW[0]));
770 /* We make a copy of the CRYPT_KEY_PROV_INFO because the caller expects
771 * keyProvInfo->pwszContainerName to be NULL or a heap-allocated container
774 memcpy(©, keyProvInfo, sizeof(copy));
775 copy.pwszContainerName = containerW;
776 matches = key_prov_info_matches_cert(pCert, ©);
779 keyProvInfo->pwszContainerName =
780 CryptMemAlloc((strlenW(containerW) + 1) * sizeof(WCHAR));
781 if (keyProvInfo->pwszContainerName)
783 strcpyW(keyProvInfo->pwszContainerName, containerW);
784 keyProvInfo->dwKeySpec = AT_SIGNATURE;
792 /* Searches the provider named keyProvInfo.pwszProvName for a container whose
793 * private key matches pCert's public key. Upon success, updates keyProvInfo
794 * with the matching container's info (free keyProvInfo.pwszContainerName upon
796 * Returns TRUE if found, FALSE if not.
798 static BOOL find_key_prov_info_in_provider(PCCERT_CONTEXT pCert,
799 CRYPT_KEY_PROV_INFO *keyProvInfo)
801 HCRYPTPROV defProvider;
802 BOOL ret, found = FALSE;
803 char containerA[MAX_PATH];
805 assert(keyProvInfo->pwszContainerName == NULL);
806 if ((ret = CryptAcquireContextW(&defProvider, NULL,
807 keyProvInfo->pwszProvName, keyProvInfo->dwProvType,
808 keyProvInfo->dwFlags | CRYPT_VERIFYCONTEXT)))
810 DWORD enumFlags = keyProvInfo->dwFlags | CRYPT_FIRST;
812 while (ret && !found)
814 DWORD size = sizeof(containerA);
816 ret = CryptGetProvParam(defProvider, PP_ENUMCONTAINERS,
817 (BYTE *)containerA, &size, enumFlags);
819 found = container_matches_cert(pCert, containerA, keyProvInfo);
820 if (enumFlags & CRYPT_FIRST)
822 enumFlags &= ~CRYPT_FIRST;
823 enumFlags |= CRYPT_NEXT;
826 CryptReleaseContext(defProvider, 0);
831 static BOOL find_matching_provider(PCCERT_CONTEXT pCert, DWORD dwFlags)
833 BOOL found = FALSE, ret = TRUE;
834 DWORD index = 0, cbProvName = 0;
835 CRYPT_KEY_PROV_INFO keyProvInfo;
837 TRACE("(%p, %08x)\n", pCert, dwFlags);
839 memset(&keyProvInfo, 0, sizeof(keyProvInfo));
840 while (ret && !found)
844 ret = CryptEnumProvidersW(index, NULL, 0, &keyProvInfo.dwProvType,
848 if (size <= cbProvName)
849 ret = CryptEnumProvidersW(index, NULL, 0,
850 &keyProvInfo.dwProvType, keyProvInfo.pwszProvName, &size);
853 CryptMemFree(keyProvInfo.pwszProvName);
854 keyProvInfo.pwszProvName = CryptMemAlloc(size);
855 if (keyProvInfo.pwszProvName)
858 ret = CryptEnumProvidersW(index, NULL, 0,
859 &keyProvInfo.dwProvType, keyProvInfo.pwszProvName, &size);
862 if (dwFlags & CRYPT_FIND_SILENT_KEYSET_FLAG)
863 keyProvInfo.dwFlags |= CRYPT_SILENT;
864 if (dwFlags & CRYPT_FIND_USER_KEYSET_FLAG ||
865 !(dwFlags & (CRYPT_FIND_USER_KEYSET_FLAG |
866 CRYPT_FIND_MACHINE_KEYSET_FLAG)))
868 keyProvInfo.dwFlags |= CRYPT_USER_KEYSET;
869 found = find_key_prov_info_in_provider(pCert,
874 if (dwFlags & CRYPT_FIND_MACHINE_KEYSET_FLAG ||
875 !(dwFlags & (CRYPT_FIND_USER_KEYSET_FLAG |
876 CRYPT_FIND_MACHINE_KEYSET_FLAG)))
878 keyProvInfo.dwFlags &= ~CRYPT_USER_KEYSET;
879 keyProvInfo.dwFlags |= CRYPT_MACHINE_KEYSET;
880 found = find_key_prov_info_in_provider(pCert,
893 CertSetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID,
895 CryptMemFree(keyProvInfo.pwszProvName);
896 CryptMemFree(keyProvInfo.pwszContainerName);
900 static BOOL cert_prov_info_matches_cert(PCCERT_CONTEXT pCert)
902 BOOL matches = FALSE;
905 if (CertGetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID,
908 CRYPT_KEY_PROV_INFO *keyProvInfo = CryptMemAlloc(size);
912 if (CertGetCertificateContextProperty(pCert,
913 CERT_KEY_PROV_INFO_PROP_ID, keyProvInfo, &size))
914 matches = key_prov_info_matches_cert(pCert, keyProvInfo);
915 CryptMemFree(keyProvInfo);
921 BOOL WINAPI CryptFindCertificateKeyProvInfo(PCCERT_CONTEXT pCert,
922 DWORD dwFlags, void *pvReserved)
924 BOOL matches = FALSE;
926 TRACE("(%p, %08x, %p)\n", pCert, dwFlags, pvReserved);
928 matches = cert_prov_info_matches_cert(pCert);
930 matches = find_matching_provider(pCert, dwFlags);
934 BOOL WINAPI CertCompareCertificate(DWORD dwCertEncodingType,
935 PCERT_INFO pCertId1, PCERT_INFO pCertId2)
939 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertId1, pCertId2);
941 ret = CertCompareCertificateName(dwCertEncodingType, &pCertId1->Issuer,
942 &pCertId2->Issuer) && CertCompareIntegerBlob(&pCertId1->SerialNumber,
943 &pCertId2->SerialNumber);
944 TRACE("returning %d\n", ret);
948 BOOL WINAPI CertCompareCertificateName(DWORD dwCertEncodingType,
949 PCERT_NAME_BLOB pCertName1, PCERT_NAME_BLOB pCertName2)
953 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertName1, pCertName2);
955 if (pCertName1->cbData == pCertName2->cbData)
957 if (pCertName1->cbData)
958 ret = !memcmp(pCertName1->pbData, pCertName2->pbData,
965 TRACE("returning %d\n", ret);
969 /* Returns the number of significant bytes in pInt, where a byte is
970 * insignificant if it's a leading 0 for positive numbers or a leading 0xff
971 * for negative numbers. pInt is assumed to be little-endian.
973 static DWORD CRYPT_significantBytes(const CRYPT_INTEGER_BLOB *pInt)
975 DWORD ret = pInt->cbData;
979 if (pInt->pbData[ret - 2] <= 0x7f && pInt->pbData[ret - 1] == 0)
981 else if (pInt->pbData[ret - 2] >= 0x80 && pInt->pbData[ret - 1] == 0xff)
989 BOOL WINAPI CertCompareIntegerBlob(PCRYPT_INTEGER_BLOB pInt1,
990 PCRYPT_INTEGER_BLOB pInt2)
995 TRACE("(%p, %p)\n", pInt1, pInt2);
997 cb1 = CRYPT_significantBytes(pInt1);
998 cb2 = CRYPT_significantBytes(pInt2);
1002 ret = !memcmp(pInt1->pbData, pInt2->pbData, cb1);
1008 TRACE("returning %d\n", ret);
1012 BOOL WINAPI CertComparePublicKeyInfo(DWORD dwCertEncodingType,
1013 PCERT_PUBLIC_KEY_INFO pPublicKey1, PCERT_PUBLIC_KEY_INFO pPublicKey2)
1017 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pPublicKey1, pPublicKey2);
1019 switch (GET_CERT_ENCODING_TYPE(dwCertEncodingType))
1021 case 0: /* Seems to mean "raw binary bits" */
1022 if (pPublicKey1->PublicKey.cbData == pPublicKey2->PublicKey.cbData &&
1023 pPublicKey1->PublicKey.cUnusedBits == pPublicKey2->PublicKey.cUnusedBits)
1025 if (pPublicKey2->PublicKey.cbData)
1026 ret = !memcmp(pPublicKey1->PublicKey.pbData,
1027 pPublicKey2->PublicKey.pbData, pPublicKey1->PublicKey.cbData);
1035 WARN("Unknown encoding type %08x\n", dwCertEncodingType);
1037 case X509_ASN_ENCODING:
1039 BLOBHEADER *pblob1, *pblob2;
1042 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1043 pPublicKey1->PublicKey.pbData, pPublicKey1->PublicKey.cbData,
1046 pblob1 = CryptMemAlloc(length);
1047 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1048 pPublicKey1->PublicKey.pbData, pPublicKey1->PublicKey.cbData,
1049 0, pblob1, &length))
1051 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1052 pPublicKey2->PublicKey.pbData, pPublicKey2->PublicKey.cbData,
1055 pblob2 = CryptMemAlloc(length);
1056 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1057 pPublicKey2->PublicKey.pbData, pPublicKey2->PublicKey.cbData,
1058 0, pblob2, &length))
1060 /* The RSAPUBKEY structure directly follows the BLOBHEADER */
1061 RSAPUBKEY *pk1 = (LPVOID)(pblob1 + 1),
1062 *pk2 = (LPVOID)(pblob2 + 1);
1063 ret = (pk1->bitlen == pk2->bitlen) && (pk1->pubexp == pk2->pubexp)
1064 && !memcmp(pk1 + 1, pk2 + 1, pk1->bitlen/8);
1066 CryptMemFree(pblob2);
1069 CryptMemFree(pblob1);
1078 DWORD WINAPI CertGetPublicKeyLength(DWORD dwCertEncodingType,
1079 PCERT_PUBLIC_KEY_INFO pPublicKey)
1083 TRACE("(%08x, %p)\n", dwCertEncodingType, pPublicKey);
1085 if (GET_CERT_ENCODING_TYPE(dwCertEncodingType) != X509_ASN_ENCODING)
1087 SetLastError(ERROR_FILE_NOT_FOUND);
1090 if (pPublicKey->Algorithm.pszObjId &&
1091 !strcmp(pPublicKey->Algorithm.pszObjId, szOID_RSA_DH))
1093 FIXME("unimplemented for DH public keys\n");
1094 SetLastError(CRYPT_E_ASN1_BADTAG);
1100 BOOL ret = CryptDecodeObjectEx(dwCertEncodingType,
1101 RSA_CSP_PUBLICKEYBLOB, pPublicKey->PublicKey.pbData,
1102 pPublicKey->PublicKey.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf,
1107 RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
1109 len = rsaPubKey->bitlen;
1116 typedef BOOL (*CertCompareFunc)(PCCERT_CONTEXT pCertContext, DWORD dwType,
1117 DWORD dwFlags, const void *pvPara);
1119 static BOOL compare_cert_any(PCCERT_CONTEXT pCertContext, DWORD dwType,
1120 DWORD dwFlags, const void *pvPara)
1125 static BOOL compare_cert_by_md5_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
1126 DWORD dwFlags, const void *pvPara)
1130 DWORD size = sizeof(hash);
1132 ret = CertGetCertificateContextProperty(pCertContext,
1133 CERT_MD5_HASH_PROP_ID, hash, &size);
1136 const CRYPT_HASH_BLOB *pHash = pvPara;
1138 if (size == pHash->cbData)
1139 ret = !memcmp(pHash->pbData, hash, size);
1146 static BOOL compare_cert_by_sha1_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
1147 DWORD dwFlags, const void *pvPara)
1151 DWORD size = sizeof(hash);
1153 ret = CertGetCertificateContextProperty(pCertContext,
1154 CERT_SHA1_HASH_PROP_ID, hash, &size);
1157 const CRYPT_HASH_BLOB *pHash = pvPara;
1159 if (size == pHash->cbData)
1160 ret = !memcmp(pHash->pbData, hash, size);
1167 static BOOL compare_cert_by_name(PCCERT_CONTEXT pCertContext, DWORD dwType,
1168 DWORD dwFlags, const void *pvPara)
1170 CERT_NAME_BLOB *blob = (CERT_NAME_BLOB *)pvPara, *toCompare;
1173 if (dwType & CERT_INFO_SUBJECT_FLAG)
1174 toCompare = &pCertContext->pCertInfo->Subject;
1176 toCompare = &pCertContext->pCertInfo->Issuer;
1177 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1182 static BOOL compare_cert_by_public_key(PCCERT_CONTEXT pCertContext,
1183 DWORD dwType, DWORD dwFlags, const void *pvPara)
1185 CERT_PUBLIC_KEY_INFO *publicKey = (CERT_PUBLIC_KEY_INFO *)pvPara;
1188 ret = CertComparePublicKeyInfo(pCertContext->dwCertEncodingType,
1189 &pCertContext->pCertInfo->SubjectPublicKeyInfo, publicKey);
1193 static BOOL compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext,
1194 DWORD dwType, DWORD dwFlags, const void *pvPara)
1196 CERT_INFO *pCertInfo = (CERT_INFO *)pvPara;
1199 /* Matching serial number and subject match.. */
1200 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1201 &pCertInfo->Issuer, &pCertContext->pCertInfo->Subject);
1203 ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
1204 &pCertInfo->SerialNumber);
1207 /* failing that, if the serial number and issuer match, we match */
1208 ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
1209 &pCertInfo->SerialNumber);
1211 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1212 &pCertInfo->Issuer, &pCertContext->pCertInfo->Issuer);
1214 TRACE("returning %d\n", ret);
1218 static BOOL compare_cert_by_cert_id(PCCERT_CONTEXT pCertContext, DWORD dwType,
1219 DWORD dwFlags, const void *pvPara)
1221 CERT_ID *id = (CERT_ID *)pvPara;
1224 switch (id->dwIdChoice)
1226 case CERT_ID_ISSUER_SERIAL_NUMBER:
1227 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1228 &pCertContext->pCertInfo->Issuer, &id->u.IssuerSerialNumber.Issuer);
1230 ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
1231 &id->u.IssuerSerialNumber.SerialNumber);
1233 case CERT_ID_SHA1_HASH:
1234 ret = compare_cert_by_sha1_hash(pCertContext, dwType, dwFlags,
1237 case CERT_ID_KEY_IDENTIFIER:
1241 ret = CertGetCertificateContextProperty(pCertContext,
1242 CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
1243 if (ret && size == id->u.KeyId.cbData)
1245 LPBYTE buf = CryptMemAlloc(size);
1249 CertGetCertificateContextProperty(pCertContext,
1250 CERT_KEY_IDENTIFIER_PROP_ID, buf, &size);
1251 ret = !memcmp(buf, id->u.KeyId.pbData, size);
1266 static BOOL compare_cert_by_issuer(PCCERT_CONTEXT pCertContext, DWORD dwType,
1267 DWORD dwFlags, const void *pvPara)
1270 PCCERT_CONTEXT subject = pvPara;
1271 PCERT_EXTENSION ext;
1274 if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER,
1275 subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
1277 CERT_AUTHORITY_KEY_ID_INFO *info;
1279 ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
1280 X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData,
1281 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1287 if (info->CertIssuer.cbData && info->CertSerialNumber.cbData)
1289 id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
1290 memcpy(&id.u.IssuerSerialNumber.Issuer, &info->CertIssuer,
1291 sizeof(CERT_NAME_BLOB));
1292 memcpy(&id.u.IssuerSerialNumber.SerialNumber,
1293 &info->CertSerialNumber, sizeof(CRYPT_INTEGER_BLOB));
1294 ret = compare_cert_by_cert_id(pCertContext, dwType, dwFlags,
1297 else if (info->KeyId.cbData)
1299 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
1300 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
1301 ret = compare_cert_by_cert_id(pCertContext, dwType, dwFlags,
1309 else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2,
1310 subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
1312 CERT_AUTHORITY_KEY_ID2_INFO *info;
1314 ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
1315 X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData,
1316 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1322 if (info->AuthorityCertIssuer.cAltEntry &&
1323 info->AuthorityCertSerialNumber.cbData)
1325 PCERT_ALT_NAME_ENTRY directoryName = NULL;
1328 for (i = 0; !directoryName &&
1329 i < info->AuthorityCertIssuer.cAltEntry; i++)
1330 if (info->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice
1331 == CERT_ALT_NAME_DIRECTORY_NAME)
1333 &info->AuthorityCertIssuer.rgAltEntry[i];
1336 id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
1337 memcpy(&id.u.IssuerSerialNumber.Issuer,
1338 &directoryName->u.DirectoryName, sizeof(CERT_NAME_BLOB));
1339 memcpy(&id.u.IssuerSerialNumber.SerialNumber,
1340 &info->AuthorityCertSerialNumber,
1341 sizeof(CRYPT_INTEGER_BLOB));
1342 ret = compare_cert_by_cert_id(pCertContext, dwType, dwFlags,
1347 FIXME("no supported name type in authority key id2\n");
1351 else if (info->KeyId.cbData)
1353 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
1354 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
1355 ret = compare_cert_by_cert_id(pCertContext, dwType, dwFlags,
1364 ret = compare_cert_by_name(pCertContext,
1365 CERT_COMPARE_NAME | CERT_COMPARE_SUBJECT_CERT, dwFlags,
1366 &subject->pCertInfo->Issuer);
1370 static BOOL compare_existing_cert(PCCERT_CONTEXT pCertContext, DWORD dwType,
1371 DWORD dwFlags, const void *pvPara)
1373 PCCERT_CONTEXT toCompare = pvPara;
1374 return CertCompareCertificate(pCertContext->dwCertEncodingType,
1375 pCertContext->pCertInfo, toCompare->pCertInfo);
1378 static BOOL compare_cert_by_signature_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
1379 DWORD dwFlags, const void *pvPara)
1381 const CRYPT_HASH_BLOB *hash = pvPara;
1385 ret = CertGetCertificateContextProperty(pCertContext,
1386 CERT_SIGNATURE_HASH_PROP_ID, NULL, &size);
1387 if (ret && size == hash->cbData)
1389 LPBYTE buf = CryptMemAlloc(size);
1393 CertGetCertificateContextProperty(pCertContext,
1394 CERT_SIGNATURE_HASH_PROP_ID, buf, &size);
1395 ret = !memcmp(buf, hash->pbData, size);
1404 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
1405 DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType, const void *pvPara,
1406 PCCERT_CONTEXT pPrevCertContext)
1409 CertCompareFunc compare;
1411 TRACE("(%p, %08x, %08x, %08x, %p, %p)\n", hCertStore, dwCertEncodingType,
1412 dwFlags, dwType, pvPara, pPrevCertContext);
1414 switch (dwType >> CERT_COMPARE_SHIFT)
1416 case CERT_COMPARE_ANY:
1417 compare = compare_cert_any;
1419 case CERT_COMPARE_MD5_HASH:
1420 compare = compare_cert_by_md5_hash;
1422 case CERT_COMPARE_SHA1_HASH:
1423 compare = compare_cert_by_sha1_hash;
1425 case CERT_COMPARE_NAME:
1426 compare = compare_cert_by_name;
1428 case CERT_COMPARE_PUBLIC_KEY:
1429 compare = compare_cert_by_public_key;
1431 case CERT_COMPARE_SUBJECT_CERT:
1432 compare = compare_cert_by_subject_cert;
1434 case CERT_COMPARE_CERT_ID:
1435 compare = compare_cert_by_cert_id;
1437 case CERT_COMPARE_ISSUER_OF:
1438 compare = compare_cert_by_issuer;
1440 case CERT_COMPARE_EXISTING:
1441 compare = compare_existing_cert;
1443 case CERT_COMPARE_SIGNATURE_HASH:
1444 compare = compare_cert_by_signature_hash;
1447 FIXME("find type %08x unimplemented\n", dwType);
1453 BOOL matches = FALSE;
1455 ret = pPrevCertContext;
1457 ret = CertEnumCertificatesInStore(hCertStore, ret);
1459 matches = compare(ret, dwType, dwFlags, pvPara);
1460 } while (ret != NULL && !matches);
1462 SetLastError(CRYPT_E_NOT_FOUND);
1466 SetLastError(CRYPT_E_NOT_FOUND);
1469 TRACE("returning %p\n", ret);
1473 PCCERT_CONTEXT WINAPI CertGetSubjectCertificateFromStore(HCERTSTORE hCertStore,
1474 DWORD dwCertEncodingType, PCERT_INFO pCertId)
1476 TRACE("(%p, %08x, %p)\n", hCertStore, dwCertEncodingType, pCertId);
1480 SetLastError(E_INVALIDARG);
1483 return CertFindCertificateInStore(hCertStore, dwCertEncodingType, 0,
1484 CERT_FIND_SUBJECT_CERT, pCertId, NULL);
1487 BOOL WINAPI CertVerifySubjectCertificateContext(PCCERT_CONTEXT pSubject,
1488 PCCERT_CONTEXT pIssuer, DWORD *pdwFlags)
1490 static const DWORD supportedFlags = CERT_STORE_REVOCATION_FLAG |
1491 CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG;
1493 if (*pdwFlags & ~supportedFlags)
1495 SetLastError(E_INVALIDARG);
1498 if (*pdwFlags & CERT_STORE_REVOCATION_FLAG)
1501 PCCRL_CONTEXT crl = CertGetCRLFromStore(pSubject->hCertStore, pSubject,
1504 /* FIXME: what if the CRL has expired? */
1507 if (CertVerifyCRLRevocation(pSubject->dwCertEncodingType,
1508 pSubject->pCertInfo, 1, (PCRL_INFO *)&crl->pCrlInfo))
1509 *pdwFlags &= CERT_STORE_REVOCATION_FLAG;
1512 *pdwFlags |= CERT_STORE_NO_CRL_FLAG;
1514 if (*pdwFlags & CERT_STORE_TIME_VALIDITY_FLAG)
1516 if (0 == CertVerifyTimeValidity(NULL, pSubject->pCertInfo))
1517 *pdwFlags &= ~CERT_STORE_TIME_VALIDITY_FLAG;
1519 if (*pdwFlags & CERT_STORE_SIGNATURE_FLAG)
1521 if (CryptVerifyCertificateSignatureEx(0, pSubject->dwCertEncodingType,
1522 CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)pSubject,
1523 CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)pIssuer, 0, NULL))
1524 *pdwFlags &= ~CERT_STORE_SIGNATURE_FLAG;
1529 PCCERT_CONTEXT WINAPI CertGetIssuerCertificateFromStore(HCERTSTORE hCertStore,
1530 PCCERT_CONTEXT pSubjectContext, PCCERT_CONTEXT pPrevIssuerContext,
1535 TRACE("(%p, %p, %p, %08x)\n", hCertStore, pSubjectContext,
1536 pPrevIssuerContext, *pdwFlags);
1538 if (!pSubjectContext)
1540 SetLastError(E_INVALIDARG);
1544 ret = CertFindCertificateInStore(hCertStore,
1545 pSubjectContext->dwCertEncodingType, 0, CERT_FIND_ISSUER_OF,
1546 pSubjectContext, pPrevIssuerContext);
1549 if (!CertVerifySubjectCertificateContext(pSubjectContext, ret,
1552 CertFreeCertificateContext(ret);
1556 TRACE("returning %p\n", ret);
1560 typedef struct _OLD_CERT_REVOCATION_STATUS {
1565 } OLD_CERT_REVOCATION_STATUS, *POLD_CERT_REVOCATION_STATUS;
1567 typedef BOOL (WINAPI *CertVerifyRevocationFunc)(DWORD, DWORD, DWORD,
1568 void **, DWORD, PCERT_REVOCATION_PARA, PCERT_REVOCATION_STATUS);
1570 BOOL WINAPI CertVerifyRevocation(DWORD dwEncodingType, DWORD dwRevType,
1571 DWORD cContext, PVOID rgpvContext[], DWORD dwFlags,
1572 PCERT_REVOCATION_PARA pRevPara, PCERT_REVOCATION_STATUS pRevStatus)
1576 TRACE("(%08x, %d, %d, %p, %08x, %p, %p)\n", dwEncodingType, dwRevType,
1577 cContext, rgpvContext, dwFlags, pRevPara, pRevStatus);
1579 if (pRevStatus->cbSize != sizeof(OLD_CERT_REVOCATION_STATUS) &&
1580 pRevStatus->cbSize != sizeof(CERT_REVOCATION_STATUS))
1582 SetLastError(E_INVALIDARG);
1587 static HCRYPTOIDFUNCSET set = NULL;
1591 set = CryptInitOIDFunctionSet(CRYPT_OID_VERIFY_REVOCATION_FUNC, 0);
1592 ret = CryptGetDefaultOIDDllList(set, dwEncodingType, NULL, &size);
1598 SetLastError(CRYPT_E_NO_REVOCATION_DLL);
1603 LPWSTR dllList = CryptMemAlloc(size * sizeof(WCHAR)), ptr;
1607 ret = CryptGetDefaultOIDDllList(set, dwEncodingType,
1611 for (ptr = dllList; ret && *ptr;
1612 ptr += lstrlenW(ptr) + 1)
1614 CertVerifyRevocationFunc func;
1615 HCRYPTOIDFUNCADDR hFunc;
1617 ret = CryptGetDefaultOIDFunctionAddress(set,
1618 dwEncodingType, ptr, 0, (void **)&func, &hFunc);
1621 ret = func(dwEncodingType, dwRevType, cContext,
1622 rgpvContext, dwFlags, pRevPara, pRevStatus);
1623 CryptFreeOIDFunctionAddress(hFunc, 0);
1627 CryptMemFree(dllList);
1631 SetLastError(ERROR_OUTOFMEMORY);
1642 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
1643 CRYPT_ATTRIBUTE rgAttr[])
1645 PCRYPT_ATTRIBUTE ret = NULL;
1648 TRACE("%s %d %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
1654 SetLastError(ERROR_INVALID_PARAMETER);
1658 for (i = 0; !ret && i < cAttr; i++)
1659 if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
1664 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
1665 CERT_EXTENSION rgExtensions[])
1667 PCERT_EXTENSION ret = NULL;
1670 TRACE("%s %d %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
1676 SetLastError(ERROR_INVALID_PARAMETER);
1680 for (i = 0; !ret && i < cExtensions; i++)
1681 if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
1682 rgExtensions[i].pszObjId))
1683 ret = &rgExtensions[i];
1687 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
1689 PCERT_RDN_ATTR ret = NULL;
1692 TRACE("%s %p\n", debugstr_a(pszObjId), pName);
1696 SetLastError(ERROR_INVALID_PARAMETER);
1700 for (i = 0; !ret && i < pName->cRDN; i++)
1701 for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
1702 if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
1703 pName->rgRDN[i].rgRDNAttr[j].pszObjId))
1704 ret = &pName->rgRDN[i].rgRDNAttr[j];
1708 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
1709 PCERT_INFO pCertInfo)
1716 GetSystemTimeAsFileTime(&fileTime);
1717 pTimeToVerify = &fileTime;
1719 if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
1721 ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
1728 BOOL WINAPI CertVerifyValidityNesting(PCERT_INFO pSubjectInfo,
1729 PCERT_INFO pIssuerInfo)
1731 TRACE("(%p, %p)\n", pSubjectInfo, pIssuerInfo);
1733 return CertVerifyTimeValidity(&pSubjectInfo->NotBefore, pIssuerInfo) == 0
1734 && CertVerifyTimeValidity(&pSubjectInfo->NotAfter, pIssuerInfo) == 0;
1737 BOOL WINAPI CryptHashCertificate(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
1738 DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
1739 DWORD *pcbComputedHash)
1742 HCRYPTHASH hHash = 0;
1744 TRACE("(%08lx, %d, %08x, %p, %d, %p, %p)\n", hCryptProv, Algid, dwFlags,
1745 pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
1748 hCryptProv = CRYPT_GetDefaultProvider();
1753 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
1756 ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
1758 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
1759 pcbComputedHash, 0);
1760 CryptDestroyHash(hHash);
1766 BOOL WINAPI CryptHashPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
1767 DWORD dwFlags, DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo,
1768 BYTE *pbComputedHash, DWORD *pcbComputedHash)
1771 HCRYPTHASH hHash = 0;
1773 TRACE("(%08lx, %d, %08x, %d, %p, %p, %p)\n", hCryptProv, Algid, dwFlags,
1774 dwCertEncodingType, pInfo, pbComputedHash, pcbComputedHash);
1777 hCryptProv = CRYPT_GetDefaultProvider();
1785 ret = CryptEncodeObjectEx(dwCertEncodingType, X509_PUBLIC_KEY_INFO,
1786 pInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
1789 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
1792 ret = CryptHashData(hHash, buf, size, 0);
1794 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
1795 pcbComputedHash, 0);
1796 CryptDestroyHash(hHash);
1804 BOOL WINAPI CryptHashToBeSigned(HCRYPTPROV_LEGACY hCryptProv,
1805 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
1806 BYTE *pbComputedHash, DWORD *pcbComputedHash)
1809 CERT_SIGNED_CONTENT_INFO *info;
1812 TRACE("(%08lx, %08x, %p, %d, %p, %d)\n", hCryptProv, dwCertEncodingType,
1813 pbEncoded, cbEncoded, pbComputedHash, *pcbComputedHash);
1815 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
1816 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size);
1819 PCCRYPT_OID_INFO oidInfo;
1823 hCryptProv = CRYPT_GetDefaultProvider();
1824 oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1825 info->SignatureAlgorithm.pszObjId, 0);
1828 SetLastError(NTE_BAD_ALGID);
1833 ret = CryptCreateHash(hCryptProv, oidInfo->u.Algid, 0, 0, &hHash);
1836 ret = CryptHashData(hHash, info->ToBeSigned.pbData,
1837 info->ToBeSigned.cbData, 0);
1839 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
1840 pcbComputedHash, 0);
1841 CryptDestroyHash(hHash);
1849 BOOL WINAPI CryptSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
1850 DWORD dwKeySpec, DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned,
1851 DWORD cbEncodedToBeSigned, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
1852 const void *pvHashAuxInfo, BYTE *pbSignature, DWORD *pcbSignature)
1855 PCCRYPT_OID_INFO info;
1858 TRACE("(%08lx, %d, %d, %p, %d, %p, %p, %p, %p)\n", hCryptProv,
1859 dwKeySpec, dwCertEncodingType, pbEncodedToBeSigned, cbEncodedToBeSigned,
1860 pSignatureAlgorithm, pvHashAuxInfo, pbSignature, pcbSignature);
1862 info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1863 pSignatureAlgorithm->pszObjId, 0);
1866 SetLastError(NTE_BAD_ALGID);
1869 if (info->dwGroupId == CRYPT_HASH_ALG_OID_GROUP_ID)
1872 hCryptProv = CRYPT_GetDefaultProvider();
1873 ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
1876 ret = CryptHashData(hHash, pbEncodedToBeSigned,
1877 cbEncodedToBeSigned, 0);
1879 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbSignature,
1881 CryptDestroyHash(hHash);
1888 SetLastError(ERROR_INVALID_PARAMETER);
1893 ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
1896 ret = CryptHashData(hHash, pbEncodedToBeSigned,
1897 cbEncodedToBeSigned, 0);
1899 ret = CryptSignHashW(hHash, dwKeySpec, NULL, 0, pbSignature,
1901 CryptDestroyHash(hHash);
1908 BOOL WINAPI CryptSignAndEncodeCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
1909 DWORD dwKeySpec, DWORD dwCertEncodingType, LPCSTR lpszStructType,
1910 const void *pvStructInfo, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
1911 const void *pvHashAuxInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
1914 DWORD encodedSize, hashSize;
1916 TRACE("(%08lx, %d, %d, %s, %p, %p, %p, %p, %p)\n", hCryptProv, dwKeySpec,
1917 dwCertEncodingType, debugstr_a(lpszStructType), pvStructInfo,
1918 pSignatureAlgorithm, pvHashAuxInfo, pbEncoded, pcbEncoded);
1920 ret = CryptEncodeObject(dwCertEncodingType, lpszStructType, pvStructInfo,
1921 NULL, &encodedSize);
1924 PBYTE encoded = CryptMemAlloc(encodedSize);
1928 ret = CryptEncodeObject(dwCertEncodingType, lpszStructType,
1929 pvStructInfo, encoded, &encodedSize);
1932 ret = CryptSignCertificate(hCryptProv, dwKeySpec,
1933 dwCertEncodingType, encoded, encodedSize, pSignatureAlgorithm,
1934 pvHashAuxInfo, NULL, &hashSize);
1937 PBYTE hash = CryptMemAlloc(hashSize);
1941 ret = CryptSignCertificate(hCryptProv, dwKeySpec,
1942 dwCertEncodingType, encoded, encodedSize,
1943 pSignatureAlgorithm, pvHashAuxInfo, hash, &hashSize);
1946 CERT_SIGNED_CONTENT_INFO info = { { 0 } };
1948 info.ToBeSigned.cbData = encodedSize;
1949 info.ToBeSigned.pbData = encoded;
1950 memcpy(&info.SignatureAlgorithm,
1951 pSignatureAlgorithm,
1952 sizeof(info.SignatureAlgorithm));
1953 info.Signature.cbData = hashSize;
1954 info.Signature.pbData = hash;
1955 info.Signature.cUnusedBits = 0;
1956 ret = CryptEncodeObject(dwCertEncodingType,
1957 X509_CERT, &info, pbEncoded, pcbEncoded);
1963 CryptMemFree(encoded);
1969 BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV_LEGACY hCryptProv,
1970 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
1971 PCERT_PUBLIC_KEY_INFO pPublicKey)
1973 return CryptVerifyCertificateSignatureEx(hCryptProv, dwCertEncodingType,
1974 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, (void *)pbEncoded,
1975 CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
1978 static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv,
1979 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pubKeyInfo,
1980 const CERT_SIGNED_CONTENT_INFO *signedCert)
1984 PCCRYPT_OID_INFO info;
1985 ALG_ID pubKeyID, hashID;
1987 info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1988 signedCert->SignatureAlgorithm.pszObjId, 0);
1989 if (!info || info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID)
1991 SetLastError(NTE_BAD_ALGID);
1994 hashID = info->u.Algid;
1995 if (info->ExtraInfo.cbData >= sizeof(ALG_ID))
1996 pubKeyID = *(ALG_ID *)info->ExtraInfo.pbData;
1999 /* Load the default provider if necessary */
2001 hCryptProv = CRYPT_GetDefaultProvider();
2002 ret = CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType,
2003 pubKeyInfo, pubKeyID, 0, NULL, &key);
2008 ret = CryptCreateHash(hCryptProv, hashID, 0, 0, &hash);
2011 ret = CryptHashData(hash, signedCert->ToBeSigned.pbData,
2012 signedCert->ToBeSigned.cbData, 0);
2014 ret = CryptVerifySignatureW(hash, signedCert->Signature.pbData,
2015 signedCert->Signature.cbData, key, NULL, 0);
2016 CryptDestroyHash(hash);
2018 CryptDestroyKey(key);
2023 BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV_LEGACY hCryptProv,
2024 DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
2025 DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
2028 CRYPT_DATA_BLOB subjectBlob;
2030 TRACE("(%08lx, %d, %d, %p, %d, %p, %08x, %p)\n", hCryptProv,
2031 dwCertEncodingType, dwSubjectType, pvSubject, dwIssuerType, pvIssuer,
2032 dwFlags, pvReserved);
2034 switch (dwSubjectType)
2036 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB:
2038 PCRYPT_DATA_BLOB blob = pvSubject;
2040 subjectBlob.pbData = blob->pbData;
2041 subjectBlob.cbData = blob->cbData;
2044 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT:
2046 PCERT_CONTEXT context = pvSubject;
2048 subjectBlob.pbData = context->pbCertEncoded;
2049 subjectBlob.cbData = context->cbCertEncoded;
2052 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL:
2054 PCRL_CONTEXT context = pvSubject;
2056 subjectBlob.pbData = context->pbCrlEncoded;
2057 subjectBlob.cbData = context->cbCrlEncoded;
2061 SetLastError(E_INVALIDARG);
2067 PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
2070 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
2071 subjectBlob.pbData, subjectBlob.cbData,
2072 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
2073 &signedCert, &size);
2076 switch (dwIssuerType)
2078 case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY:
2079 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
2080 dwCertEncodingType, pvIssuer,
2083 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT:
2084 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
2086 &((PCCERT_CONTEXT)pvIssuer)->pCertInfo->SubjectPublicKeyInfo,
2089 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN:
2090 FIXME("CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: stub\n");
2093 case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL:
2096 SetLastError(E_INVALIDARG);
2101 FIXME("unimplemented for NULL signer\n");
2102 SetLastError(E_INVALIDARG);
2107 SetLastError(E_INVALIDARG);
2110 LocalFree(signedCert);
2116 BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags,
2117 PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage)
2119 PCERT_ENHKEY_USAGE usage = NULL;
2123 if (!pCertContext || !pcbUsage)
2125 SetLastError(ERROR_INVALID_PARAMETER);
2129 TRACE("(%p, %08x, %p, %d)\n", pCertContext, dwFlags, pUsage, *pcbUsage);
2131 if (!(dwFlags & CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG))
2135 if (CertGetCertificateContextProperty(pCertContext,
2136 CERT_ENHKEY_USAGE_PROP_ID, NULL, &propSize))
2138 LPBYTE buf = CryptMemAlloc(propSize);
2142 if (CertGetCertificateContextProperty(pCertContext,
2143 CERT_ENHKEY_USAGE_PROP_ID, buf, &propSize))
2145 ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
2146 X509_ENHANCED_KEY_USAGE, buf, propSize,
2147 CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
2153 if (!usage && !(dwFlags & CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG))
2155 PCERT_EXTENSION ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
2156 pCertContext->pCertInfo->cExtension,
2157 pCertContext->pCertInfo->rgExtension);
2161 ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
2162 X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
2163 CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
2168 /* If a particular location is specified, this should fail. Otherwise
2169 * it should succeed with an empty usage. (This is true on Win2k and
2170 * later, which we emulate.)
2174 SetLastError(CRYPT_E_NOT_FOUND);
2178 bytesNeeded = sizeof(CERT_ENHKEY_USAGE);
2184 *pcbUsage = bytesNeeded;
2185 else if (*pcbUsage < bytesNeeded)
2187 SetLastError(ERROR_MORE_DATA);
2188 *pcbUsage = bytesNeeded;
2193 *pcbUsage = bytesNeeded;
2197 LPSTR nextOID = (LPSTR)((LPBYTE)pUsage +
2198 sizeof(CERT_ENHKEY_USAGE) +
2199 usage->cUsageIdentifier * sizeof(LPSTR));
2201 pUsage->cUsageIdentifier = usage->cUsageIdentifier;
2202 pUsage->rgpszUsageIdentifier = (LPSTR *)((LPBYTE)pUsage +
2203 sizeof(CERT_ENHKEY_USAGE));
2204 for (i = 0; i < usage->cUsageIdentifier; i++)
2206 pUsage->rgpszUsageIdentifier[i] = nextOID;
2207 strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
2208 nextOID += strlen(nextOID) + 1;
2212 pUsage->cUsageIdentifier = 0;
2217 TRACE("returning %d\n", ret);
2221 BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext,
2222 PCERT_ENHKEY_USAGE pUsage)
2226 TRACE("(%p, %p)\n", pCertContext, pUsage);
2230 CRYPT_DATA_BLOB blob = { 0, NULL };
2232 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
2233 pUsage, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData, &blob.cbData);
2236 ret = CertSetCertificateContextProperty(pCertContext,
2237 CERT_ENHKEY_USAGE_PROP_ID, 0, &blob);
2238 LocalFree(blob.pbData);
2242 ret = CertSetCertificateContextProperty(pCertContext,
2243 CERT_ENHKEY_USAGE_PROP_ID, 0, NULL);
2247 BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
2248 LPCSTR pszUsageIdentifier)
2253 TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
2255 if (CertGetEnhancedKeyUsage(pCertContext,
2256 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size))
2258 PCERT_ENHKEY_USAGE usage = CryptMemAlloc(size);
2262 ret = CertGetEnhancedKeyUsage(pCertContext,
2263 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size);
2267 BOOL exists = FALSE;
2269 /* Make sure usage doesn't already exist */
2270 for (i = 0; !exists && i < usage->cUsageIdentifier; i++)
2272 if (!strcmp(usage->rgpszUsageIdentifier[i],
2273 pszUsageIdentifier))
2278 PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size +
2279 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
2285 newUsage->rgpszUsageIdentifier = (LPSTR *)
2286 ((LPBYTE)newUsage + sizeof(CERT_ENHKEY_USAGE));
2287 nextOID = (LPSTR)((LPBYTE)newUsage->rgpszUsageIdentifier
2288 + (usage->cUsageIdentifier + 1) * sizeof(LPSTR));
2289 for (i = 0; i < usage->cUsageIdentifier; i++)
2291 newUsage->rgpszUsageIdentifier[i] = nextOID;
2292 strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
2293 nextOID += strlen(nextOID) + 1;
2295 newUsage->rgpszUsageIdentifier[i] = nextOID;
2296 strcpy(nextOID, pszUsageIdentifier);
2297 newUsage->cUsageIdentifier = i + 1;
2298 ret = CertSetEnhancedKeyUsage(pCertContext, newUsage);
2299 CryptMemFree(newUsage);
2305 CryptMemFree(usage);
2312 PCERT_ENHKEY_USAGE usage = CryptMemAlloc(sizeof(CERT_ENHKEY_USAGE) +
2313 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
2317 usage->rgpszUsageIdentifier =
2318 (LPSTR *)((LPBYTE)usage + sizeof(CERT_ENHKEY_USAGE));
2319 usage->rgpszUsageIdentifier[0] = (LPSTR)((LPBYTE)usage +
2320 sizeof(CERT_ENHKEY_USAGE) + sizeof(LPSTR));
2321 strcpy(usage->rgpszUsageIdentifier[0], pszUsageIdentifier);
2322 usage->cUsageIdentifier = 1;
2323 ret = CertSetEnhancedKeyUsage(pCertContext, usage);
2324 CryptMemFree(usage);
2332 BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
2333 LPCSTR pszUsageIdentifier)
2337 CERT_ENHKEY_USAGE usage;
2339 TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
2341 size = sizeof(usage);
2342 ret = CertGetEnhancedKeyUsage(pCertContext,
2343 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, &usage, &size);
2344 if (!ret && GetLastError() == ERROR_MORE_DATA)
2346 PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
2350 ret = CertGetEnhancedKeyUsage(pCertContext,
2351 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
2354 if (pUsage->cUsageIdentifier)
2359 for (i = 0; i < pUsage->cUsageIdentifier; i++)
2361 if (!strcmp(pUsage->rgpszUsageIdentifier[i],
2362 pszUsageIdentifier))
2364 if (found && i < pUsage->cUsageIdentifier - 1)
2365 pUsage->rgpszUsageIdentifier[i] =
2366 pUsage->rgpszUsageIdentifier[i + 1];
2368 pUsage->cUsageIdentifier--;
2369 /* Remove the usage if it's empty */
2370 if (pUsage->cUsageIdentifier)
2371 ret = CertSetEnhancedKeyUsage(pCertContext, pUsage);
2373 ret = CertSetEnhancedKeyUsage(pCertContext, NULL);
2376 CryptMemFree(pUsage);
2383 /* it fit in an empty usage, therefore there's nothing to remove */
2395 #define BITS_PER_DWORD (sizeof(DWORD) * 8)
2397 static void CRYPT_SetBitInField(struct BitField *field, DWORD bit)
2399 DWORD indexIndex = bit / BITS_PER_DWORD;
2401 if (indexIndex + 1 > field->cIndexes)
2403 if (field->cIndexes)
2404 field->indexes = CryptMemRealloc(field->indexes,
2405 (indexIndex + 1) * sizeof(DWORD));
2407 field->indexes = CryptMemAlloc(sizeof(DWORD));
2410 field->indexes[indexIndex] = 0;
2411 field->cIndexes = indexIndex + 1;
2415 field->indexes[indexIndex] |= 1 << (bit % BITS_PER_DWORD);
2418 static BOOL CRYPT_IsBitInFieldSet(struct BitField *field, DWORD bit)
2421 DWORD indexIndex = bit / BITS_PER_DWORD;
2423 assert(field->cIndexes);
2424 set = field->indexes[indexIndex] & (1 << (bit % BITS_PER_DWORD));
2428 BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts,
2429 int *cNumOIDs, LPSTR *rghOIDs, DWORD *pcbOIDs)
2432 DWORD i, cbOIDs = 0;
2433 BOOL allUsagesValid = TRUE;
2434 CERT_ENHKEY_USAGE validUsages = { 0, NULL };
2436 TRACE("(%d, %p, %d, %p, %d)\n", cCerts, rghCerts, *cNumOIDs,
2439 for (i = 0; i < cCerts; i++)
2441 CERT_ENHKEY_USAGE usage;
2442 DWORD size = sizeof(usage);
2444 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, &usage, &size);
2445 /* Success is deliberately ignored: it implies all usages are valid */
2446 if (!ret && GetLastError() == ERROR_MORE_DATA)
2448 PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
2450 allUsagesValid = FALSE;
2453 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, pUsage, &size);
2456 if (!validUsages.cUsageIdentifier)
2460 cbOIDs = pUsage->cUsageIdentifier * sizeof(LPSTR);
2461 validUsages.cUsageIdentifier = pUsage->cUsageIdentifier;
2462 for (j = 0; j < validUsages.cUsageIdentifier; j++)
2463 cbOIDs += lstrlenA(pUsage->rgpszUsageIdentifier[j])
2465 validUsages.rgpszUsageIdentifier =
2466 CryptMemAlloc(cbOIDs);
2467 if (validUsages.rgpszUsageIdentifier)
2469 LPSTR nextOID = (LPSTR)
2470 ((LPBYTE)validUsages.rgpszUsageIdentifier +
2471 validUsages.cUsageIdentifier * sizeof(LPSTR));
2473 for (j = 0; j < validUsages.cUsageIdentifier; j++)
2475 validUsages.rgpszUsageIdentifier[j] = nextOID;
2476 lstrcpyA(validUsages.rgpszUsageIdentifier[j],
2477 pUsage->rgpszUsageIdentifier[j]);
2478 nextOID += lstrlenA(nextOID) + 1;
2484 struct BitField validIndexes = { 0, NULL };
2485 DWORD j, k, numRemoved = 0;
2487 /* Merge: build a bitmap of all the indexes of
2488 * validUsages.rgpszUsageIdentifier that are in pUsage.
2490 for (j = 0; j < pUsage->cUsageIdentifier; j++)
2492 for (k = 0; k < validUsages.cUsageIdentifier; k++)
2494 if (!strcmp(pUsage->rgpszUsageIdentifier[j],
2495 validUsages.rgpszUsageIdentifier[k]))
2497 CRYPT_SetBitInField(&validIndexes, k);
2502 /* Merge by removing from validUsages those that are
2503 * not in the bitmap.
2505 for (j = 0; j < validUsages.cUsageIdentifier; j++)
2507 if (!CRYPT_IsBitInFieldSet(&validIndexes, j))
2509 if (j < validUsages.cUsageIdentifier - 1)
2511 memmove(&validUsages.rgpszUsageIdentifier[j],
2512 &validUsages.rgpszUsageIdentifier[j +
2514 (validUsages.cUsageIdentifier - numRemoved
2515 - j - 1) * sizeof(LPSTR));
2517 validUsages.rgpszUsageIdentifier[j]) + 1 +
2519 validUsages.cUsageIdentifier--;
2523 validUsages.cUsageIdentifier--;
2526 CryptMemFree(validIndexes.indexes);
2529 CryptMemFree(pUsage);
2541 *cNumOIDs = validUsages.cUsageIdentifier;
2544 else if (*pcbOIDs < cbOIDs)
2547 SetLastError(ERROR_MORE_DATA);
2552 LPSTR nextOID = (LPSTR)((LPBYTE)rghOIDs +
2553 validUsages.cUsageIdentifier * sizeof(LPSTR));
2556 for (i = 0; i < validUsages.cUsageIdentifier; i++)
2558 rghOIDs[i] = nextOID;
2559 lstrcpyA(nextOID, validUsages.rgpszUsageIdentifier[i]);
2560 nextOID += lstrlenA(nextOID) + 1;
2564 CryptMemFree(validUsages.rgpszUsageIdentifier);
2565 TRACE("cNumOIDs: %d\n", *cNumOIDs);
2566 TRACE("returning %d\n", ret);
2570 /* Sets the CERT_KEY_PROV_INFO_PROP_ID property of context from pInfo, or, if
2571 * pInfo is NULL, from the attributes of hProv.
2573 static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context,
2574 const CRYPT_KEY_PROV_INFO *pInfo, HCRYPTPROV hProv)
2576 CRYPT_KEY_PROV_INFO info = { 0 };
2584 ret = CryptGetProvParam(hProv, PP_CONTAINER, NULL, &size, 0);
2587 LPSTR szContainer = CryptMemAlloc(size);
2591 ret = CryptGetProvParam(hProv, PP_CONTAINER,
2592 (BYTE *)szContainer, &size, 0);
2595 len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
2599 info.pwszContainerName = CryptMemAlloc(len *
2601 len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
2602 info.pwszContainerName, len);
2605 CryptMemFree(szContainer);
2608 ret = CryptGetProvParam(hProv, PP_NAME, NULL, &size, 0);
2611 LPSTR szProvider = CryptMemAlloc(size);
2615 ret = CryptGetProvParam(hProv, PP_NAME, (BYTE *)szProvider,
2619 len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
2623 info.pwszProvName = CryptMemAlloc(len *
2625 len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
2626 info.pwszProvName, len);
2629 CryptMemFree(szProvider);
2632 size = sizeof(info.dwKeySpec);
2633 /* in case no CRYPT_KEY_PROV_INFO given,
2634 * we always use AT_SIGNATURE key spec
2636 info.dwKeySpec = AT_SIGNATURE;
2637 size = sizeof(info.dwProvType);
2638 ret = CryptGetProvParam(hProv, PP_PROVTYPE, (LPBYTE)&info.dwProvType,
2641 info.dwProvType = PROV_RSA_FULL;
2645 ret = CertSetCertificateContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID,
2650 CryptMemFree(info.pwszContainerName);
2651 CryptMemFree(info.pwszProvName);
2655 /* Creates a signed certificate context from the unsigned, encoded certificate
2656 * in blob, using the crypto provider hProv and the signature algorithm sigAlgo.
2658 static PCCERT_CONTEXT CRYPT_CreateSignedCert(const CRYPT_DER_BLOB *blob,
2659 HCRYPTPROV hProv, DWORD dwKeySpec, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo)
2661 PCCERT_CONTEXT context = NULL;
2665 ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
2666 blob->pbData, blob->cbData, sigAlgo, NULL, NULL, &sigSize);
2669 LPBYTE sig = CryptMemAlloc(sigSize);
2671 ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
2672 blob->pbData, blob->cbData, sigAlgo, NULL, sig, &sigSize);
2675 CERT_SIGNED_CONTENT_INFO signedInfo;
2676 BYTE *encodedSignedCert = NULL;
2677 DWORD encodedSignedCertSize = 0;
2679 signedInfo.ToBeSigned.cbData = blob->cbData;
2680 signedInfo.ToBeSigned.pbData = blob->pbData;
2681 memcpy(&signedInfo.SignatureAlgorithm, sigAlgo,
2682 sizeof(signedInfo.SignatureAlgorithm));
2683 signedInfo.Signature.cbData = sigSize;
2684 signedInfo.Signature.pbData = sig;
2685 signedInfo.Signature.cUnusedBits = 0;
2686 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT,
2687 &signedInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
2688 &encodedSignedCert, &encodedSignedCertSize);
2691 context = CertCreateCertificateContext(X509_ASN_ENCODING,
2692 encodedSignedCert, encodedSignedCertSize);
2693 LocalFree(encodedSignedCert);
2701 /* Copies data from the parameters into info, where:
2702 * pSerialNumber: The serial number. Must not be NULL.
2703 * pSubjectIssuerBlob: Specifies both the subject and issuer for info.
2705 * pSignatureAlgorithm: Optional.
2706 * pStartTime: The starting time of the certificate. If NULL, the current
2707 * system time is used.
2708 * pEndTime: The ending time of the certificate. If NULL, one year past the
2709 * starting time is used.
2710 * pubKey: The public key of the certificate. Must not be NULL.
2711 * pExtensions: Extensions to be included with the certificate. Optional.
2713 static void CRYPT_MakeCertInfo(PCERT_INFO info, const CRYPT_DATA_BLOB *pSerialNumber,
2714 const CERT_NAME_BLOB *pSubjectIssuerBlob,
2715 const CRYPT_ALGORITHM_IDENTIFIER *pSignatureAlgorithm, const SYSTEMTIME *pStartTime,
2716 const SYSTEMTIME *pEndTime, const CERT_PUBLIC_KEY_INFO *pubKey,
2717 const CERT_EXTENSIONS *pExtensions)
2719 static CHAR oid[] = szOID_RSA_SHA1RSA;
2722 assert(pSerialNumber);
2723 assert(pSubjectIssuerBlob);
2726 info->dwVersion = CERT_V3;
2727 info->SerialNumber.cbData = pSerialNumber->cbData;
2728 info->SerialNumber.pbData = pSerialNumber->pbData;
2729 if (pSignatureAlgorithm)
2730 memcpy(&info->SignatureAlgorithm, pSignatureAlgorithm,
2731 sizeof(info->SignatureAlgorithm));
2734 info->SignatureAlgorithm.pszObjId = oid;
2735 info->SignatureAlgorithm.Parameters.cbData = 0;
2736 info->SignatureAlgorithm.Parameters.pbData = NULL;
2738 info->Issuer.cbData = pSubjectIssuerBlob->cbData;
2739 info->Issuer.pbData = pSubjectIssuerBlob->pbData;
2741 SystemTimeToFileTime(pStartTime, &info->NotBefore);
2743 GetSystemTimeAsFileTime(&info->NotBefore);
2745 SystemTimeToFileTime(pEndTime, &info->NotAfter);
2750 if (FileTimeToSystemTime(&info->NotBefore, &endTime))
2753 SystemTimeToFileTime(&endTime, &info->NotAfter);
2756 info->Subject.cbData = pSubjectIssuerBlob->cbData;
2757 info->Subject.pbData = pSubjectIssuerBlob->pbData;
2758 memcpy(&info->SubjectPublicKeyInfo, pubKey,
2759 sizeof(info->SubjectPublicKeyInfo));
2762 info->cExtension = pExtensions->cExtension;
2763 info->rgExtension = pExtensions->rgExtension;
2767 info->cExtension = 0;
2768 info->rgExtension = NULL;
2772 typedef RPC_STATUS (RPC_ENTRY *UuidCreateFunc)(UUID *);
2773 typedef RPC_STATUS (RPC_ENTRY *UuidToStringFunc)(UUID *, unsigned char **);
2774 typedef RPC_STATUS (RPC_ENTRY *RpcStringFreeFunc)(unsigned char **);
2776 static HCRYPTPROV CRYPT_CreateKeyProv(void)
2778 HCRYPTPROV hProv = 0;
2779 HMODULE rpcrt = LoadLibraryA("rpcrt4");
2783 UuidCreateFunc uuidCreate = (UuidCreateFunc)GetProcAddress(rpcrt,
2785 UuidToStringFunc uuidToString = (UuidToStringFunc)GetProcAddress(rpcrt,
2787 RpcStringFreeFunc rpcStringFree = (RpcStringFreeFunc)GetProcAddress(
2788 rpcrt, "RpcStringFreeA");
2790 if (uuidCreate && uuidToString && rpcStringFree)
2793 RPC_STATUS status = uuidCreate(&uuid);
2795 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY)
2797 unsigned char *uuidStr;
2799 status = uuidToString(&uuid, &uuidStr);
2800 if (status == RPC_S_OK)
2802 BOOL ret = CryptAcquireContextA(&hProv, (LPCSTR)uuidStr,
2803 MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_NEWKEYSET);
2809 ret = CryptGenKey(hProv, AT_SIGNATURE, 0, &key);
2811 CryptDestroyKey(key);
2813 rpcStringFree(&uuidStr);
2822 PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hProv,
2823 PCERT_NAME_BLOB pSubjectIssuerBlob, DWORD dwFlags,
2824 PCRYPT_KEY_PROV_INFO pKeyProvInfo,
2825 PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime,
2826 PSYSTEMTIME pEndTime, PCERT_EXTENSIONS pExtensions)
2828 PCCERT_CONTEXT context = NULL;
2829 BOOL ret, releaseContext = FALSE;
2830 PCERT_PUBLIC_KEY_INFO pubKey = NULL;
2831 DWORD pubKeySize = 0,dwKeySpec = AT_SIGNATURE;
2833 TRACE("(%08lx, %p, %08x, %p, %p, %p, %p, %p)\n", hProv,
2834 pSubjectIssuerBlob, dwFlags, pKeyProvInfo, pSignatureAlgorithm, pStartTime,
2835 pExtensions, pExtensions);
2837 if(!pSubjectIssuerBlob)
2839 SetLastError(ERROR_INVALID_PARAMETER);
2847 hProv = CRYPT_CreateKeyProv();
2848 releaseContext = TRUE;
2850 else if (pKeyProvInfo->dwFlags & CERT_SET_KEY_PROV_HANDLE_PROP_ID)
2852 SetLastError(NTE_BAD_FLAGS);
2858 /* acquire the context using the given information*/
2859 ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
2860 pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
2861 pKeyProvInfo->dwFlags);
2864 if(GetLastError() != NTE_BAD_KEYSET)
2866 /* create the key set */
2867 ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
2868 pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
2869 pKeyProvInfo->dwFlags|CRYPT_NEWKEYSET);
2873 dwKeySpec = pKeyProvInfo->dwKeySpec;
2874 /* check if the key is here */
2875 ret = CryptGetUserKey(hProv,dwKeySpec,&hKey);
2878 if (NTE_NO_KEY == GetLastError())
2879 { /* generate the key */
2880 ret = CryptGenKey(hProv,dwKeySpec,0,&hKey);
2884 CryptReleaseContext(hProv,0);
2885 SetLastError(NTE_BAD_KEYSET);
2889 CryptDestroyKey(hKey);
2890 releaseContext = TRUE;
2893 else if (pKeyProvInfo)
2895 SetLastError(ERROR_INVALID_PARAMETER);
2899 CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING, NULL,
2901 pubKey = CryptMemAlloc(pubKeySize);
2904 ret = CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING,
2905 pubKey, &pubKeySize);
2908 CERT_INFO info = { 0 };
2909 CRYPT_DER_BLOB blob = { 0, NULL };
2911 CRYPT_DATA_BLOB serialBlob = { sizeof(serial), serial };
2913 CryptGenRandom(hProv, sizeof(serial), serial);
2914 CRYPT_MakeCertInfo(&info, &serialBlob, pSubjectIssuerBlob,
2915 pSignatureAlgorithm, pStartTime, pEndTime, pubKey, pExtensions);
2916 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
2917 &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData,
2921 if (!(dwFlags & CERT_CREATE_SELFSIGN_NO_SIGN))
2922 context = CRYPT_CreateSignedCert(&blob, hProv,dwKeySpec,
2923 &info.SignatureAlgorithm);
2925 context = CertCreateCertificateContext(X509_ASN_ENCODING,
2926 blob.pbData, blob.cbData);
2927 if (context && !(dwFlags & CERT_CREATE_SELFSIGN_NO_KEY_INFO))
2928 CertContext_SetKeyProvInfo(context, pKeyProvInfo, hProv);
2929 LocalFree(blob.pbData);
2932 CryptMemFree(pubKey);
2935 CryptReleaseContext(hProv, 0);
2939 BOOL WINAPI CertVerifyCTLUsage(DWORD dwEncodingType, DWORD dwSubjectType,
2940 void *pvSubject, PCTL_USAGE pSubjectUsage, DWORD dwFlags,
2941 PCTL_VERIFY_USAGE_PARA pVerifyUsagePara,
2942 PCTL_VERIFY_USAGE_STATUS pVerifyUsageStatus)
2944 FIXME("(0x%x, %d, %p, %p, 0x%x, %p, %p): stub\n", dwEncodingType,
2945 dwSubjectType, pvSubject, pSubjectUsage, dwFlags, pVerifyUsagePara,
2946 pVerifyUsageStatus);
2947 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);