0088f006d3db04e465e781efb97a59b153e70b66
[reactos.git] / dll / win32 / crypt32 / cert.c
1 /*
2 * Copyright 2004-2006 Juan Lang
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 *
18 */
19
20 #include <assert.h>
21 #include <stdarg.h>
22
23 #define NONAMELESSUNION
24 #include "ntstatus.h"
25 #define WIN32_NO_STATUS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wine/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"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
39
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.)
45 */
46 static BOOL CertContext_GetProperty(cert_t *cert, DWORD dwPropId,
47 void *pvData, DWORD *pcbData);
48
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.
53 */
54 static BOOL CertContext_SetProperty(cert_t *cert, DWORD dwPropId,
55 DWORD dwFlags, const void *pvData);
56
57 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
58 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
59 DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
60 {
61 PCCERT_CONTEXT cert = CertCreateCertificateContext(dwCertEncodingType,
62 pbCertEncoded, cbCertEncoded);
63 BOOL ret;
64
65 TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore, dwCertEncodingType,
66 pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
67
68 if (cert)
69 {
70 ret = CertAddCertificateContextToStore(hCertStore, cert,
71 dwAddDisposition, ppCertContext);
72 CertFreeCertificateContext(cert);
73 }
74 else
75 ret = FALSE;
76 return ret;
77 }
78
79 BOOL WINAPI CertAddEncodedCertificateToSystemStoreA(LPCSTR pszCertStoreName,
80 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
81 {
82 HCERTSTORE store;
83 BOOL ret = FALSE;
84
85 TRACE("(%s, %p, %d)\n", debugstr_a(pszCertStoreName), pbCertEncoded,
86 cbCertEncoded);
87
88 store = CertOpenSystemStoreA(0, pszCertStoreName);
89 if (store)
90 {
91 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
92 pbCertEncoded, cbCertEncoded, CERT_STORE_ADD_USE_EXISTING, NULL);
93 CertCloseStore(store, 0);
94 }
95 return ret;
96 }
97
98 BOOL WINAPI CertAddEncodedCertificateToSystemStoreW(LPCWSTR pszCertStoreName,
99 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
100 {
101 HCERTSTORE store;
102 BOOL ret = FALSE;
103
104 TRACE("(%s, %p, %d)\n", debugstr_w(pszCertStoreName), pbCertEncoded,
105 cbCertEncoded);
106
107 store = CertOpenSystemStoreW(0, pszCertStoreName);
108 if (store)
109 {
110 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
111 pbCertEncoded, cbCertEncoded, CERT_STORE_ADD_USE_EXISTING, NULL);
112 CertCloseStore(store, 0);
113 }
114 return ret;
115 }
116
117 static const context_vtbl_t cert_vtbl;
118
119 static void Cert_free(context_t *context)
120 {
121 cert_t *cert = (cert_t*)context;
122
123 CryptMemFree(cert->ctx.pbCertEncoded);
124 LocalFree(cert->ctx.pCertInfo);
125 }
126
127 static context_t *Cert_clone(context_t *context, WINECRYPT_CERTSTORE *store, BOOL use_link)
128 {
129 cert_t *cert;
130
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;
139
140 cert = (cert_t*)Context_CreateDataContext(sizeof(CERT_CONTEXT), &cert_vtbl, store);
141 if(!cert)
142 return NULL;
143
144 Context_CopyProperties(&cert->ctx, &cloned->ctx);
145
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;
150
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;
158 }
159 }
160
161 cert->ctx.hCertStore = store;
162 return &cert->base;
163 }
164
165 static const context_vtbl_t cert_vtbl = {
166 Cert_free,
167 Cert_clone
168 };
169
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)
172 {
173 const CERT_CONTEXT *existing = NULL;
174 BOOL ret = TRUE, inherit_props = FALSE;
175 context_t *new_context = NULL;
176
177 switch (add_disposition)
178 {
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:
187 {
188 BYTE hashToAdd[20];
189 DWORD size = sizeof(hashToAdd);
190
191 ret = CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID,
192 hashToAdd, &size);
193 if (ret)
194 {
195 CRYPT_HASH_BLOB blob = { sizeof(hashToAdd), hashToAdd };
196
197 existing = CertFindCertificateInStore(store, cert->dwCertEncodingType, 0,
198 CERT_FIND_SHA1_HASH, &blob, NULL);
199 }
200 break;
201 }
202 default:
203 FIXME("Unimplemented add disposition %d\n", add_disposition);
204 SetLastError(E_INVALIDARG);
205 return FALSE;
206 }
207
208 switch (add_disposition)
209 {
210 case CERT_STORE_ADD_ALWAYS:
211 break;
212 case CERT_STORE_ADD_NEW:
213 if (existing)
214 {
215 TRACE("found matching certificate, not adding\n");
216 SetLastError(CRYPT_E_EXISTS);
217 return FALSE;
218 }
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)
232 {
233 Context_CopyProperties(existing, cert);
234 if (ret_context)
235 *ret_context = CertDuplicateCertificateContext(existing);
236 return TRUE;
237 }
238 break;
239 case CERT_STORE_ADD_NEWER:
240 if (existing && CompareFileTime(&existing->pCertInfo->NotBefore, &cert->pCertInfo->NotBefore) >= 0)
241 {
242 TRACE("existing certificate is newer, not adding\n");
243 SetLastError(CRYPT_E_EXISTS);
244 return FALSE;
245 }
246 break;
247 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES:
248 if (existing)
249 {
250 if (CompareFileTime(&existing->pCertInfo->NotBefore, &cert->pCertInfo->NotBefore) >= 0)
251 {
252 TRACE("existing certificate is newer, not adding\n");
253 SetLastError(CRYPT_E_EXISTS);
254 return FALSE;
255 }
256 inherit_props = TRUE;
257 }
258 break;
259 }
260
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;
266 }
267
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;
272
273 if(inherit_props)
274 Context_CopyProperties(context_ptr(new_context), existing);
275
276 if(ret_context)
277 *ret_context = context_ptr(new_context);
278 else if(new_context)
279 Context_Release(new_context);
280
281 TRACE("returning %d\n", ret);
282 return ret;
283 }
284
285 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore, PCCERT_CONTEXT pCertContext,
286 DWORD dwAddDisposition, PCCERT_CONTEXT *ppStoreContext)
287 {
288 WINECRYPT_CERTSTORE *store = hCertStore;
289
290 TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCertContext, dwAddDisposition, ppStoreContext);
291
292 return add_cert_to_store(store, pCertContext, dwAddDisposition, FALSE, ppStoreContext);
293 }
294
295 BOOL WINAPI CertAddCertificateLinkToStore(HCERTSTORE hCertStore,
296 PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
297 PCCERT_CONTEXT *ppCertContext)
298 {
299 static int calls;
300 WINECRYPT_CERTSTORE *store = (WINECRYPT_CERTSTORE*)hCertStore;
301
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)
308 {
309 SetLastError(E_INVALIDARG);
310 return FALSE;
311 }
312 return add_cert_to_store(hCertStore, pCertContext, dwAddDisposition, TRUE, ppCertContext);
313 }
314
315 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
316 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
317 {
318 cert_t *cert = NULL;
319 BYTE *data = NULL;
320 BOOL ret;
321 PCERT_INFO certInfo = NULL;
322 DWORD size = 0;
323
324 TRACE("(%08x, %p, %d)\n", dwCertEncodingType, pbCertEncoded,
325 cbCertEncoded);
326
327 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
328 {
329 SetLastError(E_INVALIDARG);
330 return NULL;
331 }
332
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;
338
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)
344 {
345 Context_Release(&cert->base);
346 return NULL;
347 }
348
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;
355
356 return &cert->ctx;
357 }
358
359 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(PCCERT_CONTEXT pCertContext)
360 {
361 TRACE("(%p)\n", pCertContext);
362
363 if (!pCertContext)
364 return NULL;
365
366 Context_AddRef(&cert_from_ptr(pCertContext)->base);
367 return pCertContext;
368 }
369
370 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
371 {
372 TRACE("(%p)\n", pCertContext);
373
374 if (pCertContext)
375 Context_Release(&cert_from_ptr(pCertContext)->base);
376 return TRUE;
377 }
378
379 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
380 DWORD dwPropId)
381 {
382 cert_t *cert = cert_from_ptr(pCertContext);
383 DWORD ret;
384
385 TRACE("(%p, %d)\n", pCertContext, dwPropId);
386
387 if (cert->base.properties)
388 ret = ContextPropertyList_EnumPropIDs(cert->base.properties, dwPropId);
389 else
390 ret = 0;
391 return ret;
392 }
393
394 static BOOL CertContext_GetHashProp(cert_t *cert, DWORD dwPropId,
395 ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
396 DWORD *pcbData)
397 {
398 BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
399 pcbData);
400 if (ret && pvData)
401 {
402 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
403
404 ret = CertContext_SetProperty(cert, dwPropId, 0, &blob);
405 }
406 return ret;
407 }
408
409 static BOOL CertContext_CopyParam(void *pvData, DWORD *pcbData, const void *pb,
410 DWORD cb)
411 {
412 BOOL ret = TRUE;
413
414 if (!pvData)
415 *pcbData = cb;
416 else if (*pcbData < cb)
417 {
418 SetLastError(ERROR_MORE_DATA);
419 *pcbData = cb;
420 ret = FALSE;
421 }
422 else
423 {
424 memcpy(pvData, pb, cb);
425 *pcbData = cb;
426 }
427 return ret;
428 }
429
430 static BOOL CertContext_GetProperty(cert_t *cert, DWORD dwPropId,
431 void *pvData, DWORD *pcbData)
432 {
433 BOOL ret;
434 CRYPT_DATA_BLOB blob;
435
436 TRACE("(%p, %d, %p, %p)\n", cert, dwPropId, pvData, pcbData);
437
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
445 {
446 /* Implicit properties */
447 switch (dwPropId)
448 {
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)
482 {
483 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
484
485 ret = CertContext_SetProperty(cert, dwPropId, 0, &blob);
486 }
487 break;
488 case CERT_KEY_IDENTIFIER_PROP_ID:
489 {
490 PCERT_EXTENSION ext = CertFindExtension(
491 szOID_SUBJECT_KEY_IDENTIFIER, cert->ctx.pCertInfo->cExtension,
492 cert->ctx.pCertInfo->rgExtension);
493
494 if (ext)
495 {
496 CRYPT_DATA_BLOB value;
497 DWORD size = sizeof(value);
498
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)
504 {
505 ret = CertContext_CopyParam(pvData, pcbData, value.pbData,
506 value.cbData);
507 CertContext_SetProperty(cert, dwPropId, 0, &value);
508 }
509 }
510 else
511 SetLastError(ERROR_INVALID_DATA);
512 break;
513 }
514 default:
515 SetLastError(CRYPT_E_NOT_FOUND);
516 }
517 }
518 TRACE("returning %d\n", ret);
519 return ret;
520 }
521
522 void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info)
523 {
524 DWORD i, containerLen, provNameLen;
525 LPBYTE data = (LPBYTE)info + sizeof(CRYPT_KEY_PROV_INFO);
526
527 info->pwszContainerName = (LPWSTR)data;
528 containerLen = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
529 data += containerLen;
530
531 info->pwszProvName = (LPWSTR)data;
532 provNameLen = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
533 data += provNameLen;
534
535 info->rgProvParam = (PCRYPT_KEY_PROV_PARAM)data;
536 data += info->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
537
538 for (i = 0; i < info->cProvParam; i++)
539 {
540 info->rgProvParam[i].pbData = data;
541 data += info->rgProvParam[i].cbData;
542 }
543 }
544
545 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
546 DWORD dwPropId, void *pvData, DWORD *pcbData)
547 {
548 cert_t *cert = cert_from_ptr(pCertContext);
549 BOOL ret;
550
551 TRACE("(%p, %d, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
552
553 switch (dwPropId)
554 {
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:
566 {
567 CERT_KEY_CONTEXT keyContext;
568 DWORD size = sizeof(keyContext);
569
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;
576 }
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);
586 }
587
588 TRACE("returning %d\n", ret);
589 return ret;
590 }
591
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]...
601 */
602 static void CRYPT_CopyKeyProvInfo(PCRYPT_KEY_PROV_INFO to,
603 const CRYPT_KEY_PROV_INFO *from)
604 {
605 DWORD i;
606 LPBYTE nextData = (LPBYTE)to + sizeof(CRYPT_KEY_PROV_INFO);
607
608 if (from->pwszContainerName)
609 {
610 to->pwszContainerName = (LPWSTR)nextData;
611 lstrcpyW(to->pwszContainerName, from->pwszContainerName);
612 nextData += (lstrlenW(from->pwszContainerName) + 1) * sizeof(WCHAR);
613 }
614 else
615 to->pwszContainerName = NULL;
616 if (from->pwszProvName)
617 {
618 to->pwszProvName = (LPWSTR)nextData;
619 lstrcpyW(to->pwszProvName, from->pwszProvName);
620 nextData += (lstrlenW(from->pwszProvName) + 1) * sizeof(WCHAR);
621 }
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++)
631 {
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;
638 }
639 }
640
641 static BOOL CertContext_SetKeyProvInfoProperty(CONTEXT_PROPERTY_LIST *properties,
642 const CRYPT_KEY_PROV_INFO *info)
643 {
644 BOOL ret;
645 LPBYTE buf = NULL;
646 DWORD size = sizeof(CRYPT_KEY_PROV_INFO), i, containerSize, provNameSize;
647
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)
661 {
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);
666 }
667 else
668 ret = FALSE;
669 return ret;
670 }
671
672 static BOOL CertContext_SetProperty(cert_t *cert, DWORD dwPropId,
673 DWORD dwFlags, const void *pvData)
674 {
675 BOOL ret;
676
677 TRACE("(%p, %d, %08x, %p)\n", cert, dwPropId, dwFlags, pvData);
678
679 if (!cert->base.properties)
680 ret = FALSE;
681 else
682 {
683 switch (dwPropId)
684 {
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:
704 {
705 if (pvData)
706 {
707 const CRYPT_DATA_BLOB *blob = pvData;
708
709 ret = ContextPropertyList_SetProperty(cert->base.properties, dwPropId,
710 blob->pbData, blob->cbData);
711 }
712 else
713 {
714 ContextPropertyList_RemoveProperty(cert->base.properties, dwPropId);
715 ret = TRUE;
716 }
717 break;
718 }
719 case CERT_DATE_STAMP_PROP_ID:
720 if (pvData)
721 ret = ContextPropertyList_SetProperty(cert->base.properties, dwPropId,
722 pvData, sizeof(FILETIME));
723 else
724 {
725 ContextPropertyList_RemoveProperty(cert->base.properties, dwPropId);
726 ret = TRUE;
727 }
728 break;
729 case CERT_KEY_CONTEXT_PROP_ID:
730 {
731 if (pvData)
732 {
733 const CERT_KEY_CONTEXT *keyContext = pvData;
734
735 if (keyContext->cbSize != sizeof(CERT_KEY_CONTEXT))
736 {
737 SetLastError(E_INVALIDARG);
738 ret = FALSE;
739 }
740 else
741 ret = ContextPropertyList_SetProperty(cert->base.properties, dwPropId,
742 (const BYTE *)keyContext, keyContext->cbSize);
743 }
744 else
745 {
746 ContextPropertyList_RemoveProperty(cert->base.properties, dwPropId);
747 ret = TRUE;
748 }
749 break;
750 }
751 case CERT_KEY_PROV_INFO_PROP_ID:
752 if (pvData)
753 ret = CertContext_SetKeyProvInfoProperty(cert->base.properties, pvData);
754 else
755 {
756 ContextPropertyList_RemoveProperty(cert->base.properties, dwPropId);
757 ret = TRUE;
758 }
759 break;
760 case CERT_KEY_PROV_HANDLE_PROP_ID:
761 {
762 CERT_KEY_CONTEXT keyContext;
763 DWORD size = sizeof(keyContext);
764
765 ret = CertContext_GetProperty(cert, CERT_KEY_CONTEXT_PROP_ID,
766 &keyContext, &size);
767 if (ret)
768 {
769 if (!(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
770 CryptReleaseContext(keyContext.hCryptProv, 0);
771 }
772 keyContext.cbSize = sizeof(keyContext);
773 if (pvData)
774 keyContext.hCryptProv = *(const HCRYPTPROV *)pvData;
775 else
776 {
777 keyContext.hCryptProv = 0;
778 keyContext.dwKeySpec = AT_SIGNATURE;
779 }
780 ret = CertContext_SetProperty(cert, CERT_KEY_CONTEXT_PROP_ID,
781 0, &keyContext);
782 break;
783 }
784 default:
785 FIXME("%d: stub\n", dwPropId);
786 ret = FALSE;
787 }
788 }
789 TRACE("returning %d\n", ret);
790 return ret;
791 }
792
793 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
794 DWORD dwPropId, DWORD dwFlags, const void *pvData)
795 {
796 BOOL ret;
797
798 TRACE("(%p, %d, %08x, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
799
800 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
801 * crashes on most of these, I'll be safer.
802 */
803 switch (dwPropId)
804 {
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;
812 }
813 ret = CertContext_SetProperty(cert_from_ptr(pCertContext), dwPropId, dwFlags,
814 pvData);
815 TRACE("returning %d\n", ret);
816 return ret;
817 }
818
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.
822 */
823 static BOOL CRYPT_AcquirePrivateKeyFromProvInfo(PCCERT_CONTEXT pCert,
824 PCRYPT_KEY_PROV_INFO info, HCRYPTPROV *phCryptProv, DWORD *pdwKeySpec)
825 {
826 DWORD size = 0;
827 BOOL allocated = FALSE, ret = TRUE;
828
829 if (!info)
830 {
831 ret = CertGetCertificateContextProperty(pCert,
832 CERT_KEY_PROV_INFO_PROP_ID, 0, &size);
833 if (ret)
834 {
835 info = HeapAlloc(GetProcessHeap(), 0, size);
836 if (info)
837 {
838 ret = CertGetCertificateContextProperty(pCert,
839 CERT_KEY_PROV_INFO_PROP_ID, info, &size);
840 allocated = TRUE;
841 }
842 else
843 {
844 SetLastError(ERROR_OUTOFMEMORY);
845 ret = FALSE;
846 }
847 }
848 else
849 SetLastError(CRYPT_E_NO_KEY_PROPERTY);
850 }
851 if (ret)
852 {
853 ret = CryptAcquireContextW(phCryptProv, info->pwszContainerName,
854 info->pwszProvName, info->dwProvType, 0);
855 if (ret)
856 {
857 DWORD i;
858
859 for (i = 0; i < info->cProvParam; i++)
860 {
861 CryptSetProvParam(*phCryptProv,
862 info->rgProvParam[i].dwParam, info->rgProvParam[i].pbData,
863 info->rgProvParam[i].dwFlags);
864 }
865 *pdwKeySpec = info->dwKeySpec;
866 }
867 else
868 SetLastError(CRYPT_E_NO_KEY_PROPERTY);
869 }
870 if (allocated)
871 HeapFree(GetProcessHeap(), 0, info);
872 return ret;
873 }
874
875 BOOL WINAPI CryptAcquireCertificatePrivateKey(PCCERT_CONTEXT pCert,
876 DWORD dwFlags, void *pvReserved, HCRYPTPROV_OR_NCRYPT_KEY_HANDLE *phCryptProv,
877 DWORD *pdwKeySpec, BOOL *pfCallerFreeProv)
878 {
879 BOOL ret = FALSE, cache = FALSE;
880 PCRYPT_KEY_PROV_INFO info = NULL;
881 CERT_KEY_CONTEXT keyContext;
882 DWORD size;
883
884 TRACE("(%p, %08x, %p, %p, %p, %p)\n", pCert, dwFlags, pvReserved,
885 phCryptProv, pdwKeySpec, pfCallerFreeProv);
886
887 if (dwFlags & CRYPT_ACQUIRE_USE_PROV_INFO_FLAG)
888 {
889 DWORD size = 0;
890
891 ret = CertGetCertificateContextProperty(pCert,
892 CERT_KEY_PROV_INFO_PROP_ID, 0, &size);
893 if (ret)
894 {
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;
900 }
901 }
902 else if (dwFlags & CRYPT_ACQUIRE_CACHE_FLAG)
903 cache = TRUE;
904 *phCryptProv = 0;
905 if (cache)
906 {
907 size = sizeof(keyContext);
908 ret = CertGetCertificateContextProperty(pCert, CERT_KEY_CONTEXT_PROP_ID,
909 &keyContext, &size);
910 if (ret)
911 {
912 *phCryptProv = keyContext.hCryptProv;
913 if (pdwKeySpec)
914 *pdwKeySpec = keyContext.dwKeySpec;
915 if (pfCallerFreeProv)
916 *pfCallerFreeProv = !cache;
917 }
918 }
919 if (!*phCryptProv)
920 {
921 ret = CRYPT_AcquirePrivateKeyFromProvInfo(pCert, info,
922 &keyContext.hCryptProv, &keyContext.dwKeySpec);
923 if (ret)
924 {
925 *phCryptProv = keyContext.hCryptProv;
926 if (pdwKeySpec)
927 *pdwKeySpec = keyContext.dwKeySpec;
928 if (cache)
929 {
930 keyContext.cbSize = sizeof(keyContext);
931 if (CertSetCertificateContextProperty(pCert,
932 CERT_KEY_CONTEXT_PROP_ID, 0, &keyContext))
933 {
934 if (pfCallerFreeProv)
935 *pfCallerFreeProv = FALSE;
936 }
937 }
938 else
939 {
940 if (pfCallerFreeProv)
941 *pfCallerFreeProv = TRUE;
942 }
943 }
944 }
945 HeapFree(GetProcessHeap(), 0, info);
946 return ret;
947 }
948
949 static BOOL key_prov_info_matches_cert(PCCERT_CONTEXT pCert,
950 const CRYPT_KEY_PROV_INFO *keyProvInfo)
951 {
952 HCRYPTPROV csp;
953 BOOL matches = FALSE;
954
955 if (CryptAcquireContextW(&csp, keyProvInfo->pwszContainerName,
956 keyProvInfo->pwszProvName, keyProvInfo->dwProvType, keyProvInfo->dwFlags))
957 {
958 DWORD size;
959
960 /* Need to sign something to verify the sig. What to sign? Why not
961 * the certificate itself?
962 */
963 if (CryptSignAndEncodeCertificate(csp, AT_SIGNATURE,
964 pCert->dwCertEncodingType, X509_CERT_TO_BE_SIGNED, pCert->pCertInfo,
965 &pCert->pCertInfo->SignatureAlgorithm, NULL, NULL, &size))
966 {
967 BYTE *certEncoded = CryptMemAlloc(size);
968
969 if (certEncoded)
970 {
971 if (CryptSignAndEncodeCertificate(csp, AT_SIGNATURE,
972 pCert->dwCertEncodingType, X509_CERT_TO_BE_SIGNED,
973 pCert->pCertInfo, &pCert->pCertInfo->SignatureAlgorithm,
974 NULL, certEncoded, &size))
975 {
976 if (size == pCert->cbCertEncoded &&
977 !memcmp(certEncoded, pCert->pbCertEncoded, size))
978 matches = TRUE;
979 }
980 CryptMemFree(certEncoded);
981 }
982 }
983 CryptReleaseContext(csp, 0);
984 }
985 return matches;
986 }
987
988 static BOOL container_matches_cert(PCCERT_CONTEXT pCert, LPCSTR container,
989 CRYPT_KEY_PROV_INFO *keyProvInfo)
990 {
991 CRYPT_KEY_PROV_INFO copy;
992 WCHAR containerW[MAX_PATH];
993 BOOL matches;
994
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.
999 */
1000 copy = *keyProvInfo;
1001 copy.pwszContainerName = containerW;
1002 matches = key_prov_info_matches_cert(pCert, &copy);
1003 if (matches)
1004 {
1005 keyProvInfo->pwszContainerName =
1006 CryptMemAlloc((strlenW(containerW) + 1) * sizeof(WCHAR));
1007 if (keyProvInfo->pwszContainerName)
1008 {
1009 strcpyW(keyProvInfo->pwszContainerName, containerW);
1010 keyProvInfo->dwKeySpec = AT_SIGNATURE;
1011 }
1012 else
1013 matches = FALSE;
1014 }
1015 return matches;
1016 }
1017
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.
1023 */
1024 static BOOL find_key_prov_info_in_provider(PCCERT_CONTEXT pCert,
1025 CRYPT_KEY_PROV_INFO *keyProvInfo)
1026 {
1027 HCRYPTPROV defProvider;
1028 BOOL ret, found = FALSE;
1029 char containerA[MAX_PATH];
1030
1031 assert(keyProvInfo->pwszContainerName == NULL);
1032 if ((ret = CryptAcquireContextW(&defProvider, NULL,
1033 keyProvInfo->pwszProvName, keyProvInfo->dwProvType,
1034 keyProvInfo->dwFlags | CRYPT_VERIFYCONTEXT)))
1035 {
1036 DWORD enumFlags = keyProvInfo->dwFlags | CRYPT_FIRST;
1037
1038 while (ret && !found)
1039 {
1040 DWORD size = sizeof(containerA);
1041
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)
1047 {
1048 enumFlags &= ~CRYPT_FIRST;
1049 enumFlags |= CRYPT_NEXT;
1050 }
1051 }
1052 CryptReleaseContext(defProvider, 0);
1053 }
1054 return found;
1055 }
1056
1057 static BOOL find_matching_provider(PCCERT_CONTEXT pCert, DWORD dwFlags)
1058 {
1059 BOOL found = FALSE, ret = TRUE;
1060 DWORD index = 0, cbProvName = 0;
1061 CRYPT_KEY_PROV_INFO keyProvInfo;
1062
1063 TRACE("(%p, %08x)\n", pCert, dwFlags);
1064
1065 memset(&keyProvInfo, 0, sizeof(keyProvInfo));
1066 while (ret && !found)
1067 {
1068 DWORD size = 0;
1069
1070 ret = CryptEnumProvidersW(index, NULL, 0, &keyProvInfo.dwProvType,
1071 NULL, &size);
1072 if (ret)
1073 {
1074 if (size <= cbProvName)
1075 ret = CryptEnumProvidersW(index, NULL, 0,
1076 &keyProvInfo.dwProvType, keyProvInfo.pwszProvName, &size);
1077 else
1078 {
1079 CryptMemFree(keyProvInfo.pwszProvName);
1080 keyProvInfo.pwszProvName = CryptMemAlloc(size);
1081 if (keyProvInfo.pwszProvName)
1082 {
1083 cbProvName = size;
1084 ret = CryptEnumProvidersW(index, NULL, 0,
1085 &keyProvInfo.dwProvType, keyProvInfo.pwszProvName, &size);
1086 if (ret)
1087 {
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)))
1093 {
1094 keyProvInfo.dwFlags |= CRYPT_USER_KEYSET;
1095 found = find_key_prov_info_in_provider(pCert,
1096 &keyProvInfo);
1097 }
1098 if (!found)
1099 {
1100 if (dwFlags & CRYPT_FIND_MACHINE_KEYSET_FLAG ||
1101 !(dwFlags & (CRYPT_FIND_USER_KEYSET_FLAG |
1102 CRYPT_FIND_MACHINE_KEYSET_FLAG)))
1103 {
1104 keyProvInfo.dwFlags &= ~CRYPT_USER_KEYSET;
1105 keyProvInfo.dwFlags |= CRYPT_MACHINE_KEYSET;
1106 found = find_key_prov_info_in_provider(pCert,
1107 &keyProvInfo);
1108 }
1109 }
1110 }
1111 }
1112 else
1113 ret = FALSE;
1114 }
1115 index++;
1116 }
1117 }
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;
1124 }
1125
1126 static BOOL cert_prov_info_matches_cert(PCCERT_CONTEXT pCert)
1127 {
1128 BOOL matches = FALSE;
1129 DWORD size;
1130
1131 if (CertGetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID,
1132 NULL, &size))
1133 {
1134 CRYPT_KEY_PROV_INFO *keyProvInfo = CryptMemAlloc(size);
1135
1136 if (keyProvInfo)
1137 {
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);
1142 }
1143 }
1144 return matches;
1145 }
1146
1147 BOOL WINAPI CryptFindCertificateKeyProvInfo(PCCERT_CONTEXT pCert,
1148 DWORD dwFlags, void *pvReserved)
1149 {
1150 BOOL matches;
1151
1152 TRACE("(%p, %08x, %p)\n", pCert, dwFlags, pvReserved);
1153
1154 matches = cert_prov_info_matches_cert(pCert);
1155 if (!matches)
1156 matches = find_matching_provider(pCert, dwFlags);
1157 return matches;
1158 }
1159
1160 BOOL WINAPI CertCompareCertificate(DWORD dwCertEncodingType,
1161 PCERT_INFO pCertId1, PCERT_INFO pCertId2)
1162 {
1163 BOOL ret;
1164
1165 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertId1, pCertId2);
1166
1167 ret = CertCompareCertificateName(dwCertEncodingType, &pCertId1->Issuer,
1168 &pCertId2->Issuer) && CertCompareIntegerBlob(&pCertId1->SerialNumber,
1169 &pCertId2->SerialNumber);
1170 TRACE("returning %d\n", ret);
1171 return ret;
1172 }
1173
1174 BOOL WINAPI CertCompareCertificateName(DWORD dwCertEncodingType,
1175 PCERT_NAME_BLOB pCertName1, PCERT_NAME_BLOB pCertName2)
1176 {
1177 BOOL ret;
1178
1179 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertName1, pCertName2);
1180
1181 if (pCertName1->cbData == pCertName2->cbData)
1182 {
1183 if (pCertName1->cbData)
1184 ret = !memcmp(pCertName1->pbData, pCertName2->pbData,
1185 pCertName1->cbData);
1186 else
1187 ret = TRUE;
1188 }
1189 else
1190 ret = FALSE;
1191 TRACE("returning %d\n", ret);
1192 return ret;
1193 }
1194
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.
1198 */
1199 static DWORD CRYPT_significantBytes(const CRYPT_INTEGER_BLOB *pInt)
1200 {
1201 DWORD ret = pInt->cbData;
1202
1203 while (ret > 1)
1204 {
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;
1211 }
1212 return ret;
1213 }
1214
1215 BOOL WINAPI CertCompareIntegerBlob(PCRYPT_INTEGER_BLOB pInt1,
1216 PCRYPT_INTEGER_BLOB pInt2)
1217 {
1218 BOOL ret;
1219 DWORD cb1, cb2;
1220
1221 TRACE("(%p, %p)\n", pInt1, pInt2);
1222
1223 cb1 = CRYPT_significantBytes(pInt1);
1224 cb2 = CRYPT_significantBytes(pInt2);
1225 if (cb1 == cb2)
1226 {
1227 if (cb1)
1228 ret = !memcmp(pInt1->pbData, pInt2->pbData, cb1);
1229 else
1230 ret = TRUE;
1231 }
1232 else
1233 ret = FALSE;
1234 TRACE("returning %d\n", ret);
1235 return ret;
1236 }
1237
1238 BOOL WINAPI CertComparePublicKeyInfo(DWORD dwCertEncodingType,
1239 PCERT_PUBLIC_KEY_INFO pPublicKey1, PCERT_PUBLIC_KEY_INFO pPublicKey2)
1240 {
1241 BOOL ret;
1242
1243 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pPublicKey1, pPublicKey2);
1244
1245 switch (GET_CERT_ENCODING_TYPE(dwCertEncodingType))
1246 {
1247 case 0: /* Seems to mean "raw binary bits" */
1248 if (pPublicKey1->PublicKey.cbData == pPublicKey2->PublicKey.cbData &&
1249 pPublicKey1->PublicKey.cUnusedBits == pPublicKey2->PublicKey.cUnusedBits)
1250 {
1251 if (pPublicKey2->PublicKey.cbData)
1252 ret = !memcmp(pPublicKey1->PublicKey.pbData,
1253 pPublicKey2->PublicKey.pbData, pPublicKey1->PublicKey.cbData);
1254 else
1255 ret = TRUE;
1256 }
1257 else
1258 ret = FALSE;
1259 break;
1260 default:
1261 WARN("Unknown encoding type %08x\n", dwCertEncodingType);
1262 /* FALLTHROUGH */
1263 case X509_ASN_ENCODING:
1264 {
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))
1271 {
1272 pblob1 = CryptMemAlloc(length);
1273 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1274 pPublicKey1->PublicKey.pbData, pPublicKey1->PublicKey.cbData,
1275 0, pblob1, &length))
1276 {
1277 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1278 pPublicKey2->PublicKey.pbData, pPublicKey2->PublicKey.cbData,
1279 0, NULL, &length))
1280 {
1281 pblob2 = CryptMemAlloc(length);
1282 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1283 pPublicKey2->PublicKey.pbData, pPublicKey2->PublicKey.cbData,
1284 0, pblob2, &length))
1285 {
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);
1291 }
1292 CryptMemFree(pblob2);
1293 }
1294 }
1295 CryptMemFree(pblob1);
1296 }
1297
1298 break;
1299 }
1300 }
1301 return ret;
1302 }
1303
1304 DWORD WINAPI CertGetPublicKeyLength(DWORD dwCertEncodingType,
1305 PCERT_PUBLIC_KEY_INFO pPublicKey)
1306 {
1307 DWORD len = 0;
1308
1309 TRACE("(%08x, %p)\n", dwCertEncodingType, pPublicKey);
1310
1311 if (GET_CERT_ENCODING_TYPE(dwCertEncodingType) != X509_ASN_ENCODING)
1312 {
1313 SetLastError(ERROR_FILE_NOT_FOUND);
1314 return 0;
1315 }
1316 if (pPublicKey->Algorithm.pszObjId &&
1317 !strcmp(pPublicKey->Algorithm.pszObjId, szOID_RSA_DH))
1318 {
1319 FIXME("unimplemented for DH public keys\n");
1320 SetLastError(CRYPT_E_ASN1_BADTAG);
1321 }
1322 else
1323 {
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);
1330
1331 if (ret)
1332 {
1333 RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
1334
1335 len = rsaPubKey->bitlen;
1336 LocalFree(buf);
1337 }
1338 }
1339 return len;
1340 }
1341
1342 typedef BOOL (*CertCompareFunc)(PCCERT_CONTEXT pCertContext, DWORD dwType,
1343 DWORD dwFlags, const void *pvPara);
1344
1345 static BOOL compare_cert_by_md5_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
1346 DWORD dwFlags, const void *pvPara)
1347 {
1348 BOOL ret;
1349 BYTE hash[16];
1350 DWORD size = sizeof(hash);
1351
1352 ret = CertGetCertificateContextProperty(pCertContext,
1353 CERT_MD5_HASH_PROP_ID, hash, &size);
1354 if (ret)
1355 {
1356 const CRYPT_HASH_BLOB *pHash = pvPara;
1357
1358 if (size == pHash->cbData)
1359 ret = !memcmp(pHash->pbData, hash, size);
1360 else
1361 ret = FALSE;
1362 }
1363 return ret;
1364 }
1365
1366 static BOOL compare_cert_by_sha1_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
1367 DWORD dwFlags, const void *pvPara)
1368 {
1369 BOOL ret;
1370 BYTE hash[20];
1371 DWORD size = sizeof(hash);
1372
1373 ret = CertGetCertificateContextProperty(pCertContext,
1374 CERT_SHA1_HASH_PROP_ID, hash, &size);
1375 if (ret)
1376 {
1377 const CRYPT_HASH_BLOB *pHash = pvPara;
1378
1379 if (size == pHash->cbData)
1380 ret = !memcmp(pHash->pbData, hash, size);
1381 else
1382 ret = FALSE;
1383 }
1384 return ret;
1385 }
1386
1387 static BOOL compare_cert_by_name(PCCERT_CONTEXT pCertContext, DWORD dwType,
1388 DWORD dwFlags, const void *pvPara)
1389 {
1390 CERT_NAME_BLOB *blob = (CERT_NAME_BLOB *)pvPara, *toCompare;
1391 BOOL ret;
1392
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;
1400 }
1401
1402 static BOOL compare_cert_by_public_key(PCCERT_CONTEXT pCertContext,
1403 DWORD dwType, DWORD dwFlags, const void *pvPara)
1404 {
1405 CERT_PUBLIC_KEY_INFO *publicKey = (CERT_PUBLIC_KEY_INFO *)pvPara;
1406 BOOL ret;
1407
1408 ret = CertComparePublicKeyInfo(pCertContext->dwCertEncodingType,
1409 &pCertContext->pCertInfo->SubjectPublicKeyInfo, publicKey);
1410 return ret;
1411 }
1412
1413 static BOOL compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext,
1414 DWORD dwType, DWORD dwFlags, const void *pvPara)
1415 {
1416 CERT_INFO *pCertInfo = (CERT_INFO *)pvPara;
1417 BOOL ret;
1418
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
1426 {
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);
1433 }
1434 TRACE("returning %d\n", ret);
1435 return ret;
1436 }
1437
1438 static BOOL compare_cert_by_cert_id(PCCERT_CONTEXT pCertContext, DWORD dwType,
1439 DWORD dwFlags, const void *pvPara)
1440 {
1441 CERT_ID *id = (CERT_ID *)pvPara;
1442 BOOL ret;
1443
1444 switch (id->dwIdChoice)
1445 {
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:
1458 {
1459 DWORD size = 0;
1460
1461 ret = CertGetCertificateContextProperty(pCertContext,
1462 CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
1463 if (ret && size == id->u.KeyId.cbData)
1464 {
1465 LPBYTE buf = CryptMemAlloc(size);
1466
1467 if (buf)
1468 {
1469 CertGetCertificateContextProperty(pCertContext,
1470 CERT_KEY_IDENTIFIER_PROP_ID, buf, &size);
1471 ret = !memcmp(buf, id->u.KeyId.pbData, size);
1472 CryptMemFree(buf);
1473 }
1474 else
1475 ret = FALSE;
1476 }
1477 else
1478 ret = FALSE;
1479 break;
1480 }
1481 default:
1482 ret = FALSE;
1483 break;
1484 }
1485 return ret;
1486 }
1487
1488 static BOOL compare_existing_cert(PCCERT_CONTEXT pCertContext, DWORD dwType,
1489 DWORD dwFlags, const void *pvPara)
1490 {
1491 PCCERT_CONTEXT toCompare = pvPara;
1492 return CertCompareCertificate(pCertContext->dwCertEncodingType,
1493 pCertContext->pCertInfo, toCompare->pCertInfo);
1494 }
1495
1496 static BOOL compare_cert_by_signature_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
1497 DWORD dwFlags, const void *pvPara)
1498 {
1499 const CRYPT_HASH_BLOB *hash = pvPara;
1500 DWORD size = 0;
1501 BOOL ret;
1502
1503 ret = CertGetCertificateContextProperty(pCertContext,
1504 CERT_SIGNATURE_HASH_PROP_ID, NULL, &size);
1505 if (ret && size == hash->cbData)
1506 {
1507 LPBYTE buf = CryptMemAlloc(size);
1508
1509 if (buf)
1510 {
1511 CertGetCertificateContextProperty(pCertContext,
1512 CERT_SIGNATURE_HASH_PROP_ID, buf, &size);
1513 ret = !memcmp(buf, hash->pbData, size);
1514 CryptMemFree(buf);
1515 }
1516 else
1517 ret = FALSE;
1518 }
1519 else
1520 ret = FALSE;
1521 return ret;
1522 }
1523
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)
1527 {
1528 BOOL matches = FALSE;
1529 PCCERT_CONTEXT ret;
1530
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;
1538 }
1539
1540 typedef PCCERT_CONTEXT (*CertFindFunc)(HCERTSTORE store, DWORD dwType,
1541 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev);
1542
1543 static PCCERT_CONTEXT find_cert_any(HCERTSTORE store, DWORD dwType,
1544 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1545 {
1546 return CertEnumCertificatesInStore(store, prev);
1547 }
1548
1549 static PCCERT_CONTEXT find_cert_by_issuer(HCERTSTORE store, DWORD dwType,
1550 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1551 {
1552 BOOL ret;
1553 PCCERT_CONTEXT found = NULL, subject = pvPara;
1554 PCERT_EXTENSION ext;
1555 DWORD size;
1556
1557 if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER,
1558 subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
1559 {
1560 CERT_AUTHORITY_KEY_ID_INFO *info;
1561
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)
1567 {
1568 CERT_ID id;
1569
1570 if (info->CertIssuer.cbData && info->CertSerialNumber.cbData)
1571 {
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));
1577 }
1578 else if (info->KeyId.cbData)
1579 {
1580 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
1581 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
1582 }
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);
1589 }
1590 }
1591 else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2,
1592 subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
1593 {
1594 CERT_AUTHORITY_KEY_ID2_INFO *info;
1595
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)
1601 {
1602 CERT_ID id;
1603
1604 if (info->AuthorityCertIssuer.cAltEntry &&
1605 info->AuthorityCertSerialNumber.cbData)
1606 {
1607 PCERT_ALT_NAME_ENTRY directoryName = NULL;
1608 DWORD i;
1609
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)
1617 {
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));
1624 }
1625 else
1626 {
1627 FIXME("no supported name type in authority key id2\n");
1628 ret = FALSE;
1629 }
1630 }
1631 else if (info->KeyId.cbData)
1632 {
1633 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
1634 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
1635 }
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);
1642 }
1643 }
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;
1649 }
1650
1651 static BOOL compare_cert_by_name_str(PCCERT_CONTEXT pCertContext,
1652 DWORD dwType, DWORD dwFlags, const void *pvPara)
1653 {
1654 PCERT_NAME_BLOB name;
1655 DWORD len;
1656 BOOL ret = FALSE;
1657
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)
1665 {
1666 LPWSTR str = CryptMemAlloc(len * sizeof(WCHAR));
1667
1668 if (str)
1669 {
1670 LPWSTR ptr;
1671
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);
1679 }
1680 }
1681 return ret;
1682 }
1683
1684 static PCCERT_CONTEXT find_cert_by_name_str_a(HCERTSTORE store, DWORD dwType,
1685 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1686 {
1687 PCCERT_CONTEXT found = NULL;
1688
1689 TRACE("%s\n", debugstr_a(pvPara));
1690
1691 if (pvPara)
1692 {
1693 int len = MultiByteToWideChar(CP_ACP, 0, pvPara, -1, NULL, 0);
1694 LPWSTR str = CryptMemAlloc(len * sizeof(WCHAR));
1695
1696 if (str)
1697 {
1698 LPWSTR ptr;
1699
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);
1706 }
1707 }
1708 else
1709 found = find_cert_any(store, dwType, dwFlags, NULL, prev);
1710 return found;
1711 }
1712
1713 static PCCERT_CONTEXT find_cert_by_name_str_w(HCERTSTORE store, DWORD dwType,
1714 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1715 {
1716 PCCERT_CONTEXT found = NULL;
1717
1718 TRACE("%s\n", debugstr_w(pvPara));
1719
1720 if (pvPara)
1721 {
1722 DWORD len = strlenW(pvPara);
1723 LPWSTR str = CryptMemAlloc((len + 1) * sizeof(WCHAR));
1724
1725 if (str)
1726 {
1727 LPCWSTR src;
1728 LPWSTR dst;
1729
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);
1736 }
1737 }
1738 else
1739 found = find_cert_any(store, dwType, dwFlags, NULL, prev);
1740 return found;
1741 }
1742
1743 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
1744 DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType, const void *pvPara,
1745 PCCERT_CONTEXT pPrevCertContext)
1746 {
1747 PCCERT_CONTEXT ret;
1748 CertFindFunc find = NULL;
1749 CertCompareFunc compare = NULL;
1750
1751 TRACE("(%p, %08x, %08x, %08x, %p, %p)\n", hCertStore, dwCertEncodingType,
1752 dwFlags, dwType, pvPara, pPrevCertContext);
1753
1754 switch (dwType >> CERT_COMPARE_SHIFT)
1755 {
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);
1794 }
1795
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;
1807 }
1808
1809 PCCERT_CONTEXT WINAPI CertGetSubjectCertificateFromStore(HCERTSTORE hCertStore,
1810 DWORD dwCertEncodingType, PCERT_INFO pCertId)
1811 {
1812 TRACE("(%p, %08x, %p)\n", hCertStore, dwCertEncodingType, pCertId);
1813
1814 if (!pCertId)
1815 {
1816 SetLastError(E_INVALIDARG);
1817 return NULL;
1818 }
1819 return CertFindCertificateInStore(hCertStore, dwCertEncodingType, 0,
1820 CERT_FIND_SUBJECT_CERT, pCertId, NULL);
1821 }
1822
1823 BOOL WINAPI CertVerifySubjectCertificateContext(PCCERT_CONTEXT pSubject,
1824 PCCERT_CONTEXT pIssuer, DWORD *pdwFlags)
1825 {
1826 static const DWORD supportedFlags = CERT_STORE_REVOCATION_FLAG |
1827 CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG;
1828
1829 if (*pdwFlags & ~supportedFlags)
1830 {
1831 SetLastError(E_INVALIDARG);
1832 return FALSE;
1833 }
1834 if (*pdwFlags & CERT_STORE_REVOCATION_FLAG)
1835 {
1836 DWORD flags = 0;
1837 PCCRL_CONTEXT crl = CertGetCRLFromStore(pSubject->hCertStore, pSubject,
1838 NULL, &flags);
1839
1840 /* FIXME: what if the CRL has expired? */
1841 if (crl)
1842 {
1843 if (CertVerifyCRLRevocation(pSubject->dwCertEncodingType,
1844 pSubject->pCertInfo, 1, (PCRL_INFO *)&crl->pCrlInfo))
1845 *pdwFlags &= CERT_STORE_REVOCATION_FLAG;
1846 }
1847 else
1848 *pdwFlags |= CERT_STORE_NO_CRL_FLAG;
1849 }
1850 if (*pdwFlags & CERT_STORE_TIME_VALIDITY_FLAG)
1851 {
1852 if (0 == CertVerifyTimeValidity(NULL, pSubject->pCertInfo))
1853 *pdwFlags &= ~CERT_STORE_TIME_VALIDITY_FLAG;
1854 }
1855 if (*pdwFlags & CERT_STORE_SIGNATURE_FLAG)
1856 {
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;
1861 }
1862 return TRUE;
1863 }
1864
1865 PCCERT_CONTEXT WINAPI CertGetIssuerCertificateFromStore(HCERTSTORE hCertStore,
1866 PCCERT_CONTEXT pSubjectContext, PCCERT_CONTEXT pPrevIssuerContext,
1867 DWORD *pdwFlags)
1868 {
1869 PCCERT_CONTEXT ret;
1870
1871 TRACE("(%p, %p, %p, %08x)\n", hCertStore, pSubjectContext,
1872 pPrevIssuerContext, *pdwFlags);
1873
1874 if (!pSubjectContext)
1875 {
1876 SetLastError(E_INVALIDARG);
1877 return NULL;
1878 }
1879
1880 ret = CertFindCertificateInStore(hCertStore,
1881 pSubjectContext->dwCertEncodingType, 0, CERT_FIND_ISSUER_OF,
1882 pSubjectContext, pPrevIssuerContext);
1883 if (ret)
1884 {
1885 if (!CertVerifySubjectCertificateContext(pSubjectContext, ret,
1886 pdwFlags))
1887 {
1888 CertFreeCertificateContext(ret);
1889 ret = NULL;
1890 }
1891 if (CRYPT_IsCertificateSelfSigned(pSubjectContext))
1892 {
1893 CertFreeCertificateContext(ret);
1894 ret = NULL;
1895 SetLastError(CRYPT_E_SELF_SIGNED);
1896 }
1897 }
1898 TRACE("returning %p\n", ret);
1899 return ret;
1900 }
1901
1902 typedef struct _OLD_CERT_REVOCATION_STATUS {
1903 DWORD cbSize;
1904 DWORD dwIndex;
1905 DWORD dwError;
1906 DWORD dwReason;
1907 } OLD_CERT_REVOCATION_STATUS;
1908
1909 typedef BOOL (WINAPI *CertVerifyRevocationFunc)(DWORD, DWORD, DWORD,
1910 void **, DWORD, PCERT_REVOCATION_PARA, PCERT_REVOCATION_STATUS);
1911
1912 BOOL WINAPI CertVerifyRevocation(DWORD dwEncodingType, DWORD dwRevType,
1913 DWORD cContext, PVOID rgpvContext[], DWORD dwFlags,
1914 PCERT_REVOCATION_PARA pRevPara, PCERT_REVOCATION_STATUS pRevStatus)
1915 {
1916 BOOL ret;
1917
1918 TRACE("(%08x, %d, %d, %p, %08x, %p, %p)\n", dwEncodingType, dwRevType,
1919 cContext, rgpvContext, dwFlags, pRevPara, pRevStatus);
1920
1921 if (pRevStatus->cbSize != sizeof(OLD_CERT_REVOCATION_STATUS) &&
1922 pRevStatus->cbSize != sizeof(CERT_REVOCATION_STATUS))
1923 {
1924 SetLastError(E_INVALIDARG);
1925 return FALSE;
1926 }
1927 if (cContext)
1928 {
1929 static HCRYPTOIDFUNCSET set = NULL;
1930 DWORD size;
1931
1932 if (!set)
1933 set = CryptInitOIDFunctionSet(CRYPT_OID_VERIFY_REVOCATION_FUNC, 0);
1934 ret = CryptGetDefaultOIDDllList(set, dwEncodingType, NULL, &size);
1935 if (ret)
1936 {
1937 if (size == 1)
1938 {
1939 /* empty list */
1940 SetLastError(CRYPT_E_NO_REVOCATION_DLL);
1941 ret = FALSE;
1942 }
1943 else
1944 {
1945 LPWSTR dllList = CryptMemAlloc(size * sizeof(WCHAR)), ptr;
1946
1947 if (dllList)
1948 {
1949 ret = CryptGetDefaultOIDDllList(set, dwEncodingType,
1950 dllList, &size);
1951 if (ret)
1952 {
1953 for (ptr = dllList; ret && *ptr;
1954 ptr += lstrlenW(ptr) + 1)
1955 {
1956 CertVerifyRevocationFunc func;
1957 HCRYPTOIDFUNCADDR hFunc;
1958
1959 ret = CryptGetDefaultOIDFunctionAddress(set,
1960 dwEncodingType, ptr, 0, (void **)&func, &hFunc);
1961 if (ret)
1962 {
1963 ret = func(dwEncodingType, dwRevType, cContext,
1964 rgpvContext, dwFlags, pRevPara, pRevStatus);
1965 CryptFreeOIDFunctionAddress(hFunc, 0);
1966 }
1967 }
1968 }
1969 CryptMemFree(dllList);
1970 }
1971 else
1972 {
1973 SetLastError(ERROR_OUTOFMEMORY);
1974 ret = FALSE;
1975 }
1976 }
1977 }
1978 }
1979 else
1980 ret = TRUE;
1981 return ret;
1982 }
1983
1984 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
1985 CRYPT_ATTRIBUTE rgAttr[])
1986 {
1987 PCRYPT_ATTRIBUTE ret = NULL;
1988 DWORD i;
1989
1990 TRACE("%s %d %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
1991
1992 if (!cAttr)
1993 return NULL;
1994 if (!pszObjId)
1995 {
1996 SetLastError(ERROR_INVALID_PARAMETER);
1997 return NULL;
1998 }
1999
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;
2004 }
2005
2006 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
2007 CERT_EXTENSION rgExtensions[])
2008 {
2009 PCERT_EXTENSION ret = NULL;
2010 DWORD i;
2011
2012 TRACE("%s %d %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
2013
2014 if (!cExtensions)
2015 return NULL;
2016 if (!pszObjId)
2017 {
2018 SetLastError(ERROR_INVALID_PARAMETER);
2019 return NULL;
2020 }
2021
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;
2027 }
2028
2029 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
2030 {
2031 PCERT_RDN_ATTR ret = NULL;
2032 DWORD i, j;
2033
2034 TRACE("%s %p\n", debugstr_a(pszObjId), pName);
2035
2036 if (!pszObjId)
2037 {
2038 SetLastError(ERROR_INVALID_PARAMETER);
2039 return NULL;
2040 }
2041
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;
2048 }
2049
2050 static BOOL find_matching_rdn_attr(DWORD dwFlags, const CERT_NAME_INFO *name,
2051 const CERT_RDN_ATTR *attr)
2052 {
2053 DWORD i, j;
2054 BOOL match = FALSE;
2055
2056 for (i = 0; !match && i < name->cRDN; i++)
2057 {
2058 for (j = 0; j < name->rgRDN[i].cRDNAttr; j++)
2059 {
2060 if (!strcmp(name->rgRDN[i].rgRDNAttr[j].pszObjId,
2061 attr->pszObjId) &&
2062 name->rgRDN[i].rgRDNAttr[j].dwValueType ==
2063 attr->dwValueType)
2064 {
2065 if (dwFlags & CERT_UNICODE_IS_RDN_ATTRS_FLAG)
2066 {
2067 LPCWSTR nameStr =
2068 (LPCWSTR)name->rgRDN[i].rgRDNAttr[j].Value.pbData;
2069 LPCWSTR attrStr = (LPCWSTR)attr->Value.pbData;
2070
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);
2084 }
2085 else
2086 {
2087 LPCSTR nameStr =
2088 (LPCSTR)name->rgRDN[i].rgRDNAttr[j].Value.pbData;
2089 LPCSTR attrStr = (LPCSTR)attr->Value.pbData;
2090
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);
2102 }
2103 }
2104 }
2105 }
2106 return match;
2107 }
2108
2109 BOOL WINAPI CertIsRDNAttrsInCertificateName(DWORD dwCertEncodingType,
2110 DWORD dwFlags, PCERT_NAME_BLOB pCertName, PCERT_RDN pRDN)
2111 {
2112 CERT_NAME_INFO *name;
2113 LPCSTR type;
2114 DWORD size;
2115 BOOL ret;
2116
2117 TRACE("(%08x, %08x, %p, %p)\n", dwCertEncodingType, dwFlags, pCertName,
2118 pRDN);
2119
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)))
2124 {
2125 DWORD i;
2126
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);
2132 }
2133 return ret;
2134 }
2135
2136 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
2137 PCERT_INFO pCertInfo)
2138 {
2139 FILETIME fileTime;
2140 LONG ret;
2141
2142 if (!pTimeToVerify)
2143 {
2144 GetSystemTimeAsFileTime(&fileTime);
2145 pTimeToVerify = &fileTime;
2146 }
2147 if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
2148 {
2149 ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
2150 if (ret < 0)
2151 ret = 0;
2152 }
2153 return ret;
2154 }
2155
2156 BOOL WINAPI CertVerifyValidityNesting(PCERT_INFO pSubjectInfo,
2157 PCERT_INFO pIssuerInfo)
2158 {
2159 TRACE("(%p, %p)\n", pSubjectInfo, pIssuerInfo);
2160
2161 return CertVerifyTimeValidity(&pSubjectInfo->NotBefore, pIssuerInfo) == 0
2162 && CertVerifyTimeValidity(&pSubjectInfo->NotAfter, pIssuerInfo) == 0;
2163 }
2164
2165 BOOL WINAPI CryptHashCertificate(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
2166 DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
2167 DWORD *pcbComputedHash)
2168 {
2169 BOOL ret = TRUE;
2170 HCRYPTHASH hHash = 0;
2171
2172 TRACE("(%08lx, %d, %08x, %p, %d, %p, %p)\n", hCryptProv, Algid, dwFlags,
2173 pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
2174
2175 if (!hCryptProv)
2176 hCryptProv = CRYPT_GetDefaultProvider();
2177 if (!Algid)
2178 Algid = CALG_SHA1;
2179 if (ret)
2180 {
2181 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
2182 if (ret)
2183 {
2184 ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
2185 if (ret)
2186 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
2187 pcbComputedHash, 0);
2188 CryptDestroyHash(hHash);
2189 }
2190 }
2191 return ret;
2192 }
2193
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)
2197 {
2198 BOOL ret = TRUE;
2199 HCRYPTHASH hHash = 0;
2200
2201 TRACE("(%08lx, %d, %08x, %d, %p, %p, %p)\n", hCryptProv, Algid, dwFlags,
2202 dwCertEncodingType, pInfo, pbComputedHash, pcbComputedHash);
2203
2204 if (!hCryptProv)
2205 hCryptProv = CRYPT_GetDefaultProvider();
2206 if (!Algid)
2207 Algid = CALG_MD5;
2208 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
2209 {
2210 SetLastError(ERROR_FILE_NOT_FOUND);
2211 return FALSE;
2212 }
2213 if (ret)
2214 {
2215 BYTE *buf;
2216 DWORD size = 0;
2217
2218 ret = CRYPT_AsnEncodePubKeyInfoNoNull(dwCertEncodingType,
2219 X509_PUBLIC_KEY_INFO, pInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
2220 (LPBYTE)&buf, &size);
2221 if (ret)
2222 {
2223 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
2224 if (ret)
2225 {
2226 ret = CryptHashData(hHash, buf, size, 0);
2227 if (ret)
2228 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
2229 pcbComputedHash, 0);
2230 CryptDestroyHash(hHash);
2231 }
2232 LocalFree(buf);
2233 }
2234 }
2235 return ret;
2236 }
2237
2238 BOOL WINAPI CryptHashToBeSigned(HCRYPTPROV_LEGACY hCryptProv,
2239 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
2240 BYTE *pbComputedHash, DWORD *pcbComputedHash)
2241 {
2242 BOOL ret;
2243 CERT_SIGNED_CONTENT_INFO *info;
2244 DWORD size;
2245
2246 TRACE("(%08lx, %08x, %p, %d, %p, %d)\n", hCryptProv, dwCertEncodingType,
2247 pbEncoded, cbEncoded, pbComputedHash, *pcbComputedHash);
2248
2249 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
2250 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size);
2251 if (ret)
2252 {
2253 PCCRYPT_OID_INFO oidInfo;
2254 HCRYPTHASH hHash;
2255
2256 if (!hCryptProv)
2257 hCryptProv = CRYPT_GetDefaultProvider();
2258 oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2259 info->SignatureAlgorithm.pszObjId, 0);
2260 if (!oidInfo)
2261 {
2262 SetLastError(NTE_BAD_ALGID);
2263 ret = FALSE;
2264 }
2265 else
2266 {
2267 ret = CryptCreateHash(hCryptProv, oidInfo->u.Algid, 0, 0, &hHash);
2268 if (ret)
2269 {
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);
2276 }
2277 }
2278 LocalFree(info);
2279 }
2280 return ret;
2281 }
2282
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)
2287 {
2288 BOOL ret;
2289 PCCRYPT_OID_INFO info;
2290 HCRYPTHASH hHash;
2291
2292 TRACE("(%08lx, %d, %d, %p, %d, %p, %p, %p, %p)\n", hCryptProv,
2293 dwKeySpec, dwCertEncodingType, pbEncodedToBeSigned, cbEncodedToBeSigned,
2294 pSignatureAlgorithm, pvHashAuxInfo, pbSignature, pcbSignature);
2295
2296 info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2297 pSignatureAlgorithm->pszObjId, 0);
2298 if (!info)
2299 {
2300 SetLastError(NTE_BAD_ALGID);
2301 return FALSE;
2302 }
2303 if (info->dwGroupId == CRYPT_HASH_ALG_OID_GROUP_ID)
2304 {
2305 if (!hCryptProv)
2306 hCryptProv = CRYPT_GetDefaultProvider();
2307 ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
2308 if (ret)
2309 {
2310 ret = CryptHashData(hHash, pbEncodedToBeSigned,
2311 cbEncodedToBeSigned, 0);
2312 if (ret)
2313 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbSignature,
2314 pcbSignature, 0);
2315 CryptDestroyHash(hHash);
2316 }
2317 }
2318 else
2319 {
2320 if (!hCryptProv)
2321 {
2322 SetLastError(ERROR_INVALID_PARAMETER);
2323 ret = FALSE;
2324 }
2325 else
2326 {
2327 ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
2328 if (ret)
2329 {
2330 ret = CryptHashData(hHash, pbEncodedToBeSigned,
2331 cbEncodedToBeSigned, 0);
2332 if (ret)
2333 ret = CryptSignHashW(hHash, dwKeySpec, NULL, 0, pbSignature,
2334 pcbSignature);
2335 CryptDestroyHash(hHash);
2336 }
2337 }
2338 }
2339 return ret;
2340 }
2341
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)
2346 {
2347 BOOL ret;
2348 DWORD encodedSize, hashSize;
2349
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);
2353
2354 ret = CryptEncodeObject(dwCertEncodingType, lpszStructType, pvStructInfo,
2355 NULL, &encodedSize);
2356 if (ret)
2357 {
2358 PBYTE encoded = CryptMemAlloc(encodedSize);
2359
2360 if (encoded)
2361 {
2362 ret = CryptEncodeObject(dwCertEncodingType, lpszStructType,
2363 pvStructInfo, encoded, &encodedSize);
2364 if (ret)
2365 {
2366 ret = CryptSignCertificate(hCryptProv, dwKeySpec,
2367 dwCertEncodingType, encoded, encodedSize, pSignatureAlgorithm,
2368 pvHashAuxInfo, NULL, &hashSize);
2369 if (ret)
2370 {
2371 PBYTE hash = CryptMemAlloc(hashSize);
2372
2373 if (hash)
2374 {
2375 ret = CryptSignCertificate(hCryptProv, dwKeySpec,
2376 dwCertEncodingType, encoded, encodedSize,
2377 pSignatureAlgorithm, pvHashAuxInfo, hash, &hashSize);
2378 if (ret)
2379 {
2380 CERT_SIGNED_CONTENT_INFO info = { { 0 } };
2381
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);
2390 }
2391 CryptMemFree(hash);
2392 }
2393 else
2394 ret = FALSE;
2395 }
2396 }
2397 CryptMemFree(encoded);
2398 }
2399 else
2400 ret = FALSE;
2401 }
2402 return ret;
2403 }
2404
2405 BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV_LEGACY hCryptProv,
2406 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
2407 PCERT_PUBLIC_KEY_INFO pPublicKey)
2408 {
2409 CRYPT_DATA_BLOB blob = { cbEncoded, (BYTE *)pbEncoded };
2410
2411 return CryptVerifyCertificateSignatureEx(hCryptProv, dwCertEncodingType,
2412 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &blob,
2413 CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
2414 }
2415
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)
2418 {
2419 BOOL ret;
2420 HCRYPTKEY key;
2421 ALG_ID pubKeyID, hashID;
2422
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)
2434 {
2435 HCRYPTHASH hash;
2436
2437 ret = CryptCreateHash(hCryptProv, hashID, 0, 0, &hash);
2438 if (ret)
2439 {
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);
2446 }
2447 CryptDestroyKey(key);
2448 }
2449 return ret;
2450 }
2451
2452 static BOOL CNG_CalcHash(const WCHAR *algorithm, const CERT_SIGNED_CONTENT_INFO *signedCert,
2453 BYTE **hash_value, DWORD *hash_len)
2454 {
2455 BCRYPT_HASH_HANDLE hash = NULL;
2456 BCRYPT_ALG_HANDLE alg = NULL;
2457 NTSTATUS status;
2458 DWORD size;
2459
2460 if ((status = BCryptOpenAlgorithmProvider(&alg, algorithm, NULL, 0)))
2461 goto done;
2462
2463 if ((status = BCryptCreateHash(alg, &hash, NULL, 0, NULL, 0, 0)))
2464 goto done;
2465
2466 if ((status = BCryptHashData(hash, signedCert->ToBeSigned.pbData, signedCert->ToBeSigned.cbData, 0)))
2467 goto done;
2468
2469 if ((status = BCryptGetProperty(hash, BCRYPT_HASH_LENGTH, (BYTE *)hash_len, sizeof(*hash_len), &size, 0)))
2470 goto done;
2471
2472 if (!(*hash_value = CryptMemAlloc(*hash_len)))
2473 {
2474 status = STATUS_NO_MEMORY;
2475 goto done;
2476 }
2477
2478 if ((status = BCryptFinishHash(hash, *hash_value, *hash_len, 0)))
2479 {
2480 CryptMemFree(*hash_value);
2481 goto done;
2482 }
2483
2484 done:
2485 if (hash) BCryptDestroyHash(hash);
2486 if (alg) BCryptCloseAlgorithmProvider(alg, 0);
2487 if (status) SetLastError(RtlNtStatusToDosError(status));
2488 return status == 0;
2489 }
2490
2491 static BOOL CNG_ImportECCPubKey(CERT_PUBLIC_KEY_INFO *pubKeyInfo, BCRYPT_KEY_HANDLE *key)
2492 {
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;
2499
2500 if (!pubKeyInfo->PublicKey.cbData)
2501 {
2502 SetLastError(NTE_BAD_ALGID);
2503 return FALSE;
2504 }
2505
2506 if (pubKeyInfo->PublicKey.pbData[0] != 0x4)
2507 {
2508 FIXME("Compressed ECC curves (%02x) not yet supported\n", pubKeyInfo->PublicKey.pbData[0]);
2509 SetLastError(NTE_BAD_ALGID);
2510 return FALSE;
2511 }
2512
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;
2516
2517 if (!strcmp(*ecc_curve, szOID_ECC_CURVE_P256))
2518 {
2519 sign_algo = BCRYPT_ECDSA_P256_ALGORITHM;
2520 blob_magic = BCRYPT_ECDSA_PUBLIC_P256_MAGIC;
2521 }
2522 else if (!strcmp(*ecc_curve, szOID_ECC_CURVE_P384))
2523 {
2524 sign_algo = BCRYPT_ECDSA_P384_ALGORITHM;
2525 blob_magic = BCRYPT_ECDSA_PUBLIC_P384_MAGIC;
2526 }
2527 else
2528 {
2529 FIXME("Unsupported ecc curve type: %s\n", *ecc_curve);
2530 sign_algo = NULL;
2531 blob_magic = 0;
2532 }
2533 LocalFree(ecc_curve);
2534
2535 if (!sign_algo)
2536 {
2537 SetLastError(NTE_BAD_ALGID);
2538 return FALSE;
2539 }
2540
2541 if ((status = BCryptOpenAlgorithmProvider(&alg, sign_algo, NULL, 0)))
2542 goto done;
2543
2544 ecckey_len = sizeof(BCRYPT_ECCKEY_BLOB) + pubKeyInfo->PublicKey.cbData - 1;
2545 if (!(ecckey = CryptMemAlloc(ecckey_len)))
2546 {
2547 status = STATUS_NO_MEMORY;
2548 goto done;
2549 }
2550
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);
2554
2555 status = BCryptImportKeyPair(alg, NULL, BCRYPT_ECCPUBLIC_BLOB, key, (BYTE*)ecckey, ecckey_len, 0);
2556 CryptMemFree(ecckey);
2557
2558 done:
2559 if (alg) BCryptCloseAlgorithmProvider(alg, 0);
2560 if (status) SetLastError(RtlNtStatusToDosError(status));
2561 return !status;
2562 }
2563
2564 static BOOL CNG_ImportPubKey(CERT_PUBLIC_KEY_INFO *pubKeyInfo, BCRYPT_KEY_HANDLE *key)
2565 {
2566 if (!strcmp(pubKeyInfo->Algorithm.pszObjId, szOID_ECC_PUBLIC_KEY))
2567 return CNG_ImportECCPubKey(pubKeyInfo, key);
2568
2569 FIXME("Unsupported public key type: %s\n", debugstr_a(pubKeyInfo->Algorithm.pszObjId));
2570 SetLastError(NTE_BAD_ALGID);
2571 return FALSE;
2572 }
2573
2574 static BOOL CNG_PrepareSignatureECC(BYTE *encoded_sig, DWORD encoded_size, BYTE **sig_value, DWORD *sig_len)
2575 {
2576 CERT_ECC_SIGNATURE *ecc_sig;
2577 DWORD size;
2578 int i;
2579
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;
2583
2584 if (!ecc_sig->r.cbData || !ecc_sig->s.cbData)
2585 {
2586 LocalFree(ecc_sig);
2587 SetLastError(ERROR_INVALID_DATA);
2588 return FALSE;
2589 }
2590
2591 *sig_len = ecc_sig->r.cbData + ecc_sig->s.cbData;
2592 if (!(*sig_value = CryptMemAlloc(*sig_len)))
2593 {
2594 LocalFree(ecc_sig);
2595 SetLastError(ERROR_OUTOFMEMORY);
2596 return FALSE;
2597 }
2598
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];
2603
2604 LocalFree(ecc_sig);
2605 return TRUE;
2606 }
2607
2608 static BOOL CNG_PrepareSignature(CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert,
2609 BYTE **sig_value, DWORD *sig_len)
2610 {
2611 BYTE *encoded_sig;
2612 BOOL ret = FALSE;
2613 int i;
2614
2615 if (!signedCert->Signature.cbData)
2616 {
2617 SetLastError(ERROR_INVALID_DATA);
2618 return FALSE;
2619 }
2620
2621 if (!(encoded_sig = CryptMemAlloc(signedCert->Signature.cbData)))
2622 {
2623 SetLastError(ERROR_OUTOFMEMORY);
2624 return FALSE;
2625 }
2626
2627 for (i = 0; i < signedCert->Signature.cbData; i++)
2628 encoded_sig[i] = signedCert->Signature.pbData[signedCert->Signature.cbData - i - 1];
2629
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
2633 {
2634 FIXME("Unsupported public key type: %s\n", debugstr_a(pubKeyInfo->Algorithm.pszObjId));
2635 SetLastError(NTE_BAD_ALGID);
2636 }
2637
2638 CryptMemFree(encoded_sig);
2639 return ret;
2640 }
2641
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)
2644 {
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;
2650
2651 ret = CNG_ImportPubKey(pubKeyInfo, &key);
2652 if (ret)
2653 {
2654 ret = CNG_CalcHash(info->pwszCNGAlgid, signedCert, &hash_value, &hash_len);
2655 if (ret)
2656 {
2657 ret = CNG_PrepareSignature(pubKeyInfo, signedCert, &sig_value, &sig_len);
2658 if (ret)
2659 {
2660 status = BCryptVerifySignature(key, NULL, hash_value, hash_len, sig_value, sig_len, 0);
2661 if (status)
2662 {
2663 FIXME("Failed to verify signature: %08x\n", status);
2664 SetLastError(RtlNtStatusToDosError(status));
2665 ret = FALSE;
2666 }
2667 CryptMemFree(sig_value);
2668 }
2669 CryptMemFree(hash_value);
2670 }
2671 BCryptDestroyKey(key);
2672 }
2673
2674 return ret;
2675 }
2676
2677 static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv, DWORD dwCertEncodingType,
2678 CERT_PUBLIC_KEY_INFO *pubKeyInfo, const CERT_SIGNED_CONTENT_INFO *signedCert)
2679 {
2680 CCRYPT_OID_INFO *info;
2681
2682 info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, signedCert->SignatureAlgorithm.pszObjId, 0);
2683 if (!info || info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID)
2684 {
2685 SetLastError(NTE_BAD_ALGID);
2686 return FALSE;
2687 }
2688
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);
2693 }
2694
2695 BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV_LEGACY hCryptProv,
2696 DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
2697 DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
2698 {
2699 BOOL ret = TRUE;
2700 CRYPT_DATA_BLOB subjectBlob;
2701
2702 TRACE("(%08lx, %d, %d, %p, %d, %p, %08x, %p)\n", hCryptProv,
2703 dwCertEncodingType, dwSubjectType, pvSubject, dwIssuerType, pvIssuer,
2704 dwFlags, pvReserved);
2705
2706 switch (dwSubjectType)
2707 {
2708 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB:
2709 {
2710 PCRYPT_DATA_BLOB blob = pvSubject;
2711
2712 subjectBlob.pbData = blob->pbData;
2713 subjectBlob.cbData = blob->cbData;
2714 break;
2715 }
2716 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT:
2717 {
2718 PCERT_CONTEXT context = pvSubject;
2719
2720 subjectBlob.pbData = context->pbCertEncoded;
2721 subjectBlob.cbData = context->cbCertEncoded;
2722 break;
2723 }
2724 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL:
2725 {
2726 PCRL_CONTEXT context = pvSubject;
2727
2728 subjectBlob.pbData = context->pbCrlEncoded;
2729 subjectBlob.cbData = context->cbCrlEncoded;
2730 break;
2731 }
2732 default:
2733 SetLastError(E_INVALIDARG);
2734 ret = FALSE;
2735 }
2736
2737 if (ret)
2738 {
2739 PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
2740 DWORD size = 0;
2741
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)
2747 {
2748 switch (dwIssuerType)
2749 {
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)
2767 {
2768 SetLastError(E_INVALIDARG);
2769 ret = FALSE;
2770 }
2771 else
2772 {
2773 FIXME("unimplemented for NULL signer\n");
2774 SetLastError(E_INVALIDARG);
2775 ret = FALSE;
2776 }
2777 break;
2778 default:
2779 SetLastError(E_INVALIDARG);
2780 ret = FALSE;
2781 }
2782 LocalFree(signedCert);
2783 }
2784 }
2785 return ret;
2786 }
2787
2788 BOOL WINAPI CertGetIntendedKeyUsage(DWORD dwCertEncodingType,
2789 PCERT_INFO pCertInfo, BYTE *pbKeyUsage, DWORD cbKeyUsage)
2790 {
2791 PCERT_EXTENSION ext;
2792 BOOL ret = FALSE;
2793
2794 TRACE("(%08x, %p, %p, %d)\n", dwCertEncodingType, pCertInfo, pbKeyUsage,
2795 cbKeyUsage);
2796
2797 ext = CertFindExtension(szOID_KEY_USAGE, pCertInfo->cExtension,
2798 pCertInfo->rgExtension);
2799 if (ext)
2800 {
2801 CRYPT_BIT_BLOB usage;
2802 DWORD size = sizeof(usage);
2803
2804 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS,
2805 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL,
2806 &usage, &size);
2807 if (ret)
2808 {
2809 if (cbKeyUsage < usage.cbData)
2810 ret = FALSE;
2811 else
2812 {
2813 memcpy(pbKeyUsage, usage.pbData, usage.cbData);
2814 if (cbKeyUsage > usage.cbData)
2815 memset(pbKeyUsage + usage.cbData, 0,
2816 cbKeyUsage - usage.cbData);
2817 }
2818 }
2819 }
2820 else
2821 SetLastError(0);
2822 return ret;
2823 }
2824
2825 BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags,
2826 PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage)
2827 {
2828 PCERT_ENHKEY_USAGE usage = NULL;
2829 DWORD bytesNeeded;
2830 BOOL ret = TRUE;
2831
2832 if (!pCertContext || !pcbUsage)
2833 {
2834 SetLastError(ERROR_INVALID_PARAMETER);
2835 return FALSE;
2836 }
2837
2838 TRACE("(%p, %08x, %p, %d)\n", pCertContext, dwFlags, pUsage, *pcbUsage);
2839
2840 if (!(dwFlags & CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG))
2841 {
2842 DWORD propSize = 0;
2843
2844 if (CertGetCertificateContextProperty(pCertContext,
2845 CERT_ENHKEY_USAGE_PROP_ID, NULL, &propSize))
2846 {
2847 LPBYTE buf = CryptMemAlloc(propSize);
2848
2849 if (buf)
2850 {
2851 if (CertGetCertificateContextProperty(pCertContext,
2852 CERT_ENHKEY_USAGE_PROP_ID, buf, &propSize))
2853 {
2854 ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
2855 X509_ENHANCED_KEY_USAGE, buf, propSize,
2856 CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
2857 }
2858 CryptMemFree(buf);
2859 }
2860 }
2861 }
2862 if (!usage && !(dwFlags & CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG))
2863 {
2864 PCERT_EXTENSION ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
2865 pCertContext->pCertInfo->cExtension,
2866 pCertContext->pCertInfo->rgExtension);
2867
2868 if (ext)
2869 {
2870 ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
2871 X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
2872 CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
2873 }
2874 }
2875 if (!usage)
2876 {
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.)
2880 */
2881 if (dwFlags)
2882 {
2883 SetLastError(CRYPT_E_NOT_FOUND);
2884 ret = FALSE;
2885 }
2886 else
2887 bytesNeeded = sizeof(CERT_ENHKEY_USAGE);
2888 }
2889
2890 if (ret)
2891 {
2892 if (!pUsage)
2893 *pcbUsage = bytesNeeded;
2894 else if (*pcbUsage < bytesNeeded)
2895 {
2896 SetLastError(ERROR_MORE_DATA);
2897 *pcbUsage = bytesNeeded;
2898 ret = FALSE;
2899 }
2900 else
2901 {
2902 *pcbUsage = bytesNeeded;
2903 if (usage)
2904 {
2905 DWORD i;
2906 LPSTR nextOID = (LPSTR)((LPBYTE)pUsage +
2907 sizeof(CERT_ENHKEY_USAGE) +
2908 usage->cUsageIdentifier * sizeof(LPSTR));
2909
2910 pUsage->cUsageIdentifier = usage->cUsageIdentifier;
2911 pUsage->rgpszUsageIdentifier = (LPSTR *)((LPBYTE)pUsage +
2912 sizeof(CERT_ENHKEY_USAGE));
2913 for (i = 0; i < usage->cUsageIdentifier; i++)
2914 {
2915 pUsage->rgpszUsageIdentifier[i] = nextOID;
2916 strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
2917 nextOID += strlen(nextOID) + 1;
2918 }
2919 }
2920 else
2921 pUsage->cUsageIdentifier = 0;
2922 }
2923 }
2924 if (usage)
2925 LocalFree(usage);
2926 TRACE("returning %d\n", ret);
2927 return ret;
2928 }
2929
2930 BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext,
2931 PCERT_ENHKEY_USAGE pUsage)
2932 {
2933 BOOL ret;
2934
2935 TRACE("(%p, %p)\n", pCertContext, pUsage);
2936
2937 if (pUsage)
2938 {
2939 CRYPT_DATA_BLOB blob = { 0, NULL };
2940
2941 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
2942 pUsage, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData, &blob.cbData);
2943 if (ret)
2944 {
2945 ret = CertSetCertificateContextProperty(pCertContext,
2946 CERT_ENHKEY_USAGE_PROP_ID, 0, &blob);
2947 LocalFree(blob.pbData);
2948 }
2949 }
2950 else
2951 ret = CertSetCertificateContextProperty(pCertContext,
2952 CERT_ENHKEY_USAGE_PROP_ID, 0, NULL);
2953 return ret;
2954 }
2955
2956 BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
2957 LPCSTR pszUsageIdentifier)
2958 {
2959 BOOL ret;
2960 DWORD size;
2961
2962 TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
2963
2964 if (CertGetEnhancedKeyUsage(pCertContext,
2965 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size))
2966 {
2967 PCERT_ENHKEY_USAGE usage = CryptMemAlloc(size);
2968
2969 if (usage)
2970 {
2971 ret = CertGetEnhancedKeyUsage(pCertContext,
2972 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size);
2973 if (ret)
2974 {
2975 DWORD i;
2976 BOOL exists = FALSE;
2977
2978 /* Make sure usage doesn't already exist */
2979 for (i = 0; !exists && i < usage->cUsageIdentifier; i++)
2980 {
2981 if (!strcmp(usage->rgpszUsageIdentifier[i],
2982 pszUsageIdentifier))
2983 exists = TRUE;
2984 }
2985 if (!exists)
2986 {
2987 PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size +
2988 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
2989
2990 if (newUsage)
2991 {
2992 LPSTR nextOID;
2993
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++)
2999 {
3000 newUsage->rgpszUsageIdentifier[i] = nextOID;
3001 strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
3002 nextOID += strlen(nextOID) + 1;
3003 }
3004 newUsage->rgpszUsageIdentifier[i] = nextOID;
3005 strcpy(nextOID, pszUsageIdentifier);
3006 newUsage->cUsageIdentifier = i + 1;
3007 ret = CertSetEnhancedKeyUsage(pCertContext, newUsage);
3008 CryptMemFree(newUsage);
3009 }
3010 else
3011 ret = FALSE;
3012 }
3013 }
3014 CryptMemFree(usage);
3015 }
3016 else
3017 ret = FALSE;
3018 }
3019 else
3020 {
3021 PCERT_ENHKEY_USAGE usage = CryptMemAlloc(sizeof(CERT_ENHKEY_USAGE) +
3022 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
3023
3024 if (usage)
3025 {
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);
3034 }
3035 else
3036 ret = FALSE;
3037 }
3038 return ret;
3039 }
3040
3041 BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
3042 LPCSTR pszUsageIdentifier)
3043 {
3044 BOOL ret;
3045 DWORD size;
3046 CERT_ENHKEY_USAGE usage;
3047
3048 TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
3049
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)
3054 {
3055 PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
3056
3057 if (pUsage)
3058 {
3059 ret = CertGetEnhancedKeyUsage(pCertContext,
3060 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
3061 if (ret)
3062 {
3063 if (pUsage->cUsageIdentifier)
3064 {
3065 DWORD i;
3066 BOOL found = FALSE;
3067
3068 for (i = 0; i < pUsage->cUsageIdentifier; i++)
3069 {
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];
3076 }
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);
3083 }
3084 }
3085 CryptMemFree(pUsage);
3086 }
3087 else
3088 ret = FALSE;
3089 }
3090 else
3091 {
3092 /* it fit in an empty usage, therefore there's nothing to remove */
3093 ret = TRUE;
3094 }
3095 return ret;
3096 }
3097
3098 struct BitField
3099 {
3100 DWORD cIndexes;
3101 DWORD *indexes;
3102 };
3103
3104 #define BITS_PER_DWORD (sizeof(DWORD) * 8)
3105
3106 static void CRYPT_SetBitInField(struct BitField *field, DWORD bit)
3107 {
3108 DWORD indexIndex = bit / BITS_PER_DWORD;
3109
3110 if (indexIndex + 1 > field->cIndexes)
3111 {
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)
3118 {
3119 field->indexes[indexIndex] = 0;
3120 field->cIndexes = indexIndex + 1;
3121 }
3122 }
3123 if (field->indexes)
3124 field->indexes[indexIndex] |= 1 << (bit % BITS_PER_DWORD);
3125 }
3126
3127 static BOOL CRYPT_IsBitInFieldSet(const struct BitField *field, DWORD bit)
3128 {
3129 BOOL set;
3130 DWORD indexIndex = bit / BITS_PER_DWORD;
3131
3132 assert(field->cIndexes);
3133 set = field->indexes[indexIndex] & (1 << (bit % BITS_PER_DWORD));
3134 return set;
3135 }
3136
3137 BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts,
3138 int *cNumOIDs, LPSTR *rghOIDs, DWORD *pcbOIDs)
3139 {
3140 BOOL ret = TRUE;
3141 DWORD i, cbOIDs = 0;
3142 BOOL allUsagesValid = TRUE;
3143 CERT_ENHKEY_USAGE validUsages = { 0, NULL };
3144
3145 TRACE("(%d, %p, %d, %p, %d)\n", cCerts, rghCerts, *cNumOIDs,
3146 rghOIDs, *pcbOIDs);
3147
3148 for (i = 0; i < cCerts; i++)
3149 {
3150 CERT_ENHKEY_USAGE usage;
3151 DWORD size = sizeof(usage);
3152
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)
3156 {
3157 PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
3158
3159 allUsagesValid = FALSE;
3160 if (pUsage)
3161 {
3162 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, pUsage, &size);
3163 if (ret)
3164 {
3165 if (!validUsages.cUsageIdentifier)
3166 {
3167 DWORD j;
3168
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)
3177 {
3178 LPSTR nextOID = (LPSTR)
3179 ((LPBYTE)validUsages.rgpszUsageIdentifier +
3180 validUsages.cUsageIdentifier * sizeof(LPSTR));
3181
3182 for (j = 0; j < validUsages.cUsageIdentifier; j++)
3183 {
3184 validUsages.rgpszUsageIdentifier[j] = nextOID;
3185 lstrcpyA(validUsages.rgpszUsageIdentifier[j],
3186 pUsage->rgpszUsageIdentifier[j]);
3187 nextOID += lstrlenA(nextOID) + 1;
3188 }
3189 }
3190 }
3191 else
3192 {
3193 struct BitField validIndexes = { 0, NULL };
3194 DWORD j, k, numRemoved = 0;
3195
3196 /* Merge: build a bitmap of all the indexes of
3197 * validUsages.rgpszUsageIdentifier that are in pUsage.
3198 */
3199 for (j = 0; j < pUsage->cUsageIdentifier; j++)
3200 {
3201 for (k = 0; k < validUsages.cUsageIdentifier; k++)
3202 {
3203 if (!strcmp(pUsage->rgpszUsageIdentifier[j],
3204 validUsages.rgpszUsageIdentifier[k]))
3205 {
3206 CRYPT_SetBitInField(&validIndexes, k);
3207 break;
3208 }
3209 }
3210 }
3211 /* Merge by removing from validUsages those that are
3212 * not in the bitmap.
3213 */
3214 for (j = 0; j < validUsages.cUsageIdentifier; j++)
3215 {
3216 if (!CRYPT_IsBitInFieldSet(&validIndexes, j))
3217 {
3218 if (j < validUsages.cUsageIdentifier - 1)
3219 {
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++;
3230 }
3231 else
3232 validUsages.cUsageIdentifier--;
3233 }
3234 }
3235 CryptMemFree(validIndexes.indexes);
3236 }
3237 }
3238 CryptMemFree(pUsage);
3239 }
3240 }
3241 }
3242 ret = TRUE;
3243 if (allUsagesValid)
3244 {
3245 *cNumOIDs = -1;
3246 *pcbOIDs = 0;
3247 }
3248 else
3249 {
3250 *cNumOIDs = validUsages.cUsageIdentifier;
3251 if (!rghOIDs)
3252 *pcbOIDs = cbOIDs;
3253 else if (*pcbOIDs < cbOIDs)
3254 {
3255 *pcbOIDs = cbOIDs;
3256 SetLastError(ERROR_MORE_DATA);
3257 ret = FALSE;
3258 }
3259 else
3260 {
3261 LPSTR nextOID = (LPSTR)((LPBYTE)rghOIDs +
3262 validUsages.cUsageIdentifier * sizeof(LPSTR));
3263
3264 *pcbOIDs = cbOIDs;
3265 for (i = 0; i < validUsages.cUsageIdentifier; i++)
3266 {
3267 rghOIDs[i] = nextOID;
3268 lstrcpyA(nextOID, validUsages.rgpszUsageIdentifier[i]);
3269 nextOID += lstrlenA(nextOID) + 1;
3270 }
3271 }
3272 }
3273 CryptMemFree(validUsages.rgpszUsageIdentifier);
3274 TRACE("cNumOIDs: %d\n", *cNumOIDs);
3275 TRACE("returning %d\n", ret);
3276 return ret;
3277 }
3278
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.
3281 */
3282 static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context,
3283 const CRYPT_KEY_PROV_INFO *pInfo, HCRYPTPROV hProv)
3284 {
3285 CRYPT_KEY_PROV_INFO info = { 0 };
3286 BOOL ret;
3287
3288 if (!pInfo)
3289 {
3290 DWORD size;
3291 int len;
3292
3293 ret = CryptGetProvParam(hProv, PP_CONTAINER, NULL, &size, 0);
3294 if (ret)
3295 {
3296 LPSTR szContainer = CryptMemAlloc(size);
3297
3298 if (szContainer)
3299 {
3300 ret = CryptGetProvParam(hProv, PP_CONTAINER,
3301 (BYTE *)szContainer, &size, 0);
3302 if (ret)
3303 {
3304 len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
3305 NULL, 0);
3306 if (len)
3307 {
3308 info.pwszContainerName = CryptMemAlloc(len *
3309 sizeof(WCHAR));
3310 MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
3311 info.pwszContainerName, len);
3312 }
3313 }
3314 CryptMemFree(szContainer);
3315 }
3316 }
3317 ret = CryptGetProvParam(hProv, PP_NAME, NULL, &size, 0);
3318 if (ret)
3319 {
3320 LPSTR szProvider = CryptMemAlloc(size);
3321
3322 if (szProvider)
3323 {
3324 ret = CryptGetProvParam(hProv, PP_NAME, (BYTE *)szProvider,
3325 &size, 0);
3326 if (ret)
3327 {
3328 len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
3329 NULL, 0);
3330 if (len)
3331 {
3332 info.pwszProvName = CryptMemAlloc(len *
3333 sizeof(WCHAR));
3334 MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
3335 info.pwszProvName, len);
3336 }
3337 }
3338 CryptMemFree(szProvider);
3339 }
3340 }
3341 /* in case no CRYPT_KEY_PROV_INFO given,
3342 * we always use AT_SIGNATURE key spec
3343 */
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;
3351 }
3352
3353 CertSetCertificateContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID,
3354 0, pInfo);
3355
3356 if (pInfo == &info)
3357 {
3358 CryptMemFree(info.pwszContainerName);
3359 CryptMemFree(info.pwszProvName);
3360 }
3361 }
3362
3363 /* Creates a signed certificate context from the unsigned, encoded certificate
3364 * in blob, using the crypto provider hProv and the signature algorithm sigAlgo.
3365 */
3366 static PCCERT_CONTEXT CRYPT_CreateSignedCert(const CRYPT_DER_BLOB *blob,
3367 HCRYPTPROV hProv, DWORD dwKeySpec, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo)
3368 {
3369 PCCERT_CONTEXT context = NULL;
3370 BOOL ret;
3371 DWORD sigSize = 0;
3372
3373 ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
3374 blob->pbData, blob->cbData, sigAlgo, NULL, NULL, &sigSize);
3375 if (ret)
3376 {
3377 LPBYTE sig = CryptMemAlloc(sigSize);
3378
3379 ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
3380 blob->pbData, blob->cbData, sigAlgo, NULL, sig, &sigSize);
3381 if (ret)
3382 {
3383 CERT_SIGNED_CONTENT_INFO signedInfo;
3384 BYTE *encodedSignedCert = NULL;
3385 DWORD encodedSignedCertSize = 0;
3386
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)
3397 {
3398 context = CertCreateCertificateContext(X509_ASN_ENCODING,
3399 encodedSignedCert, encodedSignedCertSize);
3400 LocalFree(encodedSignedCert);
3401 }
3402 }
3403 CryptMemFree(sig);
3404 }
3405 return context;
3406 }
3407
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.
3419 */
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)
3425 {
3426 static CHAR oid[] = szOID_RSA_SHA1RSA;
3427
3428 assert(info);
3429 assert(pSerialNumber);
3430 assert(pSubjectIssuerBlob);
3431 assert(pubKey);
3432
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
3442 {
3443 info->SignatureAlgorithm.pszObjId = oid;
3444 info->SignatureAlgorithm.Parameters.cbData = 0;
3445 info->SignatureAlgorithm.Parameters.pbData = NULL;
3446 }
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
3456 {
3457 SYSTEMTIME endTime;
3458
3459 if (FileTimeToSystemTime(&info->NotBefore, &endTime))
3460 {
3461 endTime.wYear++;
3462 SystemTimeToFileTime(&endTime, &info->NotAfter);
3463 }
3464 }
3465 info->Subject.cbData = pSubjectIssuerBlob->cbData;
3466 info->Subject.pbData = pSubjectIssuerBlob->pbData;
3467 info->SubjectPublicKeyInfo = *pubKey;
3468 if (pExtensions)
3469 {
3470 info->cExtension = pExtensions->cExtension;
3471 info->rgExtension = pExtensions->rgExtension;
3472 }
3473 else
3474 {
3475 info->cExtension = 0;
3476 info->rgExtension = NULL;
3477 }
3478 }
3479
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 **);
3483
3484 static HCRYPTPROV CRYPT_CreateKeyProv(void)
3485 {
3486 HCRYPTPROV hProv = 0;
3487 HMODULE rpcrt = LoadLibraryA("rpcrt4");
3488
3489 if (rpcrt)
3490 {
3491 UuidCreateFunc uuidCreate = (UuidCreateFunc)GetProcAddress(rpcrt,
3492 "UuidCreate");
3493 UuidToStringFunc uuidToString = (UuidToStringFunc)GetProcAddress(rpcrt,
3494 "UuidToStringA");
3495 RpcStringFreeFunc rpcStringFree = (RpcStringFreeFunc)GetProcAddress(
3496 rpcrt, "RpcStringFreeA");
3497
3498 if (uuidCreate && uuidToString && rpcStringFree)
3499 {
3500 UUID uuid;
3501 RPC_STATUS status = uuidCreate(&uuid);
3502
3503 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY)
3504 {
3505 unsigned char *uuidStr;
3506
3507 status = uuidToString(&uuid, &uuidStr);
3508 if (status == RPC_S_OK)
3509 {
3510 BOOL ret = CryptAcquireContextA(&hProv, (LPCSTR)uuidStr,
3511 MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_NEWKEYSET);
3512
3513 if (ret)
3514 {
3515 HCRYPTKEY key;
3516
3517 ret = CryptGenKey(hProv, AT_SIGNATURE, 0, &key);
3518 if (ret)
3519 CryptDestroyKey(key);
3520 }
3521 rpcStringFree(&uuidStr);
3522 }
3523 }
3524 }
3525 FreeLibrary(rpcrt);
3526 }
3527 return hProv;
3528 }
3529
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)
3535 {
3536 PCCERT_CONTEXT context = NULL;
3537 BOOL ret, releaseContext = FALSE;
3538 PCERT_PUBLIC_KEY_INFO pubKey = NULL;
3539 DWORD pubKeySize = 0, dwKeySpec;
3540
3541 TRACE("(%08lx, %p, %08x, %p, %p, %p, %p, %p)\n", hProv,
3542 pSubjectIssuerBlob, dwFlags, pKeyProvInfo, pSignatureAlgorithm, pStartTime,
3543 pExtensions, pExtensions);
3544
3545 if(!pSubjectIssuerBlob)
3546 {
3547 SetLastError(ERROR_INVALID_PARAMETER);
3548 return NULL;
3549 }
3550
3551 dwKeySpec = pKeyProvInfo ? pKeyProvInfo->dwKeySpec : AT_SIGNATURE;
3552 if (!hProv)
3553 {
3554 if (!pKeyProvInfo)
3555 {
3556 hProv = CRYPT_CreateKeyProv();
3557 releaseContext = TRUE;
3558 }
3559 else if (pKeyProvInfo->dwFlags & CERT_SET_KEY_PROV_HANDLE_PROP_ID)
3560 {
3561 SetLastError(NTE_BAD_FLAGS);
3562 return NULL;
3563 }
3564 else
3565 {
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)
3572 {
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;
3581 }
3582 /* check if the key is here */
3583 ret = CryptGetUserKey(hProv,dwKeySpec,&hKey);
3584 if(!ret)
3585 {
3586 if (NTE_NO_KEY == GetLastError())
3587 { /* generate the key */
3588 ret = CryptGenKey(hProv,dwKeySpec,0,&hKey);
3589 }
3590 if (!ret)
3591 {
3592 CryptReleaseContext(hProv,0);
3593 SetLastError(NTE_BAD_KEYSET);
3594 return NULL;
3595 }
3596 }
3597 CryptDestroyKey(hKey);
3598 releaseContext = TRUE;
3599 }
3600 }
3601
3602 ret = CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING, NULL,
3603 &pubKeySize);
3604 if (!ret)
3605 goto end;
3606 pubKey = CryptMemAlloc(pubKeySize);
3607 if (pubKey)
3608 {
3609 ret = CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING,
3610 pubKey, &pubKeySize);
3611 if (ret)
3612 {
3613 CERT_INFO info = { 0 };
3614 CRYPT_DER_BLOB blob = { 0, NULL };
3615 BYTE serial[16];
3616 CRYPT_DATA_BLOB serialBlob = { sizeof(serial), serial };
3617
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)
3625 {
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);
3635 }
3636 }
3637 CryptMemFree(pubKey);
3638 }
3639 end:
3640 if (releaseContext)
3641 CryptReleaseContext(hProv, 0);
3642 return context;
3643 }
3644
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)
3649 {
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;
3655 }
3656
3657 const void * WINAPI CertCreateContext(DWORD dwContextType, DWORD dwEncodingType,
3658 const BYTE *pbEncoded, DWORD cbEncoded,
3659 DWORD dwFlags, PCERT_CREATE_CONTEXT_PARA pCreatePara)
3660 {
3661 TRACE("(0x%x, 0x%x, %p, %d, 0x%08x, %p)\n", dwContextType, dwEncodingType,
3662 pbEncoded, cbEncoded, dwFlags, pCreatePara);
3663
3664 if (dwFlags)
3665 {
3666 FIXME("dwFlags 0x%08x not handled\n", dwFlags);
3667 return NULL;
3668 }
3669 if (pCreatePara)
3670 {
3671 FIXME("pCreatePara not handled\n");
3672 return NULL;
3673 }
3674
3675 switch (dwContextType)
3676 {
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;
3686 }
3687 }