server: Create the initial thread as a separate request.
[wine.git] / dlls / crypt32 / cert.c
blob4a7a1fe15799b32c285951115a663214f6aa7a0a
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 "bcrypt.h"
32 #include "winnls.h"
33 #include "rpc.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
36 #include "crypt32_private.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
40 /* Internal version of CertGetCertificateContextProperty that gets properties
41 * directly from the context (or the context it's linked to, depending on its
42 * type.) Doesn't handle special-case properties, since they are handled by
43 * CertGetCertificateContextProperty, and are particular to the store in which
44 * the property exists (which is separate from the context.)
46 static BOOL CertContext_GetProperty(cert_t *cert, DWORD dwPropId,
47 void *pvData, DWORD *pcbData);
49 /* Internal version of CertSetCertificateContextProperty that sets properties
50 * directly on the context (or the context it's linked to, depending on its
51 * type.) Doesn't handle special cases, since they're handled by
52 * CertSetCertificateContextProperty anyway.
54 static BOOL CertContext_SetProperty(cert_t *cert, DWORD dwPropId,
55 DWORD dwFlags, const void *pvData);
57 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
58 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
59 DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
61 PCCERT_CONTEXT cert = CertCreateCertificateContext(dwCertEncodingType,
62 pbCertEncoded, cbCertEncoded);
63 BOOL ret;
65 TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore, dwCertEncodingType,
66 pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
68 if (cert)
70 ret = CertAddCertificateContextToStore(hCertStore, cert,
71 dwAddDisposition, ppCertContext);
72 CertFreeCertificateContext(cert);
74 else
75 ret = FALSE;
76 return ret;
79 BOOL WINAPI CertAddEncodedCertificateToSystemStoreA(LPCSTR pszCertStoreName,
80 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
82 HCERTSTORE store;
83 BOOL ret = FALSE;
85 TRACE("(%s, %p, %d)\n", debugstr_a(pszCertStoreName), pbCertEncoded,
86 cbCertEncoded);
88 store = CertOpenSystemStoreA(0, pszCertStoreName);
89 if (store)
91 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
92 pbCertEncoded, cbCertEncoded, CERT_STORE_ADD_USE_EXISTING, NULL);
93 CertCloseStore(store, 0);
95 return ret;
98 BOOL WINAPI CertAddEncodedCertificateToSystemStoreW(LPCWSTR pszCertStoreName,
99 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
101 HCERTSTORE store;
102 BOOL ret = FALSE;
104 TRACE("(%s, %p, %d)\n", debugstr_w(pszCertStoreName), pbCertEncoded,
105 cbCertEncoded);
107 store = CertOpenSystemStoreW(0, pszCertStoreName);
108 if (store)
110 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
111 pbCertEncoded, cbCertEncoded, CERT_STORE_ADD_USE_EXISTING, NULL);
112 CertCloseStore(store, 0);
114 return ret;
117 static const context_vtbl_t cert_vtbl;
119 static void Cert_free(context_t *context)
121 cert_t *cert = (cert_t*)context;
123 CryptMemFree(cert->ctx.pbCertEncoded);
124 LocalFree(cert->ctx.pCertInfo);
127 static context_t *Cert_clone(context_t *context, WINECRYPT_CERTSTORE *store, BOOL use_link)
129 cert_t *cert;
131 if(use_link) {
132 cert = (cert_t*)Context_CreateLinkContext(sizeof(CERT_CONTEXT), context, store);
133 if(!cert)
134 return NULL;
135 }else {
136 const cert_t *cloned = (const cert_t*)context;
137 DWORD size = 0;
138 BOOL res;
140 cert = (cert_t*)Context_CreateDataContext(sizeof(CERT_CONTEXT), &cert_vtbl, store);
141 if(!cert)
142 return NULL;
144 Context_CopyProperties(&cert->ctx, &cloned->ctx);
146 cert->ctx.dwCertEncodingType = cloned->ctx.dwCertEncodingType;
147 cert->ctx.pbCertEncoded = CryptMemAlloc(cloned->ctx.cbCertEncoded);
148 memcpy(cert->ctx.pbCertEncoded, cloned->ctx.pbCertEncoded, cloned->ctx.cbCertEncoded);
149 cert->ctx.cbCertEncoded = cloned->ctx.cbCertEncoded;
151 /* FIXME: We don't need to decode the object here, we could just clone cert info. */
152 res = CryptDecodeObjectEx(cert->ctx.dwCertEncodingType, X509_CERT_TO_BE_SIGNED,
153 cert->ctx.pbCertEncoded, cert->ctx.cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL,
154 &cert->ctx.pCertInfo, &size);
155 if(!res) {
156 CertFreeCertificateContext(&cert->ctx);
157 return NULL;
161 cert->ctx.hCertStore = store;
162 return &cert->base;
165 static const context_vtbl_t cert_vtbl = {
166 Cert_free,
167 Cert_clone
170 static BOOL add_cert_to_store(WINECRYPT_CERTSTORE *store, const CERT_CONTEXT *cert,
171 DWORD add_disposition, BOOL use_link, PCCERT_CONTEXT *ret_context)
173 const CERT_CONTEXT *existing = NULL;
174 BOOL ret = TRUE, inherit_props = FALSE;
175 context_t *new_context = NULL;
177 switch (add_disposition)
179 case CERT_STORE_ADD_ALWAYS:
180 break;
181 case CERT_STORE_ADD_NEW:
182 case CERT_STORE_ADD_REPLACE_EXISTING:
183 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
184 case CERT_STORE_ADD_USE_EXISTING:
185 case CERT_STORE_ADD_NEWER:
186 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES:
188 BYTE hashToAdd[20];
189 DWORD size = sizeof(hashToAdd);
191 ret = CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID,
192 hashToAdd, &size);
193 if (ret)
195 CRYPT_HASH_BLOB blob = { sizeof(hashToAdd), hashToAdd };
197 existing = CertFindCertificateInStore(store, cert->dwCertEncodingType, 0,
198 CERT_FIND_SHA1_HASH, &blob, NULL);
200 break;
202 default:
203 FIXME("Unimplemented add disposition %d\n", add_disposition);
204 SetLastError(E_INVALIDARG);
205 return FALSE;
208 switch (add_disposition)
210 case CERT_STORE_ADD_ALWAYS:
211 break;
212 case CERT_STORE_ADD_NEW:
213 if (existing)
215 TRACE("found matching certificate, not adding\n");
216 SetLastError(CRYPT_E_EXISTS);
217 return FALSE;
219 break;
220 case CERT_STORE_ADD_REPLACE_EXISTING:
221 break;
222 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
223 if (use_link)
224 FIXME("CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES: semi-stub for links\n");
225 if (existing)
226 inherit_props = TRUE;
227 break;
228 case CERT_STORE_ADD_USE_EXISTING:
229 if(use_link)
230 FIXME("CERT_STORE_ADD_USE_EXISTING: semi-stub for links\n");
231 if (existing)
233 Context_CopyProperties(existing, cert);
234 if (ret_context)
235 *ret_context = CertDuplicateCertificateContext(existing);
236 return TRUE;
238 break;
239 case CERT_STORE_ADD_NEWER:
240 if (existing && CompareFileTime(&existing->pCertInfo->NotBefore, &cert->pCertInfo->NotBefore) >= 0)
242 TRACE("existing certificate is newer, not adding\n");
243 SetLastError(CRYPT_E_EXISTS);
244 return FALSE;
246 break;
247 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES:
248 if (existing)
250 if (CompareFileTime(&existing->pCertInfo->NotBefore, &cert->pCertInfo->NotBefore) >= 0)
252 TRACE("existing certificate is newer, not adding\n");
253 SetLastError(CRYPT_E_EXISTS);
254 return FALSE;
256 inherit_props = TRUE;
258 break;
261 /* FIXME: We have tests that this works, but what should we really do in this case? */
262 if(!store) {
263 if(ret_context)
264 *ret_context = CertDuplicateCertificateContext(cert);
265 return TRUE;
268 ret = store->vtbl->certs.addContext(store, context_from_ptr(cert), existing ? context_from_ptr(existing) : NULL,
269 (ret_context || inherit_props) ? &new_context : NULL, use_link);
270 if(!ret)
271 return FALSE;
273 if(inherit_props)
274 Context_CopyProperties(context_ptr(new_context), existing);
276 if(ret_context)
277 *ret_context = context_ptr(new_context);
278 else if(new_context)
279 Context_Release(new_context);
281 TRACE("returning %d\n", ret);
282 return ret;
285 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore, PCCERT_CONTEXT pCertContext,
286 DWORD dwAddDisposition, PCCERT_CONTEXT *ppStoreContext)
288 WINECRYPT_CERTSTORE *store = hCertStore;
290 TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCertContext, dwAddDisposition, ppStoreContext);
292 return add_cert_to_store(store, pCertContext, dwAddDisposition, FALSE, ppStoreContext);
295 BOOL WINAPI CertAddCertificateLinkToStore(HCERTSTORE hCertStore,
296 PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
297 PCCERT_CONTEXT *ppCertContext)
299 static int calls;
300 WINECRYPT_CERTSTORE *store = (WINECRYPT_CERTSTORE*)hCertStore;
302 if (!(calls++))
303 FIXME("(%p, %p, %08x, %p): semi-stub\n", hCertStore, pCertContext,
304 dwAddDisposition, ppCertContext);
305 if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
306 return FALSE;
307 if (store->type == StoreTypeCollection)
309 SetLastError(E_INVALIDARG);
310 return FALSE;
312 return add_cert_to_store(hCertStore, pCertContext, dwAddDisposition, TRUE, ppCertContext);
315 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
316 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
318 cert_t *cert = NULL;
319 BYTE *data = NULL;
320 BOOL ret;
321 PCERT_INFO certInfo = NULL;
322 DWORD size = 0;
324 TRACE("(%08x, %p, %d)\n", dwCertEncodingType, pbCertEncoded,
325 cbCertEncoded);
327 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
329 SetLastError(E_INVALIDARG);
330 return NULL;
333 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT_TO_BE_SIGNED,
334 pbCertEncoded, cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL,
335 &certInfo, &size);
336 if (!ret)
337 return NULL;
339 cert = (cert_t*)Context_CreateDataContext(sizeof(CERT_CONTEXT), &cert_vtbl, &empty_store);
340 if (!cert)
341 return NULL;
342 data = CryptMemAlloc(cbCertEncoded);
343 if (!data)
345 Context_Release(&cert->base);
346 return NULL;
349 memcpy(data, pbCertEncoded, cbCertEncoded);
350 cert->ctx.dwCertEncodingType = dwCertEncodingType;
351 cert->ctx.pbCertEncoded = data;
352 cert->ctx.cbCertEncoded = cbCertEncoded;
353 cert->ctx.pCertInfo = certInfo;
354 cert->ctx.hCertStore = &empty_store;
356 return &cert->ctx;
359 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(PCCERT_CONTEXT pCertContext)
361 TRACE("(%p)\n", pCertContext);
363 if (!pCertContext)
364 return NULL;
366 Context_AddRef(&cert_from_ptr(pCertContext)->base);
367 return pCertContext;
370 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
372 TRACE("(%p)\n", pCertContext);
374 if (pCertContext)
375 Context_Release(&cert_from_ptr(pCertContext)->base);
376 return TRUE;
379 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
380 DWORD dwPropId)
382 cert_t *cert = cert_from_ptr(pCertContext);
383 DWORD ret;
385 TRACE("(%p, %d)\n", pCertContext, dwPropId);
387 if (cert->base.properties)
388 ret = ContextPropertyList_EnumPropIDs(cert->base.properties, dwPropId);
389 else
390 ret = 0;
391 return ret;
394 static BOOL CertContext_GetHashProp(cert_t *cert, DWORD dwPropId,
395 ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
396 DWORD *pcbData)
398 BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
399 pcbData);
400 if (ret && pvData)
402 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
404 ret = CertContext_SetProperty(cert, dwPropId, 0, &blob);
406 return ret;
409 static BOOL CertContext_CopyParam(void *pvData, DWORD *pcbData, const void *pb,
410 DWORD cb)
412 BOOL ret = TRUE;
414 if (!pvData)
415 *pcbData = cb;
416 else if (*pcbData < cb)
418 SetLastError(ERROR_MORE_DATA);
419 *pcbData = cb;
420 ret = FALSE;
422 else
424 memcpy(pvData, pb, cb);
425 *pcbData = cb;
427 return ret;
430 static BOOL CertContext_GetProperty(cert_t *cert, DWORD dwPropId,
431 void *pvData, DWORD *pcbData)
433 BOOL ret;
434 CRYPT_DATA_BLOB blob;
436 TRACE("(%p, %d, %p, %p)\n", cert, dwPropId, pvData, pcbData);
438 if (cert->base.properties)
439 ret = ContextPropertyList_FindProperty(cert->base.properties, dwPropId, &blob);
440 else
441 ret = FALSE;
442 if (ret)
443 ret = CertContext_CopyParam(pvData, pcbData, blob.pbData, blob.cbData);
444 else
446 /* Implicit properties */
447 switch (dwPropId)
449 case CERT_SHA1_HASH_PROP_ID:
450 ret = CertContext_GetHashProp(cert, dwPropId, CALG_SHA1,
451 cert->ctx.pbCertEncoded, cert->ctx.cbCertEncoded, pvData,
452 pcbData);
453 break;
454 case CERT_MD5_HASH_PROP_ID:
455 ret = CertContext_GetHashProp(cert, dwPropId, CALG_MD5,
456 cert->ctx.pbCertEncoded, cert->ctx.cbCertEncoded, pvData,
457 pcbData);
458 break;
459 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
460 ret = CertContext_GetHashProp(cert, dwPropId, CALG_MD5,
461 cert->ctx.pCertInfo->Subject.pbData,
462 cert->ctx.pCertInfo->Subject.cbData,
463 pvData, pcbData);
464 break;
465 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
466 ret = CertContext_GetHashProp(cert, dwPropId, CALG_MD5,
467 cert->ctx.pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
468 cert->ctx.pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
469 pvData, pcbData);
470 break;
471 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
472 ret = CertContext_GetHashProp(cert, dwPropId, CALG_MD5,
473 cert->ctx.pCertInfo->SerialNumber.pbData,
474 cert->ctx.pCertInfo->SerialNumber.cbData,
475 pvData, pcbData);
476 break;
477 case CERT_SIGNATURE_HASH_PROP_ID:
478 ret = CryptHashToBeSigned(0, cert->ctx.dwCertEncodingType,
479 cert->ctx.pbCertEncoded, cert->ctx.cbCertEncoded, pvData,
480 pcbData);
481 if (ret && pvData)
483 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
485 ret = CertContext_SetProperty(cert, dwPropId, 0, &blob);
487 break;
488 case CERT_KEY_IDENTIFIER_PROP_ID:
490 PCERT_EXTENSION ext = CertFindExtension(
491 szOID_SUBJECT_KEY_IDENTIFIER, cert->ctx.pCertInfo->cExtension,
492 cert->ctx.pCertInfo->rgExtension);
494 if (ext)
496 CRYPT_DATA_BLOB value;
497 DWORD size = sizeof(value);
499 ret = CryptDecodeObjectEx(X509_ASN_ENCODING,
500 szOID_SUBJECT_KEY_IDENTIFIER, ext->Value.pbData,
501 ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &value,
502 &size);
503 if (ret)
505 ret = CertContext_CopyParam(pvData, pcbData, value.pbData,
506 value.cbData);
507 CertContext_SetProperty(cert, dwPropId, 0, &value);
510 else
511 SetLastError(ERROR_INVALID_DATA);
512 break;
514 default:
515 SetLastError(CRYPT_E_NOT_FOUND);
518 TRACE("returning %d\n", ret);
519 return ret;
522 void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info)
524 DWORD i, containerLen, provNameLen;
525 LPBYTE data = (LPBYTE)info + sizeof(CRYPT_KEY_PROV_INFO);
527 info->pwszContainerName = (LPWSTR)data;
528 containerLen = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
529 data += containerLen;
531 info->pwszProvName = (LPWSTR)data;
532 provNameLen = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
533 data += provNameLen;
535 info->rgProvParam = (PCRYPT_KEY_PROV_PARAM)data;
536 data += info->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
538 for (i = 0; i < info->cProvParam; i++)
540 info->rgProvParam[i].pbData = data;
541 data += info->rgProvParam[i].cbData;
545 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
546 DWORD dwPropId, void *pvData, DWORD *pcbData)
548 cert_t *cert = cert_from_ptr(pCertContext);
549 BOOL ret;
551 TRACE("(%p, %d, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
553 switch (dwPropId)
555 case 0:
556 case CERT_CERT_PROP_ID:
557 case CERT_CRL_PROP_ID:
558 case CERT_CTL_PROP_ID:
559 SetLastError(E_INVALIDARG);
560 ret = FALSE;
561 break;
562 case CERT_ACCESS_STATE_PROP_ID:
563 ret = CertGetStoreProperty(cert->ctx.hCertStore, dwPropId, pvData, pcbData);
564 break;
565 case CERT_KEY_PROV_HANDLE_PROP_ID:
567 CERT_KEY_CONTEXT keyContext;
568 DWORD size = sizeof(keyContext);
570 ret = CertContext_GetProperty(cert,
571 CERT_KEY_CONTEXT_PROP_ID, &keyContext, &size);
572 if (ret)
573 ret = CertContext_CopyParam(pvData, pcbData, &keyContext.hCryptProv,
574 sizeof(keyContext.hCryptProv));
575 break;
577 case CERT_KEY_PROV_INFO_PROP_ID:
578 ret = CertContext_GetProperty(cert, dwPropId, pvData,
579 pcbData);
580 if (ret && pvData)
581 CRYPT_FixKeyProvInfoPointers(pvData);
582 break;
583 default:
584 ret = CertContext_GetProperty(cert, dwPropId, pvData,
585 pcbData);
588 TRACE("returning %d\n", ret);
589 return ret;
592 /* Copies key provider info from from into to, where to is assumed to be a
593 * contiguous buffer of memory large enough for from and all its associated
594 * data, but whose pointers are uninitialized.
595 * Upon return, to contains a contiguous copy of from, packed in the following
596 * order:
597 * - CRYPT_KEY_PROV_INFO
598 * - pwszContainerName
599 * - pwszProvName
600 * - rgProvParam[0]...
602 static void CRYPT_CopyKeyProvInfo(PCRYPT_KEY_PROV_INFO to,
603 const CRYPT_KEY_PROV_INFO *from)
605 DWORD i;
606 LPBYTE nextData = (LPBYTE)to + sizeof(CRYPT_KEY_PROV_INFO);
608 if (from->pwszContainerName)
610 to->pwszContainerName = (LPWSTR)nextData;
611 lstrcpyW(to->pwszContainerName, from->pwszContainerName);
612 nextData += (lstrlenW(from->pwszContainerName) + 1) * sizeof(WCHAR);
614 else
615 to->pwszContainerName = NULL;
616 if (from->pwszProvName)
618 to->pwszProvName = (LPWSTR)nextData;
619 lstrcpyW(to->pwszProvName, from->pwszProvName);
620 nextData += (lstrlenW(from->pwszProvName) + 1) * sizeof(WCHAR);
622 else
623 to->pwszProvName = NULL;
624 to->dwProvType = from->dwProvType;
625 to->dwFlags = from->dwFlags;
626 to->cProvParam = from->cProvParam;
627 to->rgProvParam = (PCRYPT_KEY_PROV_PARAM)nextData;
628 nextData += to->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
629 to->dwKeySpec = from->dwKeySpec;
630 for (i = 0; i < to->cProvParam; i++)
632 memcpy(&to->rgProvParam[i], &from->rgProvParam[i],
633 sizeof(CRYPT_KEY_PROV_PARAM));
634 to->rgProvParam[i].pbData = nextData;
635 memcpy(to->rgProvParam[i].pbData, from->rgProvParam[i].pbData,
636 from->rgProvParam[i].cbData);
637 nextData += from->rgProvParam[i].cbData;
641 static BOOL CertContext_SetKeyProvInfoProperty(CONTEXT_PROPERTY_LIST *properties,
642 const CRYPT_KEY_PROV_INFO *info)
644 BOOL ret;
645 LPBYTE buf = NULL;
646 DWORD size = sizeof(CRYPT_KEY_PROV_INFO), i, containerSize, provNameSize;
648 if (info->pwszContainerName)
649 containerSize = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
650 else
651 containerSize = 0;
652 if (info->pwszProvName)
653 provNameSize = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
654 else
655 provNameSize = 0;
656 size += containerSize + provNameSize;
657 for (i = 0; i < info->cProvParam; i++)
658 size += sizeof(CRYPT_KEY_PROV_PARAM) + info->rgProvParam[i].cbData;
659 buf = CryptMemAlloc(size);
660 if (buf)
662 CRYPT_CopyKeyProvInfo((PCRYPT_KEY_PROV_INFO)buf, info);
663 ret = ContextPropertyList_SetProperty(properties,
664 CERT_KEY_PROV_INFO_PROP_ID, buf, size);
665 CryptMemFree(buf);
667 else
668 ret = FALSE;
669 return ret;
672 static BOOL CertContext_SetProperty(cert_t *cert, DWORD dwPropId,
673 DWORD dwFlags, const void *pvData)
675 BOOL ret;
677 TRACE("(%p, %d, %08x, %p)\n", cert, dwPropId, dwFlags, pvData);
679 if (!cert->base.properties)
680 ret = FALSE;
681 else
683 switch (dwPropId)
685 case CERT_AUTO_ENROLL_PROP_ID:
686 case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */
687 case CERT_DESCRIPTION_PROP_ID:
688 case CERT_FRIENDLY_NAME_PROP_ID:
689 case CERT_HASH_PROP_ID:
690 case CERT_KEY_IDENTIFIER_PROP_ID:
691 case CERT_MD5_HASH_PROP_ID:
692 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
693 case CERT_PUBKEY_ALG_PARA_PROP_ID:
694 case CERT_PVK_FILE_PROP_ID:
695 case CERT_SIGNATURE_HASH_PROP_ID:
696 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
697 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
698 case CERT_EXTENDED_ERROR_INFO_PROP_ID:
699 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
700 case CERT_ENROLLMENT_PROP_ID:
701 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
702 case CERT_OCSP_RESPONSE_PROP_ID:
703 case CERT_RENEWAL_PROP_ID:
705 if (pvData)
707 const CRYPT_DATA_BLOB *blob = pvData;
709 ret = ContextPropertyList_SetProperty(cert->base.properties, dwPropId,
710 blob->pbData, blob->cbData);
712 else
714 ContextPropertyList_RemoveProperty(cert->base.properties, dwPropId);
715 ret = TRUE;
717 break;
719 case CERT_DATE_STAMP_PROP_ID:
720 if (pvData)
721 ret = ContextPropertyList_SetProperty(cert->base.properties, dwPropId,
722 pvData, sizeof(FILETIME));
723 else
725 ContextPropertyList_RemoveProperty(cert->base.properties, dwPropId);
726 ret = TRUE;
728 break;
729 case CERT_KEY_CONTEXT_PROP_ID:
731 if (pvData)
733 const CERT_KEY_CONTEXT *keyContext = pvData;
735 if (keyContext->cbSize != sizeof(CERT_KEY_CONTEXT))
737 SetLastError(E_INVALIDARG);
738 ret = FALSE;
740 else
741 ret = ContextPropertyList_SetProperty(cert->base.properties, dwPropId,
742 (const BYTE *)keyContext, keyContext->cbSize);
744 else
746 ContextPropertyList_RemoveProperty(cert->base.properties, dwPropId);
747 ret = TRUE;
749 break;
751 case CERT_KEY_PROV_INFO_PROP_ID:
752 if (pvData)
753 ret = CertContext_SetKeyProvInfoProperty(cert->base.properties, pvData);
754 else
756 ContextPropertyList_RemoveProperty(cert->base.properties, dwPropId);
757 ret = TRUE;
759 break;
760 case CERT_KEY_PROV_HANDLE_PROP_ID:
762 CERT_KEY_CONTEXT keyContext;
763 DWORD size = sizeof(keyContext);
765 ret = CertContext_GetProperty(cert, CERT_KEY_CONTEXT_PROP_ID,
766 &keyContext, &size);
767 if (ret)
769 if (!(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
770 CryptReleaseContext(keyContext.hCryptProv, 0);
772 keyContext.cbSize = sizeof(keyContext);
773 if (pvData)
774 keyContext.hCryptProv = *(const HCRYPTPROV *)pvData;
775 else
777 keyContext.hCryptProv = 0;
778 keyContext.dwKeySpec = AT_SIGNATURE;
780 ret = CertContext_SetProperty(cert, CERT_KEY_CONTEXT_PROP_ID,
781 0, &keyContext);
782 break;
784 default:
785 FIXME("%d: stub\n", dwPropId);
786 ret = FALSE;
789 TRACE("returning %d\n", ret);
790 return ret;
793 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
794 DWORD dwPropId, DWORD dwFlags, const void *pvData)
796 BOOL ret;
798 TRACE("(%p, %d, %08x, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
800 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
801 * crashes on most of these, I'll be safer.
803 switch (dwPropId)
805 case 0:
806 case CERT_ACCESS_STATE_PROP_ID:
807 case CERT_CERT_PROP_ID:
808 case CERT_CRL_PROP_ID:
809 case CERT_CTL_PROP_ID:
810 SetLastError(E_INVALIDARG);
811 return FALSE;
813 ret = CertContext_SetProperty(cert_from_ptr(pCertContext), dwPropId, dwFlags,
814 pvData);
815 TRACE("returning %d\n", ret);
816 return ret;
819 /* Acquires the private key using the key provider info, retrieving info from
820 * the certificate if info is NULL. The acquired provider is returned in
821 * *phCryptProv, and the key spec for the provider is returned in *pdwKeySpec.
823 static BOOL CRYPT_AcquirePrivateKeyFromProvInfo(PCCERT_CONTEXT pCert,
824 PCRYPT_KEY_PROV_INFO info, HCRYPTPROV *phCryptProv, DWORD *pdwKeySpec)
826 DWORD size = 0;
827 BOOL allocated = FALSE, ret = TRUE;
829 if (!info)
831 ret = CertGetCertificateContextProperty(pCert,
832 CERT_KEY_PROV_INFO_PROP_ID, 0, &size);
833 if (ret)
835 info = HeapAlloc(GetProcessHeap(), 0, size);
836 if (info)
838 ret = CertGetCertificateContextProperty(pCert,
839 CERT_KEY_PROV_INFO_PROP_ID, info, &size);
840 allocated = TRUE;
842 else
844 SetLastError(ERROR_OUTOFMEMORY);
845 ret = FALSE;
848 else
849 SetLastError(CRYPT_E_NO_KEY_PROPERTY);
851 if (ret)
853 ret = CryptAcquireContextW(phCryptProv, info->pwszContainerName,
854 info->pwszProvName, info->dwProvType, 0);
855 if (ret)
857 DWORD i;
859 for (i = 0; i < info->cProvParam; i++)
861 CryptSetProvParam(*phCryptProv,
862 info->rgProvParam[i].dwParam, info->rgProvParam[i].pbData,
863 info->rgProvParam[i].dwFlags);
865 *pdwKeySpec = info->dwKeySpec;
867 else
868 SetLastError(CRYPT_E_NO_KEY_PROPERTY);
870 if (allocated)
871 HeapFree(GetProcessHeap(), 0, info);
872 return ret;
875 BOOL WINAPI CryptAcquireCertificatePrivateKey(PCCERT_CONTEXT pCert,
876 DWORD dwFlags, void *pvReserved, HCRYPTPROV_OR_NCRYPT_KEY_HANDLE *phCryptProv,
877 DWORD *pdwKeySpec, BOOL *pfCallerFreeProv)
879 BOOL ret = FALSE, cache = FALSE;
880 PCRYPT_KEY_PROV_INFO info = NULL;
881 CERT_KEY_CONTEXT keyContext;
882 DWORD size;
884 TRACE("(%p, %08x, %p, %p, %p, %p)\n", pCert, dwFlags, pvReserved,
885 phCryptProv, pdwKeySpec, pfCallerFreeProv);
887 if (dwFlags & CRYPT_ACQUIRE_USE_PROV_INFO_FLAG)
889 DWORD size = 0;
891 ret = CertGetCertificateContextProperty(pCert,
892 CERT_KEY_PROV_INFO_PROP_ID, 0, &size);
893 if (ret)
895 info = HeapAlloc(GetProcessHeap(), 0, size);
896 ret = CertGetCertificateContextProperty(pCert,
897 CERT_KEY_PROV_INFO_PROP_ID, info, &size);
898 if (ret)
899 cache = info->dwFlags & CERT_SET_KEY_CONTEXT_PROP_ID;
902 else if (dwFlags & CRYPT_ACQUIRE_CACHE_FLAG)
903 cache = TRUE;
904 *phCryptProv = 0;
905 if (cache)
907 size = sizeof(keyContext);
908 ret = CertGetCertificateContextProperty(pCert, CERT_KEY_CONTEXT_PROP_ID,
909 &keyContext, &size);
910 if (ret)
912 *phCryptProv = keyContext.hCryptProv;
913 if (pdwKeySpec)
914 *pdwKeySpec = keyContext.dwKeySpec;
915 if (pfCallerFreeProv)
916 *pfCallerFreeProv = !cache;
919 if (!*phCryptProv)
921 ret = CRYPT_AcquirePrivateKeyFromProvInfo(pCert, info,
922 &keyContext.hCryptProv, &keyContext.dwKeySpec);
923 if (ret)
925 *phCryptProv = keyContext.hCryptProv;
926 if (pdwKeySpec)
927 *pdwKeySpec = keyContext.dwKeySpec;
928 if (cache)
930 keyContext.cbSize = sizeof(keyContext);
931 if (CertSetCertificateContextProperty(pCert,
932 CERT_KEY_CONTEXT_PROP_ID, 0, &keyContext))
934 if (pfCallerFreeProv)
935 *pfCallerFreeProv = FALSE;
938 else
940 if (pfCallerFreeProv)
941 *pfCallerFreeProv = TRUE;
945 HeapFree(GetProcessHeap(), 0, info);
946 return ret;
949 static BOOL key_prov_info_matches_cert(PCCERT_CONTEXT pCert,
950 const CRYPT_KEY_PROV_INFO *keyProvInfo)
952 HCRYPTPROV csp;
953 BOOL matches = FALSE;
955 if (CryptAcquireContextW(&csp, keyProvInfo->pwszContainerName,
956 keyProvInfo->pwszProvName, keyProvInfo->dwProvType, keyProvInfo->dwFlags))
958 DWORD size;
960 /* Need to sign something to verify the sig. What to sign? Why not
961 * the certificate itself?
963 if (CryptSignAndEncodeCertificate(csp, AT_SIGNATURE,
964 pCert->dwCertEncodingType, X509_CERT_TO_BE_SIGNED, pCert->pCertInfo,
965 &pCert->pCertInfo->SignatureAlgorithm, NULL, NULL, &size))
967 BYTE *certEncoded = CryptMemAlloc(size);
969 if (certEncoded)
971 if (CryptSignAndEncodeCertificate(csp, AT_SIGNATURE,
972 pCert->dwCertEncodingType, X509_CERT_TO_BE_SIGNED,
973 pCert->pCertInfo, &pCert->pCertInfo->SignatureAlgorithm,
974 NULL, certEncoded, &size))
976 if (size == pCert->cbCertEncoded &&
977 !memcmp(certEncoded, pCert->pbCertEncoded, size))
978 matches = TRUE;
980 CryptMemFree(certEncoded);
983 CryptReleaseContext(csp, 0);
985 return matches;
988 static BOOL container_matches_cert(PCCERT_CONTEXT pCert, LPCSTR container,
989 CRYPT_KEY_PROV_INFO *keyProvInfo)
991 CRYPT_KEY_PROV_INFO copy;
992 WCHAR containerW[MAX_PATH];
993 BOOL matches;
995 MultiByteToWideChar(CP_ACP, 0, container, -1, containerW, ARRAY_SIZE(containerW));
996 /* We make a copy of the CRYPT_KEY_PROV_INFO because the caller expects
997 * keyProvInfo->pwszContainerName to be NULL or a heap-allocated container
998 * name.
1000 copy = *keyProvInfo;
1001 copy.pwszContainerName = containerW;
1002 matches = key_prov_info_matches_cert(pCert, &copy);
1003 if (matches)
1005 keyProvInfo->pwszContainerName =
1006 CryptMemAlloc((strlenW(containerW) + 1) * sizeof(WCHAR));
1007 if (keyProvInfo->pwszContainerName)
1009 strcpyW(keyProvInfo->pwszContainerName, containerW);
1010 keyProvInfo->dwKeySpec = AT_SIGNATURE;
1012 else
1013 matches = FALSE;
1015 return matches;
1018 /* Searches the provider named keyProvInfo.pwszProvName for a container whose
1019 * private key matches pCert's public key. Upon success, updates keyProvInfo
1020 * with the matching container's info (free keyProvInfo.pwszContainerName upon
1021 * success.)
1022 * Returns TRUE if found, FALSE if not.
1024 static BOOL find_key_prov_info_in_provider(PCCERT_CONTEXT pCert,
1025 CRYPT_KEY_PROV_INFO *keyProvInfo)
1027 HCRYPTPROV defProvider;
1028 BOOL ret, found = FALSE;
1029 char containerA[MAX_PATH];
1031 assert(keyProvInfo->pwszContainerName == NULL);
1032 if ((ret = CryptAcquireContextW(&defProvider, NULL,
1033 keyProvInfo->pwszProvName, keyProvInfo->dwProvType,
1034 keyProvInfo->dwFlags | CRYPT_VERIFYCONTEXT)))
1036 DWORD enumFlags = keyProvInfo->dwFlags | CRYPT_FIRST;
1038 while (ret && !found)
1040 DWORD size = sizeof(containerA);
1042 ret = CryptGetProvParam(defProvider, PP_ENUMCONTAINERS,
1043 (BYTE *)containerA, &size, enumFlags);
1044 if (ret)
1045 found = container_matches_cert(pCert, containerA, keyProvInfo);
1046 if (enumFlags & CRYPT_FIRST)
1048 enumFlags &= ~CRYPT_FIRST;
1049 enumFlags |= CRYPT_NEXT;
1052 CryptReleaseContext(defProvider, 0);
1054 return found;
1057 static BOOL find_matching_provider(PCCERT_CONTEXT pCert, DWORD dwFlags)
1059 BOOL found = FALSE, ret = TRUE;
1060 DWORD index = 0, cbProvName = 0;
1061 CRYPT_KEY_PROV_INFO keyProvInfo;
1063 TRACE("(%p, %08x)\n", pCert, dwFlags);
1065 memset(&keyProvInfo, 0, sizeof(keyProvInfo));
1066 while (ret && !found)
1068 DWORD size = 0;
1070 ret = CryptEnumProvidersW(index, NULL, 0, &keyProvInfo.dwProvType,
1071 NULL, &size);
1072 if (ret)
1074 if (size <= cbProvName)
1075 ret = CryptEnumProvidersW(index, NULL, 0,
1076 &keyProvInfo.dwProvType, keyProvInfo.pwszProvName, &size);
1077 else
1079 CryptMemFree(keyProvInfo.pwszProvName);
1080 keyProvInfo.pwszProvName = CryptMemAlloc(size);
1081 if (keyProvInfo.pwszProvName)
1083 cbProvName = size;
1084 ret = CryptEnumProvidersW(index, NULL, 0,
1085 &keyProvInfo.dwProvType, keyProvInfo.pwszProvName, &size);
1086 if (ret)
1088 if (dwFlags & CRYPT_FIND_SILENT_KEYSET_FLAG)
1089 keyProvInfo.dwFlags |= CRYPT_SILENT;
1090 if (dwFlags & CRYPT_FIND_USER_KEYSET_FLAG ||
1091 !(dwFlags & (CRYPT_FIND_USER_KEYSET_FLAG |
1092 CRYPT_FIND_MACHINE_KEYSET_FLAG)))
1094 keyProvInfo.dwFlags |= CRYPT_USER_KEYSET;
1095 found = find_key_prov_info_in_provider(pCert,
1096 &keyProvInfo);
1098 if (!found)
1100 if (dwFlags & CRYPT_FIND_MACHINE_KEYSET_FLAG ||
1101 !(dwFlags & (CRYPT_FIND_USER_KEYSET_FLAG |
1102 CRYPT_FIND_MACHINE_KEYSET_FLAG)))
1104 keyProvInfo.dwFlags &= ~CRYPT_USER_KEYSET;
1105 keyProvInfo.dwFlags |= CRYPT_MACHINE_KEYSET;
1106 found = find_key_prov_info_in_provider(pCert,
1107 &keyProvInfo);
1112 else
1113 ret = FALSE;
1115 index++;
1118 if (found)
1119 CertSetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID,
1120 0, &keyProvInfo);
1121 CryptMemFree(keyProvInfo.pwszProvName);
1122 CryptMemFree(keyProvInfo.pwszContainerName);
1123 return found;
1126 static BOOL cert_prov_info_matches_cert(PCCERT_CONTEXT pCert)
1128 BOOL matches = FALSE;
1129 DWORD size;
1131 if (CertGetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID,
1132 NULL, &size))
1134 CRYPT_KEY_PROV_INFO *keyProvInfo = CryptMemAlloc(size);
1136 if (keyProvInfo)
1138 if (CertGetCertificateContextProperty(pCert,
1139 CERT_KEY_PROV_INFO_PROP_ID, keyProvInfo, &size))
1140 matches = key_prov_info_matches_cert(pCert, keyProvInfo);
1141 CryptMemFree(keyProvInfo);
1144 return matches;
1147 BOOL WINAPI CryptFindCertificateKeyProvInfo(PCCERT_CONTEXT pCert,
1148 DWORD dwFlags, void *pvReserved)
1150 BOOL matches;
1152 TRACE("(%p, %08x, %p)\n", pCert, dwFlags, pvReserved);
1154 matches = cert_prov_info_matches_cert(pCert);
1155 if (!matches)
1156 matches = find_matching_provider(pCert, dwFlags);
1157 return matches;
1160 BOOL WINAPI CertCompareCertificate(DWORD dwCertEncodingType,
1161 PCERT_INFO pCertId1, PCERT_INFO pCertId2)
1163 BOOL ret;
1165 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertId1, pCertId2);
1167 ret = CertCompareCertificateName(dwCertEncodingType, &pCertId1->Issuer,
1168 &pCertId2->Issuer) && CertCompareIntegerBlob(&pCertId1->SerialNumber,
1169 &pCertId2->SerialNumber);
1170 TRACE("returning %d\n", ret);
1171 return ret;
1174 BOOL WINAPI CertCompareCertificateName(DWORD dwCertEncodingType,
1175 PCERT_NAME_BLOB pCertName1, PCERT_NAME_BLOB pCertName2)
1177 BOOL ret;
1179 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertName1, pCertName2);
1181 if (pCertName1->cbData == pCertName2->cbData)
1183 if (pCertName1->cbData)
1184 ret = !memcmp(pCertName1->pbData, pCertName2->pbData,
1185 pCertName1->cbData);
1186 else
1187 ret = TRUE;
1189 else
1190 ret = FALSE;
1191 TRACE("returning %d\n", ret);
1192 return ret;
1195 /* Returns the number of significant bytes in pInt, where a byte is
1196 * insignificant if it's a leading 0 for positive numbers or a leading 0xff
1197 * for negative numbers. pInt is assumed to be little-endian.
1199 static DWORD CRYPT_significantBytes(const CRYPT_INTEGER_BLOB *pInt)
1201 DWORD ret = pInt->cbData;
1203 while (ret > 1)
1205 if (pInt->pbData[ret - 2] <= 0x7f && pInt->pbData[ret - 1] == 0)
1206 ret--;
1207 else if (pInt->pbData[ret - 2] >= 0x80 && pInt->pbData[ret - 1] == 0xff)
1208 ret--;
1209 else
1210 break;
1212 return ret;
1215 BOOL WINAPI CertCompareIntegerBlob(PCRYPT_INTEGER_BLOB pInt1,
1216 PCRYPT_INTEGER_BLOB pInt2)
1218 BOOL ret;
1219 DWORD cb1, cb2;
1221 TRACE("(%p, %p)\n", pInt1, pInt2);
1223 cb1 = CRYPT_significantBytes(pInt1);
1224 cb2 = CRYPT_significantBytes(pInt2);
1225 if (cb1 == cb2)
1227 if (cb1)
1228 ret = !memcmp(pInt1->pbData, pInt2->pbData, cb1);
1229 else
1230 ret = TRUE;
1232 else
1233 ret = FALSE;
1234 TRACE("returning %d\n", ret);
1235 return ret;
1238 BOOL WINAPI CertComparePublicKeyInfo(DWORD dwCertEncodingType,
1239 PCERT_PUBLIC_KEY_INFO pPublicKey1, PCERT_PUBLIC_KEY_INFO pPublicKey2)
1241 BOOL ret;
1243 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pPublicKey1, pPublicKey2);
1245 switch (GET_CERT_ENCODING_TYPE(dwCertEncodingType))
1247 case 0: /* Seems to mean "raw binary bits" */
1248 if (pPublicKey1->PublicKey.cbData == pPublicKey2->PublicKey.cbData &&
1249 pPublicKey1->PublicKey.cUnusedBits == pPublicKey2->PublicKey.cUnusedBits)
1251 if (pPublicKey2->PublicKey.cbData)
1252 ret = !memcmp(pPublicKey1->PublicKey.pbData,
1253 pPublicKey2->PublicKey.pbData, pPublicKey1->PublicKey.cbData);
1254 else
1255 ret = TRUE;
1257 else
1258 ret = FALSE;
1259 break;
1260 default:
1261 WARN("Unknown encoding type %08x\n", dwCertEncodingType);
1262 /* FALLTHROUGH */
1263 case X509_ASN_ENCODING:
1265 BLOBHEADER *pblob1, *pblob2;
1266 DWORD length;
1267 ret = FALSE;
1268 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1269 pPublicKey1->PublicKey.pbData, pPublicKey1->PublicKey.cbData,
1270 0, NULL, &length))
1272 pblob1 = CryptMemAlloc(length);
1273 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1274 pPublicKey1->PublicKey.pbData, pPublicKey1->PublicKey.cbData,
1275 0, pblob1, &length))
1277 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1278 pPublicKey2->PublicKey.pbData, pPublicKey2->PublicKey.cbData,
1279 0, NULL, &length))
1281 pblob2 = CryptMemAlloc(length);
1282 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1283 pPublicKey2->PublicKey.pbData, pPublicKey2->PublicKey.cbData,
1284 0, pblob2, &length))
1286 /* The RSAPUBKEY structure directly follows the BLOBHEADER */
1287 RSAPUBKEY *pk1 = (LPVOID)(pblob1 + 1),
1288 *pk2 = (LPVOID)(pblob2 + 1);
1289 ret = (pk1->bitlen == pk2->bitlen) && (pk1->pubexp == pk2->pubexp)
1290 && !memcmp(pk1 + 1, pk2 + 1, pk1->bitlen/8);
1292 CryptMemFree(pblob2);
1295 CryptMemFree(pblob1);
1298 break;
1301 return ret;
1304 DWORD WINAPI CertGetPublicKeyLength(DWORD dwCertEncodingType,
1305 PCERT_PUBLIC_KEY_INFO pPublicKey)
1307 DWORD len = 0;
1309 TRACE("(%08x, %p)\n", dwCertEncodingType, pPublicKey);
1311 if (GET_CERT_ENCODING_TYPE(dwCertEncodingType) != X509_ASN_ENCODING)
1313 SetLastError(ERROR_FILE_NOT_FOUND);
1314 return 0;
1316 if (pPublicKey->Algorithm.pszObjId &&
1317 !strcmp(pPublicKey->Algorithm.pszObjId, szOID_RSA_DH))
1319 FIXME("unimplemented for DH public keys\n");
1320 SetLastError(CRYPT_E_ASN1_BADTAG);
1322 else
1324 DWORD size;
1325 PBYTE buf;
1326 BOOL ret = CryptDecodeObjectEx(dwCertEncodingType,
1327 RSA_CSP_PUBLICKEYBLOB, pPublicKey->PublicKey.pbData,
1328 pPublicKey->PublicKey.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf,
1329 &size);
1331 if (ret)
1333 RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
1335 len = rsaPubKey->bitlen;
1336 LocalFree(buf);
1339 return len;
1342 typedef BOOL (*CertCompareFunc)(PCCERT_CONTEXT pCertContext, DWORD dwType,
1343 DWORD dwFlags, const void *pvPara);
1345 static BOOL compare_cert_by_md5_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
1346 DWORD dwFlags, const void *pvPara)
1348 BOOL ret;
1349 BYTE hash[16];
1350 DWORD size = sizeof(hash);
1352 ret = CertGetCertificateContextProperty(pCertContext,
1353 CERT_MD5_HASH_PROP_ID, hash, &size);
1354 if (ret)
1356 const CRYPT_HASH_BLOB *pHash = pvPara;
1358 if (size == pHash->cbData)
1359 ret = !memcmp(pHash->pbData, hash, size);
1360 else
1361 ret = FALSE;
1363 return ret;
1366 static BOOL compare_cert_by_sha1_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
1367 DWORD dwFlags, const void *pvPara)
1369 BOOL ret;
1370 BYTE hash[20];
1371 DWORD size = sizeof(hash);
1373 ret = CertGetCertificateContextProperty(pCertContext,
1374 CERT_SHA1_HASH_PROP_ID, hash, &size);
1375 if (ret)
1377 const CRYPT_HASH_BLOB *pHash = pvPara;
1379 if (size == pHash->cbData)
1380 ret = !memcmp(pHash->pbData, hash, size);
1381 else
1382 ret = FALSE;
1384 return ret;
1387 static BOOL compare_cert_by_name(PCCERT_CONTEXT pCertContext, DWORD dwType,
1388 DWORD dwFlags, const void *pvPara)
1390 CERT_NAME_BLOB *blob = (CERT_NAME_BLOB *)pvPara, *toCompare;
1391 BOOL ret;
1393 if (dwType & CERT_INFO_SUBJECT_FLAG)
1394 toCompare = &pCertContext->pCertInfo->Subject;
1395 else
1396 toCompare = &pCertContext->pCertInfo->Issuer;
1397 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1398 toCompare, blob);
1399 return ret;
1402 static BOOL compare_cert_by_public_key(PCCERT_CONTEXT pCertContext,
1403 DWORD dwType, DWORD dwFlags, const void *pvPara)
1405 CERT_PUBLIC_KEY_INFO *publicKey = (CERT_PUBLIC_KEY_INFO *)pvPara;
1406 BOOL ret;
1408 ret = CertComparePublicKeyInfo(pCertContext->dwCertEncodingType,
1409 &pCertContext->pCertInfo->SubjectPublicKeyInfo, publicKey);
1410 return ret;
1413 static BOOL compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext,
1414 DWORD dwType, DWORD dwFlags, const void *pvPara)
1416 CERT_INFO *pCertInfo = (CERT_INFO *)pvPara;
1417 BOOL ret;
1419 /* Matching serial number and subject match.. */
1420 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1421 &pCertContext->pCertInfo->Subject, &pCertInfo->Issuer);
1422 if (ret)
1423 ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
1424 &pCertInfo->SerialNumber);
1425 else
1427 /* failing that, if the serial number and issuer match, we match */
1428 ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
1429 &pCertInfo->SerialNumber);
1430 if (ret)
1431 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1432 &pCertContext->pCertInfo->Issuer, &pCertInfo->Issuer);
1434 TRACE("returning %d\n", ret);
1435 return ret;
1438 static BOOL compare_cert_by_cert_id(PCCERT_CONTEXT pCertContext, DWORD dwType,
1439 DWORD dwFlags, const void *pvPara)
1441 CERT_ID *id = (CERT_ID *)pvPara;
1442 BOOL ret;
1444 switch (id->dwIdChoice)
1446 case CERT_ID_ISSUER_SERIAL_NUMBER:
1447 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1448 &pCertContext->pCertInfo->Issuer, &id->u.IssuerSerialNumber.Issuer);
1449 if (ret)
1450 ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
1451 &id->u.IssuerSerialNumber.SerialNumber);
1452 break;
1453 case CERT_ID_SHA1_HASH:
1454 ret = compare_cert_by_sha1_hash(pCertContext, dwType, dwFlags,
1455 &id->u.HashId);
1456 break;
1457 case CERT_ID_KEY_IDENTIFIER:
1459 DWORD size = 0;
1461 ret = CertGetCertificateContextProperty(pCertContext,
1462 CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
1463 if (ret && size == id->u.KeyId.cbData)
1465 LPBYTE buf = CryptMemAlloc(size);
1467 if (buf)
1469 CertGetCertificateContextProperty(pCertContext,
1470 CERT_KEY_IDENTIFIER_PROP_ID, buf, &size);
1471 ret = !memcmp(buf, id->u.KeyId.pbData, size);
1472 CryptMemFree(buf);
1474 else
1475 ret = FALSE;
1477 else
1478 ret = FALSE;
1479 break;
1481 default:
1482 ret = FALSE;
1483 break;
1485 return ret;
1488 static BOOL compare_existing_cert(PCCERT_CONTEXT pCertContext, DWORD dwType,
1489 DWORD dwFlags, const void *pvPara)
1491 PCCERT_CONTEXT toCompare = pvPara;
1492 return CertCompareCertificate(pCertContext->dwCertEncodingType,
1493 pCertContext->pCertInfo, toCompare->pCertInfo);
1496 static BOOL compare_cert_by_signature_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
1497 DWORD dwFlags, const void *pvPara)
1499 const CRYPT_HASH_BLOB *hash = pvPara;
1500 DWORD size = 0;
1501 BOOL ret;
1503 ret = CertGetCertificateContextProperty(pCertContext,
1504 CERT_SIGNATURE_HASH_PROP_ID, NULL, &size);
1505 if (ret && size == hash->cbData)
1507 LPBYTE buf = CryptMemAlloc(size);
1509 if (buf)
1511 CertGetCertificateContextProperty(pCertContext,
1512 CERT_SIGNATURE_HASH_PROP_ID, buf, &size);
1513 ret = !memcmp(buf, hash->pbData, size);
1514 CryptMemFree(buf);
1516 else
1517 ret = FALSE;
1519 else
1520 ret = FALSE;
1521 return ret;
1524 static inline PCCERT_CONTEXT cert_compare_certs_in_store(HCERTSTORE store,
1525 PCCERT_CONTEXT prev, CertCompareFunc compare, DWORD dwType, DWORD dwFlags,
1526 const void *pvPara)
1528 BOOL matches = FALSE;
1529 PCCERT_CONTEXT ret;
1531 ret = prev;
1532 do {
1533 ret = CertEnumCertificatesInStore(store, ret);
1534 if (ret)
1535 matches = compare(ret, dwType, dwFlags, pvPara);
1536 } while (ret != NULL && !matches);
1537 return ret;
1540 typedef PCCERT_CONTEXT (*CertFindFunc)(HCERTSTORE store, DWORD dwType,
1541 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev);
1543 static PCCERT_CONTEXT find_cert_any(HCERTSTORE store, DWORD dwType,
1544 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1546 return CertEnumCertificatesInStore(store, prev);
1549 static PCCERT_CONTEXT find_cert_by_issuer(HCERTSTORE store, DWORD dwType,
1550 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1552 BOOL ret;
1553 PCCERT_CONTEXT found = NULL, subject = pvPara;
1554 PCERT_EXTENSION ext;
1555 DWORD size;
1557 if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER,
1558 subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
1560 CERT_AUTHORITY_KEY_ID_INFO *info;
1562 ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
1563 X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData,
1564 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1565 &info, &size);
1566 if (ret)
1568 CERT_ID id;
1570 if (info->CertIssuer.cbData && info->CertSerialNumber.cbData)
1572 id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
1573 memcpy(&id.u.IssuerSerialNumber.Issuer, &info->CertIssuer,
1574 sizeof(CERT_NAME_BLOB));
1575 memcpy(&id.u.IssuerSerialNumber.SerialNumber,
1576 &info->CertSerialNumber, sizeof(CRYPT_INTEGER_BLOB));
1578 else if (info->KeyId.cbData)
1580 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
1581 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
1583 else
1584 ret = FALSE;
1585 if (ret)
1586 found = cert_compare_certs_in_store(store, prev,
1587 compare_cert_by_cert_id, dwType, dwFlags, &id);
1588 LocalFree(info);
1591 else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2,
1592 subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
1594 CERT_AUTHORITY_KEY_ID2_INFO *info;
1596 ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
1597 X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData,
1598 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1599 &info, &size);
1600 if (ret)
1602 CERT_ID id;
1604 if (info->AuthorityCertIssuer.cAltEntry &&
1605 info->AuthorityCertSerialNumber.cbData)
1607 PCERT_ALT_NAME_ENTRY directoryName = NULL;
1608 DWORD i;
1610 for (i = 0; !directoryName &&
1611 i < info->AuthorityCertIssuer.cAltEntry; i++)
1612 if (info->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice
1613 == CERT_ALT_NAME_DIRECTORY_NAME)
1614 directoryName =
1615 &info->AuthorityCertIssuer.rgAltEntry[i];
1616 if (directoryName)
1618 id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
1619 memcpy(&id.u.IssuerSerialNumber.Issuer,
1620 &directoryName->u.DirectoryName, sizeof(CERT_NAME_BLOB));
1621 memcpy(&id.u.IssuerSerialNumber.SerialNumber,
1622 &info->AuthorityCertSerialNumber,
1623 sizeof(CRYPT_INTEGER_BLOB));
1625 else
1627 FIXME("no supported name type in authority key id2\n");
1628 ret = FALSE;
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
1645 found = cert_compare_certs_in_store(store, prev,
1646 compare_cert_by_name, CERT_COMPARE_NAME | CERT_COMPARE_SUBJECT_CERT,
1647 dwFlags, &subject->pCertInfo->Issuer);
1648 return found;
1651 static BOOL compare_cert_by_name_str(PCCERT_CONTEXT pCertContext,
1652 DWORD dwType, DWORD dwFlags, const void *pvPara)
1654 PCERT_NAME_BLOB name;
1655 DWORD len;
1656 BOOL ret = FALSE;
1658 if (dwType & CERT_INFO_SUBJECT_FLAG)
1659 name = &pCertContext->pCertInfo->Subject;
1660 else
1661 name = &pCertContext->pCertInfo->Issuer;
1662 len = CertNameToStrW(pCertContext->dwCertEncodingType, name,
1663 CERT_SIMPLE_NAME_STR, NULL, 0);
1664 if (len)
1666 LPWSTR str = CryptMemAlloc(len * sizeof(WCHAR));
1668 if (str)
1670 LPWSTR ptr;
1672 CertNameToStrW(pCertContext->dwCertEncodingType, name,
1673 CERT_SIMPLE_NAME_STR, str, len);
1674 for (ptr = str; *ptr; ptr++)
1675 *ptr = tolowerW(*ptr);
1676 if (strstrW(str, pvPara))
1677 ret = TRUE;
1678 CryptMemFree(str);
1681 return ret;
1684 static PCCERT_CONTEXT find_cert_by_name_str_a(HCERTSTORE store, DWORD dwType,
1685 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1687 PCCERT_CONTEXT found = NULL;
1689 TRACE("%s\n", debugstr_a(pvPara));
1691 if (pvPara)
1693 int len = MultiByteToWideChar(CP_ACP, 0, pvPara, -1, NULL, 0);
1694 LPWSTR str = CryptMemAlloc(len * sizeof(WCHAR));
1696 if (str)
1698 LPWSTR ptr;
1700 MultiByteToWideChar(CP_ACP, 0, pvPara, -1, str, len);
1701 for (ptr = str; *ptr; ptr++)
1702 *ptr = tolowerW(*ptr);
1703 found = cert_compare_certs_in_store(store, prev,
1704 compare_cert_by_name_str, dwType, dwFlags, str);
1705 CryptMemFree(str);
1708 else
1709 found = find_cert_any(store, dwType, dwFlags, NULL, prev);
1710 return found;
1713 static PCCERT_CONTEXT find_cert_by_name_str_w(HCERTSTORE store, DWORD dwType,
1714 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1716 PCCERT_CONTEXT found = NULL;
1718 TRACE("%s\n", debugstr_w(pvPara));
1720 if (pvPara)
1722 DWORD len = strlenW(pvPara);
1723 LPWSTR str = CryptMemAlloc((len + 1) * sizeof(WCHAR));
1725 if (str)
1727 LPCWSTR src;
1728 LPWSTR dst;
1730 for (src = pvPara, dst = str; *src; src++, dst++)
1731 *dst = tolowerW(*src);
1732 *dst = 0;
1733 found = cert_compare_certs_in_store(store, prev,
1734 compare_cert_by_name_str, dwType, dwFlags, str);
1735 CryptMemFree(str);
1738 else
1739 found = find_cert_any(store, dwType, dwFlags, NULL, prev);
1740 return found;
1743 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
1744 DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType, const void *pvPara,
1745 PCCERT_CONTEXT pPrevCertContext)
1747 PCCERT_CONTEXT ret;
1748 CertFindFunc find = NULL;
1749 CertCompareFunc compare = NULL;
1751 TRACE("(%p, %08x, %08x, %08x, %p, %p)\n", hCertStore, dwCertEncodingType,
1752 dwFlags, dwType, pvPara, pPrevCertContext);
1754 switch (dwType >> CERT_COMPARE_SHIFT)
1756 case CERT_COMPARE_ANY:
1757 find = find_cert_any;
1758 break;
1759 case CERT_COMPARE_MD5_HASH:
1760 compare = compare_cert_by_md5_hash;
1761 break;
1762 case CERT_COMPARE_SHA1_HASH:
1763 compare = compare_cert_by_sha1_hash;
1764 break;
1765 case CERT_COMPARE_NAME:
1766 compare = compare_cert_by_name;
1767 break;
1768 case CERT_COMPARE_PUBLIC_KEY:
1769 compare = compare_cert_by_public_key;
1770 break;
1771 case CERT_COMPARE_NAME_STR_A:
1772 find = find_cert_by_name_str_a;
1773 break;
1774 case CERT_COMPARE_NAME_STR_W:
1775 find = find_cert_by_name_str_w;
1776 break;
1777 case CERT_COMPARE_SUBJECT_CERT:
1778 compare = compare_cert_by_subject_cert;
1779 break;
1780 case CERT_COMPARE_CERT_ID:
1781 compare = compare_cert_by_cert_id;
1782 break;
1783 case CERT_COMPARE_ISSUER_OF:
1784 find = find_cert_by_issuer;
1785 break;
1786 case CERT_COMPARE_EXISTING:
1787 compare = compare_existing_cert;
1788 break;
1789 case CERT_COMPARE_SIGNATURE_HASH:
1790 compare = compare_cert_by_signature_hash;
1791 break;
1792 default:
1793 FIXME("find type %08x unimplemented\n", dwType);
1796 if (find)
1797 ret = find(hCertStore, dwFlags, dwType, pvPara, pPrevCertContext);
1798 else if (compare)
1799 ret = cert_compare_certs_in_store(hCertStore, pPrevCertContext,
1800 compare, dwType, dwFlags, pvPara);
1801 else
1802 ret = NULL;
1803 if (!ret)
1804 SetLastError(CRYPT_E_NOT_FOUND);
1805 TRACE("returning %p\n", ret);
1806 return ret;
1809 PCCERT_CONTEXT WINAPI CertGetSubjectCertificateFromStore(HCERTSTORE hCertStore,
1810 DWORD dwCertEncodingType, PCERT_INFO pCertId)
1812 TRACE("(%p, %08x, %p)\n", hCertStore, dwCertEncodingType, pCertId);
1814 if (!pCertId)
1816 SetLastError(E_INVALIDARG);
1817 return NULL;
1819 return CertFindCertificateInStore(hCertStore, dwCertEncodingType, 0,
1820 CERT_FIND_SUBJECT_CERT, pCertId, NULL);
1823 BOOL WINAPI CertVerifySubjectCertificateContext(PCCERT_CONTEXT pSubject,
1824 PCCERT_CONTEXT pIssuer, DWORD *pdwFlags)
1826 static const DWORD supportedFlags = CERT_STORE_REVOCATION_FLAG |
1827 CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG;
1829 if (*pdwFlags & ~supportedFlags)
1831 SetLastError(E_INVALIDARG);
1832 return FALSE;
1834 if (*pdwFlags & CERT_STORE_REVOCATION_FLAG)
1836 DWORD flags = 0;
1837 PCCRL_CONTEXT crl = CertGetCRLFromStore(pSubject->hCertStore, pSubject,
1838 NULL, &flags);
1840 /* FIXME: what if the CRL has expired? */
1841 if (crl)
1843 if (CertVerifyCRLRevocation(pSubject->dwCertEncodingType,
1844 pSubject->pCertInfo, 1, (PCRL_INFO *)&crl->pCrlInfo))
1845 *pdwFlags &= CERT_STORE_REVOCATION_FLAG;
1847 else
1848 *pdwFlags |= CERT_STORE_NO_CRL_FLAG;
1850 if (*pdwFlags & CERT_STORE_TIME_VALIDITY_FLAG)
1852 if (0 == CertVerifyTimeValidity(NULL, pSubject->pCertInfo))
1853 *pdwFlags &= ~CERT_STORE_TIME_VALIDITY_FLAG;
1855 if (*pdwFlags & CERT_STORE_SIGNATURE_FLAG)
1857 if (CryptVerifyCertificateSignatureEx(0, pSubject->dwCertEncodingType,
1858 CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)pSubject,
1859 CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)pIssuer, 0, NULL))
1860 *pdwFlags &= ~CERT_STORE_SIGNATURE_FLAG;
1862 return TRUE;
1865 PCCERT_CONTEXT WINAPI CertGetIssuerCertificateFromStore(HCERTSTORE hCertStore,
1866 PCCERT_CONTEXT pSubjectContext, PCCERT_CONTEXT pPrevIssuerContext,
1867 DWORD *pdwFlags)
1869 PCCERT_CONTEXT ret;
1871 TRACE("(%p, %p, %p, %08x)\n", hCertStore, pSubjectContext,
1872 pPrevIssuerContext, *pdwFlags);
1874 if (!pSubjectContext)
1876 SetLastError(E_INVALIDARG);
1877 return NULL;
1880 ret = CertFindCertificateInStore(hCertStore,
1881 pSubjectContext->dwCertEncodingType, 0, CERT_FIND_ISSUER_OF,
1882 pSubjectContext, pPrevIssuerContext);
1883 if (ret)
1885 if (!CertVerifySubjectCertificateContext(pSubjectContext, ret,
1886 pdwFlags))
1888 CertFreeCertificateContext(ret);
1889 ret = NULL;
1891 if (CRYPT_IsCertificateSelfSigned(pSubjectContext))
1893 CertFreeCertificateContext(ret);
1894 ret = NULL;
1895 SetLastError(CRYPT_E_SELF_SIGNED);
1898 TRACE("returning %p\n", ret);
1899 return ret;
1902 typedef struct _OLD_CERT_REVOCATION_STATUS {
1903 DWORD cbSize;
1904 DWORD dwIndex;
1905 DWORD dwError;
1906 DWORD dwReason;
1907 } OLD_CERT_REVOCATION_STATUS;
1909 typedef BOOL (WINAPI *CertVerifyRevocationFunc)(DWORD, DWORD, DWORD,
1910 void **, DWORD, PCERT_REVOCATION_PARA, PCERT_REVOCATION_STATUS);
1912 BOOL WINAPI CertVerifyRevocation(DWORD dwEncodingType, DWORD dwRevType,
1913 DWORD cContext, PVOID rgpvContext[], DWORD dwFlags,
1914 PCERT_REVOCATION_PARA pRevPara, PCERT_REVOCATION_STATUS pRevStatus)
1916 BOOL ret;
1918 TRACE("(%08x, %d, %d, %p, %08x, %p, %p)\n", dwEncodingType, dwRevType,
1919 cContext, rgpvContext, dwFlags, pRevPara, pRevStatus);
1921 if (pRevStatus->cbSize != sizeof(OLD_CERT_REVOCATION_STATUS) &&
1922 pRevStatus->cbSize != sizeof(CERT_REVOCATION_STATUS))
1924 SetLastError(E_INVALIDARG);
1925 return FALSE;
1927 if (cContext)
1929 static HCRYPTOIDFUNCSET set = NULL;
1930 DWORD size;
1932 if (!set)
1933 set = CryptInitOIDFunctionSet(CRYPT_OID_VERIFY_REVOCATION_FUNC, 0);
1934 ret = CryptGetDefaultOIDDllList(set, dwEncodingType, NULL, &size);
1935 if (ret)
1937 if (size == 1)
1939 /* empty list */
1940 SetLastError(CRYPT_E_NO_REVOCATION_DLL);
1941 ret = FALSE;
1943 else
1945 LPWSTR dllList = CryptMemAlloc(size * sizeof(WCHAR)), ptr;
1947 if (dllList)
1949 ret = CryptGetDefaultOIDDllList(set, dwEncodingType,
1950 dllList, &size);
1951 if (ret)
1953 for (ptr = dllList; ret && *ptr;
1954 ptr += lstrlenW(ptr) + 1)
1956 CertVerifyRevocationFunc func;
1957 HCRYPTOIDFUNCADDR hFunc;
1959 ret = CryptGetDefaultOIDFunctionAddress(set,
1960 dwEncodingType, ptr, 0, (void **)&func, &hFunc);
1961 if (ret)
1963 ret = func(dwEncodingType, dwRevType, cContext,
1964 rgpvContext, dwFlags, pRevPara, pRevStatus);
1965 CryptFreeOIDFunctionAddress(hFunc, 0);
1969 CryptMemFree(dllList);
1971 else
1973 SetLastError(ERROR_OUTOFMEMORY);
1974 ret = FALSE;
1979 else
1980 ret = TRUE;
1981 return ret;
1984 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
1985 CRYPT_ATTRIBUTE rgAttr[])
1987 PCRYPT_ATTRIBUTE ret = NULL;
1988 DWORD i;
1990 TRACE("%s %d %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
1992 if (!cAttr)
1993 return NULL;
1994 if (!pszObjId)
1996 SetLastError(ERROR_INVALID_PARAMETER);
1997 return NULL;
2000 for (i = 0; !ret && i < cAttr; i++)
2001 if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
2002 ret = &rgAttr[i];
2003 return ret;
2006 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
2007 CERT_EXTENSION rgExtensions[])
2009 PCERT_EXTENSION ret = NULL;
2010 DWORD i;
2012 TRACE("%s %d %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
2014 if (!cExtensions)
2015 return NULL;
2016 if (!pszObjId)
2018 SetLastError(ERROR_INVALID_PARAMETER);
2019 return NULL;
2022 for (i = 0; !ret && i < cExtensions; i++)
2023 if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
2024 rgExtensions[i].pszObjId))
2025 ret = &rgExtensions[i];
2026 return ret;
2029 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
2031 PCERT_RDN_ATTR ret = NULL;
2032 DWORD i, j;
2034 TRACE("%s %p\n", debugstr_a(pszObjId), pName);
2036 if (!pszObjId)
2038 SetLastError(ERROR_INVALID_PARAMETER);
2039 return NULL;
2042 for (i = 0; !ret && i < pName->cRDN; i++)
2043 for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
2044 if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
2045 pName->rgRDN[i].rgRDNAttr[j].pszObjId))
2046 ret = &pName->rgRDN[i].rgRDNAttr[j];
2047 return ret;
2050 static BOOL find_matching_rdn_attr(DWORD dwFlags, const CERT_NAME_INFO *name,
2051 const CERT_RDN_ATTR *attr)
2053 DWORD i, j;
2054 BOOL match = FALSE;
2056 for (i = 0; !match && i < name->cRDN; i++)
2058 for (j = 0; j < name->rgRDN[i].cRDNAttr; j++)
2060 if (!strcmp(name->rgRDN[i].rgRDNAttr[j].pszObjId,
2061 attr->pszObjId) &&
2062 name->rgRDN[i].rgRDNAttr[j].dwValueType ==
2063 attr->dwValueType)
2065 if (dwFlags & CERT_UNICODE_IS_RDN_ATTRS_FLAG)
2067 LPCWSTR nameStr =
2068 (LPCWSTR)name->rgRDN[i].rgRDNAttr[j].Value.pbData;
2069 LPCWSTR attrStr = (LPCWSTR)attr->Value.pbData;
2071 if (attr->Value.cbData !=
2072 name->rgRDN[i].rgRDNAttr[j].Value.cbData)
2073 match = FALSE;
2074 else if (dwFlags & CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG)
2075 match = !strncmpiW(nameStr, attrStr,
2076 attr->Value.cbData / sizeof(WCHAR));
2077 else
2078 match = !strncmpW(nameStr, attrStr,
2079 attr->Value.cbData / sizeof(WCHAR));
2080 TRACE("%s : %s => %d\n",
2081 debugstr_wn(nameStr, attr->Value.cbData / sizeof(WCHAR)),
2082 debugstr_wn(attrStr, attr->Value.cbData / sizeof(WCHAR)),
2083 match);
2085 else
2087 LPCSTR nameStr =
2088 (LPCSTR)name->rgRDN[i].rgRDNAttr[j].Value.pbData;
2089 LPCSTR attrStr = (LPCSTR)attr->Value.pbData;
2091 if (attr->Value.cbData !=
2092 name->rgRDN[i].rgRDNAttr[j].Value.cbData)
2093 match = FALSE;
2094 else if (dwFlags & CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG)
2095 match = !strncasecmp(nameStr, attrStr,
2096 attr->Value.cbData);
2097 else
2098 match = !strncmp(nameStr, attrStr, attr->Value.cbData);
2099 TRACE("%s : %s => %d\n",
2100 debugstr_an(nameStr, attr->Value.cbData),
2101 debugstr_an(attrStr, attr->Value.cbData), match);
2106 return match;
2109 BOOL WINAPI CertIsRDNAttrsInCertificateName(DWORD dwCertEncodingType,
2110 DWORD dwFlags, PCERT_NAME_BLOB pCertName, PCERT_RDN pRDN)
2112 CERT_NAME_INFO *name;
2113 LPCSTR type;
2114 DWORD size;
2115 BOOL ret;
2117 TRACE("(%08x, %08x, %p, %p)\n", dwCertEncodingType, dwFlags, pCertName,
2118 pRDN);
2120 type = dwFlags & CERT_UNICODE_IS_RDN_ATTRS_FLAG ? X509_UNICODE_NAME :
2121 X509_NAME;
2122 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, type, pCertName->pbData,
2123 pCertName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &name, &size)))
2125 DWORD i;
2127 for (i = 0; ret && i < pRDN->cRDNAttr; i++)
2128 ret = find_matching_rdn_attr(dwFlags, name, &pRDN->rgRDNAttr[i]);
2129 if (!ret)
2130 SetLastError(CRYPT_E_NO_MATCH);
2131 LocalFree(name);
2133 return ret;
2136 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
2137 PCERT_INFO pCertInfo)
2139 FILETIME fileTime;
2140 LONG ret;
2142 if (!pTimeToVerify)
2144 GetSystemTimeAsFileTime(&fileTime);
2145 pTimeToVerify = &fileTime;
2147 if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
2149 ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
2150 if (ret < 0)
2151 ret = 0;
2153 return ret;
2156 BOOL WINAPI CertVerifyValidityNesting(PCERT_INFO pSubjectInfo,
2157 PCERT_INFO pIssuerInfo)
2159 TRACE("(%p, %p)\n", pSubjectInfo, pIssuerInfo);
2161 return CertVerifyTimeValidity(&pSubjectInfo->NotBefore, pIssuerInfo) == 0
2162 && CertVerifyTimeValidity(&pSubjectInfo->NotAfter, pIssuerInfo) == 0;
2165 BOOL WINAPI CryptHashCertificate(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
2166 DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
2167 DWORD *pcbComputedHash)
2169 BOOL ret = TRUE;
2170 HCRYPTHASH hHash = 0;
2172 TRACE("(%08lx, %d, %08x, %p, %d, %p, %p)\n", hCryptProv, Algid, dwFlags,
2173 pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
2175 if (!hCryptProv)
2176 hCryptProv = CRYPT_GetDefaultProvider();
2177 if (!Algid)
2178 Algid = CALG_SHA1;
2179 if (ret)
2181 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
2182 if (ret)
2184 ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
2185 if (ret)
2186 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
2187 pcbComputedHash, 0);
2188 CryptDestroyHash(hHash);
2191 return ret;
2194 BOOL WINAPI CryptHashPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
2195 DWORD dwFlags, DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo,
2196 BYTE *pbComputedHash, DWORD *pcbComputedHash)
2198 BOOL ret = TRUE;
2199 HCRYPTHASH hHash = 0;
2201 TRACE("(%08lx, %d, %08x, %d, %p, %p, %p)\n", hCryptProv, Algid, dwFlags,
2202 dwCertEncodingType, pInfo, pbComputedHash, pcbComputedHash);
2204 if (!hCryptProv)
2205 hCryptProv = CRYPT_GetDefaultProvider();
2206 if (!Algid)
2207 Algid = CALG_MD5;
2208 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
2210 SetLastError(ERROR_FILE_NOT_FOUND);
2211 return FALSE;
2213 if (ret)
2215 BYTE *buf;
2216 DWORD size = 0;
2218 ret = CRYPT_AsnEncodePubKeyInfoNoNull(dwCertEncodingType,
2219 X509_PUBLIC_KEY_INFO, pInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
2220 (LPBYTE)&buf, &size);
2221 if (ret)
2223 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
2224 if (ret)
2226 ret = CryptHashData(hHash, buf, size, 0);
2227 if (ret)
2228 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
2229 pcbComputedHash, 0);
2230 CryptDestroyHash(hHash);
2232 LocalFree(buf);
2235 return ret;
2238 BOOL WINAPI CryptHashToBeSigned(HCRYPTPROV_LEGACY hCryptProv,
2239 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
2240 BYTE *pbComputedHash, DWORD *pcbComputedHash)
2242 BOOL ret;
2243 CERT_SIGNED_CONTENT_INFO *info;
2244 DWORD size;
2246 TRACE("(%08lx, %08x, %p, %d, %p, %d)\n", hCryptProv, dwCertEncodingType,
2247 pbEncoded, cbEncoded, pbComputedHash, *pcbComputedHash);
2249 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
2250 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size);
2251 if (ret)
2253 PCCRYPT_OID_INFO oidInfo;
2254 HCRYPTHASH hHash;
2256 if (!hCryptProv)
2257 hCryptProv = CRYPT_GetDefaultProvider();
2258 oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2259 info->SignatureAlgorithm.pszObjId, 0);
2260 if (!oidInfo)
2262 SetLastError(NTE_BAD_ALGID);
2263 ret = FALSE;
2265 else
2267 ret = CryptCreateHash(hCryptProv, oidInfo->u.Algid, 0, 0, &hHash);
2268 if (ret)
2270 ret = CryptHashData(hHash, info->ToBeSigned.pbData,
2271 info->ToBeSigned.cbData, 0);
2272 if (ret)
2273 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
2274 pcbComputedHash, 0);
2275 CryptDestroyHash(hHash);
2278 LocalFree(info);
2280 return ret;
2283 BOOL WINAPI CryptSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
2284 DWORD dwKeySpec, DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned,
2285 DWORD cbEncodedToBeSigned, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
2286 const void *pvHashAuxInfo, BYTE *pbSignature, DWORD *pcbSignature)
2288 BOOL ret;
2289 PCCRYPT_OID_INFO info;
2290 HCRYPTHASH hHash;
2292 TRACE("(%08lx, %d, %d, %p, %d, %p, %p, %p, %p)\n", hCryptProv,
2293 dwKeySpec, dwCertEncodingType, pbEncodedToBeSigned, cbEncodedToBeSigned,
2294 pSignatureAlgorithm, pvHashAuxInfo, pbSignature, pcbSignature);
2296 info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2297 pSignatureAlgorithm->pszObjId, 0);
2298 if (!info)
2300 SetLastError(NTE_BAD_ALGID);
2301 return FALSE;
2303 if (info->dwGroupId == CRYPT_HASH_ALG_OID_GROUP_ID)
2305 if (!hCryptProv)
2306 hCryptProv = CRYPT_GetDefaultProvider();
2307 ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
2308 if (ret)
2310 ret = CryptHashData(hHash, pbEncodedToBeSigned,
2311 cbEncodedToBeSigned, 0);
2312 if (ret)
2313 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbSignature,
2314 pcbSignature, 0);
2315 CryptDestroyHash(hHash);
2318 else
2320 if (!hCryptProv)
2322 SetLastError(ERROR_INVALID_PARAMETER);
2323 ret = FALSE;
2325 else
2327 ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
2328 if (ret)
2330 ret = CryptHashData(hHash, pbEncodedToBeSigned,
2331 cbEncodedToBeSigned, 0);
2332 if (ret)
2333 ret = CryptSignHashW(hHash, dwKeySpec, NULL, 0, pbSignature,
2334 pcbSignature);
2335 CryptDestroyHash(hHash);
2339 return ret;
2342 BOOL WINAPI CryptSignAndEncodeCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
2343 DWORD dwKeySpec, DWORD dwCertEncodingType, LPCSTR lpszStructType,
2344 const void *pvStructInfo, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
2345 const void *pvHashAuxInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
2347 BOOL ret;
2348 DWORD encodedSize, hashSize;
2350 TRACE("(%08lx, %d, %d, %s, %p, %p, %p, %p, %p)\n", hCryptProv, dwKeySpec,
2351 dwCertEncodingType, debugstr_a(lpszStructType), pvStructInfo,
2352 pSignatureAlgorithm, pvHashAuxInfo, pbEncoded, pcbEncoded);
2354 ret = CryptEncodeObject(dwCertEncodingType, lpszStructType, pvStructInfo,
2355 NULL, &encodedSize);
2356 if (ret)
2358 PBYTE encoded = CryptMemAlloc(encodedSize);
2360 if (encoded)
2362 ret = CryptEncodeObject(dwCertEncodingType, lpszStructType,
2363 pvStructInfo, encoded, &encodedSize);
2364 if (ret)
2366 ret = CryptSignCertificate(hCryptProv, dwKeySpec,
2367 dwCertEncodingType, encoded, encodedSize, pSignatureAlgorithm,
2368 pvHashAuxInfo, NULL, &hashSize);
2369 if (ret)
2371 PBYTE hash = CryptMemAlloc(hashSize);
2373 if (hash)
2375 ret = CryptSignCertificate(hCryptProv, dwKeySpec,
2376 dwCertEncodingType, encoded, encodedSize,
2377 pSignatureAlgorithm, pvHashAuxInfo, hash, &hashSize);
2378 if (ret)
2380 CERT_SIGNED_CONTENT_INFO info = { { 0 } };
2382 info.ToBeSigned.cbData = encodedSize;
2383 info.ToBeSigned.pbData = encoded;
2384 info.SignatureAlgorithm = *pSignatureAlgorithm;
2385 info.Signature.cbData = hashSize;
2386 info.Signature.pbData = hash;
2387 info.Signature.cUnusedBits = 0;
2388 ret = CryptEncodeObject(dwCertEncodingType,
2389 X509_CERT, &info, pbEncoded, pcbEncoded);
2391 CryptMemFree(hash);
2393 else
2394 ret = FALSE;
2397 CryptMemFree(encoded);
2399 else
2400 ret = FALSE;
2402 return ret;
2405 BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV_LEGACY hCryptProv,
2406 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
2407 PCERT_PUBLIC_KEY_INFO pPublicKey)
2409 CRYPT_DATA_BLOB blob = { cbEncoded, (BYTE *)pbEncoded };
2411 return CryptVerifyCertificateSignatureEx(hCryptProv, dwCertEncodingType,
2412 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &blob,
2413 CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
2416 static BOOL CRYPT_VerifySignature(HCRYPTPROV_LEGACY hCryptProv, DWORD dwCertEncodingType,
2417 CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert, const CRYPT_OID_INFO *info)
2419 BOOL ret;
2420 HCRYPTKEY key;
2421 ALG_ID pubKeyID, hashID;
2423 hashID = info->u.Algid;
2424 if (info->ExtraInfo.cbData >= sizeof(ALG_ID))
2425 pubKeyID = *(ALG_ID *)info->ExtraInfo.pbData;
2426 else
2427 pubKeyID = hashID;
2428 /* Load the default provider if necessary */
2429 if (!hCryptProv)
2430 hCryptProv = CRYPT_GetDefaultProvider();
2431 ret = CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType,
2432 pubKeyInfo, pubKeyID, 0, NULL, &key);
2433 if (ret)
2435 HCRYPTHASH hash;
2437 ret = CryptCreateHash(hCryptProv, hashID, 0, 0, &hash);
2438 if (ret)
2440 ret = CryptHashData(hash, signedCert->ToBeSigned.pbData,
2441 signedCert->ToBeSigned.cbData, 0);
2442 if (ret)
2443 ret = CryptVerifySignatureW(hash, signedCert->Signature.pbData,
2444 signedCert->Signature.cbData, key, NULL, 0);
2445 CryptDestroyHash(hash);
2447 CryptDestroyKey(key);
2449 return ret;
2452 static BOOL CNG_CalcHash(const WCHAR *algorithm, const CERT_SIGNED_CONTENT_INFO *signedCert,
2453 BYTE **hash_value, DWORD *hash_len)
2455 BCRYPT_HASH_HANDLE hash = NULL;
2456 BCRYPT_ALG_HANDLE alg = NULL;
2457 NTSTATUS status;
2458 DWORD size;
2460 if ((status = BCryptOpenAlgorithmProvider(&alg, algorithm, NULL, 0)))
2461 goto done;
2463 if ((status = BCryptCreateHash(alg, &hash, NULL, 0, NULL, 0, 0)))
2464 goto done;
2466 if ((status = BCryptHashData(hash, signedCert->ToBeSigned.pbData, signedCert->ToBeSigned.cbData, 0)))
2467 goto done;
2469 if ((status = BCryptGetProperty(hash, BCRYPT_HASH_LENGTH, (BYTE *)hash_len, sizeof(*hash_len), &size, 0)))
2470 goto done;
2472 if (!(*hash_value = CryptMemAlloc(*hash_len)))
2474 status = STATUS_NO_MEMORY;
2475 goto done;
2478 if ((status = BCryptFinishHash(hash, *hash_value, *hash_len, 0)))
2480 CryptMemFree(*hash_value);
2481 goto done;
2484 done:
2485 if (hash) BCryptDestroyHash(hash);
2486 if (alg) BCryptCloseAlgorithmProvider(alg, 0);
2487 if (status) SetLastError(RtlNtStatusToDosError(status));
2488 return status == 0;
2491 static BOOL CNG_ImportECCPubKey(CERT_PUBLIC_KEY_INFO *pubKeyInfo, BCRYPT_KEY_HANDLE *key)
2493 DWORD blob_magic, ecckey_len, size;
2494 BCRYPT_ALG_HANDLE alg = NULL;
2495 BCRYPT_ECCKEY_BLOB *ecckey;
2496 const WCHAR *sign_algo;
2497 char **ecc_curve;
2498 NTSTATUS status;
2500 if (!pubKeyInfo->PublicKey.cbData)
2502 SetLastError(NTE_BAD_ALGID);
2503 return FALSE;
2506 if (pubKeyInfo->PublicKey.pbData[0] != 0x4)
2508 FIXME("Compressed ECC curves (%02x) not yet supported\n", pubKeyInfo->PublicKey.pbData[0]);
2509 SetLastError(NTE_BAD_ALGID);
2510 return FALSE;
2513 if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OBJECT_IDENTIFIER, pubKeyInfo->Algorithm.Parameters.pbData,
2514 pubKeyInfo->Algorithm.Parameters.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &ecc_curve, &size))
2515 return FALSE;
2517 if (!strcmp(*ecc_curve, szOID_ECC_CURVE_P256))
2519 sign_algo = BCRYPT_ECDSA_P256_ALGORITHM;
2520 blob_magic = BCRYPT_ECDSA_PUBLIC_P256_MAGIC;
2522 else if (!strcmp(*ecc_curve, szOID_ECC_CURVE_P384))
2524 sign_algo = BCRYPT_ECDSA_P384_ALGORITHM;
2525 blob_magic = BCRYPT_ECDSA_PUBLIC_P384_MAGIC;
2527 else
2529 FIXME("Unsupported ecc curve type: %s\n", *ecc_curve);
2530 sign_algo = NULL;
2531 blob_magic = 0;
2533 LocalFree(ecc_curve);
2535 if (!sign_algo)
2537 SetLastError(NTE_BAD_ALGID);
2538 return FALSE;
2541 if ((status = BCryptOpenAlgorithmProvider(&alg, sign_algo, NULL, 0)))
2542 goto done;
2544 ecckey_len = sizeof(BCRYPT_ECCKEY_BLOB) + pubKeyInfo->PublicKey.cbData - 1;
2545 if (!(ecckey = CryptMemAlloc(ecckey_len)))
2547 status = STATUS_NO_MEMORY;
2548 goto done;
2551 ecckey->dwMagic = blob_magic;
2552 ecckey->cbKey = (pubKeyInfo->PublicKey.cbData - 1) / 2;
2553 memcpy(ecckey + 1, pubKeyInfo->PublicKey.pbData + 1, pubKeyInfo->PublicKey.cbData - 1);
2555 status = BCryptImportKeyPair(alg, NULL, BCRYPT_ECCPUBLIC_BLOB, key, (BYTE*)ecckey, ecckey_len, 0);
2556 CryptMemFree(ecckey);
2558 done:
2559 if (alg) BCryptCloseAlgorithmProvider(alg, 0);
2560 if (status) SetLastError(RtlNtStatusToDosError(status));
2561 return !status;
2564 static BOOL CNG_ImportPubKey(CERT_PUBLIC_KEY_INFO *pubKeyInfo, BCRYPT_KEY_HANDLE *key)
2566 if (!strcmp(pubKeyInfo->Algorithm.pszObjId, szOID_ECC_PUBLIC_KEY))
2567 return CNG_ImportECCPubKey(pubKeyInfo, key);
2569 FIXME("Unsupported public key type: %s\n", debugstr_a(pubKeyInfo->Algorithm.pszObjId));
2570 SetLastError(NTE_BAD_ALGID);
2571 return FALSE;
2574 static BOOL CNG_PrepareSignatureECC(BYTE *encoded_sig, DWORD encoded_size, BYTE **sig_value, DWORD *sig_len)
2576 CERT_ECC_SIGNATURE *ecc_sig;
2577 DWORD size;
2578 int i;
2580 if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ECC_SIGNATURE, encoded_sig, encoded_size,
2581 CRYPT_DECODE_ALLOC_FLAG, NULL, &ecc_sig, &size))
2582 return FALSE;
2584 if (!ecc_sig->r.cbData || !ecc_sig->s.cbData)
2586 LocalFree(ecc_sig);
2587 SetLastError(ERROR_INVALID_DATA);
2588 return FALSE;
2591 *sig_len = ecc_sig->r.cbData + ecc_sig->s.cbData;
2592 if (!(*sig_value = CryptMemAlloc(*sig_len)))
2594 LocalFree(ecc_sig);
2595 SetLastError(ERROR_OUTOFMEMORY);
2596 return FALSE;
2599 for (i = 0; i < ecc_sig->r.cbData; i++)
2600 (*sig_value)[i] = ecc_sig->r.pbData[ecc_sig->r.cbData - i - 1];
2601 for (i = 0; i < ecc_sig->s.cbData; i++)
2602 (*sig_value)[ecc_sig->r.cbData + i] = ecc_sig->s.pbData[ecc_sig->s.cbData - i - 1];
2604 LocalFree(ecc_sig);
2605 return TRUE;
2608 static BOOL CNG_PrepareSignature(CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert,
2609 BYTE **sig_value, DWORD *sig_len)
2611 BYTE *encoded_sig;
2612 BOOL ret = FALSE;
2613 int i;
2615 if (!signedCert->Signature.cbData)
2617 SetLastError(ERROR_INVALID_DATA);
2618 return FALSE;
2621 if (!(encoded_sig = CryptMemAlloc(signedCert->Signature.cbData)))
2623 SetLastError(ERROR_OUTOFMEMORY);
2624 return FALSE;
2627 for (i = 0; i < signedCert->Signature.cbData; i++)
2628 encoded_sig[i] = signedCert->Signature.pbData[signedCert->Signature.cbData - i - 1];
2630 if (!strcmp(pubKeyInfo->Algorithm.pszObjId, szOID_ECC_PUBLIC_KEY))
2631 ret = CNG_PrepareSignatureECC(encoded_sig, signedCert->Signature.cbData, sig_value, sig_len);
2632 else
2634 FIXME("Unsupported public key type: %s\n", debugstr_a(pubKeyInfo->Algorithm.pszObjId));
2635 SetLastError(NTE_BAD_ALGID);
2638 CryptMemFree(encoded_sig);
2639 return ret;
2642 static BOOL CNG_VerifySignature(HCRYPTPROV_LEGACY hCryptProv, DWORD dwCertEncodingType,
2643 CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert, const CRYPT_OID_INFO *info)
2645 BCRYPT_KEY_HANDLE key = NULL;
2646 BYTE *hash_value = NULL, *sig_value;
2647 DWORD hash_len, sig_len;
2648 NTSTATUS status;
2649 BOOL ret;
2651 ret = CNG_ImportPubKey(pubKeyInfo, &key);
2652 if (ret)
2654 ret = CNG_CalcHash(info->pwszCNGAlgid, signedCert, &hash_value, &hash_len);
2655 if (ret)
2657 ret = CNG_PrepareSignature(pubKeyInfo, signedCert, &sig_value, &sig_len);
2658 if (ret)
2660 status = BCryptVerifySignature(key, NULL, hash_value, hash_len, sig_value, sig_len, 0);
2661 if (status)
2663 FIXME("Failed to verify signature: %08x\n", status);
2664 SetLastError(RtlNtStatusToDosError(status));
2665 ret = FALSE;
2667 CryptMemFree(sig_value);
2669 CryptMemFree(hash_value);
2671 BCryptDestroyKey(key);
2674 return ret;
2677 static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv, DWORD dwCertEncodingType,
2678 CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert)
2680 CCRYPT_OID_INFO *info;
2682 info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, signedCert->SignatureAlgorithm.pszObjId, 0);
2683 if (!info || info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID)
2685 SetLastError(NTE_BAD_ALGID);
2686 return FALSE;
2689 if (info->u.Algid == CALG_OID_INFO_CNG_ONLY)
2690 return CNG_VerifySignature(hCryptProv, dwCertEncodingType, pubKeyInfo, signedCert, info);
2691 else
2692 return CRYPT_VerifySignature(hCryptProv, dwCertEncodingType, pubKeyInfo, signedCert, info);
2695 BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV_LEGACY hCryptProv,
2696 DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
2697 DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
2699 BOOL ret = TRUE;
2700 CRYPT_DATA_BLOB subjectBlob;
2702 TRACE("(%08lx, %d, %d, %p, %d, %p, %08x, %p)\n", hCryptProv,
2703 dwCertEncodingType, dwSubjectType, pvSubject, dwIssuerType, pvIssuer,
2704 dwFlags, pvReserved);
2706 switch (dwSubjectType)
2708 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB:
2710 PCRYPT_DATA_BLOB blob = pvSubject;
2712 subjectBlob.pbData = blob->pbData;
2713 subjectBlob.cbData = blob->cbData;
2714 break;
2716 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT:
2718 PCERT_CONTEXT context = pvSubject;
2720 subjectBlob.pbData = context->pbCertEncoded;
2721 subjectBlob.cbData = context->cbCertEncoded;
2722 break;
2724 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL:
2726 PCRL_CONTEXT context = pvSubject;
2728 subjectBlob.pbData = context->pbCrlEncoded;
2729 subjectBlob.cbData = context->cbCrlEncoded;
2730 break;
2732 default:
2733 SetLastError(E_INVALIDARG);
2734 ret = FALSE;
2737 if (ret)
2739 PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
2740 DWORD size = 0;
2742 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
2743 subjectBlob.pbData, subjectBlob.cbData,
2744 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
2745 &signedCert, &size);
2746 if (ret)
2748 switch (dwIssuerType)
2750 case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY:
2751 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
2752 dwCertEncodingType, pvIssuer,
2753 signedCert);
2754 break;
2755 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT:
2756 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
2757 dwCertEncodingType,
2758 &((PCCERT_CONTEXT)pvIssuer)->pCertInfo->SubjectPublicKeyInfo,
2759 signedCert);
2760 break;
2761 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN:
2762 FIXME("CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: stub\n");
2763 ret = FALSE;
2764 break;
2765 case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL:
2766 if (pvIssuer)
2768 SetLastError(E_INVALIDARG);
2769 ret = FALSE;
2771 else
2773 FIXME("unimplemented for NULL signer\n");
2774 SetLastError(E_INVALIDARG);
2775 ret = FALSE;
2777 break;
2778 default:
2779 SetLastError(E_INVALIDARG);
2780 ret = FALSE;
2782 LocalFree(signedCert);
2785 return ret;
2788 BOOL WINAPI CertGetIntendedKeyUsage(DWORD dwCertEncodingType,
2789 PCERT_INFO pCertInfo, BYTE *pbKeyUsage, DWORD cbKeyUsage)
2791 PCERT_EXTENSION ext;
2792 BOOL ret = FALSE;
2794 TRACE("(%08x, %p, %p, %d)\n", dwCertEncodingType, pCertInfo, pbKeyUsage,
2795 cbKeyUsage);
2797 ext = CertFindExtension(szOID_KEY_USAGE, pCertInfo->cExtension,
2798 pCertInfo->rgExtension);
2799 if (ext)
2801 CRYPT_BIT_BLOB usage;
2802 DWORD size = sizeof(usage);
2804 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS,
2805 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL,
2806 &usage, &size);
2807 if (ret)
2809 if (cbKeyUsage < usage.cbData)
2810 ret = FALSE;
2811 else
2813 memcpy(pbKeyUsage, usage.pbData, usage.cbData);
2814 if (cbKeyUsage > usage.cbData)
2815 memset(pbKeyUsage + usage.cbData, 0,
2816 cbKeyUsage - usage.cbData);
2820 else
2821 SetLastError(0);
2822 return ret;
2825 BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags,
2826 PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage)
2828 PCERT_ENHKEY_USAGE usage = NULL;
2829 DWORD bytesNeeded;
2830 BOOL ret = TRUE;
2832 if (!pCertContext || !pcbUsage)
2834 SetLastError(ERROR_INVALID_PARAMETER);
2835 return FALSE;
2838 TRACE("(%p, %08x, %p, %d)\n", pCertContext, dwFlags, pUsage, *pcbUsage);
2840 if (!(dwFlags & CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG))
2842 DWORD propSize = 0;
2844 if (CertGetCertificateContextProperty(pCertContext,
2845 CERT_ENHKEY_USAGE_PROP_ID, NULL, &propSize))
2847 LPBYTE buf = CryptMemAlloc(propSize);
2849 if (buf)
2851 if (CertGetCertificateContextProperty(pCertContext,
2852 CERT_ENHKEY_USAGE_PROP_ID, buf, &propSize))
2854 ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
2855 X509_ENHANCED_KEY_USAGE, buf, propSize,
2856 CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
2858 CryptMemFree(buf);
2862 if (!usage && !(dwFlags & CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG))
2864 PCERT_EXTENSION ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
2865 pCertContext->pCertInfo->cExtension,
2866 pCertContext->pCertInfo->rgExtension);
2868 if (ext)
2870 ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
2871 X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
2872 CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
2875 if (!usage)
2877 /* If a particular location is specified, this should fail. Otherwise
2878 * it should succeed with an empty usage. (This is true on Win2k and
2879 * later, which we emulate.)
2881 if (dwFlags)
2883 SetLastError(CRYPT_E_NOT_FOUND);
2884 ret = FALSE;
2886 else
2887 bytesNeeded = sizeof(CERT_ENHKEY_USAGE);
2890 if (ret)
2892 if (!pUsage)
2893 *pcbUsage = bytesNeeded;
2894 else if (*pcbUsage < bytesNeeded)
2896 SetLastError(ERROR_MORE_DATA);
2897 *pcbUsage = bytesNeeded;
2898 ret = FALSE;
2900 else
2902 *pcbUsage = bytesNeeded;
2903 if (usage)
2905 DWORD i;
2906 LPSTR nextOID = (LPSTR)((LPBYTE)pUsage +
2907 sizeof(CERT_ENHKEY_USAGE) +
2908 usage->cUsageIdentifier * sizeof(LPSTR));
2910 pUsage->cUsageIdentifier = usage->cUsageIdentifier;
2911 pUsage->rgpszUsageIdentifier = (LPSTR *)((LPBYTE)pUsage +
2912 sizeof(CERT_ENHKEY_USAGE));
2913 for (i = 0; i < usage->cUsageIdentifier; i++)
2915 pUsage->rgpszUsageIdentifier[i] = nextOID;
2916 strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
2917 nextOID += strlen(nextOID) + 1;
2920 else
2921 pUsage->cUsageIdentifier = 0;
2924 if (usage)
2925 LocalFree(usage);
2926 TRACE("returning %d\n", ret);
2927 return ret;
2930 BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext,
2931 PCERT_ENHKEY_USAGE pUsage)
2933 BOOL ret;
2935 TRACE("(%p, %p)\n", pCertContext, pUsage);
2937 if (pUsage)
2939 CRYPT_DATA_BLOB blob = { 0, NULL };
2941 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
2942 pUsage, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData, &blob.cbData);
2943 if (ret)
2945 ret = CertSetCertificateContextProperty(pCertContext,
2946 CERT_ENHKEY_USAGE_PROP_ID, 0, &blob);
2947 LocalFree(blob.pbData);
2950 else
2951 ret = CertSetCertificateContextProperty(pCertContext,
2952 CERT_ENHKEY_USAGE_PROP_ID, 0, NULL);
2953 return ret;
2956 BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
2957 LPCSTR pszUsageIdentifier)
2959 BOOL ret;
2960 DWORD size;
2962 TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
2964 if (CertGetEnhancedKeyUsage(pCertContext,
2965 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size))
2967 PCERT_ENHKEY_USAGE usage = CryptMemAlloc(size);
2969 if (usage)
2971 ret = CertGetEnhancedKeyUsage(pCertContext,
2972 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size);
2973 if (ret)
2975 DWORD i;
2976 BOOL exists = FALSE;
2978 /* Make sure usage doesn't already exist */
2979 for (i = 0; !exists && i < usage->cUsageIdentifier; i++)
2981 if (!strcmp(usage->rgpszUsageIdentifier[i],
2982 pszUsageIdentifier))
2983 exists = TRUE;
2985 if (!exists)
2987 PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size +
2988 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
2990 if (newUsage)
2992 LPSTR nextOID;
2994 newUsage->rgpszUsageIdentifier = (LPSTR *)
2995 ((LPBYTE)newUsage + sizeof(CERT_ENHKEY_USAGE));
2996 nextOID = (LPSTR)((LPBYTE)newUsage->rgpszUsageIdentifier
2997 + (usage->cUsageIdentifier + 1) * sizeof(LPSTR));
2998 for (i = 0; i < usage->cUsageIdentifier; i++)
3000 newUsage->rgpszUsageIdentifier[i] = nextOID;
3001 strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
3002 nextOID += strlen(nextOID) + 1;
3004 newUsage->rgpszUsageIdentifier[i] = nextOID;
3005 strcpy(nextOID, pszUsageIdentifier);
3006 newUsage->cUsageIdentifier = i + 1;
3007 ret = CertSetEnhancedKeyUsage(pCertContext, newUsage);
3008 CryptMemFree(newUsage);
3010 else
3011 ret = FALSE;
3014 CryptMemFree(usage);
3016 else
3017 ret = FALSE;
3019 else
3021 PCERT_ENHKEY_USAGE usage = CryptMemAlloc(sizeof(CERT_ENHKEY_USAGE) +
3022 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
3024 if (usage)
3026 usage->rgpszUsageIdentifier =
3027 (LPSTR *)((LPBYTE)usage + sizeof(CERT_ENHKEY_USAGE));
3028 usage->rgpszUsageIdentifier[0] = (LPSTR)((LPBYTE)usage +
3029 sizeof(CERT_ENHKEY_USAGE) + sizeof(LPSTR));
3030 strcpy(usage->rgpszUsageIdentifier[0], pszUsageIdentifier);
3031 usage->cUsageIdentifier = 1;
3032 ret = CertSetEnhancedKeyUsage(pCertContext, usage);
3033 CryptMemFree(usage);
3035 else
3036 ret = FALSE;
3038 return ret;
3041 BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
3042 LPCSTR pszUsageIdentifier)
3044 BOOL ret;
3045 DWORD size;
3046 CERT_ENHKEY_USAGE usage;
3048 TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
3050 size = sizeof(usage);
3051 ret = CertGetEnhancedKeyUsage(pCertContext,
3052 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, &usage, &size);
3053 if (!ret && GetLastError() == ERROR_MORE_DATA)
3055 PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
3057 if (pUsage)
3059 ret = CertGetEnhancedKeyUsage(pCertContext,
3060 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
3061 if (ret)
3063 if (pUsage->cUsageIdentifier)
3065 DWORD i;
3066 BOOL found = FALSE;
3068 for (i = 0; i < pUsage->cUsageIdentifier; i++)
3070 if (!strcmp(pUsage->rgpszUsageIdentifier[i],
3071 pszUsageIdentifier))
3072 found = TRUE;
3073 if (found && i < pUsage->cUsageIdentifier - 1)
3074 pUsage->rgpszUsageIdentifier[i] =
3075 pUsage->rgpszUsageIdentifier[i + 1];
3077 pUsage->cUsageIdentifier--;
3078 /* Remove the usage if it's empty */
3079 if (pUsage->cUsageIdentifier)
3080 ret = CertSetEnhancedKeyUsage(pCertContext, pUsage);
3081 else
3082 ret = CertSetEnhancedKeyUsage(pCertContext, NULL);
3085 CryptMemFree(pUsage);
3087 else
3088 ret = FALSE;
3090 else
3092 /* it fit in an empty usage, therefore there's nothing to remove */
3093 ret = TRUE;
3095 return ret;
3098 struct BitField
3100 DWORD cIndexes;
3101 DWORD *indexes;
3104 #define BITS_PER_DWORD (sizeof(DWORD) * 8)
3106 static void CRYPT_SetBitInField(struct BitField *field, DWORD bit)
3108 DWORD indexIndex = bit / BITS_PER_DWORD;
3110 if (indexIndex + 1 > field->cIndexes)
3112 if (field->cIndexes)
3113 field->indexes = CryptMemRealloc(field->indexes,
3114 (indexIndex + 1) * sizeof(DWORD));
3115 else
3116 field->indexes = CryptMemAlloc(sizeof(DWORD));
3117 if (field->indexes)
3119 field->indexes[indexIndex] = 0;
3120 field->cIndexes = indexIndex + 1;
3123 if (field->indexes)
3124 field->indexes[indexIndex] |= 1 << (bit % BITS_PER_DWORD);
3127 static BOOL CRYPT_IsBitInFieldSet(const struct BitField *field, DWORD bit)
3129 BOOL set;
3130 DWORD indexIndex = bit / BITS_PER_DWORD;
3132 assert(field->cIndexes);
3133 set = field->indexes[indexIndex] & (1 << (bit % BITS_PER_DWORD));
3134 return set;
3137 BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts,
3138 int *cNumOIDs, LPSTR *rghOIDs, DWORD *pcbOIDs)
3140 BOOL ret = TRUE;
3141 DWORD i, cbOIDs = 0;
3142 BOOL allUsagesValid = TRUE;
3143 CERT_ENHKEY_USAGE validUsages = { 0, NULL };
3145 TRACE("(%d, %p, %d, %p, %d)\n", cCerts, rghCerts, *cNumOIDs,
3146 rghOIDs, *pcbOIDs);
3148 for (i = 0; i < cCerts; i++)
3150 CERT_ENHKEY_USAGE usage;
3151 DWORD size = sizeof(usage);
3153 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, &usage, &size);
3154 /* Success is deliberately ignored: it implies all usages are valid */
3155 if (!ret && GetLastError() == ERROR_MORE_DATA)
3157 PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
3159 allUsagesValid = FALSE;
3160 if (pUsage)
3162 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, pUsage, &size);
3163 if (ret)
3165 if (!validUsages.cUsageIdentifier)
3167 DWORD j;
3169 cbOIDs = pUsage->cUsageIdentifier * sizeof(LPSTR);
3170 validUsages.cUsageIdentifier = pUsage->cUsageIdentifier;
3171 for (j = 0; j < validUsages.cUsageIdentifier; j++)
3172 cbOIDs += lstrlenA(pUsage->rgpszUsageIdentifier[j])
3173 + 1;
3174 validUsages.rgpszUsageIdentifier =
3175 CryptMemAlloc(cbOIDs);
3176 if (validUsages.rgpszUsageIdentifier)
3178 LPSTR nextOID = (LPSTR)
3179 ((LPBYTE)validUsages.rgpszUsageIdentifier +
3180 validUsages.cUsageIdentifier * sizeof(LPSTR));
3182 for (j = 0; j < validUsages.cUsageIdentifier; j++)
3184 validUsages.rgpszUsageIdentifier[j] = nextOID;
3185 lstrcpyA(validUsages.rgpszUsageIdentifier[j],
3186 pUsage->rgpszUsageIdentifier[j]);
3187 nextOID += lstrlenA(nextOID) + 1;
3191 else
3193 struct BitField validIndexes = { 0, NULL };
3194 DWORD j, k, numRemoved = 0;
3196 /* Merge: build a bitmap of all the indexes of
3197 * validUsages.rgpszUsageIdentifier that are in pUsage.
3199 for (j = 0; j < pUsage->cUsageIdentifier; j++)
3201 for (k = 0; k < validUsages.cUsageIdentifier; k++)
3203 if (!strcmp(pUsage->rgpszUsageIdentifier[j],
3204 validUsages.rgpszUsageIdentifier[k]))
3206 CRYPT_SetBitInField(&validIndexes, k);
3207 break;
3211 /* Merge by removing from validUsages those that are
3212 * not in the bitmap.
3214 for (j = 0; j < validUsages.cUsageIdentifier; j++)
3216 if (!CRYPT_IsBitInFieldSet(&validIndexes, j))
3218 if (j < validUsages.cUsageIdentifier - 1)
3220 memmove(&validUsages.rgpszUsageIdentifier[j],
3221 &validUsages.rgpszUsageIdentifier[j +
3222 numRemoved + 1],
3223 (validUsages.cUsageIdentifier - numRemoved
3224 - j - 1) * sizeof(LPSTR));
3225 cbOIDs -= lstrlenA(
3226 validUsages.rgpszUsageIdentifier[j]) + 1 +
3227 sizeof(LPSTR);
3228 validUsages.cUsageIdentifier--;
3229 numRemoved++;
3231 else
3232 validUsages.cUsageIdentifier--;
3235 CryptMemFree(validIndexes.indexes);
3238 CryptMemFree(pUsage);
3242 ret = TRUE;
3243 if (allUsagesValid)
3245 *cNumOIDs = -1;
3246 *pcbOIDs = 0;
3248 else
3250 *cNumOIDs = validUsages.cUsageIdentifier;
3251 if (!rghOIDs)
3252 *pcbOIDs = cbOIDs;
3253 else if (*pcbOIDs < cbOIDs)
3255 *pcbOIDs = cbOIDs;
3256 SetLastError(ERROR_MORE_DATA);
3257 ret = FALSE;
3259 else
3261 LPSTR nextOID = (LPSTR)((LPBYTE)rghOIDs +
3262 validUsages.cUsageIdentifier * sizeof(LPSTR));
3264 *pcbOIDs = cbOIDs;
3265 for (i = 0; i < validUsages.cUsageIdentifier; i++)
3267 rghOIDs[i] = nextOID;
3268 lstrcpyA(nextOID, validUsages.rgpszUsageIdentifier[i]);
3269 nextOID += lstrlenA(nextOID) + 1;
3273 CryptMemFree(validUsages.rgpszUsageIdentifier);
3274 TRACE("cNumOIDs: %d\n", *cNumOIDs);
3275 TRACE("returning %d\n", ret);
3276 return ret;
3279 /* Sets the CERT_KEY_PROV_INFO_PROP_ID property of context from pInfo, or, if
3280 * pInfo is NULL, from the attributes of hProv.
3282 static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context,
3283 const CRYPT_KEY_PROV_INFO *pInfo, HCRYPTPROV hProv)
3285 CRYPT_KEY_PROV_INFO info = { 0 };
3286 BOOL ret;
3288 if (!pInfo)
3290 DWORD size;
3291 int len;
3293 ret = CryptGetProvParam(hProv, PP_CONTAINER, NULL, &size, 0);
3294 if (ret)
3296 LPSTR szContainer = CryptMemAlloc(size);
3298 if (szContainer)
3300 ret = CryptGetProvParam(hProv, PP_CONTAINER,
3301 (BYTE *)szContainer, &size, 0);
3302 if (ret)
3304 len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
3305 NULL, 0);
3306 if (len)
3308 info.pwszContainerName = CryptMemAlloc(len *
3309 sizeof(WCHAR));
3310 MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
3311 info.pwszContainerName, len);
3314 CryptMemFree(szContainer);
3317 ret = CryptGetProvParam(hProv, PP_NAME, NULL, &size, 0);
3318 if (ret)
3320 LPSTR szProvider = CryptMemAlloc(size);
3322 if (szProvider)
3324 ret = CryptGetProvParam(hProv, PP_NAME, (BYTE *)szProvider,
3325 &size, 0);
3326 if (ret)
3328 len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
3329 NULL, 0);
3330 if (len)
3332 info.pwszProvName = CryptMemAlloc(len *
3333 sizeof(WCHAR));
3334 MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
3335 info.pwszProvName, len);
3338 CryptMemFree(szProvider);
3341 /* in case no CRYPT_KEY_PROV_INFO given,
3342 * we always use AT_SIGNATURE key spec
3344 info.dwKeySpec = AT_SIGNATURE;
3345 size = sizeof(info.dwProvType);
3346 ret = CryptGetProvParam(hProv, PP_PROVTYPE, (LPBYTE)&info.dwProvType,
3347 &size, 0);
3348 if (!ret)
3349 info.dwProvType = PROV_RSA_FULL;
3350 pInfo = &info;
3353 CertSetCertificateContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID,
3354 0, pInfo);
3356 if (pInfo == &info)
3358 CryptMemFree(info.pwszContainerName);
3359 CryptMemFree(info.pwszProvName);
3363 /* Creates a signed certificate context from the unsigned, encoded certificate
3364 * in blob, using the crypto provider hProv and the signature algorithm sigAlgo.
3366 static PCCERT_CONTEXT CRYPT_CreateSignedCert(const CRYPT_DER_BLOB *blob,
3367 HCRYPTPROV hProv, DWORD dwKeySpec, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo)
3369 PCCERT_CONTEXT context = NULL;
3370 BOOL ret;
3371 DWORD sigSize = 0;
3373 ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
3374 blob->pbData, blob->cbData, sigAlgo, NULL, NULL, &sigSize);
3375 if (ret)
3377 LPBYTE sig = CryptMemAlloc(sigSize);
3379 ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
3380 blob->pbData, blob->cbData, sigAlgo, NULL, sig, &sigSize);
3381 if (ret)
3383 CERT_SIGNED_CONTENT_INFO signedInfo;
3384 BYTE *encodedSignedCert = NULL;
3385 DWORD encodedSignedCertSize = 0;
3387 signedInfo.ToBeSigned.cbData = blob->cbData;
3388 signedInfo.ToBeSigned.pbData = blob->pbData;
3389 signedInfo.SignatureAlgorithm = *sigAlgo;
3390 signedInfo.Signature.cbData = sigSize;
3391 signedInfo.Signature.pbData = sig;
3392 signedInfo.Signature.cUnusedBits = 0;
3393 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT,
3394 &signedInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
3395 &encodedSignedCert, &encodedSignedCertSize);
3396 if (ret)
3398 context = CertCreateCertificateContext(X509_ASN_ENCODING,
3399 encodedSignedCert, encodedSignedCertSize);
3400 LocalFree(encodedSignedCert);
3403 CryptMemFree(sig);
3405 return context;
3408 /* Copies data from the parameters into info, where:
3409 * pSerialNumber: The serial number. Must not be NULL.
3410 * pSubjectIssuerBlob: Specifies both the subject and issuer for info.
3411 * Must not be NULL
3412 * pSignatureAlgorithm: Optional.
3413 * pStartTime: The starting time of the certificate. If NULL, the current
3414 * system time is used.
3415 * pEndTime: The ending time of the certificate. If NULL, one year past the
3416 * starting time is used.
3417 * pubKey: The public key of the certificate. Must not be NULL.
3418 * pExtensions: Extensions to be included with the certificate. Optional.
3420 static void CRYPT_MakeCertInfo(PCERT_INFO info, const CRYPT_DATA_BLOB *pSerialNumber,
3421 const CERT_NAME_BLOB *pSubjectIssuerBlob,
3422 const CRYPT_ALGORITHM_IDENTIFIER *pSignatureAlgorithm, const SYSTEMTIME *pStartTime,
3423 const SYSTEMTIME *pEndTime, const CERT_PUBLIC_KEY_INFO *pubKey,
3424 const CERT_EXTENSIONS *pExtensions)
3426 static CHAR oid[] = szOID_RSA_SHA1RSA;
3428 assert(info);
3429 assert(pSerialNumber);
3430 assert(pSubjectIssuerBlob);
3431 assert(pubKey);
3433 if (pExtensions && pExtensions->cExtension)
3434 info->dwVersion = CERT_V3;
3435 else
3436 info->dwVersion = CERT_V1;
3437 info->SerialNumber.cbData = pSerialNumber->cbData;
3438 info->SerialNumber.pbData = pSerialNumber->pbData;
3439 if (pSignatureAlgorithm)
3440 info->SignatureAlgorithm = *pSignatureAlgorithm;
3441 else
3443 info->SignatureAlgorithm.pszObjId = oid;
3444 info->SignatureAlgorithm.Parameters.cbData = 0;
3445 info->SignatureAlgorithm.Parameters.pbData = NULL;
3447 info->Issuer.cbData = pSubjectIssuerBlob->cbData;
3448 info->Issuer.pbData = pSubjectIssuerBlob->pbData;
3449 if (pStartTime)
3450 SystemTimeToFileTime(pStartTime, &info->NotBefore);
3451 else
3452 GetSystemTimeAsFileTime(&info->NotBefore);
3453 if (pEndTime)
3454 SystemTimeToFileTime(pEndTime, &info->NotAfter);
3455 else
3457 SYSTEMTIME endTime;
3459 if (FileTimeToSystemTime(&info->NotBefore, &endTime))
3461 endTime.wYear++;
3462 SystemTimeToFileTime(&endTime, &info->NotAfter);
3465 info->Subject.cbData = pSubjectIssuerBlob->cbData;
3466 info->Subject.pbData = pSubjectIssuerBlob->pbData;
3467 info->SubjectPublicKeyInfo = *pubKey;
3468 if (pExtensions)
3470 info->cExtension = pExtensions->cExtension;
3471 info->rgExtension = pExtensions->rgExtension;
3473 else
3475 info->cExtension = 0;
3476 info->rgExtension = NULL;
3480 typedef RPC_STATUS (RPC_ENTRY *UuidCreateFunc)(UUID *);
3481 typedef RPC_STATUS (RPC_ENTRY *UuidToStringFunc)(UUID *, unsigned char **);
3482 typedef RPC_STATUS (RPC_ENTRY *RpcStringFreeFunc)(unsigned char **);
3484 static HCRYPTPROV CRYPT_CreateKeyProv(void)
3486 HCRYPTPROV hProv = 0;
3487 HMODULE rpcrt = LoadLibraryA("rpcrt4");
3489 if (rpcrt)
3491 UuidCreateFunc uuidCreate = (UuidCreateFunc)GetProcAddress(rpcrt,
3492 "UuidCreate");
3493 UuidToStringFunc uuidToString = (UuidToStringFunc)GetProcAddress(rpcrt,
3494 "UuidToStringA");
3495 RpcStringFreeFunc rpcStringFree = (RpcStringFreeFunc)GetProcAddress(
3496 rpcrt, "RpcStringFreeA");
3498 if (uuidCreate && uuidToString && rpcStringFree)
3500 UUID uuid;
3501 RPC_STATUS status = uuidCreate(&uuid);
3503 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY)
3505 unsigned char *uuidStr;
3507 status = uuidToString(&uuid, &uuidStr);
3508 if (status == RPC_S_OK)
3510 BOOL ret = CryptAcquireContextA(&hProv, (LPCSTR)uuidStr,
3511 MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_NEWKEYSET);
3513 if (ret)
3515 HCRYPTKEY key;
3517 ret = CryptGenKey(hProv, AT_SIGNATURE, 0, &key);
3518 if (ret)
3519 CryptDestroyKey(key);
3521 rpcStringFree(&uuidStr);
3525 FreeLibrary(rpcrt);
3527 return hProv;
3530 PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hProv,
3531 PCERT_NAME_BLOB pSubjectIssuerBlob, DWORD dwFlags,
3532 PCRYPT_KEY_PROV_INFO pKeyProvInfo,
3533 PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime,
3534 PSYSTEMTIME pEndTime, PCERT_EXTENSIONS pExtensions)
3536 PCCERT_CONTEXT context = NULL;
3537 BOOL ret, releaseContext = FALSE;
3538 PCERT_PUBLIC_KEY_INFO pubKey = NULL;
3539 DWORD pubKeySize = 0, dwKeySpec;
3541 TRACE("(%08lx, %p, %08x, %p, %p, %p, %p, %p)\n", hProv,
3542 pSubjectIssuerBlob, dwFlags, pKeyProvInfo, pSignatureAlgorithm, pStartTime,
3543 pExtensions, pExtensions);
3545 if(!pSubjectIssuerBlob)
3547 SetLastError(ERROR_INVALID_PARAMETER);
3548 return NULL;
3551 dwKeySpec = pKeyProvInfo ? pKeyProvInfo->dwKeySpec : AT_SIGNATURE;
3552 if (!hProv)
3554 if (!pKeyProvInfo)
3556 hProv = CRYPT_CreateKeyProv();
3557 releaseContext = TRUE;
3559 else if (pKeyProvInfo->dwFlags & CERT_SET_KEY_PROV_HANDLE_PROP_ID)
3561 SetLastError(NTE_BAD_FLAGS);
3562 return NULL;
3564 else
3566 HCRYPTKEY hKey = 0;
3567 /* acquire the context using the given information*/
3568 ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
3569 pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
3570 pKeyProvInfo->dwFlags);
3571 if (!ret)
3573 if(GetLastError() != NTE_BAD_KEYSET)
3574 return NULL;
3575 /* create the key set */
3576 ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
3577 pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
3578 pKeyProvInfo->dwFlags|CRYPT_NEWKEYSET);
3579 if (!ret)
3580 return NULL;
3582 /* check if the key is here */
3583 ret = CryptGetUserKey(hProv,dwKeySpec,&hKey);
3584 if(!ret)
3586 if (NTE_NO_KEY == GetLastError())
3587 { /* generate the key */
3588 ret = CryptGenKey(hProv,dwKeySpec,0,&hKey);
3590 if (!ret)
3592 CryptReleaseContext(hProv,0);
3593 SetLastError(NTE_BAD_KEYSET);
3594 return NULL;
3597 CryptDestroyKey(hKey);
3598 releaseContext = TRUE;
3602 ret = CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING, NULL,
3603 &pubKeySize);
3604 if (!ret)
3605 goto end;
3606 pubKey = CryptMemAlloc(pubKeySize);
3607 if (pubKey)
3609 ret = CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING,
3610 pubKey, &pubKeySize);
3611 if (ret)
3613 CERT_INFO info = { 0 };
3614 CRYPT_DER_BLOB blob = { 0, NULL };
3615 BYTE serial[16];
3616 CRYPT_DATA_BLOB serialBlob = { sizeof(serial), serial };
3618 CryptGenRandom(hProv, sizeof(serial), serial);
3619 CRYPT_MakeCertInfo(&info, &serialBlob, pSubjectIssuerBlob,
3620 pSignatureAlgorithm, pStartTime, pEndTime, pubKey, pExtensions);
3621 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
3622 &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData,
3623 &blob.cbData);
3624 if (ret)
3626 if (!(dwFlags & CERT_CREATE_SELFSIGN_NO_SIGN))
3627 context = CRYPT_CreateSignedCert(&blob, hProv,dwKeySpec,
3628 &info.SignatureAlgorithm);
3629 else
3630 context = CertCreateCertificateContext(X509_ASN_ENCODING,
3631 blob.pbData, blob.cbData);
3632 if (context && !(dwFlags & CERT_CREATE_SELFSIGN_NO_KEY_INFO))
3633 CertContext_SetKeyProvInfo(context, pKeyProvInfo, hProv);
3634 LocalFree(blob.pbData);
3637 CryptMemFree(pubKey);
3639 end:
3640 if (releaseContext)
3641 CryptReleaseContext(hProv, 0);
3642 return context;
3645 BOOL WINAPI CertVerifyCTLUsage(DWORD dwEncodingType, DWORD dwSubjectType,
3646 void *pvSubject, PCTL_USAGE pSubjectUsage, DWORD dwFlags,
3647 PCTL_VERIFY_USAGE_PARA pVerifyUsagePara,
3648 PCTL_VERIFY_USAGE_STATUS pVerifyUsageStatus)
3650 FIXME("(0x%x, %d, %p, %p, 0x%x, %p, %p): stub\n", dwEncodingType,
3651 dwSubjectType, pvSubject, pSubjectUsage, dwFlags, pVerifyUsagePara,
3652 pVerifyUsageStatus);
3653 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3654 return FALSE;
3657 const void * WINAPI CertCreateContext(DWORD dwContextType, DWORD dwEncodingType,
3658 const BYTE *pbEncoded, DWORD cbEncoded,
3659 DWORD dwFlags, PCERT_CREATE_CONTEXT_PARA pCreatePara)
3661 TRACE("(0x%x, 0x%x, %p, %d, 0x%08x, %p)\n", dwContextType, dwEncodingType,
3662 pbEncoded, cbEncoded, dwFlags, pCreatePara);
3664 if (dwFlags)
3666 FIXME("dwFlags 0x%08x not handled\n", dwFlags);
3667 return NULL;
3669 if (pCreatePara)
3671 FIXME("pCreatePara not handled\n");
3672 return NULL;
3675 switch (dwContextType)
3677 case CERT_STORE_CERTIFICATE_CONTEXT:
3678 return CertCreateCertificateContext(dwEncodingType, pbEncoded, cbEncoded);
3679 case CERT_STORE_CRL_CONTEXT:
3680 return CertCreateCRLContext(dwEncodingType, pbEncoded, cbEncoded);
3681 case CERT_STORE_CTL_CONTEXT:
3682 return CertCreateCTLContext(dwEncodingType, pbEncoded, cbEncoded);
3683 default:
3684 WARN("unknown context type: 0x%x\n", dwContextType);
3685 return NULL;