crypt32: CryptAcquireCertificatePrivateKey should look up certificate in the user...
[wine.git] / dlls / crypt32 / cert.c
blob02693b96d0248d7a21c40e3d829e420fb5ac3600
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 "ntstatus.h"
25 #define WIN32_NO_STATUS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winternl.h"
29 #define CRYPT_OID_INFO_HAS_EXTRA_FIELDS
30 #include "wincrypt.h"
31 #include "snmp.h"
32 #include "bcrypt.h"
33 #include "winnls.h"
34 #include "rpc.h"
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37 #include "crypt32_private.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
41 /* Internal version of CertGetCertificateContextProperty that gets properties
42 * directly from the context (or the context it's linked to, depending on its
43 * type.) Doesn't handle special-case properties, since they are handled by
44 * CertGetCertificateContextProperty, and are particular to the store in which
45 * the property exists (which is separate from the context.)
47 static BOOL CertContext_GetProperty(cert_t *cert, DWORD dwPropId,
48 void *pvData, DWORD *pcbData);
50 /* Internal version of CertSetCertificateContextProperty that sets properties
51 * directly on the context (or the context it's linked to, depending on its
52 * type.) Doesn't handle special cases, since they're handled by
53 * CertSetCertificateContextProperty anyway.
55 static BOOL CertContext_SetProperty(cert_t *cert, DWORD dwPropId,
56 DWORD dwFlags, const void *pvData);
58 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
59 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
60 DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
62 PCCERT_CONTEXT cert = CertCreateCertificateContext(dwCertEncodingType,
63 pbCertEncoded, cbCertEncoded);
64 BOOL ret;
66 TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore, dwCertEncodingType,
67 pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
69 if (cert)
71 ret = CertAddCertificateContextToStore(hCertStore, cert,
72 dwAddDisposition, ppCertContext);
73 CertFreeCertificateContext(cert);
75 else
76 ret = FALSE;
77 return ret;
80 BOOL WINAPI CertAddEncodedCertificateToSystemStoreA(LPCSTR pszCertStoreName,
81 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
83 HCERTSTORE store;
84 BOOL ret = FALSE;
86 TRACE("(%s, %p, %d)\n", debugstr_a(pszCertStoreName), pbCertEncoded,
87 cbCertEncoded);
89 store = CertOpenSystemStoreA(0, pszCertStoreName);
90 if (store)
92 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
93 pbCertEncoded, cbCertEncoded, CERT_STORE_ADD_USE_EXISTING, NULL);
94 CertCloseStore(store, 0);
96 return ret;
99 BOOL WINAPI CertAddEncodedCertificateToSystemStoreW(LPCWSTR pszCertStoreName,
100 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
102 HCERTSTORE store;
103 BOOL ret = FALSE;
105 TRACE("(%s, %p, %d)\n", debugstr_w(pszCertStoreName), pbCertEncoded,
106 cbCertEncoded);
108 store = CertOpenSystemStoreW(0, pszCertStoreName);
109 if (store)
111 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
112 pbCertEncoded, cbCertEncoded, CERT_STORE_ADD_USE_EXISTING, NULL);
113 CertCloseStore(store, 0);
115 return ret;
118 static const context_vtbl_t cert_vtbl;
120 static void Cert_free(context_t *context)
122 cert_t *cert = (cert_t*)context;
124 CryptMemFree(cert->ctx.pbCertEncoded);
125 LocalFree(cert->ctx.pCertInfo);
128 static context_t *Cert_clone(context_t *context, WINECRYPT_CERTSTORE *store, BOOL use_link)
130 cert_t *cert;
132 if(use_link) {
133 cert = (cert_t*)Context_CreateLinkContext(sizeof(CERT_CONTEXT), context, store);
134 if(!cert)
135 return NULL;
136 }else {
137 const cert_t *cloned = (const cert_t*)context;
138 DWORD size = 0;
139 BOOL res;
141 cert = (cert_t*)Context_CreateDataContext(sizeof(CERT_CONTEXT), &cert_vtbl, store);
142 if(!cert)
143 return NULL;
145 Context_CopyProperties(&cert->ctx, &cloned->ctx);
147 cert->ctx.dwCertEncodingType = cloned->ctx.dwCertEncodingType;
148 cert->ctx.pbCertEncoded = CryptMemAlloc(cloned->ctx.cbCertEncoded);
149 memcpy(cert->ctx.pbCertEncoded, cloned->ctx.pbCertEncoded, cloned->ctx.cbCertEncoded);
150 cert->ctx.cbCertEncoded = cloned->ctx.cbCertEncoded;
152 /* FIXME: We don't need to decode the object here, we could just clone cert info. */
153 res = CryptDecodeObjectEx(cert->ctx.dwCertEncodingType, X509_CERT_TO_BE_SIGNED,
154 cert->ctx.pbCertEncoded, cert->ctx.cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL,
155 &cert->ctx.pCertInfo, &size);
156 if(!res) {
157 CertFreeCertificateContext(&cert->ctx);
158 return NULL;
162 cert->ctx.hCertStore = store;
163 return &cert->base;
166 static const context_vtbl_t cert_vtbl = {
167 Cert_free,
168 Cert_clone
171 static BOOL add_cert_to_store(WINECRYPT_CERTSTORE *store, const CERT_CONTEXT *cert,
172 DWORD add_disposition, BOOL use_link, PCCERT_CONTEXT *ret_context)
174 const CERT_CONTEXT *existing = NULL;
175 BOOL ret = TRUE, inherit_props = FALSE;
176 context_t *new_context = NULL;
178 switch (add_disposition)
180 case CERT_STORE_ADD_ALWAYS:
181 break;
182 case CERT_STORE_ADD_NEW:
183 case CERT_STORE_ADD_REPLACE_EXISTING:
184 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
185 case CERT_STORE_ADD_USE_EXISTING:
186 case CERT_STORE_ADD_NEWER:
187 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES:
189 BYTE hashToAdd[20];
190 DWORD size = sizeof(hashToAdd);
192 ret = CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID,
193 hashToAdd, &size);
194 if (ret)
196 CRYPT_HASH_BLOB blob = { sizeof(hashToAdd), hashToAdd };
198 existing = CertFindCertificateInStore(store, cert->dwCertEncodingType, 0,
199 CERT_FIND_SHA1_HASH, &blob, NULL);
201 break;
203 default:
204 FIXME("Unimplemented add disposition %d\n", add_disposition);
205 SetLastError(E_INVALIDARG);
206 return FALSE;
209 switch (add_disposition)
211 case CERT_STORE_ADD_ALWAYS:
212 break;
213 case CERT_STORE_ADD_NEW:
214 if (existing)
216 TRACE("found matching certificate, not adding\n");
217 SetLastError(CRYPT_E_EXISTS);
218 return FALSE;
220 break;
221 case CERT_STORE_ADD_REPLACE_EXISTING:
222 break;
223 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
224 if (use_link)
225 FIXME("CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES: semi-stub for links\n");
226 if (existing)
227 inherit_props = TRUE;
228 break;
229 case CERT_STORE_ADD_USE_EXISTING:
230 if(use_link)
231 FIXME("CERT_STORE_ADD_USE_EXISTING: semi-stub for links\n");
232 if (existing)
234 Context_CopyProperties(existing, cert);
235 if (ret_context)
236 *ret_context = CertDuplicateCertificateContext(existing);
237 return TRUE;
239 break;
240 case CERT_STORE_ADD_NEWER:
241 if (existing && CompareFileTime(&existing->pCertInfo->NotBefore, &cert->pCertInfo->NotBefore) >= 0)
243 TRACE("existing certificate is newer, not adding\n");
244 SetLastError(CRYPT_E_EXISTS);
245 return FALSE;
247 break;
248 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES:
249 if (existing)
251 if (CompareFileTime(&existing->pCertInfo->NotBefore, &cert->pCertInfo->NotBefore) >= 0)
253 TRACE("existing certificate is newer, not adding\n");
254 SetLastError(CRYPT_E_EXISTS);
255 return FALSE;
257 inherit_props = TRUE;
259 break;
262 /* FIXME: We have tests that this works, but what should we really do in this case? */
263 if(!store) {
264 if(ret_context)
265 *ret_context = CertDuplicateCertificateContext(cert);
266 return TRUE;
269 ret = store->vtbl->certs.addContext(store, context_from_ptr(cert), existing ? context_from_ptr(existing) : NULL,
270 (ret_context || inherit_props) ? &new_context : NULL, use_link);
271 if(!ret)
272 return FALSE;
274 if(inherit_props)
275 Context_CopyProperties(context_ptr(new_context), existing);
277 if(ret_context)
278 *ret_context = context_ptr(new_context);
279 else if(new_context)
280 Context_Release(new_context);
282 TRACE("returning %d\n", ret);
283 return ret;
286 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore, PCCERT_CONTEXT pCertContext,
287 DWORD dwAddDisposition, PCCERT_CONTEXT *ppStoreContext)
289 WINECRYPT_CERTSTORE *store = hCertStore;
291 TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCertContext, dwAddDisposition, ppStoreContext);
293 return add_cert_to_store(store, pCertContext, dwAddDisposition, FALSE, ppStoreContext);
296 BOOL WINAPI CertAddCertificateLinkToStore(HCERTSTORE hCertStore,
297 PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
298 PCCERT_CONTEXT *ppCertContext)
300 static int calls;
301 WINECRYPT_CERTSTORE *store = (WINECRYPT_CERTSTORE*)hCertStore;
303 if (!(calls++))
304 FIXME("(%p, %p, %08x, %p): semi-stub\n", hCertStore, pCertContext,
305 dwAddDisposition, ppCertContext);
306 if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
307 return FALSE;
308 if (store->type == StoreTypeCollection)
310 SetLastError(E_INVALIDARG);
311 return FALSE;
313 return add_cert_to_store(hCertStore, pCertContext, dwAddDisposition, TRUE, ppCertContext);
316 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
317 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
319 cert_t *cert = NULL;
320 BYTE *data = NULL;
321 BOOL ret;
322 PCERT_INFO certInfo = NULL;
323 DWORD size = 0;
325 TRACE("(%08x, %p, %d)\n", dwCertEncodingType, pbCertEncoded,
326 cbCertEncoded);
328 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
330 SetLastError(E_INVALIDARG);
331 return NULL;
334 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT_TO_BE_SIGNED,
335 pbCertEncoded, cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL,
336 &certInfo, &size);
337 if (!ret)
338 return NULL;
340 cert = (cert_t*)Context_CreateDataContext(sizeof(CERT_CONTEXT), &cert_vtbl, &empty_store);
341 if (!cert)
342 return NULL;
343 data = CryptMemAlloc(cbCertEncoded);
344 if (!data)
346 Context_Release(&cert->base);
347 return NULL;
350 memcpy(data, pbCertEncoded, cbCertEncoded);
351 cert->ctx.dwCertEncodingType = dwCertEncodingType;
352 cert->ctx.pbCertEncoded = data;
353 cert->ctx.cbCertEncoded = cbCertEncoded;
354 cert->ctx.pCertInfo = certInfo;
355 cert->ctx.hCertStore = &empty_store;
357 return &cert->ctx;
360 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(PCCERT_CONTEXT pCertContext)
362 TRACE("(%p)\n", pCertContext);
364 if (!pCertContext)
365 return NULL;
367 Context_AddRef(&cert_from_ptr(pCertContext)->base);
368 return pCertContext;
371 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
373 TRACE("(%p)\n", pCertContext);
375 if (pCertContext)
376 Context_Release(&cert_from_ptr(pCertContext)->base);
377 return TRUE;
380 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
381 DWORD dwPropId)
383 cert_t *cert = cert_from_ptr(pCertContext);
384 DWORD ret;
386 TRACE("(%p, %d)\n", pCertContext, dwPropId);
388 if (cert->base.properties)
389 ret = ContextPropertyList_EnumPropIDs(cert->base.properties, dwPropId);
390 else
391 ret = 0;
392 return ret;
395 static BOOL CertContext_GetHashProp(cert_t *cert, DWORD dwPropId,
396 ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
397 DWORD *pcbData)
399 BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
400 pcbData);
401 if (ret && pvData)
403 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
405 ret = CertContext_SetProperty(cert, dwPropId, 0, &blob);
407 return ret;
410 static BOOL CertContext_CopyParam(void *pvData, DWORD *pcbData, const void *pb,
411 DWORD cb)
413 BOOL ret = TRUE;
415 if (!pvData)
416 *pcbData = cb;
417 else if (*pcbData < cb)
419 SetLastError(ERROR_MORE_DATA);
420 *pcbData = cb;
421 ret = FALSE;
423 else
425 memcpy(pvData, pb, cb);
426 *pcbData = cb;
428 return ret;
431 static BOOL CertContext_GetProperty(cert_t *cert, DWORD dwPropId,
432 void *pvData, DWORD *pcbData)
434 BOOL ret;
435 CRYPT_DATA_BLOB blob;
437 TRACE("(%p, %d, %p, %p)\n", cert, dwPropId, pvData, pcbData);
439 if (cert->base.properties)
440 ret = ContextPropertyList_FindProperty(cert->base.properties, dwPropId, &blob);
441 else
442 ret = FALSE;
443 if (ret)
444 ret = CertContext_CopyParam(pvData, pcbData, blob.pbData, blob.cbData);
445 else
447 /* Implicit properties */
448 switch (dwPropId)
450 case CERT_SHA1_HASH_PROP_ID:
451 ret = CertContext_GetHashProp(cert, dwPropId, CALG_SHA1,
452 cert->ctx.pbCertEncoded, cert->ctx.cbCertEncoded, pvData,
453 pcbData);
454 break;
455 case CERT_MD5_HASH_PROP_ID:
456 ret = CertContext_GetHashProp(cert, dwPropId, CALG_MD5,
457 cert->ctx.pbCertEncoded, cert->ctx.cbCertEncoded, pvData,
458 pcbData);
459 break;
460 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
461 ret = CertContext_GetHashProp(cert, dwPropId, CALG_MD5,
462 cert->ctx.pCertInfo->Subject.pbData,
463 cert->ctx.pCertInfo->Subject.cbData,
464 pvData, pcbData);
465 break;
466 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
467 ret = CertContext_GetHashProp(cert, dwPropId, CALG_MD5,
468 cert->ctx.pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
469 cert->ctx.pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
470 pvData, pcbData);
471 break;
472 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
473 ret = CertContext_GetHashProp(cert, dwPropId, CALG_MD5,
474 cert->ctx.pCertInfo->SerialNumber.pbData,
475 cert->ctx.pCertInfo->SerialNumber.cbData,
476 pvData, pcbData);
477 break;
478 case CERT_SIGNATURE_HASH_PROP_ID:
479 ret = CryptHashToBeSigned(0, cert->ctx.dwCertEncodingType,
480 cert->ctx.pbCertEncoded, cert->ctx.cbCertEncoded, pvData,
481 pcbData);
482 if (ret && pvData)
484 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
486 ret = CertContext_SetProperty(cert, dwPropId, 0, &blob);
488 break;
489 case CERT_KEY_IDENTIFIER_PROP_ID:
491 PCERT_EXTENSION ext = CertFindExtension(
492 szOID_SUBJECT_KEY_IDENTIFIER, cert->ctx.pCertInfo->cExtension,
493 cert->ctx.pCertInfo->rgExtension);
495 if (ext)
497 CRYPT_DATA_BLOB value;
498 DWORD size = sizeof(value);
500 ret = CryptDecodeObjectEx(X509_ASN_ENCODING,
501 szOID_SUBJECT_KEY_IDENTIFIER, ext->Value.pbData,
502 ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &value,
503 &size);
504 if (ret)
506 ret = CertContext_CopyParam(pvData, pcbData, value.pbData,
507 value.cbData);
508 CertContext_SetProperty(cert, dwPropId, 0, &value);
511 else
512 SetLastError(ERROR_INVALID_DATA);
513 break;
515 default:
516 SetLastError(CRYPT_E_NOT_FOUND);
519 TRACE("returning %d\n", ret);
520 return ret;
523 void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info)
525 DWORD i, containerLen, provNameLen;
526 LPBYTE data = (LPBYTE)info + sizeof(CRYPT_KEY_PROV_INFO);
528 info->pwszContainerName = (LPWSTR)data;
529 containerLen = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
530 data += containerLen;
532 info->pwszProvName = (LPWSTR)data;
533 provNameLen = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
534 data += provNameLen;
536 if (info->cProvParam)
538 info->rgProvParam = (PCRYPT_KEY_PROV_PARAM)data;
539 data += info->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
541 for (i = 0; i < info->cProvParam; i++)
543 info->rgProvParam[i].pbData = data;
544 data += info->rgProvParam[i].cbData;
547 else
548 info->rgProvParam = NULL;
551 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
552 DWORD dwPropId, void *pvData, DWORD *pcbData)
554 cert_t *cert = cert_from_ptr(pCertContext);
555 BOOL ret;
557 TRACE("(%p, %d, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
559 switch (dwPropId)
561 case 0:
562 case CERT_CERT_PROP_ID:
563 case CERT_CRL_PROP_ID:
564 case CERT_CTL_PROP_ID:
565 SetLastError(E_INVALIDARG);
566 ret = FALSE;
567 break;
568 case CERT_ACCESS_STATE_PROP_ID:
569 ret = CertGetStoreProperty(cert->ctx.hCertStore, dwPropId, pvData, pcbData);
570 break;
571 case CERT_KEY_PROV_HANDLE_PROP_ID:
573 CERT_KEY_CONTEXT keyContext;
574 DWORD size = sizeof(keyContext);
576 ret = CertContext_GetProperty(cert,
577 CERT_KEY_CONTEXT_PROP_ID, &keyContext, &size);
578 if (ret)
579 ret = CertContext_CopyParam(pvData, pcbData, &keyContext.hCryptProv,
580 sizeof(keyContext.hCryptProv));
581 break;
583 case CERT_KEY_PROV_INFO_PROP_ID:
584 ret = CertContext_GetProperty(cert, dwPropId, pvData,
585 pcbData);
586 if (ret && pvData)
587 CRYPT_FixKeyProvInfoPointers(pvData);
588 break;
589 default:
590 ret = CertContext_GetProperty(cert, dwPropId, pvData,
591 pcbData);
594 TRACE("returning %d\n", ret);
595 return ret;
598 /* Copies key provider info from from into to, where to is assumed to be a
599 * contiguous buffer of memory large enough for from and all its associated
600 * data, but whose pointers are uninitialized.
601 * Upon return, to contains a contiguous copy of from, packed in the following
602 * order:
603 * - CRYPT_KEY_PROV_INFO
604 * - pwszContainerName
605 * - pwszProvName
606 * - rgProvParam[0]...
608 static void CRYPT_CopyKeyProvInfo(PCRYPT_KEY_PROV_INFO to,
609 const CRYPT_KEY_PROV_INFO *from)
611 DWORD i;
612 LPBYTE nextData = (LPBYTE)to + sizeof(CRYPT_KEY_PROV_INFO);
614 if (from->pwszContainerName)
616 to->pwszContainerName = (LPWSTR)nextData;
617 lstrcpyW(to->pwszContainerName, from->pwszContainerName);
618 nextData += (lstrlenW(from->pwszContainerName) + 1) * sizeof(WCHAR);
620 else
621 to->pwszContainerName = NULL;
622 if (from->pwszProvName)
624 to->pwszProvName = (LPWSTR)nextData;
625 lstrcpyW(to->pwszProvName, from->pwszProvName);
626 nextData += (lstrlenW(from->pwszProvName) + 1) * sizeof(WCHAR);
628 else
629 to->pwszProvName = NULL;
630 to->dwProvType = from->dwProvType;
631 to->dwFlags = from->dwFlags;
632 to->cProvParam = from->cProvParam;
633 to->rgProvParam = (PCRYPT_KEY_PROV_PARAM)nextData;
634 nextData += to->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
635 to->dwKeySpec = from->dwKeySpec;
636 for (i = 0; i < to->cProvParam; i++)
638 memcpy(&to->rgProvParam[i], &from->rgProvParam[i],
639 sizeof(CRYPT_KEY_PROV_PARAM));
640 to->rgProvParam[i].pbData = nextData;
641 memcpy(to->rgProvParam[i].pbData, from->rgProvParam[i].pbData,
642 from->rgProvParam[i].cbData);
643 nextData += from->rgProvParam[i].cbData;
647 static BOOL CertContext_SetKeyProvInfoProperty(CONTEXT_PROPERTY_LIST *properties,
648 const CRYPT_KEY_PROV_INFO *info)
650 BOOL ret;
651 LPBYTE buf = NULL;
652 DWORD size = sizeof(CRYPT_KEY_PROV_INFO), i, containerSize, provNameSize;
654 if (info->pwszContainerName)
655 containerSize = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
656 else
657 containerSize = 0;
658 if (info->pwszProvName)
659 provNameSize = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
660 else
661 provNameSize = 0;
662 size += containerSize + provNameSize;
663 for (i = 0; i < info->cProvParam; i++)
664 size += sizeof(CRYPT_KEY_PROV_PARAM) + info->rgProvParam[i].cbData;
665 buf = CryptMemAlloc(size);
666 if (buf)
668 CRYPT_CopyKeyProvInfo((PCRYPT_KEY_PROV_INFO)buf, info);
669 ret = ContextPropertyList_SetProperty(properties,
670 CERT_KEY_PROV_INFO_PROP_ID, buf, size);
671 CryptMemFree(buf);
673 else
674 ret = FALSE;
675 return ret;
678 static BOOL CertContext_SetProperty(cert_t *cert, DWORD dwPropId,
679 DWORD dwFlags, const void *pvData)
681 BOOL ret;
683 TRACE("(%p, %d, %08x, %p)\n", cert, dwPropId, dwFlags, pvData);
685 if (!cert->base.properties)
686 ret = FALSE;
687 else
689 switch (dwPropId)
691 case CERT_AUTO_ENROLL_PROP_ID:
692 case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */
693 case CERT_DESCRIPTION_PROP_ID:
694 case CERT_FRIENDLY_NAME_PROP_ID:
695 case CERT_HASH_PROP_ID:
696 case CERT_KEY_IDENTIFIER_PROP_ID:
697 case CERT_MD5_HASH_PROP_ID:
698 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
699 case CERT_PUBKEY_ALG_PARA_PROP_ID:
700 case CERT_PVK_FILE_PROP_ID:
701 case CERT_SIGNATURE_HASH_PROP_ID:
702 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
703 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
704 case CERT_EXTENDED_ERROR_INFO_PROP_ID:
705 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
706 case CERT_ENROLLMENT_PROP_ID:
707 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
708 case CERT_OCSP_RESPONSE_PROP_ID:
709 case CERT_RENEWAL_PROP_ID:
711 if (pvData)
713 const CRYPT_DATA_BLOB *blob = pvData;
715 ret = ContextPropertyList_SetProperty(cert->base.properties, dwPropId,
716 blob->pbData, blob->cbData);
718 else
720 ContextPropertyList_RemoveProperty(cert->base.properties, dwPropId);
721 ret = TRUE;
723 break;
725 case CERT_DATE_STAMP_PROP_ID:
726 if (pvData)
727 ret = ContextPropertyList_SetProperty(cert->base.properties, dwPropId,
728 pvData, sizeof(FILETIME));
729 else
731 ContextPropertyList_RemoveProperty(cert->base.properties, dwPropId);
732 ret = TRUE;
734 break;
735 case CERT_KEY_CONTEXT_PROP_ID:
737 if (pvData)
739 const CERT_KEY_CONTEXT *keyContext = pvData;
741 if (keyContext->cbSize != sizeof(CERT_KEY_CONTEXT))
743 SetLastError(E_INVALIDARG);
744 ret = FALSE;
746 else
747 ret = ContextPropertyList_SetProperty(cert->base.properties, dwPropId,
748 (const BYTE *)keyContext, keyContext->cbSize);
750 else
752 ContextPropertyList_RemoveProperty(cert->base.properties, dwPropId);
753 ret = TRUE;
755 break;
757 case CERT_KEY_PROV_INFO_PROP_ID:
758 if (pvData)
759 ret = CertContext_SetKeyProvInfoProperty(cert->base.properties, pvData);
760 else
762 ContextPropertyList_RemoveProperty(cert->base.properties, dwPropId);
763 ret = TRUE;
765 break;
766 case CERT_KEY_PROV_HANDLE_PROP_ID:
768 CERT_KEY_CONTEXT keyContext;
769 DWORD size = sizeof(keyContext);
771 ret = CertContext_GetProperty(cert, CERT_KEY_CONTEXT_PROP_ID,
772 &keyContext, &size);
773 if (ret)
775 if (!(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
776 CryptReleaseContext(keyContext.hCryptProv, 0);
778 keyContext.cbSize = sizeof(keyContext);
779 if (pvData)
780 keyContext.hCryptProv = *(const HCRYPTPROV *)pvData;
781 else
783 keyContext.hCryptProv = 0;
784 keyContext.dwKeySpec = AT_SIGNATURE;
786 ret = CertContext_SetProperty(cert, CERT_KEY_CONTEXT_PROP_ID,
787 0, &keyContext);
788 break;
790 default:
791 FIXME("%d: stub\n", dwPropId);
792 ret = FALSE;
795 TRACE("returning %d\n", ret);
796 return ret;
799 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
800 DWORD dwPropId, DWORD dwFlags, const void *pvData)
802 BOOL ret;
804 TRACE("(%p, %d, %08x, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
806 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
807 * crashes on most of these, I'll be safer.
809 switch (dwPropId)
811 case 0:
812 case CERT_ACCESS_STATE_PROP_ID:
813 case CERT_CERT_PROP_ID:
814 case CERT_CRL_PROP_ID:
815 case CERT_CTL_PROP_ID:
816 SetLastError(E_INVALIDARG);
817 return FALSE;
819 ret = CertContext_SetProperty(cert_from_ptr(pCertContext), dwPropId, dwFlags,
820 pvData);
821 TRACE("returning %d\n", ret);
822 return ret;
825 /* Acquires the private key using the key provider info, retrieving info from
826 * the certificate if info is NULL. The acquired provider is returned in
827 * *phCryptProv, and the key spec for the provider is returned in *pdwKeySpec.
829 static BOOL CRYPT_AcquirePrivateKeyFromProvInfo(PCCERT_CONTEXT pCert, DWORD dwFlags,
830 PCRYPT_KEY_PROV_INFO info, HCRYPTPROV *phCryptProv, DWORD *pdwKeySpec)
832 DWORD size = 0;
833 BOOL allocated = FALSE, ret = TRUE;
835 if (!info)
837 ret = CertGetCertificateContextProperty(pCert,
838 CERT_KEY_PROV_INFO_PROP_ID, 0, &size);
839 if (ret)
841 info = HeapAlloc(GetProcessHeap(), 0, size);
842 if (info)
844 ret = CertGetCertificateContextProperty(pCert,
845 CERT_KEY_PROV_INFO_PROP_ID, info, &size);
846 allocated = TRUE;
848 else
850 SetLastError(ERROR_OUTOFMEMORY);
851 ret = FALSE;
854 else
855 SetLastError(CRYPT_E_NO_KEY_PROPERTY);
857 if (ret)
859 ret = CryptAcquireContextW(phCryptProv, info->pwszContainerName,
860 info->pwszProvName, info->dwProvType, (dwFlags & CRYPT_ACQUIRE_SILENT_FLAG) ? CRYPT_SILENT : 0);
861 if (ret)
863 DWORD i;
865 for (i = 0; i < info->cProvParam; i++)
867 CryptSetProvParam(*phCryptProv,
868 info->rgProvParam[i].dwParam, info->rgProvParam[i].pbData,
869 info->rgProvParam[i].dwFlags);
871 *pdwKeySpec = info->dwKeySpec;
873 else
874 SetLastError(CRYPT_E_NO_KEY_PROPERTY);
876 if (allocated)
877 HeapFree(GetProcessHeap(), 0, info);
878 return ret;
881 BOOL WINAPI CryptAcquireCertificatePrivateKey(PCCERT_CONTEXT pCert,
882 DWORD dwFlags, void *pvReserved, HCRYPTPROV_OR_NCRYPT_KEY_HANDLE *phCryptProv,
883 DWORD *pdwKeySpec, BOOL *pfCallerFreeProv)
885 BOOL ret = FALSE, cache = FALSE;
886 PCRYPT_KEY_PROV_INFO info = NULL;
887 CERT_KEY_CONTEXT keyContext;
888 DWORD size;
889 PCCERT_CONTEXT cert_in_store = NULL;
891 TRACE("(%p, %08x, %p, %p, %p, %p)\n", pCert, dwFlags, pvReserved,
892 phCryptProv, pdwKeySpec, pfCallerFreeProv);
894 if (dwFlags & CRYPT_ACQUIRE_USE_PROV_INFO_FLAG)
896 DWORD size = 0;
898 ret = CertGetCertificateContextProperty(pCert,
899 CERT_KEY_PROV_INFO_PROP_ID, 0, &size);
901 if (!ret)
903 static const WCHAR myW[] = { 'M','y',0 };
904 HCERTSTORE hstore;
906 hstore = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
907 CERT_SYSTEM_STORE_CURRENT_USER, myW);
908 if (hstore)
910 cert_in_store = CertFindCertificateInStore(hstore, pCert->dwCertEncodingType, 0,
911 CERT_FIND_EXISTING, pCert, NULL);
912 if (cert_in_store)
914 ret = CertGetCertificateContextProperty(cert_in_store, CERT_KEY_PROV_INFO_PROP_ID, 0, &size);
915 if (ret)
916 pCert = cert_in_store;
917 else
919 CertFreeCertificateContext(cert_in_store);
920 cert_in_store = NULL;
924 CertCloseStore(hstore, 0);
928 if (ret)
930 info = HeapAlloc(GetProcessHeap(), 0, size);
931 ret = CertGetCertificateContextProperty(pCert,
932 CERT_KEY_PROV_INFO_PROP_ID, info, &size);
933 if (ret)
934 cache = info->dwFlags & CERT_SET_KEY_CONTEXT_PROP_ID;
937 else if (dwFlags & CRYPT_ACQUIRE_CACHE_FLAG)
938 cache = TRUE;
939 *phCryptProv = 0;
940 if (cache)
942 size = sizeof(keyContext);
943 ret = CertGetCertificateContextProperty(pCert, CERT_KEY_CONTEXT_PROP_ID,
944 &keyContext, &size);
945 if (ret)
947 *phCryptProv = keyContext.hCryptProv;
948 if (pdwKeySpec)
949 *pdwKeySpec = keyContext.dwKeySpec;
950 if (pfCallerFreeProv)
951 *pfCallerFreeProv = FALSE;
954 if (!*phCryptProv)
956 ret = CRYPT_AcquirePrivateKeyFromProvInfo(pCert, dwFlags, info,
957 &keyContext.hCryptProv, &keyContext.dwKeySpec);
958 if (ret)
960 *phCryptProv = keyContext.hCryptProv;
961 if (pdwKeySpec)
962 *pdwKeySpec = keyContext.dwKeySpec;
963 if (cache)
965 keyContext.cbSize = sizeof(keyContext);
966 if (CertSetCertificateContextProperty(pCert,
967 CERT_KEY_CONTEXT_PROP_ID, 0, &keyContext))
969 if (pfCallerFreeProv)
970 *pfCallerFreeProv = FALSE;
973 else
975 if (pfCallerFreeProv)
976 *pfCallerFreeProv = TRUE;
980 HeapFree(GetProcessHeap(), 0, info);
981 if (cert_in_store)
982 CertFreeCertificateContext(cert_in_store);
983 return ret;
986 static BOOL key_prov_info_matches_cert(PCCERT_CONTEXT pCert,
987 const CRYPT_KEY_PROV_INFO *keyProvInfo)
989 HCRYPTPROV csp;
990 BOOL matches = FALSE;
992 if (CryptAcquireContextW(&csp, keyProvInfo->pwszContainerName,
993 keyProvInfo->pwszProvName, keyProvInfo->dwProvType, keyProvInfo->dwFlags))
995 DWORD size;
997 /* Need to sign something to verify the sig. What to sign? Why not
998 * the certificate itself?
1000 if (CryptSignAndEncodeCertificate(csp, AT_SIGNATURE,
1001 pCert->dwCertEncodingType, X509_CERT_TO_BE_SIGNED, pCert->pCertInfo,
1002 &pCert->pCertInfo->SignatureAlgorithm, NULL, NULL, &size))
1004 BYTE *certEncoded = CryptMemAlloc(size);
1006 if (certEncoded)
1008 if (CryptSignAndEncodeCertificate(csp, AT_SIGNATURE,
1009 pCert->dwCertEncodingType, X509_CERT_TO_BE_SIGNED,
1010 pCert->pCertInfo, &pCert->pCertInfo->SignatureAlgorithm,
1011 NULL, certEncoded, &size))
1013 if (size == pCert->cbCertEncoded &&
1014 !memcmp(certEncoded, pCert->pbCertEncoded, size))
1015 matches = TRUE;
1017 CryptMemFree(certEncoded);
1020 CryptReleaseContext(csp, 0);
1022 return matches;
1025 static BOOL container_matches_cert(PCCERT_CONTEXT pCert, LPCSTR container,
1026 CRYPT_KEY_PROV_INFO *keyProvInfo)
1028 CRYPT_KEY_PROV_INFO copy;
1029 WCHAR containerW[MAX_PATH];
1030 BOOL matches;
1032 MultiByteToWideChar(CP_ACP, 0, container, -1, containerW, ARRAY_SIZE(containerW));
1033 /* We make a copy of the CRYPT_KEY_PROV_INFO because the caller expects
1034 * keyProvInfo->pwszContainerName to be NULL or a heap-allocated container
1035 * name.
1037 copy = *keyProvInfo;
1038 copy.pwszContainerName = containerW;
1039 matches = key_prov_info_matches_cert(pCert, &copy);
1040 if (matches)
1042 keyProvInfo->pwszContainerName =
1043 CryptMemAlloc((strlenW(containerW) + 1) * sizeof(WCHAR));
1044 if (keyProvInfo->pwszContainerName)
1046 strcpyW(keyProvInfo->pwszContainerName, containerW);
1047 keyProvInfo->dwKeySpec = AT_SIGNATURE;
1049 else
1050 matches = FALSE;
1052 return matches;
1055 /* Searches the provider named keyProvInfo.pwszProvName for a container whose
1056 * private key matches pCert's public key. Upon success, updates keyProvInfo
1057 * with the matching container's info (free keyProvInfo.pwszContainerName upon
1058 * success.)
1059 * Returns TRUE if found, FALSE if not.
1061 static BOOL find_key_prov_info_in_provider(PCCERT_CONTEXT pCert,
1062 CRYPT_KEY_PROV_INFO *keyProvInfo)
1064 HCRYPTPROV defProvider;
1065 BOOL ret, found = FALSE;
1066 char containerA[MAX_PATH];
1068 assert(keyProvInfo->pwszContainerName == NULL);
1069 if ((ret = CryptAcquireContextW(&defProvider, NULL,
1070 keyProvInfo->pwszProvName, keyProvInfo->dwProvType,
1071 keyProvInfo->dwFlags | CRYPT_VERIFYCONTEXT)))
1073 DWORD enumFlags = keyProvInfo->dwFlags | CRYPT_FIRST;
1075 while (ret && !found)
1077 DWORD size = sizeof(containerA);
1079 ret = CryptGetProvParam(defProvider, PP_ENUMCONTAINERS,
1080 (BYTE *)containerA, &size, enumFlags);
1081 if (ret)
1082 found = container_matches_cert(pCert, containerA, keyProvInfo);
1083 if (enumFlags & CRYPT_FIRST)
1085 enumFlags &= ~CRYPT_FIRST;
1086 enumFlags |= CRYPT_NEXT;
1089 CryptReleaseContext(defProvider, 0);
1091 return found;
1094 static BOOL find_matching_provider(PCCERT_CONTEXT pCert, DWORD dwFlags)
1096 BOOL found = FALSE, ret = TRUE;
1097 DWORD index = 0, cbProvName = 0;
1098 CRYPT_KEY_PROV_INFO keyProvInfo;
1100 TRACE("(%p, %08x)\n", pCert, dwFlags);
1102 memset(&keyProvInfo, 0, sizeof(keyProvInfo));
1103 while (ret && !found)
1105 DWORD size = 0;
1107 ret = CryptEnumProvidersW(index, NULL, 0, &keyProvInfo.dwProvType,
1108 NULL, &size);
1109 if (ret)
1111 if (size <= cbProvName)
1112 ret = CryptEnumProvidersW(index, NULL, 0,
1113 &keyProvInfo.dwProvType, keyProvInfo.pwszProvName, &size);
1114 else
1116 CryptMemFree(keyProvInfo.pwszProvName);
1117 keyProvInfo.pwszProvName = CryptMemAlloc(size);
1118 if (keyProvInfo.pwszProvName)
1120 cbProvName = size;
1121 ret = CryptEnumProvidersW(index, NULL, 0,
1122 &keyProvInfo.dwProvType, keyProvInfo.pwszProvName, &size);
1123 if (ret)
1125 if (dwFlags & CRYPT_FIND_SILENT_KEYSET_FLAG)
1126 keyProvInfo.dwFlags |= CRYPT_SILENT;
1127 if (dwFlags & CRYPT_FIND_USER_KEYSET_FLAG ||
1128 !(dwFlags & (CRYPT_FIND_USER_KEYSET_FLAG |
1129 CRYPT_FIND_MACHINE_KEYSET_FLAG)))
1131 keyProvInfo.dwFlags |= CRYPT_USER_KEYSET;
1132 found = find_key_prov_info_in_provider(pCert,
1133 &keyProvInfo);
1135 if (!found)
1137 if (dwFlags & CRYPT_FIND_MACHINE_KEYSET_FLAG ||
1138 !(dwFlags & (CRYPT_FIND_USER_KEYSET_FLAG |
1139 CRYPT_FIND_MACHINE_KEYSET_FLAG)))
1141 keyProvInfo.dwFlags &= ~CRYPT_USER_KEYSET;
1142 keyProvInfo.dwFlags |= CRYPT_MACHINE_KEYSET;
1143 found = find_key_prov_info_in_provider(pCert,
1144 &keyProvInfo);
1149 else
1150 ret = FALSE;
1152 index++;
1155 if (found)
1156 CertSetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID,
1157 0, &keyProvInfo);
1158 CryptMemFree(keyProvInfo.pwszProvName);
1159 CryptMemFree(keyProvInfo.pwszContainerName);
1160 return found;
1163 static BOOL cert_prov_info_matches_cert(PCCERT_CONTEXT pCert)
1165 BOOL matches = FALSE;
1166 DWORD size;
1168 if (CertGetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID,
1169 NULL, &size))
1171 CRYPT_KEY_PROV_INFO *keyProvInfo = CryptMemAlloc(size);
1173 if (keyProvInfo)
1175 if (CertGetCertificateContextProperty(pCert,
1176 CERT_KEY_PROV_INFO_PROP_ID, keyProvInfo, &size))
1177 matches = key_prov_info_matches_cert(pCert, keyProvInfo);
1178 CryptMemFree(keyProvInfo);
1181 return matches;
1184 BOOL WINAPI CryptFindCertificateKeyProvInfo(PCCERT_CONTEXT pCert,
1185 DWORD dwFlags, void *pvReserved)
1187 BOOL matches;
1189 TRACE("(%p, %08x, %p)\n", pCert, dwFlags, pvReserved);
1191 matches = cert_prov_info_matches_cert(pCert);
1192 if (!matches)
1193 matches = find_matching_provider(pCert, dwFlags);
1194 return matches;
1197 BOOL WINAPI CertCompareCertificate(DWORD dwCertEncodingType,
1198 PCERT_INFO pCertId1, PCERT_INFO pCertId2)
1200 BOOL ret;
1202 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertId1, pCertId2);
1204 ret = CertCompareCertificateName(dwCertEncodingType, &pCertId1->Issuer,
1205 &pCertId2->Issuer) && CertCompareIntegerBlob(&pCertId1->SerialNumber,
1206 &pCertId2->SerialNumber);
1207 TRACE("returning %d\n", ret);
1208 return ret;
1211 BOOL WINAPI CertCompareCertificateName(DWORD dwCertEncodingType,
1212 PCERT_NAME_BLOB pCertName1, PCERT_NAME_BLOB pCertName2)
1214 BOOL ret;
1216 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertName1, pCertName2);
1218 if (pCertName1->cbData == pCertName2->cbData)
1220 if (pCertName1->cbData)
1221 ret = !memcmp(pCertName1->pbData, pCertName2->pbData,
1222 pCertName1->cbData);
1223 else
1224 ret = TRUE;
1226 else
1227 ret = FALSE;
1228 TRACE("returning %d\n", ret);
1229 return ret;
1232 /* Returns the number of significant bytes in pInt, where a byte is
1233 * insignificant if it's a leading 0 for positive numbers or a leading 0xff
1234 * for negative numbers. pInt is assumed to be little-endian.
1236 static DWORD CRYPT_significantBytes(const CRYPT_INTEGER_BLOB *pInt)
1238 DWORD ret = pInt->cbData;
1240 while (ret > 1)
1242 if (pInt->pbData[ret - 2] <= 0x7f && pInt->pbData[ret - 1] == 0)
1243 ret--;
1244 else if (pInt->pbData[ret - 2] >= 0x80 && pInt->pbData[ret - 1] == 0xff)
1245 ret--;
1246 else
1247 break;
1249 return ret;
1252 BOOL WINAPI CertCompareIntegerBlob(PCRYPT_INTEGER_BLOB pInt1,
1253 PCRYPT_INTEGER_BLOB pInt2)
1255 BOOL ret;
1256 DWORD cb1, cb2;
1258 TRACE("(%p, %p)\n", pInt1, pInt2);
1260 cb1 = CRYPT_significantBytes(pInt1);
1261 cb2 = CRYPT_significantBytes(pInt2);
1262 if (cb1 == cb2)
1264 if (cb1)
1265 ret = !memcmp(pInt1->pbData, pInt2->pbData, cb1);
1266 else
1267 ret = TRUE;
1269 else
1270 ret = FALSE;
1271 TRACE("returning %d\n", ret);
1272 return ret;
1275 BOOL WINAPI CertComparePublicKeyInfo(DWORD dwCertEncodingType,
1276 PCERT_PUBLIC_KEY_INFO pPublicKey1, PCERT_PUBLIC_KEY_INFO pPublicKey2)
1278 BOOL ret;
1280 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pPublicKey1, pPublicKey2);
1282 /* RSA public key data should start with ASN_SEQUENCE,
1283 * otherwise it's not a RSA_CSP_PUBLICKEYBLOB.
1285 if (!pPublicKey1->PublicKey.cbData || pPublicKey1->PublicKey.pbData[0] != ASN_SEQUENCE)
1286 dwCertEncodingType = 0;
1288 switch (GET_CERT_ENCODING_TYPE(dwCertEncodingType))
1290 case 0: /* Seems to mean "raw binary bits" */
1291 if (pPublicKey1->PublicKey.cbData == pPublicKey2->PublicKey.cbData &&
1292 pPublicKey1->PublicKey.cUnusedBits == pPublicKey2->PublicKey.cUnusedBits)
1294 if (pPublicKey2->PublicKey.cbData)
1295 ret = !memcmp(pPublicKey1->PublicKey.pbData,
1296 pPublicKey2->PublicKey.pbData, pPublicKey1->PublicKey.cbData);
1297 else
1298 ret = TRUE;
1300 else
1301 ret = FALSE;
1302 break;
1303 default:
1304 WARN("Unknown encoding type %08x\n", dwCertEncodingType);
1305 /* FALLTHROUGH */
1306 case X509_ASN_ENCODING:
1308 BLOBHEADER *pblob1, *pblob2;
1309 DWORD length;
1310 ret = FALSE;
1311 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1312 pPublicKey1->PublicKey.pbData, pPublicKey1->PublicKey.cbData,
1313 CRYPT_DECODE_ALLOC_FLAG, &pblob1, &length))
1315 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1316 pPublicKey2->PublicKey.pbData, pPublicKey2->PublicKey.cbData,
1317 CRYPT_DECODE_ALLOC_FLAG, &pblob2, &length))
1319 /* The RSAPUBKEY structure directly follows the BLOBHEADER */
1320 RSAPUBKEY *pk1 = (LPVOID)(pblob1 + 1),
1321 *pk2 = (LPVOID)(pblob2 + 1);
1322 ret = (pk1->bitlen == pk2->bitlen) && (pk1->pubexp == pk2->pubexp)
1323 && !memcmp(pk1 + 1, pk2 + 1, pk1->bitlen/8);
1325 LocalFree(pblob2);
1327 LocalFree(pblob1);
1330 break;
1333 return ret;
1336 DWORD WINAPI CertGetPublicKeyLength(DWORD dwCertEncodingType,
1337 PCERT_PUBLIC_KEY_INFO pPublicKey)
1339 DWORD len = 0;
1341 TRACE("(%08x, %p)\n", dwCertEncodingType, pPublicKey);
1343 if (GET_CERT_ENCODING_TYPE(dwCertEncodingType) != X509_ASN_ENCODING)
1345 SetLastError(ERROR_FILE_NOT_FOUND);
1346 return 0;
1348 if (pPublicKey->Algorithm.pszObjId &&
1349 !strcmp(pPublicKey->Algorithm.pszObjId, szOID_RSA_DH))
1351 FIXME("unimplemented for DH public keys\n");
1352 SetLastError(CRYPT_E_ASN1_BADTAG);
1354 else
1356 PCCRYPT_OID_INFO info;
1357 DWORD size;
1358 PBYTE buf;
1359 BOOL ret;
1361 info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, pPublicKey->Algorithm.pszObjId, 0);
1362 if (info)
1364 HCRYPTKEY key;
1366 TRACE("public key algid %#x (%s)\n", info->u.Algid, debugstr_a(pPublicKey->Algorithm.pszObjId));
1368 ret = CryptImportPublicKeyInfo(I_CryptGetDefaultCryptProv(info->u.Algid), dwCertEncodingType, pPublicKey, &key);
1369 if (ret)
1371 size = sizeof(len);
1372 ret = CryptGetKeyParam(key, KP_KEYLEN, (BYTE *)&len, &size, 0);
1373 CryptDestroyKey(key);
1374 return len;
1376 /* fallback to RSA */
1379 ret = CryptDecodeObjectEx(dwCertEncodingType,
1380 RSA_CSP_PUBLICKEYBLOB, pPublicKey->PublicKey.pbData,
1381 pPublicKey->PublicKey.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf,
1382 &size);
1384 if (ret)
1386 RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
1388 len = rsaPubKey->bitlen;
1389 LocalFree(buf);
1392 return len;
1395 typedef BOOL (*CertCompareFunc)(PCCERT_CONTEXT pCertContext, DWORD dwType,
1396 DWORD dwFlags, const void *pvPara);
1398 static BOOL compare_cert_by_md5_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
1399 DWORD dwFlags, const void *pvPara)
1401 BOOL ret;
1402 BYTE hash[16];
1403 DWORD size = sizeof(hash);
1405 ret = CertGetCertificateContextProperty(pCertContext,
1406 CERT_MD5_HASH_PROP_ID, hash, &size);
1407 if (ret)
1409 const CRYPT_HASH_BLOB *pHash = pvPara;
1411 if (size == pHash->cbData)
1412 ret = !memcmp(pHash->pbData, hash, size);
1413 else
1414 ret = FALSE;
1416 return ret;
1419 static BOOL compare_cert_by_sha1_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
1420 DWORD dwFlags, const void *pvPara)
1422 BOOL ret;
1423 BYTE hash[20];
1424 DWORD size = sizeof(hash);
1426 ret = CertGetCertificateContextProperty(pCertContext,
1427 CERT_SHA1_HASH_PROP_ID, hash, &size);
1428 if (ret)
1430 const CRYPT_HASH_BLOB *pHash = pvPara;
1432 if (size == pHash->cbData)
1433 ret = !memcmp(pHash->pbData, hash, size);
1434 else
1435 ret = FALSE;
1437 return ret;
1440 static BOOL compare_cert_by_name(PCCERT_CONTEXT pCertContext, DWORD dwType,
1441 DWORD dwFlags, const void *pvPara)
1443 CERT_NAME_BLOB *blob = (CERT_NAME_BLOB *)pvPara, *toCompare;
1444 BOOL ret;
1446 if (dwType & CERT_INFO_SUBJECT_FLAG)
1447 toCompare = &pCertContext->pCertInfo->Subject;
1448 else
1449 toCompare = &pCertContext->pCertInfo->Issuer;
1450 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1451 toCompare, blob);
1452 return ret;
1455 static BOOL compare_cert_by_public_key(PCCERT_CONTEXT pCertContext,
1456 DWORD dwType, DWORD dwFlags, const void *pvPara)
1458 CERT_PUBLIC_KEY_INFO *publicKey = (CERT_PUBLIC_KEY_INFO *)pvPara;
1459 BOOL ret;
1461 ret = CertComparePublicKeyInfo(pCertContext->dwCertEncodingType,
1462 &pCertContext->pCertInfo->SubjectPublicKeyInfo, publicKey);
1463 return ret;
1466 static BOOL compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext,
1467 DWORD dwType, DWORD dwFlags, const void *pvPara)
1469 CERT_INFO *pCertInfo = (CERT_INFO *)pvPara;
1470 BOOL ret;
1472 /* Matching serial number and subject match.. */
1473 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1474 &pCertContext->pCertInfo->Subject, &pCertInfo->Issuer);
1475 if (ret)
1476 ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
1477 &pCertInfo->SerialNumber);
1478 else
1480 /* failing that, if the serial number and issuer match, we match */
1481 ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
1482 &pCertInfo->SerialNumber);
1483 if (ret)
1484 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1485 &pCertContext->pCertInfo->Issuer, &pCertInfo->Issuer);
1487 TRACE("returning %d\n", ret);
1488 return ret;
1491 static BOOL compare_cert_by_cert_id(PCCERT_CONTEXT pCertContext, DWORD dwType,
1492 DWORD dwFlags, const void *pvPara)
1494 CERT_ID *id = (CERT_ID *)pvPara;
1495 BOOL ret;
1497 switch (id->dwIdChoice)
1499 case CERT_ID_ISSUER_SERIAL_NUMBER:
1500 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1501 &pCertContext->pCertInfo->Issuer, &id->u.IssuerSerialNumber.Issuer);
1502 if (ret)
1503 ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
1504 &id->u.IssuerSerialNumber.SerialNumber);
1505 break;
1506 case CERT_ID_SHA1_HASH:
1507 ret = compare_cert_by_sha1_hash(pCertContext, dwType, dwFlags,
1508 &id->u.HashId);
1509 break;
1510 case CERT_ID_KEY_IDENTIFIER:
1512 DWORD size = 0;
1514 ret = CertGetCertificateContextProperty(pCertContext,
1515 CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
1516 if (ret && size == id->u.KeyId.cbData)
1518 LPBYTE buf = CryptMemAlloc(size);
1520 if (buf)
1522 CertGetCertificateContextProperty(pCertContext,
1523 CERT_KEY_IDENTIFIER_PROP_ID, buf, &size);
1524 ret = !memcmp(buf, id->u.KeyId.pbData, size);
1525 CryptMemFree(buf);
1527 else
1528 ret = FALSE;
1530 else
1531 ret = FALSE;
1532 break;
1534 default:
1535 ret = FALSE;
1536 break;
1538 return ret;
1541 static BOOL compare_existing_cert(PCCERT_CONTEXT pCertContext, DWORD dwType,
1542 DWORD dwFlags, const void *pvPara)
1544 PCCERT_CONTEXT toCompare = pvPara;
1545 return CertCompareCertificate(pCertContext->dwCertEncodingType,
1546 pCertContext->pCertInfo, toCompare->pCertInfo);
1549 static BOOL compare_cert_by_signature_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
1550 DWORD dwFlags, const void *pvPara)
1552 const CRYPT_HASH_BLOB *hash = pvPara;
1553 DWORD size = 0;
1554 BOOL ret;
1556 ret = CertGetCertificateContextProperty(pCertContext,
1557 CERT_SIGNATURE_HASH_PROP_ID, NULL, &size);
1558 if (ret && size == hash->cbData)
1560 LPBYTE buf = CryptMemAlloc(size);
1562 if (buf)
1564 CertGetCertificateContextProperty(pCertContext,
1565 CERT_SIGNATURE_HASH_PROP_ID, buf, &size);
1566 ret = !memcmp(buf, hash->pbData, size);
1567 CryptMemFree(buf);
1569 else
1570 ret = FALSE;
1572 else
1573 ret = FALSE;
1574 return ret;
1577 static inline PCCERT_CONTEXT cert_compare_certs_in_store(HCERTSTORE store,
1578 PCCERT_CONTEXT prev, CertCompareFunc compare, DWORD dwType, DWORD dwFlags,
1579 const void *pvPara)
1581 BOOL matches = FALSE;
1582 PCCERT_CONTEXT ret;
1584 ret = prev;
1585 do {
1586 ret = CertEnumCertificatesInStore(store, ret);
1587 if (ret)
1588 matches = compare(ret, dwType, dwFlags, pvPara);
1589 } while (ret != NULL && !matches);
1590 return ret;
1593 typedef PCCERT_CONTEXT (*CertFindFunc)(HCERTSTORE store, DWORD dwType,
1594 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev);
1596 static PCCERT_CONTEXT find_cert_any(HCERTSTORE store, DWORD dwType,
1597 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1599 return CertEnumCertificatesInStore(store, prev);
1602 static PCCERT_CONTEXT find_cert_by_issuer(HCERTSTORE store, DWORD dwType,
1603 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1605 BOOL ret;
1606 PCCERT_CONTEXT found = NULL, subject = pvPara;
1607 PCERT_EXTENSION ext;
1608 DWORD size;
1610 if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER,
1611 subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
1613 CERT_AUTHORITY_KEY_ID_INFO *info;
1615 ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
1616 X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData,
1617 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1618 &info, &size);
1619 if (ret)
1621 CERT_ID id;
1623 if (info->CertIssuer.cbData && info->CertSerialNumber.cbData)
1625 id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
1626 memcpy(&id.u.IssuerSerialNumber.Issuer, &info->CertIssuer,
1627 sizeof(CERT_NAME_BLOB));
1628 memcpy(&id.u.IssuerSerialNumber.SerialNumber,
1629 &info->CertSerialNumber, sizeof(CRYPT_INTEGER_BLOB));
1631 else if (info->KeyId.cbData)
1633 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
1634 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
1636 else
1637 ret = FALSE;
1638 if (ret)
1639 found = cert_compare_certs_in_store(store, prev,
1640 compare_cert_by_cert_id, dwType, dwFlags, &id);
1641 LocalFree(info);
1644 else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2,
1645 subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
1647 CERT_AUTHORITY_KEY_ID2_INFO *info;
1649 ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
1650 X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData,
1651 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1652 &info, &size);
1653 if (ret)
1655 CERT_ID id;
1657 if (info->AuthorityCertIssuer.cAltEntry &&
1658 info->AuthorityCertSerialNumber.cbData)
1660 PCERT_ALT_NAME_ENTRY directoryName = NULL;
1661 DWORD i;
1663 for (i = 0; !directoryName &&
1664 i < info->AuthorityCertIssuer.cAltEntry; i++)
1665 if (info->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice
1666 == CERT_ALT_NAME_DIRECTORY_NAME)
1667 directoryName =
1668 &info->AuthorityCertIssuer.rgAltEntry[i];
1669 if (directoryName)
1671 id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
1672 memcpy(&id.u.IssuerSerialNumber.Issuer,
1673 &directoryName->u.DirectoryName, sizeof(CERT_NAME_BLOB));
1674 memcpy(&id.u.IssuerSerialNumber.SerialNumber,
1675 &info->AuthorityCertSerialNumber,
1676 sizeof(CRYPT_INTEGER_BLOB));
1678 else
1680 FIXME("no supported name type in authority key id2\n");
1681 ret = FALSE;
1684 else if (info->KeyId.cbData)
1686 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
1687 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
1689 else
1690 ret = FALSE;
1691 if (ret)
1692 found = cert_compare_certs_in_store(store, prev,
1693 compare_cert_by_cert_id, dwType, dwFlags, &id);
1694 LocalFree(info);
1697 else
1698 found = cert_compare_certs_in_store(store, prev,
1699 compare_cert_by_name, CERT_COMPARE_NAME | CERT_COMPARE_SUBJECT_CERT,
1700 dwFlags, &subject->pCertInfo->Issuer);
1701 return found;
1704 static BOOL compare_cert_by_name_str(PCCERT_CONTEXT pCertContext,
1705 DWORD dwType, DWORD dwFlags, const void *pvPara)
1707 PCERT_NAME_BLOB name;
1708 DWORD len;
1709 BOOL ret = FALSE;
1711 if (dwType & CERT_INFO_SUBJECT_FLAG)
1712 name = &pCertContext->pCertInfo->Subject;
1713 else
1714 name = &pCertContext->pCertInfo->Issuer;
1715 len = CertNameToStrW(pCertContext->dwCertEncodingType, name,
1716 CERT_SIMPLE_NAME_STR, NULL, 0);
1717 if (len)
1719 LPWSTR str = CryptMemAlloc(len * sizeof(WCHAR));
1721 if (str)
1723 LPWSTR ptr;
1725 CertNameToStrW(pCertContext->dwCertEncodingType, name,
1726 CERT_SIMPLE_NAME_STR, str, len);
1727 for (ptr = str; *ptr; ptr++)
1728 *ptr = tolowerW(*ptr);
1729 if (strstrW(str, pvPara))
1730 ret = TRUE;
1731 CryptMemFree(str);
1734 return ret;
1737 static PCCERT_CONTEXT find_cert_by_name_str_a(HCERTSTORE store, DWORD dwType,
1738 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1740 PCCERT_CONTEXT found = NULL;
1742 TRACE("%s\n", debugstr_a(pvPara));
1744 if (pvPara)
1746 int len = MultiByteToWideChar(CP_ACP, 0, pvPara, -1, NULL, 0);
1747 LPWSTR str = CryptMemAlloc(len * sizeof(WCHAR));
1749 if (str)
1751 LPWSTR ptr;
1753 MultiByteToWideChar(CP_ACP, 0, pvPara, -1, str, len);
1754 for (ptr = str; *ptr; ptr++)
1755 *ptr = tolowerW(*ptr);
1756 found = cert_compare_certs_in_store(store, prev,
1757 compare_cert_by_name_str, dwType, dwFlags, str);
1758 CryptMemFree(str);
1761 else
1762 found = find_cert_any(store, dwType, dwFlags, NULL, prev);
1763 return found;
1766 static PCCERT_CONTEXT find_cert_by_name_str_w(HCERTSTORE store, DWORD dwType,
1767 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1769 PCCERT_CONTEXT found = NULL;
1771 TRACE("%s\n", debugstr_w(pvPara));
1773 if (pvPara)
1775 DWORD len = strlenW(pvPara);
1776 LPWSTR str = CryptMemAlloc((len + 1) * sizeof(WCHAR));
1778 if (str)
1780 LPCWSTR src;
1781 LPWSTR dst;
1783 for (src = pvPara, dst = str; *src; src++, dst++)
1784 *dst = tolowerW(*src);
1785 *dst = 0;
1786 found = cert_compare_certs_in_store(store, prev,
1787 compare_cert_by_name_str, dwType, dwFlags, str);
1788 CryptMemFree(str);
1791 else
1792 found = find_cert_any(store, dwType, dwFlags, NULL, prev);
1793 return found;
1796 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
1797 DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType, const void *pvPara,
1798 PCCERT_CONTEXT pPrevCertContext)
1800 PCCERT_CONTEXT ret;
1801 CertFindFunc find = NULL;
1802 CertCompareFunc compare = NULL;
1803 CERT_ID cert_id;
1805 TRACE("(%p, %08x, %08x, %08x, %p, %p)\n", hCertStore, dwCertEncodingType,
1806 dwFlags, dwType, pvPara, pPrevCertContext);
1808 switch (dwType >> CERT_COMPARE_SHIFT)
1810 case CERT_COMPARE_ANY:
1811 find = find_cert_any;
1812 break;
1813 case CERT_COMPARE_MD5_HASH:
1814 compare = compare_cert_by_md5_hash;
1815 break;
1816 case CERT_COMPARE_SHA1_HASH:
1817 compare = compare_cert_by_sha1_hash;
1818 break;
1819 case CERT_COMPARE_NAME:
1820 compare = compare_cert_by_name;
1821 break;
1822 case CERT_COMPARE_PUBLIC_KEY:
1823 compare = compare_cert_by_public_key;
1824 break;
1825 case CERT_COMPARE_NAME_STR_A:
1826 find = find_cert_by_name_str_a;
1827 break;
1828 case CERT_COMPARE_NAME_STR_W:
1829 find = find_cert_by_name_str_w;
1830 break;
1831 case CERT_COMPARE_SUBJECT_CERT:
1832 compare = compare_cert_by_subject_cert;
1833 break;
1834 case CERT_COMPARE_KEY_IDENTIFIER:
1835 cert_id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
1836 cert_id.u.KeyId = *(const CRYPT_HASH_BLOB *)pvPara;
1837 pvPara = &cert_id;
1838 /* fall through */
1839 case CERT_COMPARE_CERT_ID:
1840 compare = compare_cert_by_cert_id;
1841 break;
1842 case CERT_COMPARE_ISSUER_OF:
1843 find = find_cert_by_issuer;
1844 break;
1845 case CERT_COMPARE_EXISTING:
1846 compare = compare_existing_cert;
1847 break;
1848 case CERT_COMPARE_SIGNATURE_HASH:
1849 compare = compare_cert_by_signature_hash;
1850 break;
1851 default:
1852 FIXME("find type %08x unimplemented\n", dwType);
1855 if (find)
1856 ret = find(hCertStore, dwType, dwFlags, pvPara, pPrevCertContext);
1857 else if (compare)
1858 ret = cert_compare_certs_in_store(hCertStore, pPrevCertContext,
1859 compare, dwType, dwFlags, pvPara);
1860 else
1861 ret = NULL;
1862 if (!ret)
1863 SetLastError(CRYPT_E_NOT_FOUND);
1864 TRACE("returning %p\n", ret);
1865 return ret;
1868 PCCERT_CONTEXT WINAPI CertGetSubjectCertificateFromStore(HCERTSTORE hCertStore,
1869 DWORD dwCertEncodingType, PCERT_INFO pCertId)
1871 TRACE("(%p, %08x, %p)\n", hCertStore, dwCertEncodingType, pCertId);
1873 if (!pCertId)
1875 SetLastError(E_INVALIDARG);
1876 return NULL;
1878 return CertFindCertificateInStore(hCertStore, dwCertEncodingType, 0,
1879 CERT_FIND_SUBJECT_CERT, pCertId, NULL);
1882 BOOL WINAPI CertVerifySubjectCertificateContext(PCCERT_CONTEXT pSubject,
1883 PCCERT_CONTEXT pIssuer, DWORD *pdwFlags)
1885 static const DWORD supportedFlags = CERT_STORE_REVOCATION_FLAG |
1886 CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG;
1888 if (*pdwFlags & ~supportedFlags)
1890 SetLastError(E_INVALIDARG);
1891 return FALSE;
1893 if (*pdwFlags & CERT_STORE_REVOCATION_FLAG)
1895 DWORD flags = 0;
1896 PCCRL_CONTEXT crl = CertGetCRLFromStore(pSubject->hCertStore, pSubject,
1897 NULL, &flags);
1899 /* FIXME: what if the CRL has expired? */
1900 if (crl)
1902 if (CertVerifyCRLRevocation(pSubject->dwCertEncodingType,
1903 pSubject->pCertInfo, 1, (PCRL_INFO *)&crl->pCrlInfo))
1904 *pdwFlags &= CERT_STORE_REVOCATION_FLAG;
1906 else
1907 *pdwFlags |= CERT_STORE_NO_CRL_FLAG;
1909 if (*pdwFlags & CERT_STORE_TIME_VALIDITY_FLAG)
1911 if (0 == CertVerifyTimeValidity(NULL, pSubject->pCertInfo))
1912 *pdwFlags &= ~CERT_STORE_TIME_VALIDITY_FLAG;
1914 if (*pdwFlags & CERT_STORE_SIGNATURE_FLAG)
1916 if (CryptVerifyCertificateSignatureEx(0, pSubject->dwCertEncodingType,
1917 CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)pSubject,
1918 CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)pIssuer, 0, NULL))
1919 *pdwFlags &= ~CERT_STORE_SIGNATURE_FLAG;
1921 return TRUE;
1924 PCCERT_CONTEXT WINAPI CertGetIssuerCertificateFromStore(HCERTSTORE hCertStore,
1925 PCCERT_CONTEXT pSubjectContext, PCCERT_CONTEXT pPrevIssuerContext,
1926 DWORD *pdwFlags)
1928 PCCERT_CONTEXT ret;
1930 TRACE("(%p, %p, %p, %08x)\n", hCertStore, pSubjectContext,
1931 pPrevIssuerContext, *pdwFlags);
1933 if (!pSubjectContext)
1935 SetLastError(E_INVALIDARG);
1936 return NULL;
1939 ret = CertFindCertificateInStore(hCertStore,
1940 pSubjectContext->dwCertEncodingType, 0, CERT_FIND_ISSUER_OF,
1941 pSubjectContext, pPrevIssuerContext);
1942 if (ret)
1944 if (!CertVerifySubjectCertificateContext(pSubjectContext, ret,
1945 pdwFlags))
1947 CertFreeCertificateContext(ret);
1948 ret = NULL;
1950 if (CRYPT_IsCertificateSelfSigned(pSubjectContext))
1952 CertFreeCertificateContext(ret);
1953 ret = NULL;
1954 SetLastError(CRYPT_E_SELF_SIGNED);
1957 TRACE("returning %p\n", ret);
1958 return ret;
1961 typedef struct _OLD_CERT_REVOCATION_STATUS {
1962 DWORD cbSize;
1963 DWORD dwIndex;
1964 DWORD dwError;
1965 DWORD dwReason;
1966 } OLD_CERT_REVOCATION_STATUS;
1968 typedef BOOL (WINAPI *CertVerifyRevocationFunc)(DWORD, DWORD, DWORD,
1969 void **, DWORD, PCERT_REVOCATION_PARA, PCERT_REVOCATION_STATUS);
1971 BOOL WINAPI CertVerifyRevocation(DWORD dwEncodingType, DWORD dwRevType,
1972 DWORD cContext, PVOID rgpvContext[], DWORD dwFlags,
1973 PCERT_REVOCATION_PARA pRevPara, PCERT_REVOCATION_STATUS pRevStatus)
1975 BOOL ret;
1977 TRACE("(%08x, %d, %d, %p, %08x, %p, %p)\n", dwEncodingType, dwRevType,
1978 cContext, rgpvContext, dwFlags, pRevPara, pRevStatus);
1980 if (pRevStatus->cbSize != sizeof(OLD_CERT_REVOCATION_STATUS) &&
1981 pRevStatus->cbSize != sizeof(CERT_REVOCATION_STATUS))
1983 SetLastError(E_INVALIDARG);
1984 return FALSE;
1986 if (cContext)
1988 static HCRYPTOIDFUNCSET set = NULL;
1989 DWORD size;
1991 if (!set)
1992 set = CryptInitOIDFunctionSet(CRYPT_OID_VERIFY_REVOCATION_FUNC, 0);
1993 ret = CryptGetDefaultOIDDllList(set, dwEncodingType, NULL, &size);
1994 if (ret)
1996 if (size == 1)
1998 /* empty list */
1999 SetLastError(CRYPT_E_NO_REVOCATION_DLL);
2000 ret = FALSE;
2002 else
2004 LPWSTR dllList = CryptMemAlloc(size * sizeof(WCHAR)), ptr;
2006 if (dllList)
2008 ret = CryptGetDefaultOIDDllList(set, dwEncodingType,
2009 dllList, &size);
2010 if (ret)
2012 for (ptr = dllList; ret && *ptr;
2013 ptr += lstrlenW(ptr) + 1)
2015 CertVerifyRevocationFunc func;
2016 HCRYPTOIDFUNCADDR hFunc;
2018 ret = CryptGetDefaultOIDFunctionAddress(set,
2019 dwEncodingType, ptr, 0, (void **)&func, &hFunc);
2020 if (ret)
2022 ret = func(dwEncodingType, dwRevType, cContext,
2023 rgpvContext, dwFlags, pRevPara, pRevStatus);
2024 CryptFreeOIDFunctionAddress(hFunc, 0);
2028 CryptMemFree(dllList);
2030 else
2032 SetLastError(ERROR_OUTOFMEMORY);
2033 ret = FALSE;
2038 else
2039 ret = TRUE;
2040 return ret;
2043 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
2044 CRYPT_ATTRIBUTE rgAttr[])
2046 PCRYPT_ATTRIBUTE ret = NULL;
2047 DWORD i;
2049 TRACE("%s %d %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
2051 if (!cAttr)
2052 return NULL;
2053 if (!pszObjId)
2055 SetLastError(ERROR_INVALID_PARAMETER);
2056 return NULL;
2059 for (i = 0; !ret && i < cAttr; i++)
2060 if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
2061 ret = &rgAttr[i];
2062 return ret;
2065 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
2066 CERT_EXTENSION rgExtensions[])
2068 PCERT_EXTENSION ret = NULL;
2069 DWORD i;
2071 TRACE("%s %d %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
2073 if (!cExtensions)
2074 return NULL;
2075 if (!pszObjId)
2077 SetLastError(ERROR_INVALID_PARAMETER);
2078 return NULL;
2081 for (i = 0; !ret && i < cExtensions; i++)
2082 if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
2083 rgExtensions[i].pszObjId))
2084 ret = &rgExtensions[i];
2085 return ret;
2088 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
2090 PCERT_RDN_ATTR ret = NULL;
2091 DWORD i, j;
2093 TRACE("%s %p\n", debugstr_a(pszObjId), pName);
2095 if (!pszObjId)
2097 SetLastError(ERROR_INVALID_PARAMETER);
2098 return NULL;
2101 for (i = 0; !ret && i < pName->cRDN; i++)
2102 for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
2103 if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
2104 pName->rgRDN[i].rgRDNAttr[j].pszObjId))
2105 ret = &pName->rgRDN[i].rgRDNAttr[j];
2106 return ret;
2109 static BOOL find_matching_rdn_attr(DWORD dwFlags, const CERT_NAME_INFO *name,
2110 const CERT_RDN_ATTR *attr)
2112 DWORD i, j;
2113 BOOL match = FALSE;
2115 for (i = 0; !match && i < name->cRDN; i++)
2117 for (j = 0; j < name->rgRDN[i].cRDNAttr; j++)
2119 if (!strcmp(name->rgRDN[i].rgRDNAttr[j].pszObjId,
2120 attr->pszObjId) &&
2121 name->rgRDN[i].rgRDNAttr[j].dwValueType ==
2122 attr->dwValueType)
2124 if (dwFlags & CERT_UNICODE_IS_RDN_ATTRS_FLAG)
2126 LPCWSTR nameStr =
2127 (LPCWSTR)name->rgRDN[i].rgRDNAttr[j].Value.pbData;
2128 LPCWSTR attrStr = (LPCWSTR)attr->Value.pbData;
2130 if (attr->Value.cbData !=
2131 name->rgRDN[i].rgRDNAttr[j].Value.cbData)
2132 match = FALSE;
2133 else if (dwFlags & CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG)
2134 match = !strncmpiW(nameStr, attrStr,
2135 attr->Value.cbData / sizeof(WCHAR));
2136 else
2137 match = !strncmpW(nameStr, attrStr,
2138 attr->Value.cbData / sizeof(WCHAR));
2139 TRACE("%s : %s => %d\n",
2140 debugstr_wn(nameStr, attr->Value.cbData / sizeof(WCHAR)),
2141 debugstr_wn(attrStr, attr->Value.cbData / sizeof(WCHAR)),
2142 match);
2144 else
2146 LPCSTR nameStr =
2147 (LPCSTR)name->rgRDN[i].rgRDNAttr[j].Value.pbData;
2148 LPCSTR attrStr = (LPCSTR)attr->Value.pbData;
2150 if (attr->Value.cbData !=
2151 name->rgRDN[i].rgRDNAttr[j].Value.cbData)
2152 match = FALSE;
2153 else if (dwFlags & CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG)
2154 match = !strncasecmp(nameStr, attrStr,
2155 attr->Value.cbData);
2156 else
2157 match = !strncmp(nameStr, attrStr, attr->Value.cbData);
2158 TRACE("%s : %s => %d\n",
2159 debugstr_an(nameStr, attr->Value.cbData),
2160 debugstr_an(attrStr, attr->Value.cbData), match);
2165 return match;
2168 BOOL WINAPI CertIsRDNAttrsInCertificateName(DWORD dwCertEncodingType,
2169 DWORD dwFlags, PCERT_NAME_BLOB pCertName, PCERT_RDN pRDN)
2171 CERT_NAME_INFO *name;
2172 LPCSTR type;
2173 DWORD size;
2174 BOOL ret;
2176 TRACE("(%08x, %08x, %p, %p)\n", dwCertEncodingType, dwFlags, pCertName,
2177 pRDN);
2179 type = dwFlags & CERT_UNICODE_IS_RDN_ATTRS_FLAG ? X509_UNICODE_NAME :
2180 X509_NAME;
2181 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, type, pCertName->pbData,
2182 pCertName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &name, &size)))
2184 DWORD i;
2186 for (i = 0; ret && i < pRDN->cRDNAttr; i++)
2187 ret = find_matching_rdn_attr(dwFlags, name, &pRDN->rgRDNAttr[i]);
2188 if (!ret)
2189 SetLastError(CRYPT_E_NO_MATCH);
2190 LocalFree(name);
2192 return ret;
2195 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
2196 PCERT_INFO pCertInfo)
2198 FILETIME fileTime;
2199 LONG ret;
2201 if (!pTimeToVerify)
2203 GetSystemTimeAsFileTime(&fileTime);
2204 pTimeToVerify = &fileTime;
2206 if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
2208 ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
2209 if (ret < 0)
2210 ret = 0;
2212 return ret;
2215 BOOL WINAPI CertVerifyValidityNesting(PCERT_INFO pSubjectInfo,
2216 PCERT_INFO pIssuerInfo)
2218 TRACE("(%p, %p)\n", pSubjectInfo, pIssuerInfo);
2220 return CertVerifyTimeValidity(&pSubjectInfo->NotBefore, pIssuerInfo) == 0
2221 && CertVerifyTimeValidity(&pSubjectInfo->NotAfter, pIssuerInfo) == 0;
2224 BOOL WINAPI CryptHashCertificate(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
2225 DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
2226 DWORD *pcbComputedHash)
2228 BOOL ret = TRUE;
2229 HCRYPTHASH hHash = 0;
2231 TRACE("(%08lx, %d, %08x, %p, %d, %p, %p)\n", hCryptProv, Algid, dwFlags,
2232 pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
2234 if (!hCryptProv)
2235 hCryptProv = I_CryptGetDefaultCryptProv(Algid);
2236 if (!Algid)
2237 Algid = CALG_SHA1;
2238 if (ret)
2240 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
2241 if (ret)
2243 ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
2244 if (ret)
2245 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
2246 pcbComputedHash, 0);
2247 CryptDestroyHash(hHash);
2250 return ret;
2253 BOOL WINAPI CryptHashCertificate2(LPCWSTR pwszCNGHashAlgid, DWORD dwFlags,
2254 void *pvReserved, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
2255 DWORD *pcbComputedHash)
2257 BCRYPT_HASH_HANDLE hash = NULL;
2258 BCRYPT_ALG_HANDLE alg = NULL;
2259 NTSTATUS status;
2260 DWORD hash_len;
2261 DWORD hash_len_size;
2263 TRACE("(%s, %08x, %p, %p, %d, %p, %p)\n", debugstr_w(pwszCNGHashAlgid),
2264 dwFlags, pvReserved, pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
2266 if ((status = BCryptOpenAlgorithmProvider(&alg, pwszCNGHashAlgid, NULL, 0)))
2268 if (status == STATUS_NOT_IMPLEMENTED)
2269 status = STATUS_NOT_FOUND;
2270 goto done;
2273 if ((status = BCryptCreateHash(alg, &hash, NULL, 0, NULL, 0, 0)))
2274 goto done;
2276 if ((status = BCryptGetProperty(hash, BCRYPT_HASH_LENGTH, (BYTE *)&hash_len, sizeof(hash_len), &hash_len_size, 0)))
2277 goto done;
2279 if (!pbComputedHash)
2281 *pcbComputedHash = hash_len;
2282 goto done;
2285 if (*pcbComputedHash < hash_len)
2287 status = ERROR_MORE_DATA;
2288 goto done;
2291 *pcbComputedHash = hash_len;
2293 if ((status = BCryptHashData(hash, (BYTE *)pbEncoded, cbEncoded, 0)))
2294 goto done;
2296 if ((status = BCryptFinishHash(hash, pbComputedHash, hash_len, 0)))
2297 goto done;
2299 done:
2300 if (hash) BCryptDestroyHash(hash);
2301 if (alg) BCryptCloseAlgorithmProvider(alg, 0);
2302 if (status) SetLastError(status);
2303 return !status;
2306 BOOL WINAPI CryptHashPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
2307 DWORD dwFlags, DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo,
2308 BYTE *pbComputedHash, DWORD *pcbComputedHash)
2310 BOOL ret = TRUE;
2311 HCRYPTHASH hHash = 0;
2313 TRACE("(%08lx, %d, %08x, %d, %p, %p, %p)\n", hCryptProv, Algid, dwFlags,
2314 dwCertEncodingType, pInfo, pbComputedHash, pcbComputedHash);
2316 if (!hCryptProv)
2317 hCryptProv = I_CryptGetDefaultCryptProv(0);
2318 if (!Algid)
2319 Algid = CALG_MD5;
2320 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
2322 SetLastError(ERROR_FILE_NOT_FOUND);
2323 return FALSE;
2325 if (ret)
2327 BYTE *buf;
2328 DWORD size = 0;
2330 ret = CRYPT_AsnEncodePubKeyInfoNoNull(dwCertEncodingType,
2331 X509_PUBLIC_KEY_INFO, pInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
2332 (LPBYTE)&buf, &size);
2333 if (ret)
2335 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
2336 if (ret)
2338 ret = CryptHashData(hHash, buf, size, 0);
2339 if (ret)
2340 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
2341 pcbComputedHash, 0);
2342 CryptDestroyHash(hHash);
2344 LocalFree(buf);
2347 return ret;
2350 BOOL WINAPI CryptHashToBeSigned(HCRYPTPROV_LEGACY hCryptProv,
2351 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
2352 BYTE *pbComputedHash, DWORD *pcbComputedHash)
2354 BOOL ret;
2355 CERT_SIGNED_CONTENT_INFO *info;
2356 DWORD size;
2358 TRACE("(%08lx, %08x, %p, %d, %p, %d)\n", hCryptProv, dwCertEncodingType,
2359 pbEncoded, cbEncoded, pbComputedHash, *pcbComputedHash);
2361 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
2362 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size);
2363 if (ret)
2365 PCCRYPT_OID_INFO oidInfo;
2366 HCRYPTHASH hHash;
2368 if (!hCryptProv)
2369 hCryptProv = I_CryptGetDefaultCryptProv(0);
2370 oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2371 info->SignatureAlgorithm.pszObjId, 0);
2372 if (!oidInfo)
2374 SetLastError(NTE_BAD_ALGID);
2375 ret = FALSE;
2377 else
2379 ret = CryptCreateHash(hCryptProv, oidInfo->u.Algid, 0, 0, &hHash);
2380 if (ret)
2382 ret = CryptHashData(hHash, info->ToBeSigned.pbData,
2383 info->ToBeSigned.cbData, 0);
2384 if (ret)
2385 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
2386 pcbComputedHash, 0);
2387 CryptDestroyHash(hHash);
2390 LocalFree(info);
2392 return ret;
2395 BOOL WINAPI CryptSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
2396 DWORD dwKeySpec, DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned,
2397 DWORD cbEncodedToBeSigned, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
2398 const void *pvHashAuxInfo, BYTE *pbSignature, DWORD *pcbSignature)
2400 BOOL ret;
2401 PCCRYPT_OID_INFO info;
2402 HCRYPTHASH hHash;
2404 TRACE("(%08lx, %d, %d, %p, %d, %p, %p, %p, %p)\n", hCryptProv,
2405 dwKeySpec, dwCertEncodingType, pbEncodedToBeSigned, cbEncodedToBeSigned,
2406 pSignatureAlgorithm, pvHashAuxInfo, pbSignature, pcbSignature);
2408 info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2409 pSignatureAlgorithm->pszObjId, 0);
2410 if (!info)
2412 SetLastError(NTE_BAD_ALGID);
2413 return FALSE;
2415 if (info->dwGroupId == CRYPT_HASH_ALG_OID_GROUP_ID)
2417 if (!hCryptProv)
2418 hCryptProv = I_CryptGetDefaultCryptProv(0);
2419 ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
2420 if (ret)
2422 ret = CryptHashData(hHash, pbEncodedToBeSigned,
2423 cbEncodedToBeSigned, 0);
2424 if (ret)
2425 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbSignature,
2426 pcbSignature, 0);
2427 CryptDestroyHash(hHash);
2430 else
2432 if (!hCryptProv)
2434 SetLastError(ERROR_INVALID_PARAMETER);
2435 ret = FALSE;
2437 else
2439 ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
2440 if (ret)
2442 ret = CryptHashData(hHash, pbEncodedToBeSigned,
2443 cbEncodedToBeSigned, 0);
2444 if (ret)
2445 ret = CryptSignHashW(hHash, dwKeySpec, NULL, 0, pbSignature,
2446 pcbSignature);
2447 CryptDestroyHash(hHash);
2451 return ret;
2454 BOOL WINAPI CryptSignAndEncodeCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
2455 DWORD dwKeySpec, DWORD dwCertEncodingType, LPCSTR lpszStructType,
2456 const void *pvStructInfo, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
2457 const void *pvHashAuxInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
2459 BOOL ret;
2460 DWORD encodedSize, hashSize;
2462 TRACE("(%08lx, %d, %d, %s, %p, %p, %p, %p, %p)\n", hCryptProv, dwKeySpec,
2463 dwCertEncodingType, debugstr_a(lpszStructType), pvStructInfo,
2464 pSignatureAlgorithm, pvHashAuxInfo, pbEncoded, pcbEncoded);
2466 ret = CryptEncodeObject(dwCertEncodingType, lpszStructType, pvStructInfo,
2467 NULL, &encodedSize);
2468 if (ret)
2470 PBYTE encoded = CryptMemAlloc(encodedSize);
2472 if (encoded)
2474 ret = CryptEncodeObject(dwCertEncodingType, lpszStructType,
2475 pvStructInfo, encoded, &encodedSize);
2476 if (ret)
2478 ret = CryptSignCertificate(hCryptProv, dwKeySpec,
2479 dwCertEncodingType, encoded, encodedSize, pSignatureAlgorithm,
2480 pvHashAuxInfo, NULL, &hashSize);
2481 if (ret)
2483 PBYTE hash = CryptMemAlloc(hashSize);
2485 if (hash)
2487 ret = CryptSignCertificate(hCryptProv, dwKeySpec,
2488 dwCertEncodingType, encoded, encodedSize,
2489 pSignatureAlgorithm, pvHashAuxInfo, hash, &hashSize);
2490 if (ret)
2492 CERT_SIGNED_CONTENT_INFO info = { { 0 } };
2494 info.ToBeSigned.cbData = encodedSize;
2495 info.ToBeSigned.pbData = encoded;
2496 info.SignatureAlgorithm = *pSignatureAlgorithm;
2497 info.Signature.cbData = hashSize;
2498 info.Signature.pbData = hash;
2499 info.Signature.cUnusedBits = 0;
2500 ret = CryptEncodeObject(dwCertEncodingType,
2501 X509_CERT, &info, pbEncoded, pcbEncoded);
2503 CryptMemFree(hash);
2505 else
2506 ret = FALSE;
2509 CryptMemFree(encoded);
2511 else
2512 ret = FALSE;
2514 return ret;
2517 BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV_LEGACY hCryptProv,
2518 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
2519 PCERT_PUBLIC_KEY_INFO pPublicKey)
2521 CRYPT_DATA_BLOB blob = { cbEncoded, (BYTE *)pbEncoded };
2523 return CryptVerifyCertificateSignatureEx(hCryptProv, dwCertEncodingType,
2524 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &blob,
2525 CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
2528 static BOOL CRYPT_VerifySignature(HCRYPTPROV_LEGACY hCryptProv, DWORD dwCertEncodingType,
2529 CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert, const CRYPT_OID_INFO *info)
2531 BOOL ret;
2532 HCRYPTKEY key;
2533 ALG_ID pubKeyID, hashID;
2535 hashID = info->u.Algid;
2536 if (info->ExtraInfo.cbData >= sizeof(ALG_ID))
2537 pubKeyID = *(ALG_ID *)info->ExtraInfo.pbData;
2538 else
2539 pubKeyID = hashID;
2540 /* Load the default provider if necessary */
2541 if (!hCryptProv)
2542 hCryptProv = I_CryptGetDefaultCryptProv(hashID);
2543 ret = CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType,
2544 pubKeyInfo, pubKeyID, 0, NULL, &key);
2545 if (ret)
2547 HCRYPTHASH hash;
2549 ret = CryptCreateHash(hCryptProv, hashID, 0, 0, &hash);
2550 if (ret)
2552 ret = CryptHashData(hash, signedCert->ToBeSigned.pbData,
2553 signedCert->ToBeSigned.cbData, 0);
2554 if (ret)
2555 ret = CryptVerifySignatureW(hash, signedCert->Signature.pbData,
2556 signedCert->Signature.cbData, key, NULL, 0);
2557 CryptDestroyHash(hash);
2559 CryptDestroyKey(key);
2561 return ret;
2564 static BOOL CNG_CalcHash(const WCHAR *algorithm, const CERT_SIGNED_CONTENT_INFO *signedCert,
2565 BYTE **hash_value, DWORD *hash_len)
2567 BCRYPT_HASH_HANDLE hash = NULL;
2568 BCRYPT_ALG_HANDLE alg = NULL;
2569 NTSTATUS status;
2570 DWORD size;
2572 if ((status = BCryptOpenAlgorithmProvider(&alg, algorithm, NULL, 0)))
2573 goto done;
2575 if ((status = BCryptCreateHash(alg, &hash, NULL, 0, NULL, 0, 0)))
2576 goto done;
2578 if ((status = BCryptHashData(hash, signedCert->ToBeSigned.pbData, signedCert->ToBeSigned.cbData, 0)))
2579 goto done;
2581 if ((status = BCryptGetProperty(hash, BCRYPT_HASH_LENGTH, (BYTE *)hash_len, sizeof(*hash_len), &size, 0)))
2582 goto done;
2584 if (!(*hash_value = CryptMemAlloc(*hash_len)))
2586 status = STATUS_NO_MEMORY;
2587 goto done;
2590 if ((status = BCryptFinishHash(hash, *hash_value, *hash_len, 0)))
2592 CryptMemFree(*hash_value);
2593 goto done;
2596 done:
2597 if (hash) BCryptDestroyHash(hash);
2598 if (alg) BCryptCloseAlgorithmProvider(alg, 0);
2599 if (status) SetLastError(RtlNtStatusToDosError(status));
2600 return status == 0;
2603 static BOOL CNG_ImportECCPubKey(CERT_PUBLIC_KEY_INFO *pubKeyInfo, BCRYPT_KEY_HANDLE *key)
2605 DWORD blob_magic, ecckey_len, size;
2606 BCRYPT_ALG_HANDLE alg = NULL;
2607 BCRYPT_ECCKEY_BLOB *ecckey;
2608 const WCHAR *sign_algo;
2609 char **ecc_curve;
2610 NTSTATUS status;
2612 if (!pubKeyInfo->PublicKey.cbData)
2614 SetLastError(NTE_BAD_ALGID);
2615 return FALSE;
2618 if (pubKeyInfo->PublicKey.pbData[0] != 0x4)
2620 FIXME("Compressed ECC curves (%02x) not yet supported\n", pubKeyInfo->PublicKey.pbData[0]);
2621 SetLastError(NTE_BAD_ALGID);
2622 return FALSE;
2625 if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OBJECT_IDENTIFIER, pubKeyInfo->Algorithm.Parameters.pbData,
2626 pubKeyInfo->Algorithm.Parameters.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &ecc_curve, &size))
2627 return FALSE;
2629 if (!strcmp(*ecc_curve, szOID_ECC_CURVE_P256))
2631 sign_algo = BCRYPT_ECDSA_P256_ALGORITHM;
2632 blob_magic = BCRYPT_ECDSA_PUBLIC_P256_MAGIC;
2634 else if (!strcmp(*ecc_curve, szOID_ECC_CURVE_P384))
2636 sign_algo = BCRYPT_ECDSA_P384_ALGORITHM;
2637 blob_magic = BCRYPT_ECDSA_PUBLIC_P384_MAGIC;
2639 else
2641 FIXME("Unsupported ecc curve type: %s\n", *ecc_curve);
2642 sign_algo = NULL;
2643 blob_magic = 0;
2645 LocalFree(ecc_curve);
2647 if (!sign_algo)
2649 SetLastError(NTE_BAD_ALGID);
2650 return FALSE;
2653 if ((status = BCryptOpenAlgorithmProvider(&alg, sign_algo, NULL, 0)))
2654 goto done;
2656 ecckey_len = sizeof(BCRYPT_ECCKEY_BLOB) + pubKeyInfo->PublicKey.cbData - 1;
2657 if (!(ecckey = CryptMemAlloc(ecckey_len)))
2659 status = STATUS_NO_MEMORY;
2660 goto done;
2663 ecckey->dwMagic = blob_magic;
2664 ecckey->cbKey = (pubKeyInfo->PublicKey.cbData - 1) / 2;
2665 memcpy(ecckey + 1, pubKeyInfo->PublicKey.pbData + 1, pubKeyInfo->PublicKey.cbData - 1);
2667 status = BCryptImportKeyPair(alg, NULL, BCRYPT_ECCPUBLIC_BLOB, key, (BYTE*)ecckey, ecckey_len, 0);
2668 CryptMemFree(ecckey);
2670 done:
2671 if (alg) BCryptCloseAlgorithmProvider(alg, 0);
2672 if (status) SetLastError(RtlNtStatusToDosError(status));
2673 return !status;
2676 static BOOL CNG_ImportPubKey(CERT_PUBLIC_KEY_INFO *pubKeyInfo, BCRYPT_KEY_HANDLE *key)
2678 if (!strcmp(pubKeyInfo->Algorithm.pszObjId, szOID_ECC_PUBLIC_KEY))
2679 return CNG_ImportECCPubKey(pubKeyInfo, key);
2681 FIXME("Unsupported public key type: %s\n", debugstr_a(pubKeyInfo->Algorithm.pszObjId));
2682 SetLastError(NTE_BAD_ALGID);
2683 return FALSE;
2686 static BOOL CNG_PrepareSignatureECC(BYTE *encoded_sig, DWORD encoded_size, BYTE **sig_value, DWORD *sig_len)
2688 CERT_ECC_SIGNATURE *ecc_sig;
2689 DWORD size;
2690 int i;
2692 if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ECC_SIGNATURE, encoded_sig, encoded_size,
2693 CRYPT_DECODE_ALLOC_FLAG, NULL, &ecc_sig, &size))
2694 return FALSE;
2696 if (!ecc_sig->r.cbData || !ecc_sig->s.cbData)
2698 LocalFree(ecc_sig);
2699 SetLastError(ERROR_INVALID_DATA);
2700 return FALSE;
2703 *sig_len = ecc_sig->r.cbData + ecc_sig->s.cbData;
2704 if (!(*sig_value = CryptMemAlloc(*sig_len)))
2706 LocalFree(ecc_sig);
2707 SetLastError(ERROR_OUTOFMEMORY);
2708 return FALSE;
2711 for (i = 0; i < ecc_sig->r.cbData; i++)
2712 (*sig_value)[i] = ecc_sig->r.pbData[ecc_sig->r.cbData - i - 1];
2713 for (i = 0; i < ecc_sig->s.cbData; i++)
2714 (*sig_value)[ecc_sig->r.cbData + i] = ecc_sig->s.pbData[ecc_sig->s.cbData - i - 1];
2716 LocalFree(ecc_sig);
2717 return TRUE;
2720 static BOOL CNG_PrepareSignature(CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert,
2721 BYTE **sig_value, DWORD *sig_len)
2723 BYTE *encoded_sig;
2724 BOOL ret = FALSE;
2725 int i;
2727 if (!signedCert->Signature.cbData)
2729 SetLastError(ERROR_INVALID_DATA);
2730 return FALSE;
2733 if (!(encoded_sig = CryptMemAlloc(signedCert->Signature.cbData)))
2735 SetLastError(ERROR_OUTOFMEMORY);
2736 return FALSE;
2739 for (i = 0; i < signedCert->Signature.cbData; i++)
2740 encoded_sig[i] = signedCert->Signature.pbData[signedCert->Signature.cbData - i - 1];
2742 if (!strcmp(pubKeyInfo->Algorithm.pszObjId, szOID_ECC_PUBLIC_KEY))
2743 ret = CNG_PrepareSignatureECC(encoded_sig, signedCert->Signature.cbData, sig_value, sig_len);
2744 else
2746 FIXME("Unsupported public key type: %s\n", debugstr_a(pubKeyInfo->Algorithm.pszObjId));
2747 SetLastError(NTE_BAD_ALGID);
2750 CryptMemFree(encoded_sig);
2751 return ret;
2754 static BOOL CNG_VerifySignature(HCRYPTPROV_LEGACY hCryptProv, DWORD dwCertEncodingType,
2755 CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert, const CRYPT_OID_INFO *info)
2757 BCRYPT_KEY_HANDLE key = NULL;
2758 BYTE *hash_value = NULL, *sig_value;
2759 DWORD hash_len, sig_len;
2760 NTSTATUS status;
2761 BOOL ret;
2763 ret = CNG_ImportPubKey(pubKeyInfo, &key);
2764 if (ret)
2766 ret = CNG_CalcHash(info->pwszCNGAlgid, signedCert, &hash_value, &hash_len);
2767 if (ret)
2769 ret = CNG_PrepareSignature(pubKeyInfo, signedCert, &sig_value, &sig_len);
2770 if (ret)
2772 status = BCryptVerifySignature(key, NULL, hash_value, hash_len, sig_value, sig_len, 0);
2773 if (status)
2775 FIXME("Failed to verify signature: %08x\n", status);
2776 SetLastError(RtlNtStatusToDosError(status));
2777 ret = FALSE;
2779 CryptMemFree(sig_value);
2781 CryptMemFree(hash_value);
2783 BCryptDestroyKey(key);
2786 return ret;
2789 static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv, DWORD dwCertEncodingType,
2790 CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert)
2792 CCRYPT_OID_INFO *info;
2794 info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, signedCert->SignatureAlgorithm.pszObjId, 0);
2795 if (!info || info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID)
2797 SetLastError(NTE_BAD_ALGID);
2798 return FALSE;
2801 if (info->u.Algid == CALG_OID_INFO_CNG_ONLY)
2802 return CNG_VerifySignature(hCryptProv, dwCertEncodingType, pubKeyInfo, signedCert, info);
2803 else
2804 return CRYPT_VerifySignature(hCryptProv, dwCertEncodingType, pubKeyInfo, signedCert, info);
2807 BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV_LEGACY hCryptProv,
2808 DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
2809 DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
2811 BOOL ret = TRUE;
2812 CRYPT_DATA_BLOB subjectBlob;
2814 TRACE("(%08lx, %d, %d, %p, %d, %p, %08x, %p)\n", hCryptProv,
2815 dwCertEncodingType, dwSubjectType, pvSubject, dwIssuerType, pvIssuer,
2816 dwFlags, pvReserved);
2818 switch (dwSubjectType)
2820 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB:
2822 PCRYPT_DATA_BLOB blob = pvSubject;
2824 subjectBlob.pbData = blob->pbData;
2825 subjectBlob.cbData = blob->cbData;
2826 break;
2828 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT:
2830 PCERT_CONTEXT context = pvSubject;
2832 subjectBlob.pbData = context->pbCertEncoded;
2833 subjectBlob.cbData = context->cbCertEncoded;
2834 break;
2836 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL:
2838 PCRL_CONTEXT context = pvSubject;
2840 subjectBlob.pbData = context->pbCrlEncoded;
2841 subjectBlob.cbData = context->cbCrlEncoded;
2842 break;
2844 default:
2845 SetLastError(E_INVALIDARG);
2846 ret = FALSE;
2849 if (ret)
2851 PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
2852 DWORD size = 0;
2854 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
2855 subjectBlob.pbData, subjectBlob.cbData,
2856 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
2857 &signedCert, &size);
2858 if (ret)
2860 switch (dwIssuerType)
2862 case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY:
2863 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
2864 dwCertEncodingType, pvIssuer,
2865 signedCert);
2866 break;
2867 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT:
2868 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
2869 dwCertEncodingType,
2870 &((PCCERT_CONTEXT)pvIssuer)->pCertInfo->SubjectPublicKeyInfo,
2871 signedCert);
2872 break;
2873 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN:
2874 FIXME("CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: stub\n");
2875 ret = FALSE;
2876 break;
2877 case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL:
2878 if (pvIssuer)
2880 SetLastError(E_INVALIDARG);
2881 ret = FALSE;
2883 else
2885 FIXME("unimplemented for NULL signer\n");
2886 SetLastError(E_INVALIDARG);
2887 ret = FALSE;
2889 break;
2890 default:
2891 SetLastError(E_INVALIDARG);
2892 ret = FALSE;
2894 LocalFree(signedCert);
2897 return ret;
2900 BOOL WINAPI CertGetIntendedKeyUsage(DWORD dwCertEncodingType,
2901 PCERT_INFO pCertInfo, BYTE *pbKeyUsage, DWORD cbKeyUsage)
2903 PCERT_EXTENSION ext;
2904 BOOL ret = FALSE;
2906 TRACE("(%08x, %p, %p, %d)\n", dwCertEncodingType, pCertInfo, pbKeyUsage,
2907 cbKeyUsage);
2909 ext = CertFindExtension(szOID_KEY_USAGE, pCertInfo->cExtension,
2910 pCertInfo->rgExtension);
2911 if (ext)
2913 CRYPT_BIT_BLOB usage;
2914 DWORD size = sizeof(usage);
2916 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS,
2917 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL,
2918 &usage, &size);
2919 if (ret)
2921 if (cbKeyUsage < usage.cbData)
2922 ret = FALSE;
2923 else
2925 memcpy(pbKeyUsage, usage.pbData, usage.cbData);
2926 if (cbKeyUsage > usage.cbData)
2927 memset(pbKeyUsage + usage.cbData, 0,
2928 cbKeyUsage - usage.cbData);
2932 else
2933 SetLastError(0);
2934 return ret;
2937 BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags,
2938 PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage)
2940 PCERT_ENHKEY_USAGE usage = NULL;
2941 DWORD bytesNeeded;
2942 BOOL ret = TRUE;
2944 if (!pCertContext || !pcbUsage)
2946 SetLastError(ERROR_INVALID_PARAMETER);
2947 return FALSE;
2950 TRACE("(%p, %08x, %p, %d)\n", pCertContext, dwFlags, pUsage, *pcbUsage);
2952 if (!(dwFlags & CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG))
2954 DWORD propSize = 0;
2956 if (CertGetCertificateContextProperty(pCertContext,
2957 CERT_ENHKEY_USAGE_PROP_ID, NULL, &propSize))
2959 LPBYTE buf = CryptMemAlloc(propSize);
2961 if (buf)
2963 if (CertGetCertificateContextProperty(pCertContext,
2964 CERT_ENHKEY_USAGE_PROP_ID, buf, &propSize))
2966 ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
2967 X509_ENHANCED_KEY_USAGE, buf, propSize,
2968 CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
2970 CryptMemFree(buf);
2974 if (!usage && !(dwFlags & CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG))
2976 PCERT_EXTENSION ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
2977 pCertContext->pCertInfo->cExtension,
2978 pCertContext->pCertInfo->rgExtension);
2980 if (ext)
2982 ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
2983 X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
2984 CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
2987 if (!usage)
2989 /* If a particular location is specified, this should fail. Otherwise
2990 * it should succeed with an empty usage. (This is true on Win2k and
2991 * later, which we emulate.)
2993 if (dwFlags)
2995 SetLastError(CRYPT_E_NOT_FOUND);
2996 ret = FALSE;
2998 else
2999 bytesNeeded = sizeof(CERT_ENHKEY_USAGE);
3002 if (ret)
3004 if (!pUsage)
3005 *pcbUsage = bytesNeeded;
3006 else if (*pcbUsage < bytesNeeded)
3008 SetLastError(ERROR_MORE_DATA);
3009 *pcbUsage = bytesNeeded;
3010 ret = FALSE;
3012 else
3014 *pcbUsage = bytesNeeded;
3015 if (usage)
3017 DWORD i;
3018 LPSTR nextOID = (LPSTR)((LPBYTE)pUsage +
3019 sizeof(CERT_ENHKEY_USAGE) +
3020 usage->cUsageIdentifier * sizeof(LPSTR));
3022 pUsage->cUsageIdentifier = usage->cUsageIdentifier;
3023 pUsage->rgpszUsageIdentifier = (LPSTR *)((LPBYTE)pUsage +
3024 sizeof(CERT_ENHKEY_USAGE));
3025 for (i = 0; i < usage->cUsageIdentifier; i++)
3027 pUsage->rgpszUsageIdentifier[i] = nextOID;
3028 strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
3029 nextOID += strlen(nextOID) + 1;
3032 else
3033 pUsage->cUsageIdentifier = 0;
3036 if (usage)
3037 LocalFree(usage);
3038 TRACE("returning %d\n", ret);
3039 return ret;
3042 BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext,
3043 PCERT_ENHKEY_USAGE pUsage)
3045 BOOL ret;
3047 TRACE("(%p, %p)\n", pCertContext, pUsage);
3049 if (pUsage)
3051 CRYPT_DATA_BLOB blob = { 0, NULL };
3053 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
3054 pUsage, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData, &blob.cbData);
3055 if (ret)
3057 ret = CertSetCertificateContextProperty(pCertContext,
3058 CERT_ENHKEY_USAGE_PROP_ID, 0, &blob);
3059 LocalFree(blob.pbData);
3062 else
3063 ret = CertSetCertificateContextProperty(pCertContext,
3064 CERT_ENHKEY_USAGE_PROP_ID, 0, NULL);
3065 return ret;
3068 BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
3069 LPCSTR pszUsageIdentifier)
3071 BOOL ret;
3072 DWORD size;
3074 TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
3076 if (CertGetEnhancedKeyUsage(pCertContext,
3077 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size))
3079 PCERT_ENHKEY_USAGE usage = CryptMemAlloc(size);
3081 if (usage)
3083 ret = CertGetEnhancedKeyUsage(pCertContext,
3084 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size);
3085 if (ret)
3087 DWORD i;
3088 BOOL exists = FALSE;
3090 /* Make sure usage doesn't already exist */
3091 for (i = 0; !exists && i < usage->cUsageIdentifier; i++)
3093 if (!strcmp(usage->rgpszUsageIdentifier[i],
3094 pszUsageIdentifier))
3095 exists = TRUE;
3097 if (!exists)
3099 PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size +
3100 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
3102 if (newUsage)
3104 LPSTR nextOID;
3106 newUsage->rgpszUsageIdentifier = (LPSTR *)
3107 ((LPBYTE)newUsage + sizeof(CERT_ENHKEY_USAGE));
3108 nextOID = (LPSTR)((LPBYTE)newUsage->rgpszUsageIdentifier
3109 + (usage->cUsageIdentifier + 1) * sizeof(LPSTR));
3110 for (i = 0; i < usage->cUsageIdentifier; i++)
3112 newUsage->rgpszUsageIdentifier[i] = nextOID;
3113 strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
3114 nextOID += strlen(nextOID) + 1;
3116 newUsage->rgpszUsageIdentifier[i] = nextOID;
3117 strcpy(nextOID, pszUsageIdentifier);
3118 newUsage->cUsageIdentifier = i + 1;
3119 ret = CertSetEnhancedKeyUsage(pCertContext, newUsage);
3120 CryptMemFree(newUsage);
3122 else
3123 ret = FALSE;
3126 CryptMemFree(usage);
3128 else
3129 ret = FALSE;
3131 else
3133 PCERT_ENHKEY_USAGE usage = CryptMemAlloc(sizeof(CERT_ENHKEY_USAGE) +
3134 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
3136 if (usage)
3138 usage->rgpszUsageIdentifier =
3139 (LPSTR *)((LPBYTE)usage + sizeof(CERT_ENHKEY_USAGE));
3140 usage->rgpszUsageIdentifier[0] = (LPSTR)((LPBYTE)usage +
3141 sizeof(CERT_ENHKEY_USAGE) + sizeof(LPSTR));
3142 strcpy(usage->rgpszUsageIdentifier[0], pszUsageIdentifier);
3143 usage->cUsageIdentifier = 1;
3144 ret = CertSetEnhancedKeyUsage(pCertContext, usage);
3145 CryptMemFree(usage);
3147 else
3148 ret = FALSE;
3150 return ret;
3153 BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
3154 LPCSTR pszUsageIdentifier)
3156 BOOL ret;
3157 DWORD size;
3158 CERT_ENHKEY_USAGE usage;
3160 TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
3162 size = sizeof(usage);
3163 ret = CertGetEnhancedKeyUsage(pCertContext,
3164 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, &usage, &size);
3165 if (!ret && GetLastError() == ERROR_MORE_DATA)
3167 PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
3169 if (pUsage)
3171 ret = CertGetEnhancedKeyUsage(pCertContext,
3172 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
3173 if (ret)
3175 if (pUsage->cUsageIdentifier)
3177 DWORD i;
3178 BOOL found = FALSE;
3180 for (i = 0; i < pUsage->cUsageIdentifier; i++)
3182 if (!strcmp(pUsage->rgpszUsageIdentifier[i],
3183 pszUsageIdentifier))
3184 found = TRUE;
3185 if (found && i < pUsage->cUsageIdentifier - 1)
3186 pUsage->rgpszUsageIdentifier[i] =
3187 pUsage->rgpszUsageIdentifier[i + 1];
3189 pUsage->cUsageIdentifier--;
3190 /* Remove the usage if it's empty */
3191 if (pUsage->cUsageIdentifier)
3192 ret = CertSetEnhancedKeyUsage(pCertContext, pUsage);
3193 else
3194 ret = CertSetEnhancedKeyUsage(pCertContext, NULL);
3197 CryptMemFree(pUsage);
3199 else
3200 ret = FALSE;
3202 else
3204 /* it fit in an empty usage, therefore there's nothing to remove */
3205 ret = TRUE;
3207 return ret;
3210 struct BitField
3212 DWORD cIndexes;
3213 DWORD *indexes;
3216 #define BITS_PER_DWORD (sizeof(DWORD) * 8)
3218 static void CRYPT_SetBitInField(struct BitField *field, DWORD bit)
3220 DWORD indexIndex = bit / BITS_PER_DWORD;
3222 if (indexIndex + 1 > field->cIndexes)
3224 if (field->cIndexes)
3225 field->indexes = CryptMemRealloc(field->indexes,
3226 (indexIndex + 1) * sizeof(DWORD));
3227 else
3228 field->indexes = CryptMemAlloc(sizeof(DWORD));
3229 if (field->indexes)
3231 field->indexes[indexIndex] = 0;
3232 field->cIndexes = indexIndex + 1;
3235 if (field->indexes)
3236 field->indexes[indexIndex] |= 1 << (bit % BITS_PER_DWORD);
3239 static BOOL CRYPT_IsBitInFieldSet(const struct BitField *field, DWORD bit)
3241 BOOL set;
3242 DWORD indexIndex = bit / BITS_PER_DWORD;
3244 assert(field->cIndexes);
3245 set = field->indexes[indexIndex] & (1 << (bit % BITS_PER_DWORD));
3246 return set;
3249 BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts,
3250 int *cNumOIDs, LPSTR *rghOIDs, DWORD *pcbOIDs)
3252 BOOL ret = TRUE;
3253 DWORD i, cbOIDs = 0;
3254 BOOL allUsagesValid = TRUE;
3255 CERT_ENHKEY_USAGE validUsages = { 0, NULL };
3257 TRACE("(%d, %p, %d, %p, %d)\n", cCerts, rghCerts, *cNumOIDs,
3258 rghOIDs, *pcbOIDs);
3260 for (i = 0; i < cCerts; i++)
3262 CERT_ENHKEY_USAGE usage;
3263 DWORD size = sizeof(usage);
3265 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, &usage, &size);
3266 /* Success is deliberately ignored: it implies all usages are valid */
3267 if (!ret && GetLastError() == ERROR_MORE_DATA)
3269 PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
3271 allUsagesValid = FALSE;
3272 if (pUsage)
3274 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, pUsage, &size);
3275 if (ret)
3277 if (!validUsages.cUsageIdentifier)
3279 DWORD j;
3281 cbOIDs = pUsage->cUsageIdentifier * sizeof(LPSTR);
3282 validUsages.cUsageIdentifier = pUsage->cUsageIdentifier;
3283 for (j = 0; j < validUsages.cUsageIdentifier; j++)
3284 cbOIDs += lstrlenA(pUsage->rgpszUsageIdentifier[j])
3285 + 1;
3286 validUsages.rgpszUsageIdentifier =
3287 CryptMemAlloc(cbOIDs);
3288 if (validUsages.rgpszUsageIdentifier)
3290 LPSTR nextOID = (LPSTR)
3291 ((LPBYTE)validUsages.rgpszUsageIdentifier +
3292 validUsages.cUsageIdentifier * sizeof(LPSTR));
3294 for (j = 0; j < validUsages.cUsageIdentifier; j++)
3296 validUsages.rgpszUsageIdentifier[j] = nextOID;
3297 lstrcpyA(validUsages.rgpszUsageIdentifier[j],
3298 pUsage->rgpszUsageIdentifier[j]);
3299 nextOID += lstrlenA(nextOID) + 1;
3303 else
3305 struct BitField validIndexes = { 0, NULL };
3306 DWORD j, k, numRemoved = 0;
3308 /* Merge: build a bitmap of all the indexes of
3309 * validUsages.rgpszUsageIdentifier that are in pUsage.
3311 for (j = 0; j < pUsage->cUsageIdentifier; j++)
3313 for (k = 0; k < validUsages.cUsageIdentifier; k++)
3315 if (!strcmp(pUsage->rgpszUsageIdentifier[j],
3316 validUsages.rgpszUsageIdentifier[k]))
3318 CRYPT_SetBitInField(&validIndexes, k);
3319 break;
3323 /* Merge by removing from validUsages those that are
3324 * not in the bitmap.
3326 for (j = 0; j < validUsages.cUsageIdentifier; j++)
3328 if (!CRYPT_IsBitInFieldSet(&validIndexes, j))
3330 if (j < validUsages.cUsageIdentifier - 1)
3332 memmove(&validUsages.rgpszUsageIdentifier[j],
3333 &validUsages.rgpszUsageIdentifier[j +
3334 numRemoved + 1],
3335 (validUsages.cUsageIdentifier - numRemoved
3336 - j - 1) * sizeof(LPSTR));
3337 cbOIDs -= lstrlenA(
3338 validUsages.rgpszUsageIdentifier[j]) + 1 +
3339 sizeof(LPSTR);
3340 validUsages.cUsageIdentifier--;
3341 numRemoved++;
3343 else
3344 validUsages.cUsageIdentifier--;
3347 CryptMemFree(validIndexes.indexes);
3350 CryptMemFree(pUsage);
3354 ret = TRUE;
3355 if (allUsagesValid)
3357 *cNumOIDs = -1;
3358 *pcbOIDs = 0;
3360 else
3362 *cNumOIDs = validUsages.cUsageIdentifier;
3363 if (!rghOIDs)
3364 *pcbOIDs = cbOIDs;
3365 else if (*pcbOIDs < cbOIDs)
3367 *pcbOIDs = cbOIDs;
3368 SetLastError(ERROR_MORE_DATA);
3369 ret = FALSE;
3371 else
3373 LPSTR nextOID = (LPSTR)((LPBYTE)rghOIDs +
3374 validUsages.cUsageIdentifier * sizeof(LPSTR));
3376 *pcbOIDs = cbOIDs;
3377 for (i = 0; i < validUsages.cUsageIdentifier; i++)
3379 rghOIDs[i] = nextOID;
3380 lstrcpyA(nextOID, validUsages.rgpszUsageIdentifier[i]);
3381 nextOID += lstrlenA(nextOID) + 1;
3385 CryptMemFree(validUsages.rgpszUsageIdentifier);
3386 TRACE("cNumOIDs: %d\n", *cNumOIDs);
3387 TRACE("returning %d\n", ret);
3388 return ret;
3391 /* Sets the CERT_KEY_PROV_INFO_PROP_ID property of context from pInfo, or, if
3392 * pInfo is NULL, from the attributes of hProv.
3394 static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context,
3395 const CRYPT_KEY_PROV_INFO *pInfo, HCRYPTPROV hProv)
3397 CRYPT_KEY_PROV_INFO info = { 0 };
3398 BOOL ret;
3400 if (!pInfo)
3402 DWORD size;
3403 int len;
3405 ret = CryptGetProvParam(hProv, PP_CONTAINER, NULL, &size, 0);
3406 if (ret)
3408 LPSTR szContainer = CryptMemAlloc(size);
3410 if (szContainer)
3412 ret = CryptGetProvParam(hProv, PP_CONTAINER,
3413 (BYTE *)szContainer, &size, 0);
3414 if (ret)
3416 len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
3417 NULL, 0);
3418 if (len)
3420 info.pwszContainerName = CryptMemAlloc(len *
3421 sizeof(WCHAR));
3422 MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
3423 info.pwszContainerName, len);
3426 CryptMemFree(szContainer);
3429 ret = CryptGetProvParam(hProv, PP_NAME, NULL, &size, 0);
3430 if (ret)
3432 LPSTR szProvider = CryptMemAlloc(size);
3434 if (szProvider)
3436 ret = CryptGetProvParam(hProv, PP_NAME, (BYTE *)szProvider,
3437 &size, 0);
3438 if (ret)
3440 len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
3441 NULL, 0);
3442 if (len)
3444 info.pwszProvName = CryptMemAlloc(len *
3445 sizeof(WCHAR));
3446 MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
3447 info.pwszProvName, len);
3450 CryptMemFree(szProvider);
3453 /* in case no CRYPT_KEY_PROV_INFO given,
3454 * we always use AT_SIGNATURE key spec
3456 info.dwKeySpec = AT_SIGNATURE;
3457 size = sizeof(info.dwProvType);
3458 ret = CryptGetProvParam(hProv, PP_PROVTYPE, (LPBYTE)&info.dwProvType,
3459 &size, 0);
3460 if (!ret)
3461 info.dwProvType = PROV_RSA_FULL;
3462 pInfo = &info;
3465 CertSetCertificateContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID,
3466 0, pInfo);
3468 if (pInfo == &info)
3470 CryptMemFree(info.pwszContainerName);
3471 CryptMemFree(info.pwszProvName);
3475 /* Creates a signed certificate context from the unsigned, encoded certificate
3476 * in blob, using the crypto provider hProv and the signature algorithm sigAlgo.
3478 static PCCERT_CONTEXT CRYPT_CreateSignedCert(const CRYPT_DER_BLOB *blob,
3479 HCRYPTPROV hProv, DWORD dwKeySpec, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo)
3481 PCCERT_CONTEXT context = NULL;
3482 BOOL ret;
3483 DWORD sigSize = 0;
3485 ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
3486 blob->pbData, blob->cbData, sigAlgo, NULL, NULL, &sigSize);
3487 if (ret)
3489 LPBYTE sig = CryptMemAlloc(sigSize);
3491 ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
3492 blob->pbData, blob->cbData, sigAlgo, NULL, sig, &sigSize);
3493 if (ret)
3495 CERT_SIGNED_CONTENT_INFO signedInfo;
3496 BYTE *encodedSignedCert = NULL;
3497 DWORD encodedSignedCertSize = 0;
3499 signedInfo.ToBeSigned.cbData = blob->cbData;
3500 signedInfo.ToBeSigned.pbData = blob->pbData;
3501 signedInfo.SignatureAlgorithm = *sigAlgo;
3502 signedInfo.Signature.cbData = sigSize;
3503 signedInfo.Signature.pbData = sig;
3504 signedInfo.Signature.cUnusedBits = 0;
3505 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT,
3506 &signedInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
3507 &encodedSignedCert, &encodedSignedCertSize);
3508 if (ret)
3510 context = CertCreateCertificateContext(X509_ASN_ENCODING,
3511 encodedSignedCert, encodedSignedCertSize);
3512 LocalFree(encodedSignedCert);
3515 CryptMemFree(sig);
3517 return context;
3520 /* Copies data from the parameters into info, where:
3521 * pSerialNumber: The serial number. Must not be NULL.
3522 * pSubjectIssuerBlob: Specifies both the subject and issuer for info.
3523 * Must not be NULL
3524 * pSignatureAlgorithm: Optional.
3525 * pStartTime: The starting time of the certificate. If NULL, the current
3526 * system time is used.
3527 * pEndTime: The ending time of the certificate. If NULL, one year past the
3528 * starting time is used.
3529 * pubKey: The public key of the certificate. Must not be NULL.
3530 * pExtensions: Extensions to be included with the certificate. Optional.
3532 static void CRYPT_MakeCertInfo(PCERT_INFO info, const CRYPT_DATA_BLOB *pSerialNumber,
3533 const CERT_NAME_BLOB *pSubjectIssuerBlob,
3534 const CRYPT_ALGORITHM_IDENTIFIER *pSignatureAlgorithm, const SYSTEMTIME *pStartTime,
3535 const SYSTEMTIME *pEndTime, const CERT_PUBLIC_KEY_INFO *pubKey,
3536 const CERT_EXTENSIONS *pExtensions)
3538 static CHAR oid[] = szOID_RSA_SHA1RSA;
3540 assert(info);
3541 assert(pSerialNumber);
3542 assert(pSubjectIssuerBlob);
3543 assert(pubKey);
3545 if (pExtensions && pExtensions->cExtension)
3546 info->dwVersion = CERT_V3;
3547 else
3548 info->dwVersion = CERT_V1;
3549 info->SerialNumber.cbData = pSerialNumber->cbData;
3550 info->SerialNumber.pbData = pSerialNumber->pbData;
3551 if (pSignatureAlgorithm)
3552 info->SignatureAlgorithm = *pSignatureAlgorithm;
3553 else
3555 info->SignatureAlgorithm.pszObjId = oid;
3556 info->SignatureAlgorithm.Parameters.cbData = 0;
3557 info->SignatureAlgorithm.Parameters.pbData = NULL;
3559 info->Issuer.cbData = pSubjectIssuerBlob->cbData;
3560 info->Issuer.pbData = pSubjectIssuerBlob->pbData;
3561 if (pStartTime)
3562 SystemTimeToFileTime(pStartTime, &info->NotBefore);
3563 else
3564 GetSystemTimeAsFileTime(&info->NotBefore);
3565 if (pEndTime)
3566 SystemTimeToFileTime(pEndTime, &info->NotAfter);
3567 else
3569 SYSTEMTIME endTime;
3571 if (FileTimeToSystemTime(&info->NotBefore, &endTime))
3573 endTime.wYear++;
3574 SystemTimeToFileTime(&endTime, &info->NotAfter);
3577 info->Subject.cbData = pSubjectIssuerBlob->cbData;
3578 info->Subject.pbData = pSubjectIssuerBlob->pbData;
3579 info->SubjectPublicKeyInfo = *pubKey;
3580 if (pExtensions)
3582 info->cExtension = pExtensions->cExtension;
3583 info->rgExtension = pExtensions->rgExtension;
3585 else
3587 info->cExtension = 0;
3588 info->rgExtension = NULL;
3592 typedef RPC_STATUS (RPC_ENTRY *UuidCreateFunc)(UUID *);
3593 typedef RPC_STATUS (RPC_ENTRY *UuidToStringFunc)(UUID *, unsigned char **);
3594 typedef RPC_STATUS (RPC_ENTRY *RpcStringFreeFunc)(unsigned char **);
3596 static HCRYPTPROV CRYPT_CreateKeyProv(void)
3598 HCRYPTPROV hProv = 0;
3599 HMODULE rpcrt = LoadLibraryA("rpcrt4");
3601 if (rpcrt)
3603 UuidCreateFunc uuidCreate = (UuidCreateFunc)GetProcAddress(rpcrt,
3604 "UuidCreate");
3605 UuidToStringFunc uuidToString = (UuidToStringFunc)GetProcAddress(rpcrt,
3606 "UuidToStringA");
3607 RpcStringFreeFunc rpcStringFree = (RpcStringFreeFunc)GetProcAddress(
3608 rpcrt, "RpcStringFreeA");
3610 if (uuidCreate && uuidToString && rpcStringFree)
3612 UUID uuid;
3613 RPC_STATUS status = uuidCreate(&uuid);
3615 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY)
3617 unsigned char *uuidStr;
3619 status = uuidToString(&uuid, &uuidStr);
3620 if (status == RPC_S_OK)
3622 BOOL ret = CryptAcquireContextA(&hProv, (LPCSTR)uuidStr,
3623 MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_NEWKEYSET);
3625 if (ret)
3627 HCRYPTKEY key;
3629 ret = CryptGenKey(hProv, AT_SIGNATURE, 0, &key);
3630 if (ret)
3631 CryptDestroyKey(key);
3633 rpcStringFree(&uuidStr);
3637 FreeLibrary(rpcrt);
3639 return hProv;
3642 PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hProv,
3643 PCERT_NAME_BLOB pSubjectIssuerBlob, DWORD dwFlags,
3644 PCRYPT_KEY_PROV_INFO pKeyProvInfo,
3645 PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime,
3646 PSYSTEMTIME pEndTime, PCERT_EXTENSIONS pExtensions)
3648 PCCERT_CONTEXT context = NULL;
3649 BOOL ret, releaseContext = FALSE;
3650 PCERT_PUBLIC_KEY_INFO pubKey = NULL;
3651 DWORD pubKeySize = 0, dwKeySpec;
3653 TRACE("(%08lx, %p, %08x, %p, %p, %p, %p, %p)\n", hProv,
3654 pSubjectIssuerBlob, dwFlags, pKeyProvInfo, pSignatureAlgorithm, pStartTime,
3655 pExtensions, pExtensions);
3657 if(!pSubjectIssuerBlob)
3659 SetLastError(ERROR_INVALID_PARAMETER);
3660 return NULL;
3663 dwKeySpec = pKeyProvInfo ? pKeyProvInfo->dwKeySpec : AT_SIGNATURE;
3664 if (!hProv)
3666 if (!pKeyProvInfo)
3668 hProv = CRYPT_CreateKeyProv();
3669 releaseContext = TRUE;
3671 else if (pKeyProvInfo->dwFlags & CERT_SET_KEY_PROV_HANDLE_PROP_ID)
3673 SetLastError(NTE_BAD_FLAGS);
3674 return NULL;
3676 else
3678 HCRYPTKEY hKey = 0;
3679 /* acquire the context using the given information*/
3680 ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
3681 pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
3682 pKeyProvInfo->dwFlags);
3683 if (!ret)
3685 if(GetLastError() != NTE_BAD_KEYSET)
3686 return NULL;
3687 /* create the key set */
3688 ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
3689 pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
3690 pKeyProvInfo->dwFlags|CRYPT_NEWKEYSET);
3691 if (!ret)
3692 return NULL;
3694 /* check if the key is here */
3695 ret = CryptGetUserKey(hProv,dwKeySpec,&hKey);
3696 if(!ret)
3698 if (NTE_NO_KEY == GetLastError())
3699 { /* generate the key */
3700 ret = CryptGenKey(hProv,dwKeySpec,0,&hKey);
3702 if (!ret)
3704 CryptReleaseContext(hProv,0);
3705 SetLastError(NTE_BAD_KEYSET);
3706 return NULL;
3709 CryptDestroyKey(hKey);
3710 releaseContext = TRUE;
3714 ret = CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING, NULL,
3715 &pubKeySize);
3716 if (!ret)
3717 goto end;
3718 pubKey = CryptMemAlloc(pubKeySize);
3719 if (pubKey)
3721 ret = CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING,
3722 pubKey, &pubKeySize);
3723 if (ret)
3725 CERT_INFO info = { 0 };
3726 CRYPT_DER_BLOB blob = { 0, NULL };
3727 BYTE serial[16];
3728 CRYPT_DATA_BLOB serialBlob = { sizeof(serial), serial };
3730 CryptGenRandom(hProv, sizeof(serial), serial);
3731 CRYPT_MakeCertInfo(&info, &serialBlob, pSubjectIssuerBlob,
3732 pSignatureAlgorithm, pStartTime, pEndTime, pubKey, pExtensions);
3733 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
3734 &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData,
3735 &blob.cbData);
3736 if (ret)
3738 if (!(dwFlags & CERT_CREATE_SELFSIGN_NO_SIGN))
3739 context = CRYPT_CreateSignedCert(&blob, hProv,dwKeySpec,
3740 &info.SignatureAlgorithm);
3741 else
3742 context = CertCreateCertificateContext(X509_ASN_ENCODING,
3743 blob.pbData, blob.cbData);
3744 if (context && !(dwFlags & CERT_CREATE_SELFSIGN_NO_KEY_INFO))
3745 CertContext_SetKeyProvInfo(context, pKeyProvInfo, hProv);
3746 LocalFree(blob.pbData);
3749 CryptMemFree(pubKey);
3751 end:
3752 if (releaseContext)
3753 CryptReleaseContext(hProv, 0);
3754 return context;
3757 BOOL WINAPI CertVerifyCTLUsage(DWORD dwEncodingType, DWORD dwSubjectType,
3758 void *pvSubject, PCTL_USAGE pSubjectUsage, DWORD dwFlags,
3759 PCTL_VERIFY_USAGE_PARA pVerifyUsagePara,
3760 PCTL_VERIFY_USAGE_STATUS pVerifyUsageStatus)
3762 FIXME("(0x%x, %d, %p, %p, 0x%x, %p, %p): stub\n", dwEncodingType,
3763 dwSubjectType, pvSubject, pSubjectUsage, dwFlags, pVerifyUsagePara,
3764 pVerifyUsageStatus);
3765 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3766 return FALSE;
3769 const void * WINAPI CertCreateContext(DWORD dwContextType, DWORD dwEncodingType,
3770 const BYTE *pbEncoded, DWORD cbEncoded,
3771 DWORD dwFlags, PCERT_CREATE_CONTEXT_PARA pCreatePara)
3773 TRACE("(0x%x, 0x%x, %p, %d, 0x%08x, %p)\n", dwContextType, dwEncodingType,
3774 pbEncoded, cbEncoded, dwFlags, pCreatePara);
3776 if (dwFlags)
3778 FIXME("dwFlags 0x%08x not handled\n", dwFlags);
3779 return NULL;
3781 if (pCreatePara)
3783 FIXME("pCreatePara not handled\n");
3784 return NULL;
3787 switch (dwContextType)
3789 case CERT_STORE_CERTIFICATE_CONTEXT:
3790 return CertCreateCertificateContext(dwEncodingType, pbEncoded, cbEncoded);
3791 case CERT_STORE_CRL_CONTEXT:
3792 return CertCreateCRLContext(dwEncodingType, pbEncoded, cbEncoded);
3793 case CERT_STORE_CTL_CONTEXT:
3794 return CertCreateCTLContext(dwEncodingType, pbEncoded, cbEncoded);
3795 default:
3796 WARN("unknown context type: 0x%x\n", dwContextType);
3797 return NULL;
3801 BOOL WINAPI CryptSetKeyIdentifierProperty(const CRYPT_HASH_BLOB *pKeyIdentifier, DWORD dwPropId,
3802 DWORD dwFlags, LPCWSTR pwszComputerName, void *pvReserved, const void *pvData)
3804 FIXME("(%p, 0x%x, 0x%x, %s, %p, %p): stub\n", pKeyIdentifier, dwPropId, dwFlags,
3805 debugstr_w(pwszComputerName), pvReserved, pvData);
3806 return FALSE;