Sync with trunk r62529.
[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 "crypt32_private.h"
21
22 #include <rpc.h>
23
24 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
25
26 /* Internal version of CertGetCertificateContextProperty that gets properties
27 * directly from the context (or the context it's linked to, depending on its
28 * type.) Doesn't handle special-case properties, since they are handled by
29 * CertGetCertificateContextProperty, and are particular to the store in which
30 * the property exists (which is separate from the context.)
31 */
32 static BOOL CertContext_GetProperty(void *context, DWORD dwPropId,
33 void *pvData, DWORD *pcbData);
34
35 /* Internal version of CertSetCertificateContextProperty that sets properties
36 * directly on the context (or the context it's linked to, depending on its
37 * type.) Doesn't handle special cases, since they're handled by
38 * CertSetCertificateContextProperty anyway.
39 */
40 static BOOL CertContext_SetProperty(void *context, DWORD dwPropId,
41 DWORD dwFlags, const void *pvData);
42
43 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
44 DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
45 DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
46 {
47 PCCERT_CONTEXT cert = CertCreateCertificateContext(dwCertEncodingType,
48 pbCertEncoded, cbCertEncoded);
49 BOOL ret;
50
51 TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore, dwCertEncodingType,
52 pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
53
54 if (cert)
55 {
56 ret = CertAddCertificateContextToStore(hCertStore, cert,
57 dwAddDisposition, ppCertContext);
58 CertFreeCertificateContext(cert);
59 }
60 else
61 ret = FALSE;
62 return ret;
63 }
64
65 BOOL WINAPI CertAddEncodedCertificateToSystemStoreA(LPCSTR pszCertStoreName,
66 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
67 {
68 HCERTSTORE store;
69 BOOL ret = FALSE;
70
71 TRACE("(%s, %p, %d)\n", debugstr_a(pszCertStoreName), pbCertEncoded,
72 cbCertEncoded);
73
74 store = CertOpenSystemStoreA(0, pszCertStoreName);
75 if (store)
76 {
77 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
78 pbCertEncoded, cbCertEncoded, CERT_STORE_ADD_USE_EXISTING, NULL);
79 CertCloseStore(store, 0);
80 }
81 return ret;
82 }
83
84 BOOL WINAPI CertAddEncodedCertificateToSystemStoreW(LPCWSTR pszCertStoreName,
85 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
86 {
87 HCERTSTORE store;
88 BOOL ret = FALSE;
89
90 TRACE("(%s, %p, %d)\n", debugstr_w(pszCertStoreName), pbCertEncoded,
91 cbCertEncoded);
92
93 store = CertOpenSystemStoreW(0, pszCertStoreName);
94 if (store)
95 {
96 ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
97 pbCertEncoded, cbCertEncoded, CERT_STORE_ADD_USE_EXISTING, NULL);
98 CertCloseStore(store, 0);
99 }
100 return ret;
101 }
102
103 BOOL WINAPI CertAddCertificateLinkToStore(HCERTSTORE hCertStore,
104 PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
105 PCCERT_CONTEXT *ppCertContext)
106 {
107 static int calls;
108 PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
109
110 if (!(calls++))
111 FIXME("(%p, %p, %08x, %p): semi-stub\n", hCertStore, pCertContext,
112 dwAddDisposition, ppCertContext);
113 if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
114 return FALSE;
115 if (store->type == StoreTypeCollection)
116 {
117 SetLastError(E_INVALIDARG);
118 return FALSE;
119 }
120 return CertAddCertificateContextToStore(hCertStore, pCertContext,
121 dwAddDisposition, ppCertContext);
122 }
123
124 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
125 const BYTE *pbCertEncoded, DWORD cbCertEncoded)
126 {
127 PCERT_CONTEXT cert = NULL;
128 BOOL ret;
129 PCERT_INFO certInfo = NULL;
130 DWORD size = 0;
131
132 TRACE("(%08x, %p, %d)\n", dwCertEncodingType, pbCertEncoded,
133 cbCertEncoded);
134
135 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
136 {
137 SetLastError(E_INVALIDARG);
138 return NULL;
139 }
140
141 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT_TO_BE_SIGNED,
142 pbCertEncoded, cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL,
143 &certInfo, &size);
144 if (ret)
145 {
146 BYTE *data = NULL;
147
148 cert = Context_CreateDataContext(sizeof(CERT_CONTEXT));
149 if (!cert)
150 goto end;
151 data = CryptMemAlloc(cbCertEncoded);
152 if (!data)
153 {
154 CertFreeCertificateContext(cert);
155 cert = NULL;
156 goto end;
157 }
158 memcpy(data, pbCertEncoded, cbCertEncoded);
159 cert->dwCertEncodingType = dwCertEncodingType;
160 cert->pbCertEncoded = data;
161 cert->cbCertEncoded = cbCertEncoded;
162 cert->pCertInfo = certInfo;
163 cert->hCertStore = 0;
164 }
165
166 end:
167 return cert;
168 }
169
170 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
171 PCCERT_CONTEXT pCertContext)
172 {
173 TRACE("(%p)\n", pCertContext);
174
175 if (!pCertContext)
176 return NULL;
177
178 Context_AddRef((void *)pCertContext, sizeof(CERT_CONTEXT));
179 return pCertContext;
180 }
181
182 static void CertDataContext_Free(void *context)
183 {
184 PCERT_CONTEXT certContext = context;
185
186 CryptMemFree(certContext->pbCertEncoded);
187 LocalFree(certContext->pCertInfo);
188 }
189
190 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
191 {
192 BOOL ret = TRUE;
193
194 TRACE("(%p)\n", pCertContext);
195
196 if (pCertContext)
197 ret = Context_Release((void *)pCertContext, sizeof(CERT_CONTEXT),
198 CertDataContext_Free);
199 return ret;
200 }
201
202 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
203 DWORD dwPropId)
204 {
205 PCONTEXT_PROPERTY_LIST properties = Context_GetProperties(
206 pCertContext, sizeof(CERT_CONTEXT));
207 DWORD ret;
208
209 TRACE("(%p, %d)\n", pCertContext, dwPropId);
210
211 if (properties)
212 ret = ContextPropertyList_EnumPropIDs(properties, dwPropId);
213 else
214 ret = 0;
215 return ret;
216 }
217
218 static BOOL CertContext_GetHashProp(void *context, DWORD dwPropId,
219 ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
220 DWORD *pcbData)
221 {
222 BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
223 pcbData);
224 if (ret && pvData)
225 {
226 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
227
228 ret = CertContext_SetProperty(context, dwPropId, 0, &blob);
229 }
230 return ret;
231 }
232
233 static BOOL CertContext_CopyParam(void *pvData, DWORD *pcbData, const void *pb,
234 DWORD cb)
235 {
236 BOOL ret = TRUE;
237
238 if (!pvData)
239 *pcbData = cb;
240 else if (*pcbData < cb)
241 {
242 SetLastError(ERROR_MORE_DATA);
243 *pcbData = cb;
244 ret = FALSE;
245 }
246 else
247 {
248 memcpy(pvData, pb, cb);
249 *pcbData = cb;
250 }
251 return ret;
252 }
253
254 static BOOL CertContext_GetProperty(void *context, DWORD dwPropId,
255 void *pvData, DWORD *pcbData)
256 {
257 PCCERT_CONTEXT pCertContext = context;
258 PCONTEXT_PROPERTY_LIST properties =
259 Context_GetProperties(context, sizeof(CERT_CONTEXT));
260 BOOL ret;
261 CRYPT_DATA_BLOB blob;
262
263 TRACE("(%p, %d, %p, %p)\n", context, dwPropId, pvData, pcbData);
264
265 if (properties)
266 ret = ContextPropertyList_FindProperty(properties, dwPropId, &blob);
267 else
268 ret = FALSE;
269 if (ret)
270 ret = CertContext_CopyParam(pvData, pcbData, blob.pbData, blob.cbData);
271 else
272 {
273 /* Implicit properties */
274 switch (dwPropId)
275 {
276 case CERT_SHA1_HASH_PROP_ID:
277 ret = CertContext_GetHashProp(context, dwPropId, CALG_SHA1,
278 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData,
279 pcbData);
280 break;
281 case CERT_MD5_HASH_PROP_ID:
282 ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
283 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData,
284 pcbData);
285 break;
286 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
287 ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
288 pCertContext->pCertInfo->Subject.pbData,
289 pCertContext->pCertInfo->Subject.cbData,
290 pvData, pcbData);
291 break;
292 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
293 ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
294 pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
295 pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
296 pvData, pcbData);
297 break;
298 case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
299 ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
300 pCertContext->pCertInfo->SerialNumber.pbData,
301 pCertContext->pCertInfo->SerialNumber.cbData,
302 pvData, pcbData);
303 break;
304 case CERT_SIGNATURE_HASH_PROP_ID:
305 ret = CryptHashToBeSigned(0, pCertContext->dwCertEncodingType,
306 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData,
307 pcbData);
308 if (ret && pvData)
309 {
310 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
311
312 ret = CertContext_SetProperty(context, dwPropId, 0, &blob);
313 }
314 break;
315 case CERT_KEY_IDENTIFIER_PROP_ID:
316 {
317 PCERT_EXTENSION ext = CertFindExtension(
318 szOID_SUBJECT_KEY_IDENTIFIER, pCertContext->pCertInfo->cExtension,
319 pCertContext->pCertInfo->rgExtension);
320
321 if (ext)
322 {
323 CRYPT_DATA_BLOB value;
324 DWORD size = sizeof(value);
325
326 ret = CryptDecodeObjectEx(X509_ASN_ENCODING,
327 szOID_SUBJECT_KEY_IDENTIFIER, ext->Value.pbData,
328 ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &value,
329 &size);
330 if (ret)
331 {
332 ret = CertContext_CopyParam(pvData, pcbData, value.pbData,
333 value.cbData);
334 CertContext_SetProperty(context, dwPropId, 0, &value);
335 }
336 }
337 else
338 SetLastError(ERROR_INVALID_DATA);
339 break;
340 }
341 default:
342 SetLastError(CRYPT_E_NOT_FOUND);
343 }
344 }
345 TRACE("returning %d\n", ret);
346 return ret;
347 }
348
349 void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info)
350 {
351 DWORD i, containerLen, provNameLen;
352 LPBYTE data = (LPBYTE)info + sizeof(CRYPT_KEY_PROV_INFO);
353
354 info->pwszContainerName = (LPWSTR)data;
355 containerLen = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
356 data += containerLen;
357
358 info->pwszProvName = (LPWSTR)data;
359 provNameLen = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
360 data += provNameLen;
361
362 info->rgProvParam = (PCRYPT_KEY_PROV_PARAM)data;
363 data += info->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
364
365 for (i = 0; i < info->cProvParam; i++)
366 {
367 info->rgProvParam[i].pbData = data;
368 data += info->rgProvParam[i].cbData;
369 }
370 }
371
372 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
373 DWORD dwPropId, void *pvData, DWORD *pcbData)
374 {
375 BOOL ret;
376
377 TRACE("(%p, %d, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
378
379 switch (dwPropId)
380 {
381 case 0:
382 case CERT_CERT_PROP_ID:
383 case CERT_CRL_PROP_ID:
384 case CERT_CTL_PROP_ID:
385 SetLastError(E_INVALIDARG);
386 ret = FALSE;
387 break;
388 case CERT_ACCESS_STATE_PROP_ID:
389 if (pCertContext->hCertStore)
390 ret = CertGetStoreProperty(pCertContext->hCertStore, dwPropId,
391 pvData, pcbData);
392 else
393 {
394 DWORD state = 0;
395
396 ret = CertContext_CopyParam(pvData, pcbData, &state, sizeof(state));
397 }
398 break;
399 case CERT_KEY_PROV_HANDLE_PROP_ID:
400 {
401 CERT_KEY_CONTEXT keyContext;
402 DWORD size = sizeof(keyContext);
403
404 ret = CertContext_GetProperty((void *)pCertContext,
405 CERT_KEY_CONTEXT_PROP_ID, &keyContext, &size);
406 if (ret)
407 ret = CertContext_CopyParam(pvData, pcbData, &keyContext.hCryptProv,
408 sizeof(keyContext.hCryptProv));
409 break;
410 }
411 case CERT_KEY_PROV_INFO_PROP_ID:
412 ret = CertContext_GetProperty((void *)pCertContext, dwPropId, pvData,
413 pcbData);
414 if (ret && pvData)
415 CRYPT_FixKeyProvInfoPointers(pvData);
416 break;
417 default:
418 ret = CertContext_GetProperty((void *)pCertContext, dwPropId, pvData,
419 pcbData);
420 }
421
422 TRACE("returning %d\n", ret);
423 return ret;
424 }
425
426 /* Copies key provider info from from into to, where to is assumed to be a
427 * contiguous buffer of memory large enough for from and all its associated
428 * data, but whose pointers are uninitialized.
429 * Upon return, to contains a contiguous copy of from, packed in the following
430 * order:
431 * - CRYPT_KEY_PROV_INFO
432 * - pwszContainerName
433 * - pwszProvName
434 * - rgProvParam[0]...
435 */
436 static void CRYPT_CopyKeyProvInfo(PCRYPT_KEY_PROV_INFO to,
437 const CRYPT_KEY_PROV_INFO *from)
438 {
439 DWORD i;
440 LPBYTE nextData = (LPBYTE)to + sizeof(CRYPT_KEY_PROV_INFO);
441
442 if (from->pwszContainerName)
443 {
444 to->pwszContainerName = (LPWSTR)nextData;
445 lstrcpyW(to->pwszContainerName, from->pwszContainerName);
446 nextData += (lstrlenW(from->pwszContainerName) + 1) * sizeof(WCHAR);
447 }
448 else
449 to->pwszContainerName = NULL;
450 if (from->pwszProvName)
451 {
452 to->pwszProvName = (LPWSTR)nextData;
453 lstrcpyW(to->pwszProvName, from->pwszProvName);
454 nextData += (lstrlenW(from->pwszProvName) + 1) * sizeof(WCHAR);
455 }
456 else
457 to->pwszProvName = NULL;
458 to->dwProvType = from->dwProvType;
459 to->dwFlags = from->dwFlags;
460 to->cProvParam = from->cProvParam;
461 to->rgProvParam = (PCRYPT_KEY_PROV_PARAM)nextData;
462 nextData += to->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
463 to->dwKeySpec = from->dwKeySpec;
464 for (i = 0; i < to->cProvParam; i++)
465 {
466 memcpy(&to->rgProvParam[i], &from->rgProvParam[i],
467 sizeof(CRYPT_KEY_PROV_PARAM));
468 to->rgProvParam[i].pbData = nextData;
469 memcpy(to->rgProvParam[i].pbData, from->rgProvParam[i].pbData,
470 from->rgProvParam[i].cbData);
471 nextData += from->rgProvParam[i].cbData;
472 }
473 }
474
475 static BOOL CertContext_SetKeyProvInfoProperty(PCONTEXT_PROPERTY_LIST properties,
476 const CRYPT_KEY_PROV_INFO *info)
477 {
478 BOOL ret;
479 LPBYTE buf = NULL;
480 DWORD size = sizeof(CRYPT_KEY_PROV_INFO), i, containerSize, provNameSize;
481
482 if (info->pwszContainerName)
483 containerSize = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
484 else
485 containerSize = 0;
486 if (info->pwszProvName)
487 provNameSize = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
488 else
489 provNameSize = 0;
490 size += containerSize + provNameSize;
491 for (i = 0; i < info->cProvParam; i++)
492 size += sizeof(CRYPT_KEY_PROV_PARAM) + info->rgProvParam[i].cbData;
493 buf = CryptMemAlloc(size);
494 if (buf)
495 {
496 CRYPT_CopyKeyProvInfo((PCRYPT_KEY_PROV_INFO)buf, info);
497 ret = ContextPropertyList_SetProperty(properties,
498 CERT_KEY_PROV_INFO_PROP_ID, buf, size);
499 CryptMemFree(buf);
500 }
501 else
502 ret = FALSE;
503 return ret;
504 }
505
506 static BOOL CertContext_SetProperty(void *context, DWORD dwPropId,
507 DWORD dwFlags, const void *pvData)
508 {
509 PCONTEXT_PROPERTY_LIST properties =
510 Context_GetProperties(context, sizeof(CERT_CONTEXT));
511 BOOL ret;
512
513 TRACE("(%p, %d, %08x, %p)\n", context, dwPropId, dwFlags, pvData);
514
515 if (!properties)
516 ret = FALSE;
517 else
518 {
519 switch (dwPropId)
520 {
521 case CERT_AUTO_ENROLL_PROP_ID:
522 case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */
523 case CERT_DESCRIPTION_PROP_ID:
524 case CERT_FRIENDLY_NAME_PROP_ID:
525 case CERT_HASH_PROP_ID:
526 case CERT_KEY_IDENTIFIER_PROP_ID:
527 case CERT_MD5_HASH_PROP_ID:
528 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
529 case CERT_PUBKEY_ALG_PARA_PROP_ID:
530 case CERT_PVK_FILE_PROP_ID:
531 case CERT_SIGNATURE_HASH_PROP_ID:
532 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
533 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
534 case CERT_EXTENDED_ERROR_INFO_PROP_ID:
535 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
536 case CERT_ENROLLMENT_PROP_ID:
537 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
538 case CERT_RENEWAL_PROP_ID:
539 {
540 if (pvData)
541 {
542 const CRYPT_DATA_BLOB *blob = pvData;
543
544 ret = ContextPropertyList_SetProperty(properties, dwPropId,
545 blob->pbData, blob->cbData);
546 }
547 else
548 {
549 ContextPropertyList_RemoveProperty(properties, dwPropId);
550 ret = TRUE;
551 }
552 break;
553 }
554 case CERT_DATE_STAMP_PROP_ID:
555 if (pvData)
556 ret = ContextPropertyList_SetProperty(properties, dwPropId,
557 pvData, sizeof(FILETIME));
558 else
559 {
560 ContextPropertyList_RemoveProperty(properties, dwPropId);
561 ret = TRUE;
562 }
563 break;
564 case CERT_KEY_CONTEXT_PROP_ID:
565 {
566 if (pvData)
567 {
568 const CERT_KEY_CONTEXT *keyContext = pvData;
569
570 if (keyContext->cbSize != sizeof(CERT_KEY_CONTEXT))
571 {
572 SetLastError(E_INVALIDARG);
573 ret = FALSE;
574 }
575 else
576 ret = ContextPropertyList_SetProperty(properties, dwPropId,
577 (const BYTE *)keyContext, keyContext->cbSize);
578 }
579 else
580 {
581 ContextPropertyList_RemoveProperty(properties, dwPropId);
582 ret = TRUE;
583 }
584 break;
585 }
586 case CERT_KEY_PROV_INFO_PROP_ID:
587 if (pvData)
588 ret = CertContext_SetKeyProvInfoProperty(properties, pvData);
589 else
590 {
591 ContextPropertyList_RemoveProperty(properties, dwPropId);
592 ret = TRUE;
593 }
594 break;
595 case CERT_KEY_PROV_HANDLE_PROP_ID:
596 {
597 CERT_KEY_CONTEXT keyContext;
598 DWORD size = sizeof(keyContext);
599
600 ret = CertContext_GetProperty(context, CERT_KEY_CONTEXT_PROP_ID,
601 &keyContext, &size);
602 if (ret)
603 {
604 if (!(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
605 CryptReleaseContext(keyContext.hCryptProv, 0);
606 }
607 keyContext.cbSize = sizeof(keyContext);
608 if (pvData)
609 keyContext.hCryptProv = *(const HCRYPTPROV *)pvData;
610 else
611 {
612 keyContext.hCryptProv = 0;
613 keyContext.dwKeySpec = AT_SIGNATURE;
614 }
615 ret = CertContext_SetProperty(context, CERT_KEY_CONTEXT_PROP_ID,
616 0, &keyContext);
617 break;
618 }
619 default:
620 FIXME("%d: stub\n", dwPropId);
621 ret = FALSE;
622 }
623 }
624 TRACE("returning %d\n", ret);
625 return ret;
626 }
627
628 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
629 DWORD dwPropId, DWORD dwFlags, const void *pvData)
630 {
631 BOOL ret;
632
633 TRACE("(%p, %d, %08x, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
634
635 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
636 * crashes on most of these, I'll be safer.
637 */
638 switch (dwPropId)
639 {
640 case 0:
641 case CERT_ACCESS_STATE_PROP_ID:
642 case CERT_CERT_PROP_ID:
643 case CERT_CRL_PROP_ID:
644 case CERT_CTL_PROP_ID:
645 SetLastError(E_INVALIDARG);
646 return FALSE;
647 }
648 ret = CertContext_SetProperty((void *)pCertContext, dwPropId, dwFlags,
649 pvData);
650 TRACE("returning %d\n", ret);
651 return ret;
652 }
653
654 /* Acquires the private key using the key provider info, retrieving info from
655 * the certificate if info is NULL. The acquired provider is returned in
656 * *phCryptProv, and the key spec for the provider is returned in *pdwKeySpec.
657 */
658 static BOOL CRYPT_AcquirePrivateKeyFromProvInfo(PCCERT_CONTEXT pCert,
659 PCRYPT_KEY_PROV_INFO info, HCRYPTPROV *phCryptProv, DWORD *pdwKeySpec)
660 {
661 DWORD size = 0;
662 BOOL allocated = FALSE, ret = TRUE;
663
664 if (!info)
665 {
666 ret = CertGetCertificateContextProperty(pCert,
667 CERT_KEY_PROV_INFO_PROP_ID, 0, &size);
668 if (ret)
669 {
670 info = HeapAlloc(GetProcessHeap(), 0, size);
671 if (info)
672 {
673 ret = CertGetCertificateContextProperty(pCert,
674 CERT_KEY_PROV_INFO_PROP_ID, info, &size);
675 allocated = TRUE;
676 }
677 else
678 {
679 SetLastError(ERROR_OUTOFMEMORY);
680 ret = FALSE;
681 }
682 }
683 else
684 SetLastError(CRYPT_E_NO_KEY_PROPERTY);
685 }
686 if (ret)
687 {
688 ret = CryptAcquireContextW(phCryptProv, info->pwszContainerName,
689 info->pwszProvName, info->dwProvType, 0);
690 if (ret)
691 {
692 DWORD i;
693
694 for (i = 0; i < info->cProvParam; i++)
695 {
696 CryptSetProvParam(*phCryptProv,
697 info->rgProvParam[i].dwParam, info->rgProvParam[i].pbData,
698 info->rgProvParam[i].dwFlags);
699 }
700 *pdwKeySpec = info->dwKeySpec;
701 }
702 else
703 SetLastError(CRYPT_E_NO_KEY_PROPERTY);
704 }
705 if (allocated)
706 HeapFree(GetProcessHeap(), 0, info);
707 return ret;
708 }
709
710 BOOL WINAPI CryptAcquireCertificatePrivateKey(PCCERT_CONTEXT pCert,
711 DWORD dwFlags, void *pvReserved, HCRYPTPROV_OR_NCRYPT_KEY_HANDLE *phCryptProv,
712 DWORD *pdwKeySpec, BOOL *pfCallerFreeProv)
713 {
714 BOOL ret = FALSE, cache = FALSE;
715 PCRYPT_KEY_PROV_INFO info = NULL;
716 CERT_KEY_CONTEXT keyContext;
717 DWORD size;
718
719 TRACE("(%p, %08x, %p, %p, %p, %p)\n", pCert, dwFlags, pvReserved,
720 phCryptProv, pdwKeySpec, pfCallerFreeProv);
721
722 if (dwFlags & CRYPT_ACQUIRE_USE_PROV_INFO_FLAG)
723 {
724 DWORD size = 0;
725
726 ret = CertGetCertificateContextProperty(pCert,
727 CERT_KEY_PROV_INFO_PROP_ID, 0, &size);
728 if (ret)
729 {
730 info = HeapAlloc(GetProcessHeap(), 0, size);
731 ret = CertGetCertificateContextProperty(pCert,
732 CERT_KEY_PROV_INFO_PROP_ID, info, &size);
733 if (ret)
734 cache = info->dwFlags & CERT_SET_KEY_CONTEXT_PROP_ID;
735 }
736 }
737 else if (dwFlags & CRYPT_ACQUIRE_CACHE_FLAG)
738 cache = TRUE;
739 *phCryptProv = 0;
740 if (cache)
741 {
742 size = sizeof(keyContext);
743 ret = CertGetCertificateContextProperty(pCert, CERT_KEY_CONTEXT_PROP_ID,
744 &keyContext, &size);
745 if (ret)
746 {
747 *phCryptProv = keyContext.hCryptProv;
748 if (pdwKeySpec)
749 *pdwKeySpec = keyContext.dwKeySpec;
750 if (pfCallerFreeProv)
751 *pfCallerFreeProv = !cache;
752 }
753 }
754 if (!*phCryptProv)
755 {
756 ret = CRYPT_AcquirePrivateKeyFromProvInfo(pCert, info,
757 &keyContext.hCryptProv, &keyContext.dwKeySpec);
758 if (ret)
759 {
760 *phCryptProv = keyContext.hCryptProv;
761 if (pdwKeySpec)
762 *pdwKeySpec = keyContext.dwKeySpec;
763 if (cache)
764 {
765 keyContext.cbSize = sizeof(keyContext);
766 if (CertSetCertificateContextProperty(pCert,
767 CERT_KEY_CONTEXT_PROP_ID, 0, &keyContext))
768 {
769 if (pfCallerFreeProv)
770 *pfCallerFreeProv = FALSE;
771 }
772 }
773 else
774 {
775 if (pfCallerFreeProv)
776 *pfCallerFreeProv = TRUE;
777 }
778 }
779 }
780 HeapFree(GetProcessHeap(), 0, info);
781 return ret;
782 }
783
784 static BOOL key_prov_info_matches_cert(PCCERT_CONTEXT pCert,
785 const CRYPT_KEY_PROV_INFO *keyProvInfo)
786 {
787 HCRYPTPROV csp;
788 BOOL matches = FALSE;
789
790 if (CryptAcquireContextW(&csp, keyProvInfo->pwszContainerName,
791 keyProvInfo->pwszProvName, keyProvInfo->dwProvType, keyProvInfo->dwFlags))
792 {
793 DWORD size;
794
795 /* Need to sign something to verify the sig. What to sign? Why not
796 * the certificate itself?
797 */
798 if (CryptSignAndEncodeCertificate(csp, AT_SIGNATURE,
799 pCert->dwCertEncodingType, X509_CERT_TO_BE_SIGNED, pCert->pCertInfo,
800 &pCert->pCertInfo->SignatureAlgorithm, NULL, NULL, &size))
801 {
802 BYTE *certEncoded = CryptMemAlloc(size);
803
804 if (certEncoded)
805 {
806 if (CryptSignAndEncodeCertificate(csp, AT_SIGNATURE,
807 pCert->dwCertEncodingType, X509_CERT_TO_BE_SIGNED,
808 pCert->pCertInfo, &pCert->pCertInfo->SignatureAlgorithm,
809 NULL, certEncoded, &size))
810 {
811 if (size == pCert->cbCertEncoded &&
812 !memcmp(certEncoded, pCert->pbCertEncoded, size))
813 matches = TRUE;
814 }
815 CryptMemFree(certEncoded);
816 }
817 }
818 CryptReleaseContext(csp, 0);
819 }
820 return matches;
821 }
822
823 static BOOL container_matches_cert(PCCERT_CONTEXT pCert, LPCSTR container,
824 CRYPT_KEY_PROV_INFO *keyProvInfo)
825 {
826 CRYPT_KEY_PROV_INFO copy;
827 WCHAR containerW[MAX_PATH];
828 BOOL matches = FALSE;
829
830 MultiByteToWideChar(CP_ACP, 0, container, -1,
831 containerW, sizeof(containerW) / sizeof(containerW[0]));
832 /* We make a copy of the CRYPT_KEY_PROV_INFO because the caller expects
833 * keyProvInfo->pwszContainerName to be NULL or a heap-allocated container
834 * name.
835 */
836 copy = *keyProvInfo;
837 copy.pwszContainerName = containerW;
838 matches = key_prov_info_matches_cert(pCert, &copy);
839 if (matches)
840 {
841 keyProvInfo->pwszContainerName =
842 CryptMemAlloc((strlenW(containerW) + 1) * sizeof(WCHAR));
843 if (keyProvInfo->pwszContainerName)
844 {
845 strcpyW(keyProvInfo->pwszContainerName, containerW);
846 keyProvInfo->dwKeySpec = AT_SIGNATURE;
847 }
848 else
849 matches = FALSE;
850 }
851 return matches;
852 }
853
854 /* Searches the provider named keyProvInfo.pwszProvName for a container whose
855 * private key matches pCert's public key. Upon success, updates keyProvInfo
856 * with the matching container's info (free keyProvInfo.pwszContainerName upon
857 * success.)
858 * Returns TRUE if found, FALSE if not.
859 */
860 static BOOL find_key_prov_info_in_provider(PCCERT_CONTEXT pCert,
861 CRYPT_KEY_PROV_INFO *keyProvInfo)
862 {
863 HCRYPTPROV defProvider;
864 BOOL ret, found = FALSE;
865 char containerA[MAX_PATH];
866
867 assert(keyProvInfo->pwszContainerName == NULL);
868 if ((ret = CryptAcquireContextW(&defProvider, NULL,
869 keyProvInfo->pwszProvName, keyProvInfo->dwProvType,
870 keyProvInfo->dwFlags | CRYPT_VERIFYCONTEXT)))
871 {
872 DWORD enumFlags = keyProvInfo->dwFlags | CRYPT_FIRST;
873
874 while (ret && !found)
875 {
876 DWORD size = sizeof(containerA);
877
878 ret = CryptGetProvParam(defProvider, PP_ENUMCONTAINERS,
879 (BYTE *)containerA, &size, enumFlags);
880 if (ret)
881 found = container_matches_cert(pCert, containerA, keyProvInfo);
882 if (enumFlags & CRYPT_FIRST)
883 {
884 enumFlags &= ~CRYPT_FIRST;
885 enumFlags |= CRYPT_NEXT;
886 }
887 }
888 CryptReleaseContext(defProvider, 0);
889 }
890 return found;
891 }
892
893 static BOOL find_matching_provider(PCCERT_CONTEXT pCert, DWORD dwFlags)
894 {
895 BOOL found = FALSE, ret = TRUE;
896 DWORD index = 0, cbProvName = 0;
897 CRYPT_KEY_PROV_INFO keyProvInfo;
898
899 TRACE("(%p, %08x)\n", pCert, dwFlags);
900
901 memset(&keyProvInfo, 0, sizeof(keyProvInfo));
902 while (ret && !found)
903 {
904 DWORD size = 0;
905
906 ret = CryptEnumProvidersW(index, NULL, 0, &keyProvInfo.dwProvType,
907 NULL, &size);
908 if (ret)
909 {
910 if (size <= cbProvName)
911 ret = CryptEnumProvidersW(index, NULL, 0,
912 &keyProvInfo.dwProvType, keyProvInfo.pwszProvName, &size);
913 else
914 {
915 CryptMemFree(keyProvInfo.pwszProvName);
916 keyProvInfo.pwszProvName = CryptMemAlloc(size);
917 if (keyProvInfo.pwszProvName)
918 {
919 cbProvName = size;
920 ret = CryptEnumProvidersW(index, NULL, 0,
921 &keyProvInfo.dwProvType, keyProvInfo.pwszProvName, &size);
922 if (ret)
923 {
924 if (dwFlags & CRYPT_FIND_SILENT_KEYSET_FLAG)
925 keyProvInfo.dwFlags |= CRYPT_SILENT;
926 if (dwFlags & CRYPT_FIND_USER_KEYSET_FLAG ||
927 !(dwFlags & (CRYPT_FIND_USER_KEYSET_FLAG |
928 CRYPT_FIND_MACHINE_KEYSET_FLAG)))
929 {
930 keyProvInfo.dwFlags |= CRYPT_USER_KEYSET;
931 found = find_key_prov_info_in_provider(pCert,
932 &keyProvInfo);
933 }
934 if (!found)
935 {
936 if (dwFlags & CRYPT_FIND_MACHINE_KEYSET_FLAG ||
937 !(dwFlags & (CRYPT_FIND_USER_KEYSET_FLAG |
938 CRYPT_FIND_MACHINE_KEYSET_FLAG)))
939 {
940 keyProvInfo.dwFlags &= ~CRYPT_USER_KEYSET;
941 keyProvInfo.dwFlags |= CRYPT_MACHINE_KEYSET;
942 found = find_key_prov_info_in_provider(pCert,
943 &keyProvInfo);
944 }
945 }
946 }
947 }
948 else
949 ret = FALSE;
950 }
951 index++;
952 }
953 }
954 if (found)
955 CertSetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID,
956 0, &keyProvInfo);
957 CryptMemFree(keyProvInfo.pwszProvName);
958 CryptMemFree(keyProvInfo.pwszContainerName);
959 return found;
960 }
961
962 static BOOL cert_prov_info_matches_cert(PCCERT_CONTEXT pCert)
963 {
964 BOOL matches = FALSE;
965 DWORD size;
966
967 if (CertGetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID,
968 NULL, &size))
969 {
970 CRYPT_KEY_PROV_INFO *keyProvInfo = CryptMemAlloc(size);
971
972 if (keyProvInfo)
973 {
974 if (CertGetCertificateContextProperty(pCert,
975 CERT_KEY_PROV_INFO_PROP_ID, keyProvInfo, &size))
976 matches = key_prov_info_matches_cert(pCert, keyProvInfo);
977 CryptMemFree(keyProvInfo);
978 }
979 }
980 return matches;
981 }
982
983 BOOL WINAPI CryptFindCertificateKeyProvInfo(PCCERT_CONTEXT pCert,
984 DWORD dwFlags, void *pvReserved)
985 {
986 BOOL matches = FALSE;
987
988 TRACE("(%p, %08x, %p)\n", pCert, dwFlags, pvReserved);
989
990 matches = cert_prov_info_matches_cert(pCert);
991 if (!matches)
992 matches = find_matching_provider(pCert, dwFlags);
993 return matches;
994 }
995
996 BOOL WINAPI CertCompareCertificate(DWORD dwCertEncodingType,
997 PCERT_INFO pCertId1, PCERT_INFO pCertId2)
998 {
999 BOOL ret;
1000
1001 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertId1, pCertId2);
1002
1003 ret = CertCompareCertificateName(dwCertEncodingType, &pCertId1->Issuer,
1004 &pCertId2->Issuer) && CertCompareIntegerBlob(&pCertId1->SerialNumber,
1005 &pCertId2->SerialNumber);
1006 TRACE("returning %d\n", ret);
1007 return ret;
1008 }
1009
1010 BOOL WINAPI CertCompareCertificateName(DWORD dwCertEncodingType,
1011 PCERT_NAME_BLOB pCertName1, PCERT_NAME_BLOB pCertName2)
1012 {
1013 BOOL ret;
1014
1015 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertName1, pCertName2);
1016
1017 if (pCertName1->cbData == pCertName2->cbData)
1018 {
1019 if (pCertName1->cbData)
1020 ret = !memcmp(pCertName1->pbData, pCertName2->pbData,
1021 pCertName1->cbData);
1022 else
1023 ret = TRUE;
1024 }
1025 else
1026 ret = FALSE;
1027 TRACE("returning %d\n", ret);
1028 return ret;
1029 }
1030
1031 /* Returns the number of significant bytes in pInt, where a byte is
1032 * insignificant if it's a leading 0 for positive numbers or a leading 0xff
1033 * for negative numbers. pInt is assumed to be little-endian.
1034 */
1035 static DWORD CRYPT_significantBytes(const CRYPT_INTEGER_BLOB *pInt)
1036 {
1037 DWORD ret = pInt->cbData;
1038
1039 while (ret > 1)
1040 {
1041 if (pInt->pbData[ret - 2] <= 0x7f && pInt->pbData[ret - 1] == 0)
1042 ret--;
1043 else if (pInt->pbData[ret - 2] >= 0x80 && pInt->pbData[ret - 1] == 0xff)
1044 ret--;
1045 else
1046 break;
1047 }
1048 return ret;
1049 }
1050
1051 BOOL WINAPI CertCompareIntegerBlob(PCRYPT_INTEGER_BLOB pInt1,
1052 PCRYPT_INTEGER_BLOB pInt2)
1053 {
1054 BOOL ret;
1055 DWORD cb1, cb2;
1056
1057 TRACE("(%p, %p)\n", pInt1, pInt2);
1058
1059 cb1 = CRYPT_significantBytes(pInt1);
1060 cb2 = CRYPT_significantBytes(pInt2);
1061 if (cb1 == cb2)
1062 {
1063 if (cb1)
1064 ret = !memcmp(pInt1->pbData, pInt2->pbData, cb1);
1065 else
1066 ret = TRUE;
1067 }
1068 else
1069 ret = FALSE;
1070 TRACE("returning %d\n", ret);
1071 return ret;
1072 }
1073
1074 BOOL WINAPI CertComparePublicKeyInfo(DWORD dwCertEncodingType,
1075 PCERT_PUBLIC_KEY_INFO pPublicKey1, PCERT_PUBLIC_KEY_INFO pPublicKey2)
1076 {
1077 BOOL ret;
1078
1079 TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pPublicKey1, pPublicKey2);
1080
1081 switch (GET_CERT_ENCODING_TYPE(dwCertEncodingType))
1082 {
1083 case 0: /* Seems to mean "raw binary bits" */
1084 if (pPublicKey1->PublicKey.cbData == pPublicKey2->PublicKey.cbData &&
1085 pPublicKey1->PublicKey.cUnusedBits == pPublicKey2->PublicKey.cUnusedBits)
1086 {
1087 if (pPublicKey2->PublicKey.cbData)
1088 ret = !memcmp(pPublicKey1->PublicKey.pbData,
1089 pPublicKey2->PublicKey.pbData, pPublicKey1->PublicKey.cbData);
1090 else
1091 ret = TRUE;
1092 }
1093 else
1094 ret = FALSE;
1095 break;
1096 default:
1097 WARN("Unknown encoding type %08x\n", dwCertEncodingType);
1098 /* FALLTHROUGH */
1099 case X509_ASN_ENCODING:
1100 {
1101 BLOBHEADER *pblob1, *pblob2;
1102 DWORD length;
1103 ret = FALSE;
1104 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1105 pPublicKey1->PublicKey.pbData, pPublicKey1->PublicKey.cbData,
1106 0, NULL, &length))
1107 {
1108 pblob1 = CryptMemAlloc(length);
1109 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1110 pPublicKey1->PublicKey.pbData, pPublicKey1->PublicKey.cbData,
1111 0, pblob1, &length))
1112 {
1113 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1114 pPublicKey2->PublicKey.pbData, pPublicKey2->PublicKey.cbData,
1115 0, NULL, &length))
1116 {
1117 pblob2 = CryptMemAlloc(length);
1118 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
1119 pPublicKey2->PublicKey.pbData, pPublicKey2->PublicKey.cbData,
1120 0, pblob2, &length))
1121 {
1122 /* The RSAPUBKEY structure directly follows the BLOBHEADER */
1123 RSAPUBKEY *pk1 = (LPVOID)(pblob1 + 1),
1124 *pk2 = (LPVOID)(pblob2 + 1);
1125 ret = (pk1->bitlen == pk2->bitlen) && (pk1->pubexp == pk2->pubexp)
1126 && !memcmp(pk1 + 1, pk2 + 1, pk1->bitlen/8);
1127 }
1128 CryptMemFree(pblob2);
1129 }
1130 }
1131 CryptMemFree(pblob1);
1132 }
1133
1134 break;
1135 }
1136 }
1137 return ret;
1138 }
1139
1140 DWORD WINAPI CertGetPublicKeyLength(DWORD dwCertEncodingType,
1141 PCERT_PUBLIC_KEY_INFO pPublicKey)
1142 {
1143 DWORD len = 0;
1144
1145 TRACE("(%08x, %p)\n", dwCertEncodingType, pPublicKey);
1146
1147 if (GET_CERT_ENCODING_TYPE(dwCertEncodingType) != X509_ASN_ENCODING)
1148 {
1149 SetLastError(ERROR_FILE_NOT_FOUND);
1150 return 0;
1151 }
1152 if (pPublicKey->Algorithm.pszObjId &&
1153 !strcmp(pPublicKey->Algorithm.pszObjId, szOID_RSA_DH))
1154 {
1155 FIXME("unimplemented for DH public keys\n");
1156 SetLastError(CRYPT_E_ASN1_BADTAG);
1157 }
1158 else
1159 {
1160 DWORD size;
1161 PBYTE buf;
1162 BOOL ret = CryptDecodeObjectEx(dwCertEncodingType,
1163 RSA_CSP_PUBLICKEYBLOB, pPublicKey->PublicKey.pbData,
1164 pPublicKey->PublicKey.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf,
1165 &size);
1166
1167 if (ret)
1168 {
1169 RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
1170
1171 len = rsaPubKey->bitlen;
1172 LocalFree(buf);
1173 }
1174 }
1175 return len;
1176 }
1177
1178 typedef BOOL (*CertCompareFunc)(PCCERT_CONTEXT pCertContext, DWORD dwType,
1179 DWORD dwFlags, const void *pvPara);
1180
1181 static BOOL compare_cert_by_md5_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
1182 DWORD dwFlags, const void *pvPara)
1183 {
1184 BOOL ret;
1185 BYTE hash[16];
1186 DWORD size = sizeof(hash);
1187
1188 ret = CertGetCertificateContextProperty(pCertContext,
1189 CERT_MD5_HASH_PROP_ID, hash, &size);
1190 if (ret)
1191 {
1192 const CRYPT_HASH_BLOB *pHash = pvPara;
1193
1194 if (size == pHash->cbData)
1195 ret = !memcmp(pHash->pbData, hash, size);
1196 else
1197 ret = FALSE;
1198 }
1199 return ret;
1200 }
1201
1202 static BOOL compare_cert_by_sha1_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
1203 DWORD dwFlags, const void *pvPara)
1204 {
1205 BOOL ret;
1206 BYTE hash[20];
1207 DWORD size = sizeof(hash);
1208
1209 ret = CertGetCertificateContextProperty(pCertContext,
1210 CERT_SHA1_HASH_PROP_ID, hash, &size);
1211 if (ret)
1212 {
1213 const CRYPT_HASH_BLOB *pHash = pvPara;
1214
1215 if (size == pHash->cbData)
1216 ret = !memcmp(pHash->pbData, hash, size);
1217 else
1218 ret = FALSE;
1219 }
1220 return ret;
1221 }
1222
1223 static BOOL compare_cert_by_name(PCCERT_CONTEXT pCertContext, DWORD dwType,
1224 DWORD dwFlags, const void *pvPara)
1225 {
1226 CERT_NAME_BLOB *blob = (CERT_NAME_BLOB *)pvPara, *toCompare;
1227 BOOL ret;
1228
1229 if (dwType & CERT_INFO_SUBJECT_FLAG)
1230 toCompare = &pCertContext->pCertInfo->Subject;
1231 else
1232 toCompare = &pCertContext->pCertInfo->Issuer;
1233 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1234 toCompare, blob);
1235 return ret;
1236 }
1237
1238 static BOOL compare_cert_by_public_key(PCCERT_CONTEXT pCertContext,
1239 DWORD dwType, DWORD dwFlags, const void *pvPara)
1240 {
1241 CERT_PUBLIC_KEY_INFO *publicKey = (CERT_PUBLIC_KEY_INFO *)pvPara;
1242 BOOL ret;
1243
1244 ret = CertComparePublicKeyInfo(pCertContext->dwCertEncodingType,
1245 &pCertContext->pCertInfo->SubjectPublicKeyInfo, publicKey);
1246 return ret;
1247 }
1248
1249 static BOOL compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext,
1250 DWORD dwType, DWORD dwFlags, const void *pvPara)
1251 {
1252 CERT_INFO *pCertInfo = (CERT_INFO *)pvPara;
1253 BOOL ret;
1254
1255 /* Matching serial number and subject match.. */
1256 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1257 &pCertContext->pCertInfo->Subject, &pCertInfo->Issuer);
1258 if (ret)
1259 ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
1260 &pCertInfo->SerialNumber);
1261 else
1262 {
1263 /* failing that, if the serial number and issuer match, we match */
1264 ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
1265 &pCertInfo->SerialNumber);
1266 if (ret)
1267 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1268 &pCertContext->pCertInfo->Issuer, &pCertInfo->Issuer);
1269 }
1270 TRACE("returning %d\n", ret);
1271 return ret;
1272 }
1273
1274 static BOOL compare_cert_by_cert_id(PCCERT_CONTEXT pCertContext, DWORD dwType,
1275 DWORD dwFlags, const void *pvPara)
1276 {
1277 CERT_ID *id = (CERT_ID *)pvPara;
1278 BOOL ret;
1279
1280 switch (id->dwIdChoice)
1281 {
1282 case CERT_ID_ISSUER_SERIAL_NUMBER:
1283 ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
1284 &pCertContext->pCertInfo->Issuer, &id->u.IssuerSerialNumber.Issuer);
1285 if (ret)
1286 ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
1287 &id->u.IssuerSerialNumber.SerialNumber);
1288 break;
1289 case CERT_ID_SHA1_HASH:
1290 ret = compare_cert_by_sha1_hash(pCertContext, dwType, dwFlags,
1291 &id->u.HashId);
1292 break;
1293 case CERT_ID_KEY_IDENTIFIER:
1294 {
1295 DWORD size = 0;
1296
1297 ret = CertGetCertificateContextProperty(pCertContext,
1298 CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
1299 if (ret && size == id->u.KeyId.cbData)
1300 {
1301 LPBYTE buf = CryptMemAlloc(size);
1302
1303 if (buf)
1304 {
1305 CertGetCertificateContextProperty(pCertContext,
1306 CERT_KEY_IDENTIFIER_PROP_ID, buf, &size);
1307 ret = !memcmp(buf, id->u.KeyId.pbData, size);
1308 CryptMemFree(buf);
1309 }
1310 }
1311 else
1312 ret = FALSE;
1313 break;
1314 }
1315 default:
1316 ret = FALSE;
1317 break;
1318 }
1319 return ret;
1320 }
1321
1322 static BOOL compare_existing_cert(PCCERT_CONTEXT pCertContext, DWORD dwType,
1323 DWORD dwFlags, const void *pvPara)
1324 {
1325 PCCERT_CONTEXT toCompare = pvPara;
1326 return CertCompareCertificate(pCertContext->dwCertEncodingType,
1327 pCertContext->pCertInfo, toCompare->pCertInfo);
1328 }
1329
1330 static BOOL compare_cert_by_signature_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
1331 DWORD dwFlags, const void *pvPara)
1332 {
1333 const CRYPT_HASH_BLOB *hash = pvPara;
1334 DWORD size = 0;
1335 BOOL ret;
1336
1337 ret = CertGetCertificateContextProperty(pCertContext,
1338 CERT_SIGNATURE_HASH_PROP_ID, NULL, &size);
1339 if (ret && size == hash->cbData)
1340 {
1341 LPBYTE buf = CryptMemAlloc(size);
1342
1343 if (buf)
1344 {
1345 CertGetCertificateContextProperty(pCertContext,
1346 CERT_SIGNATURE_HASH_PROP_ID, buf, &size);
1347 ret = !memcmp(buf, hash->pbData, size);
1348 CryptMemFree(buf);
1349 }
1350 }
1351 else
1352 ret = FALSE;
1353 return ret;
1354 }
1355
1356 static inline PCCERT_CONTEXT cert_compare_certs_in_store(HCERTSTORE store,
1357 PCCERT_CONTEXT prev, CertCompareFunc compare, DWORD dwType, DWORD dwFlags,
1358 const void *pvPara)
1359 {
1360 BOOL matches = FALSE;
1361 PCCERT_CONTEXT ret;
1362
1363 ret = prev;
1364 do {
1365 ret = CertEnumCertificatesInStore(store, ret);
1366 if (ret)
1367 matches = compare(ret, dwType, dwFlags, pvPara);
1368 } while (ret != NULL && !matches);
1369 return ret;
1370 }
1371
1372 typedef PCCERT_CONTEXT (*CertFindFunc)(HCERTSTORE store, DWORD dwType,
1373 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev);
1374
1375 static PCCERT_CONTEXT find_cert_any(HCERTSTORE store, DWORD dwType,
1376 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1377 {
1378 return CertEnumCertificatesInStore(store, prev);
1379 }
1380
1381 static PCCERT_CONTEXT find_cert_by_issuer(HCERTSTORE store, DWORD dwType,
1382 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1383 {
1384 BOOL ret;
1385 PCCERT_CONTEXT found = NULL, subject = pvPara;
1386 PCERT_EXTENSION ext;
1387 DWORD size;
1388
1389 if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER,
1390 subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
1391 {
1392 CERT_AUTHORITY_KEY_ID_INFO *info;
1393
1394 ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
1395 X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData,
1396 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1397 &info, &size);
1398 if (ret)
1399 {
1400 CERT_ID id;
1401
1402 if (info->CertIssuer.cbData && info->CertSerialNumber.cbData)
1403 {
1404 id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
1405 memcpy(&id.u.IssuerSerialNumber.Issuer, &info->CertIssuer,
1406 sizeof(CERT_NAME_BLOB));
1407 memcpy(&id.u.IssuerSerialNumber.SerialNumber,
1408 &info->CertSerialNumber, sizeof(CRYPT_INTEGER_BLOB));
1409 }
1410 else if (info->KeyId.cbData)
1411 {
1412 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
1413 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
1414 }
1415 else
1416 ret = FALSE;
1417 if (ret)
1418 found = cert_compare_certs_in_store(store, prev,
1419 compare_cert_by_cert_id, dwType, dwFlags, &id);
1420 LocalFree(info);
1421 }
1422 }
1423 else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2,
1424 subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
1425 {
1426 CERT_AUTHORITY_KEY_ID2_INFO *info;
1427
1428 ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
1429 X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData,
1430 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1431 &info, &size);
1432 if (ret)
1433 {
1434 CERT_ID id;
1435
1436 if (info->AuthorityCertIssuer.cAltEntry &&
1437 info->AuthorityCertSerialNumber.cbData)
1438 {
1439 PCERT_ALT_NAME_ENTRY directoryName = NULL;
1440 DWORD i;
1441
1442 for (i = 0; !directoryName &&
1443 i < info->AuthorityCertIssuer.cAltEntry; i++)
1444 if (info->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice
1445 == CERT_ALT_NAME_DIRECTORY_NAME)
1446 directoryName =
1447 &info->AuthorityCertIssuer.rgAltEntry[i];
1448 if (directoryName)
1449 {
1450 id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
1451 memcpy(&id.u.IssuerSerialNumber.Issuer,
1452 &directoryName->u.DirectoryName, sizeof(CERT_NAME_BLOB));
1453 memcpy(&id.u.IssuerSerialNumber.SerialNumber,
1454 &info->AuthorityCertSerialNumber,
1455 sizeof(CRYPT_INTEGER_BLOB));
1456 }
1457 else
1458 {
1459 FIXME("no supported name type in authority key id2\n");
1460 ret = FALSE;
1461 }
1462 }
1463 else if (info->KeyId.cbData)
1464 {
1465 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
1466 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
1467 }
1468 else
1469 ret = FALSE;
1470 if (ret)
1471 found = cert_compare_certs_in_store(store, prev,
1472 compare_cert_by_cert_id, dwType, dwFlags, &id);
1473 LocalFree(info);
1474 }
1475 }
1476 else
1477 found = cert_compare_certs_in_store(store, prev,
1478 compare_cert_by_name, CERT_COMPARE_NAME | CERT_COMPARE_SUBJECT_CERT,
1479 dwFlags, &subject->pCertInfo->Issuer);
1480 return found;
1481 }
1482
1483 static BOOL compare_cert_by_name_str(PCCERT_CONTEXT pCertContext,
1484 DWORD dwType, DWORD dwFlags, const void *pvPara)
1485 {
1486 PCERT_NAME_BLOB name;
1487 DWORD len;
1488 BOOL ret = FALSE;
1489
1490 if (dwType & CERT_INFO_SUBJECT_FLAG)
1491 name = &pCertContext->pCertInfo->Subject;
1492 else
1493 name = &pCertContext->pCertInfo->Issuer;
1494 len = CertNameToStrW(pCertContext->dwCertEncodingType, name,
1495 CERT_SIMPLE_NAME_STR, NULL, 0);
1496 if (len)
1497 {
1498 LPWSTR str = CryptMemAlloc(len * sizeof(WCHAR));
1499
1500 if (str)
1501 {
1502 LPWSTR ptr;
1503
1504 CertNameToStrW(pCertContext->dwCertEncodingType, name,
1505 CERT_SIMPLE_NAME_STR, str, len);
1506 for (ptr = str; *ptr; ptr++)
1507 *ptr = tolowerW(*ptr);
1508 if (strstrW(str, pvPara))
1509 ret = TRUE;
1510 CryptMemFree(str);
1511 }
1512 }
1513 return ret;
1514 }
1515
1516 static PCCERT_CONTEXT find_cert_by_name_str_a(HCERTSTORE store, DWORD dwType,
1517 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1518 {
1519 PCCERT_CONTEXT found = NULL;
1520
1521 TRACE("%s\n", debugstr_a(pvPara));
1522
1523 if (pvPara)
1524 {
1525 int len = MultiByteToWideChar(CP_ACP, 0, pvPara, -1, NULL, 0);
1526 LPWSTR str = CryptMemAlloc(len * sizeof(WCHAR));
1527
1528 if (str)
1529 {
1530 LPWSTR ptr;
1531
1532 MultiByteToWideChar(CP_ACP, 0, pvPara, -1, str, len);
1533 for (ptr = str; *ptr; ptr++)
1534 *ptr = tolowerW(*ptr);
1535 found = cert_compare_certs_in_store(store, prev,
1536 compare_cert_by_name_str, dwType, dwFlags, str);
1537 CryptMemFree(str);
1538 }
1539 }
1540 else
1541 found = find_cert_any(store, dwType, dwFlags, NULL, prev);
1542 return found;
1543 }
1544
1545 static PCCERT_CONTEXT find_cert_by_name_str_w(HCERTSTORE store, DWORD dwType,
1546 DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
1547 {
1548 PCCERT_CONTEXT found = NULL;
1549
1550 TRACE("%s\n", debugstr_w(pvPara));
1551
1552 if (pvPara)
1553 {
1554 DWORD len = strlenW(pvPara);
1555 LPWSTR str = CryptMemAlloc((len + 1) * sizeof(WCHAR));
1556
1557 if (str)
1558 {
1559 LPCWSTR src;
1560 LPWSTR dst;
1561
1562 for (src = pvPara, dst = str; *src; src++, dst++)
1563 *dst = tolowerW(*src);
1564 *dst = 0;
1565 found = cert_compare_certs_in_store(store, prev,
1566 compare_cert_by_name_str, dwType, dwFlags, str);
1567 CryptMemFree(str);
1568 }
1569 }
1570 else
1571 found = find_cert_any(store, dwType, dwFlags, NULL, prev);
1572 return found;
1573 }
1574
1575 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
1576 DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType, const void *pvPara,
1577 PCCERT_CONTEXT pPrevCertContext)
1578 {
1579 PCCERT_CONTEXT ret;
1580 CertFindFunc find = NULL;
1581 CertCompareFunc compare = NULL;
1582
1583 TRACE("(%p, %08x, %08x, %08x, %p, %p)\n", hCertStore, dwCertEncodingType,
1584 dwFlags, dwType, pvPara, pPrevCertContext);
1585
1586 switch (dwType >> CERT_COMPARE_SHIFT)
1587 {
1588 case CERT_COMPARE_ANY:
1589 find = find_cert_any;
1590 break;
1591 case CERT_COMPARE_MD5_HASH:
1592 compare = compare_cert_by_md5_hash;
1593 break;
1594 case CERT_COMPARE_SHA1_HASH:
1595 compare = compare_cert_by_sha1_hash;
1596 break;
1597 case CERT_COMPARE_NAME:
1598 compare = compare_cert_by_name;
1599 break;
1600 case CERT_COMPARE_PUBLIC_KEY:
1601 compare = compare_cert_by_public_key;
1602 break;
1603 case CERT_COMPARE_NAME_STR_A:
1604 find = find_cert_by_name_str_a;
1605 break;
1606 case CERT_COMPARE_NAME_STR_W:
1607 find = find_cert_by_name_str_w;
1608 break;
1609 case CERT_COMPARE_SUBJECT_CERT:
1610 compare = compare_cert_by_subject_cert;
1611 break;
1612 case CERT_COMPARE_CERT_ID:
1613 compare = compare_cert_by_cert_id;
1614 break;
1615 case CERT_COMPARE_ISSUER_OF:
1616 find = find_cert_by_issuer;
1617 break;
1618 case CERT_COMPARE_EXISTING:
1619 compare = compare_existing_cert;
1620 break;
1621 case CERT_COMPARE_SIGNATURE_HASH:
1622 compare = compare_cert_by_signature_hash;
1623 break;
1624 default:
1625 FIXME("find type %08x unimplemented\n", dwType);
1626 }
1627
1628 if (find)
1629 ret = find(hCertStore, dwFlags, dwType, pvPara, pPrevCertContext);
1630 else if (compare)
1631 ret = cert_compare_certs_in_store(hCertStore, pPrevCertContext,
1632 compare, dwType, dwFlags, pvPara);
1633 else
1634 ret = NULL;
1635 if (!ret)
1636 SetLastError(CRYPT_E_NOT_FOUND);
1637 TRACE("returning %p\n", ret);
1638 return ret;
1639 }
1640
1641 PCCERT_CONTEXT WINAPI CertGetSubjectCertificateFromStore(HCERTSTORE hCertStore,
1642 DWORD dwCertEncodingType, PCERT_INFO pCertId)
1643 {
1644 TRACE("(%p, %08x, %p)\n", hCertStore, dwCertEncodingType, pCertId);
1645
1646 if (!pCertId)
1647 {
1648 SetLastError(E_INVALIDARG);
1649 return NULL;
1650 }
1651 return CertFindCertificateInStore(hCertStore, dwCertEncodingType, 0,
1652 CERT_FIND_SUBJECT_CERT, pCertId, NULL);
1653 }
1654
1655 BOOL WINAPI CertVerifySubjectCertificateContext(PCCERT_CONTEXT pSubject,
1656 PCCERT_CONTEXT pIssuer, DWORD *pdwFlags)
1657 {
1658 static const DWORD supportedFlags = CERT_STORE_REVOCATION_FLAG |
1659 CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG;
1660
1661 if (*pdwFlags & ~supportedFlags)
1662 {
1663 SetLastError(E_INVALIDARG);
1664 return FALSE;
1665 }
1666 if (*pdwFlags & CERT_STORE_REVOCATION_FLAG)
1667 {
1668 DWORD flags = 0;
1669 PCCRL_CONTEXT crl = CertGetCRLFromStore(pSubject->hCertStore, pSubject,
1670 NULL, &flags);
1671
1672 /* FIXME: what if the CRL has expired? */
1673 if (crl)
1674 {
1675 if (CertVerifyCRLRevocation(pSubject->dwCertEncodingType,
1676 pSubject->pCertInfo, 1, (PCRL_INFO *)&crl->pCrlInfo))
1677 *pdwFlags &= CERT_STORE_REVOCATION_FLAG;
1678 }
1679 else
1680 *pdwFlags |= CERT_STORE_NO_CRL_FLAG;
1681 }
1682 if (*pdwFlags & CERT_STORE_TIME_VALIDITY_FLAG)
1683 {
1684 if (0 == CertVerifyTimeValidity(NULL, pSubject->pCertInfo))
1685 *pdwFlags &= ~CERT_STORE_TIME_VALIDITY_FLAG;
1686 }
1687 if (*pdwFlags & CERT_STORE_SIGNATURE_FLAG)
1688 {
1689 if (CryptVerifyCertificateSignatureEx(0, pSubject->dwCertEncodingType,
1690 CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)pSubject,
1691 CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)pIssuer, 0, NULL))
1692 *pdwFlags &= ~CERT_STORE_SIGNATURE_FLAG;
1693 }
1694 return TRUE;
1695 }
1696
1697 PCCERT_CONTEXT WINAPI CertGetIssuerCertificateFromStore(HCERTSTORE hCertStore,
1698 PCCERT_CONTEXT pSubjectContext, PCCERT_CONTEXT pPrevIssuerContext,
1699 DWORD *pdwFlags)
1700 {
1701 PCCERT_CONTEXT ret;
1702
1703 TRACE("(%p, %p, %p, %08x)\n", hCertStore, pSubjectContext,
1704 pPrevIssuerContext, *pdwFlags);
1705
1706 if (!pSubjectContext)
1707 {
1708 SetLastError(E_INVALIDARG);
1709 return NULL;
1710 }
1711
1712 ret = CertFindCertificateInStore(hCertStore,
1713 pSubjectContext->dwCertEncodingType, 0, CERT_FIND_ISSUER_OF,
1714 pSubjectContext, pPrevIssuerContext);
1715 if (ret)
1716 {
1717 if (!CertVerifySubjectCertificateContext(pSubjectContext, ret,
1718 pdwFlags))
1719 {
1720 CertFreeCertificateContext(ret);
1721 ret = NULL;
1722 }
1723 }
1724 TRACE("returning %p\n", ret);
1725 return ret;
1726 }
1727
1728 typedef struct _OLD_CERT_REVOCATION_STATUS {
1729 DWORD cbSize;
1730 DWORD dwIndex;
1731 DWORD dwError;
1732 DWORD dwReason;
1733 } OLD_CERT_REVOCATION_STATUS, *POLD_CERT_REVOCATION_STATUS;
1734
1735 typedef BOOL (WINAPI *CertVerifyRevocationFunc)(DWORD, DWORD, DWORD,
1736 void **, DWORD, PCERT_REVOCATION_PARA, PCERT_REVOCATION_STATUS);
1737
1738 BOOL WINAPI CertVerifyRevocation(DWORD dwEncodingType, DWORD dwRevType,
1739 DWORD cContext, PVOID rgpvContext[], DWORD dwFlags,
1740 PCERT_REVOCATION_PARA pRevPara, PCERT_REVOCATION_STATUS pRevStatus)
1741 {
1742 BOOL ret;
1743
1744 TRACE("(%08x, %d, %d, %p, %08x, %p, %p)\n", dwEncodingType, dwRevType,
1745 cContext, rgpvContext, dwFlags, pRevPara, pRevStatus);
1746
1747 if (pRevStatus->cbSize != sizeof(OLD_CERT_REVOCATION_STATUS) &&
1748 pRevStatus->cbSize != sizeof(CERT_REVOCATION_STATUS))
1749 {
1750 SetLastError(E_INVALIDARG);
1751 return FALSE;
1752 }
1753 if (cContext)
1754 {
1755 static HCRYPTOIDFUNCSET set = NULL;
1756 DWORD size;
1757
1758 if (!set)
1759 set = CryptInitOIDFunctionSet(CRYPT_OID_VERIFY_REVOCATION_FUNC, 0);
1760 ret = CryptGetDefaultOIDDllList(set, dwEncodingType, NULL, &size);
1761 if (ret)
1762 {
1763 if (size == 1)
1764 {
1765 /* empty list */
1766 SetLastError(CRYPT_E_NO_REVOCATION_DLL);
1767 ret = FALSE;
1768 }
1769 else
1770 {
1771 LPWSTR dllList = CryptMemAlloc(size * sizeof(WCHAR)), ptr;
1772
1773 if (dllList)
1774 {
1775 ret = CryptGetDefaultOIDDllList(set, dwEncodingType,
1776 dllList, &size);
1777 if (ret)
1778 {
1779 for (ptr = dllList; ret && *ptr;
1780 ptr += lstrlenW(ptr) + 1)
1781 {
1782 CertVerifyRevocationFunc func;
1783 HCRYPTOIDFUNCADDR hFunc;
1784
1785 ret = CryptGetDefaultOIDFunctionAddress(set,
1786 dwEncodingType, ptr, 0, (void **)&func, &hFunc);
1787 if (ret)
1788 {
1789 ret = func(dwEncodingType, dwRevType, cContext,
1790 rgpvContext, dwFlags, pRevPara, pRevStatus);
1791 CryptFreeOIDFunctionAddress(hFunc, 0);
1792 }
1793 }
1794 }
1795 CryptMemFree(dllList);
1796 }
1797 else
1798 {
1799 SetLastError(ERROR_OUTOFMEMORY);
1800 ret = FALSE;
1801 }
1802 }
1803 }
1804 }
1805 else
1806 ret = TRUE;
1807 return ret;
1808 }
1809
1810 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
1811 CRYPT_ATTRIBUTE rgAttr[])
1812 {
1813 PCRYPT_ATTRIBUTE ret = NULL;
1814 DWORD i;
1815
1816 TRACE("%s %d %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
1817
1818 if (!cAttr)
1819 return NULL;
1820 if (!pszObjId)
1821 {
1822 SetLastError(ERROR_INVALID_PARAMETER);
1823 return NULL;
1824 }
1825
1826 for (i = 0; !ret && i < cAttr; i++)
1827 if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
1828 ret = &rgAttr[i];
1829 return ret;
1830 }
1831
1832 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
1833 CERT_EXTENSION rgExtensions[])
1834 {
1835 PCERT_EXTENSION ret = NULL;
1836 DWORD i;
1837
1838 TRACE("%s %d %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
1839
1840 if (!cExtensions)
1841 return NULL;
1842 if (!pszObjId)
1843 {
1844 SetLastError(ERROR_INVALID_PARAMETER);
1845 return NULL;
1846 }
1847
1848 for (i = 0; !ret && i < cExtensions; i++)
1849 if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
1850 rgExtensions[i].pszObjId))
1851 ret = &rgExtensions[i];
1852 return ret;
1853 }
1854
1855 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
1856 {
1857 PCERT_RDN_ATTR ret = NULL;
1858 DWORD i, j;
1859
1860 TRACE("%s %p\n", debugstr_a(pszObjId), pName);
1861
1862 if (!pszObjId)
1863 {
1864 SetLastError(ERROR_INVALID_PARAMETER);
1865 return NULL;
1866 }
1867
1868 for (i = 0; !ret && i < pName->cRDN; i++)
1869 for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
1870 if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
1871 pName->rgRDN[i].rgRDNAttr[j].pszObjId))
1872 ret = &pName->rgRDN[i].rgRDNAttr[j];
1873 return ret;
1874 }
1875
1876 static BOOL find_matching_rdn_attr(DWORD dwFlags, const CERT_NAME_INFO *name,
1877 const CERT_RDN_ATTR *attr)
1878 {
1879 DWORD i, j;
1880 BOOL match = FALSE;
1881
1882 for (i = 0; !match && i < name->cRDN; i++)
1883 {
1884 for (j = 0; j < name->rgRDN[i].cRDNAttr; j++)
1885 {
1886 if (!strcmp(name->rgRDN[i].rgRDNAttr[j].pszObjId,
1887 attr->pszObjId) &&
1888 name->rgRDN[i].rgRDNAttr[j].dwValueType ==
1889 attr->dwValueType)
1890 {
1891 if (dwFlags & CERT_UNICODE_IS_RDN_ATTRS_FLAG)
1892 {
1893 LPCWSTR nameStr =
1894 (LPCWSTR)name->rgRDN[i].rgRDNAttr[j].Value.pbData;
1895 LPCWSTR attrStr = (LPCWSTR)attr->Value.pbData;
1896
1897 if (attr->Value.cbData !=
1898 name->rgRDN[i].rgRDNAttr[j].Value.cbData)
1899 match = FALSE;
1900 else if (dwFlags & CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG)
1901 match = !strncmpiW(nameStr, attrStr,
1902 attr->Value.cbData / sizeof(WCHAR));
1903 else
1904 match = !strncmpW(nameStr, attrStr,
1905 attr->Value.cbData / sizeof(WCHAR));
1906 TRACE("%s : %s => %d\n",
1907 debugstr_wn(nameStr, attr->Value.cbData / sizeof(WCHAR)),
1908 debugstr_wn(attrStr, attr->Value.cbData / sizeof(WCHAR)),
1909 match);
1910 }
1911 else
1912 {
1913 LPCSTR nameStr =
1914 (LPCSTR)name->rgRDN[i].rgRDNAttr[j].Value.pbData;
1915 LPCSTR attrStr = (LPCSTR)attr->Value.pbData;
1916
1917 if (attr->Value.cbData !=
1918 name->rgRDN[i].rgRDNAttr[j].Value.cbData)
1919 match = FALSE;
1920 else if (dwFlags & CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG)
1921 match = !strncasecmp(nameStr, attrStr,
1922 attr->Value.cbData);
1923 else
1924 match = !strncmp(nameStr, attrStr, attr->Value.cbData);
1925 TRACE("%s : %s => %d\n",
1926 debugstr_an(nameStr, attr->Value.cbData),
1927 debugstr_an(attrStr, attr->Value.cbData), match);
1928 }
1929 }
1930 }
1931 }
1932 return match;
1933 }
1934
1935 BOOL WINAPI CertIsRDNAttrsInCertificateName(DWORD dwCertEncodingType,
1936 DWORD dwFlags, PCERT_NAME_BLOB pCertName, PCERT_RDN pRDN)
1937 {
1938 CERT_NAME_INFO *name;
1939 LPCSTR type;
1940 DWORD size;
1941 BOOL ret;
1942
1943 TRACE("(%08x, %08x, %p, %p)\n", dwCertEncodingType, dwFlags, pCertName,
1944 pRDN);
1945
1946 type = dwFlags & CERT_UNICODE_IS_RDN_ATTRS_FLAG ? X509_UNICODE_NAME :
1947 X509_NAME;
1948 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, type, pCertName->pbData,
1949 pCertName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &name, &size)))
1950 {
1951 DWORD i;
1952
1953 for (i = 0; ret && i < pRDN->cRDNAttr; i++)
1954 ret = find_matching_rdn_attr(dwFlags, name, &pRDN->rgRDNAttr[i]);
1955 if (!ret)
1956 SetLastError(CRYPT_E_NO_MATCH);
1957 LocalFree(name);
1958 }
1959 return ret;
1960 }
1961
1962 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
1963 PCERT_INFO pCertInfo)
1964 {
1965 FILETIME fileTime;
1966 LONG ret;
1967
1968 if (!pTimeToVerify)
1969 {
1970 GetSystemTimeAsFileTime(&fileTime);
1971 pTimeToVerify = &fileTime;
1972 }
1973 if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
1974 {
1975 ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
1976 if (ret < 0)
1977 ret = 0;
1978 }
1979 return ret;
1980 }
1981
1982 BOOL WINAPI CertVerifyValidityNesting(PCERT_INFO pSubjectInfo,
1983 PCERT_INFO pIssuerInfo)
1984 {
1985 TRACE("(%p, %p)\n", pSubjectInfo, pIssuerInfo);
1986
1987 return CertVerifyTimeValidity(&pSubjectInfo->NotBefore, pIssuerInfo) == 0
1988 && CertVerifyTimeValidity(&pSubjectInfo->NotAfter, pIssuerInfo) == 0;
1989 }
1990
1991 BOOL WINAPI CryptHashCertificate(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
1992 DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
1993 DWORD *pcbComputedHash)
1994 {
1995 BOOL ret = TRUE;
1996 HCRYPTHASH hHash = 0;
1997
1998 TRACE("(%08lx, %d, %08x, %p, %d, %p, %p)\n", hCryptProv, Algid, dwFlags,
1999 pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
2000
2001 if (!hCryptProv)
2002 hCryptProv = CRYPT_GetDefaultProvider();
2003 if (!Algid)
2004 Algid = CALG_SHA1;
2005 if (ret)
2006 {
2007 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
2008 if (ret)
2009 {
2010 ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
2011 if (ret)
2012 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
2013 pcbComputedHash, 0);
2014 CryptDestroyHash(hHash);
2015 }
2016 }
2017 return ret;
2018 }
2019
2020 BOOL WINAPI CryptHashPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
2021 DWORD dwFlags, DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo,
2022 BYTE *pbComputedHash, DWORD *pcbComputedHash)
2023 {
2024 BOOL ret = TRUE;
2025 HCRYPTHASH hHash = 0;
2026
2027 TRACE("(%08lx, %d, %08x, %d, %p, %p, %p)\n", hCryptProv, Algid, dwFlags,
2028 dwCertEncodingType, pInfo, pbComputedHash, pcbComputedHash);
2029
2030 if (!hCryptProv)
2031 hCryptProv = CRYPT_GetDefaultProvider();
2032 if (!Algid)
2033 Algid = CALG_MD5;
2034 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
2035 {
2036 SetLastError(ERROR_FILE_NOT_FOUND);
2037 return FALSE;
2038 }
2039 if (ret)
2040 {
2041 BYTE *buf;
2042 DWORD size = 0;
2043
2044 ret = CRYPT_AsnEncodePubKeyInfoNoNull(dwCertEncodingType,
2045 X509_PUBLIC_KEY_INFO, pInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
2046 (LPBYTE)&buf, &size);
2047 if (ret)
2048 {
2049 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
2050 if (ret)
2051 {
2052 ret = CryptHashData(hHash, buf, size, 0);
2053 if (ret)
2054 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
2055 pcbComputedHash, 0);
2056 CryptDestroyHash(hHash);
2057 }
2058 LocalFree(buf);
2059 }
2060 }
2061 return ret;
2062 }
2063
2064 BOOL WINAPI CryptHashToBeSigned(HCRYPTPROV_LEGACY hCryptProv,
2065 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
2066 BYTE *pbComputedHash, DWORD *pcbComputedHash)
2067 {
2068 BOOL ret;
2069 CERT_SIGNED_CONTENT_INFO *info;
2070 DWORD size;
2071
2072 TRACE("(%08lx, %08x, %p, %d, %p, %d)\n", hCryptProv, dwCertEncodingType,
2073 pbEncoded, cbEncoded, pbComputedHash, *pcbComputedHash);
2074
2075 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
2076 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size);
2077 if (ret)
2078 {
2079 PCCRYPT_OID_INFO oidInfo;
2080 HCRYPTHASH hHash;
2081
2082 if (!hCryptProv)
2083 hCryptProv = CRYPT_GetDefaultProvider();
2084 oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2085 info->SignatureAlgorithm.pszObjId, 0);
2086 if (!oidInfo)
2087 {
2088 SetLastError(NTE_BAD_ALGID);
2089 ret = FALSE;
2090 }
2091 else
2092 {
2093 ret = CryptCreateHash(hCryptProv, oidInfo->u.Algid, 0, 0, &hHash);
2094 if (ret)
2095 {
2096 ret = CryptHashData(hHash, info->ToBeSigned.pbData,
2097 info->ToBeSigned.cbData, 0);
2098 if (ret)
2099 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
2100 pcbComputedHash, 0);
2101 CryptDestroyHash(hHash);
2102 }
2103 }
2104 LocalFree(info);
2105 }
2106 return ret;
2107 }
2108
2109 BOOL WINAPI CryptSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
2110 DWORD dwKeySpec, DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned,
2111 DWORD cbEncodedToBeSigned, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
2112 const void *pvHashAuxInfo, BYTE *pbSignature, DWORD *pcbSignature)
2113 {
2114 BOOL ret;
2115 PCCRYPT_OID_INFO info;
2116 HCRYPTHASH hHash;
2117
2118 TRACE("(%08lx, %d, %d, %p, %d, %p, %p, %p, %p)\n", hCryptProv,
2119 dwKeySpec, dwCertEncodingType, pbEncodedToBeSigned, cbEncodedToBeSigned,
2120 pSignatureAlgorithm, pvHashAuxInfo, pbSignature, pcbSignature);
2121
2122 info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2123 pSignatureAlgorithm->pszObjId, 0);
2124 if (!info)
2125 {
2126 SetLastError(NTE_BAD_ALGID);
2127 return FALSE;
2128 }
2129 if (info->dwGroupId == CRYPT_HASH_ALG_OID_GROUP_ID)
2130 {
2131 if (!hCryptProv)
2132 hCryptProv = CRYPT_GetDefaultProvider();
2133 ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
2134 if (ret)
2135 {
2136 ret = CryptHashData(hHash, pbEncodedToBeSigned,
2137 cbEncodedToBeSigned, 0);
2138 if (ret)
2139 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbSignature,
2140 pcbSignature, 0);
2141 CryptDestroyHash(hHash);
2142 }
2143 }
2144 else
2145 {
2146 if (!hCryptProv)
2147 {
2148 SetLastError(ERROR_INVALID_PARAMETER);
2149 ret = FALSE;
2150 }
2151 else
2152 {
2153 ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
2154 if (ret)
2155 {
2156 ret = CryptHashData(hHash, pbEncodedToBeSigned,
2157 cbEncodedToBeSigned, 0);
2158 if (ret)
2159 ret = CryptSignHashW(hHash, dwKeySpec, NULL, 0, pbSignature,
2160 pcbSignature);
2161 CryptDestroyHash(hHash);
2162 }
2163 }
2164 }
2165 return ret;
2166 }
2167
2168 BOOL WINAPI CryptSignAndEncodeCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
2169 DWORD dwKeySpec, DWORD dwCertEncodingType, LPCSTR lpszStructType,
2170 const void *pvStructInfo, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
2171 const void *pvHashAuxInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
2172 {
2173 BOOL ret;
2174 DWORD encodedSize, hashSize;
2175
2176 TRACE("(%08lx, %d, %d, %s, %p, %p, %p, %p, %p)\n", hCryptProv, dwKeySpec,
2177 dwCertEncodingType, debugstr_a(lpszStructType), pvStructInfo,
2178 pSignatureAlgorithm, pvHashAuxInfo, pbEncoded, pcbEncoded);
2179
2180 ret = CryptEncodeObject(dwCertEncodingType, lpszStructType, pvStructInfo,
2181 NULL, &encodedSize);
2182 if (ret)
2183 {
2184 PBYTE encoded = CryptMemAlloc(encodedSize);
2185
2186 if (encoded)
2187 {
2188 ret = CryptEncodeObject(dwCertEncodingType, lpszStructType,
2189 pvStructInfo, encoded, &encodedSize);
2190 if (ret)
2191 {
2192 ret = CryptSignCertificate(hCryptProv, dwKeySpec,
2193 dwCertEncodingType, encoded, encodedSize, pSignatureAlgorithm,
2194 pvHashAuxInfo, NULL, &hashSize);
2195 if (ret)
2196 {
2197 PBYTE hash = CryptMemAlloc(hashSize);
2198
2199 if (hash)
2200 {
2201 ret = CryptSignCertificate(hCryptProv, dwKeySpec,
2202 dwCertEncodingType, encoded, encodedSize,
2203 pSignatureAlgorithm, pvHashAuxInfo, hash, &hashSize);
2204 if (ret)
2205 {
2206 CERT_SIGNED_CONTENT_INFO info = { { 0 } };
2207
2208 info.ToBeSigned.cbData = encodedSize;
2209 info.ToBeSigned.pbData = encoded;
2210 info.SignatureAlgorithm = *pSignatureAlgorithm;
2211 info.Signature.cbData = hashSize;
2212 info.Signature.pbData = hash;
2213 info.Signature.cUnusedBits = 0;
2214 ret = CryptEncodeObject(dwCertEncodingType,
2215 X509_CERT, &info, pbEncoded, pcbEncoded);
2216 }
2217 CryptMemFree(hash);
2218 }
2219 }
2220 }
2221 CryptMemFree(encoded);
2222 }
2223 }
2224 return ret;
2225 }
2226
2227 BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV_LEGACY hCryptProv,
2228 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
2229 PCERT_PUBLIC_KEY_INFO pPublicKey)
2230 {
2231 CRYPT_DATA_BLOB blob = { cbEncoded, (BYTE *)pbEncoded };
2232
2233 return CryptVerifyCertificateSignatureEx(hCryptProv, dwCertEncodingType,
2234 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, &blob,
2235 CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
2236 }
2237
2238 static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv,
2239 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pubKeyInfo,
2240 const CERT_SIGNED_CONTENT_INFO *signedCert)
2241 {
2242 BOOL ret;
2243 HCRYPTKEY key;
2244 PCCRYPT_OID_INFO info;
2245 ALG_ID pubKeyID, hashID;
2246
2247 info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2248 signedCert->SignatureAlgorithm.pszObjId, 0);
2249 if (!info || info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID)
2250 {
2251 SetLastError(NTE_BAD_ALGID);
2252 return FALSE;
2253 }
2254 hashID = info->u.Algid;
2255 if (info->ExtraInfo.cbData >= sizeof(ALG_ID))
2256 pubKeyID = *(ALG_ID *)info->ExtraInfo.pbData;
2257 else
2258 pubKeyID = hashID;
2259 /* Load the default provider if necessary */
2260 if (!hCryptProv)
2261 hCryptProv = CRYPT_GetDefaultProvider();
2262 ret = CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType,
2263 pubKeyInfo, pubKeyID, 0, NULL, &key);
2264 if (ret)
2265 {
2266 HCRYPTHASH hash;
2267
2268 ret = CryptCreateHash(hCryptProv, hashID, 0, 0, &hash);
2269 if (ret)
2270 {
2271 ret = CryptHashData(hash, signedCert->ToBeSigned.pbData,
2272 signedCert->ToBeSigned.cbData, 0);
2273 if (ret)
2274 ret = CryptVerifySignatureW(hash, signedCert->Signature.pbData,
2275 signedCert->Signature.cbData, key, NULL, 0);
2276 CryptDestroyHash(hash);
2277 }
2278 CryptDestroyKey(key);
2279 }
2280 return ret;
2281 }
2282
2283 BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV_LEGACY hCryptProv,
2284 DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
2285 DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
2286 {
2287 BOOL ret = TRUE;
2288 CRYPT_DATA_BLOB subjectBlob;
2289
2290 TRACE("(%08lx, %d, %d, %p, %d, %p, %08x, %p)\n", hCryptProv,
2291 dwCertEncodingType, dwSubjectType, pvSubject, dwIssuerType, pvIssuer,
2292 dwFlags, pvReserved);
2293
2294 switch (dwSubjectType)
2295 {
2296 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB:
2297 {
2298 PCRYPT_DATA_BLOB blob = pvSubject;
2299
2300 subjectBlob.pbData = blob->pbData;
2301 subjectBlob.cbData = blob->cbData;
2302 break;
2303 }
2304 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT:
2305 {
2306 PCERT_CONTEXT context = pvSubject;
2307
2308 subjectBlob.pbData = context->pbCertEncoded;
2309 subjectBlob.cbData = context->cbCertEncoded;
2310 break;
2311 }
2312 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL:
2313 {
2314 PCRL_CONTEXT context = pvSubject;
2315
2316 subjectBlob.pbData = context->pbCrlEncoded;
2317 subjectBlob.cbData = context->cbCrlEncoded;
2318 break;
2319 }
2320 default:
2321 SetLastError(E_INVALIDARG);
2322 ret = FALSE;
2323 }
2324
2325 if (ret)
2326 {
2327 PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
2328 DWORD size = 0;
2329
2330 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
2331 subjectBlob.pbData, subjectBlob.cbData,
2332 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
2333 &signedCert, &size);
2334 if (ret)
2335 {
2336 switch (dwIssuerType)
2337 {
2338 case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY:
2339 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
2340 dwCertEncodingType, pvIssuer,
2341 signedCert);
2342 break;
2343 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT:
2344 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
2345 dwCertEncodingType,
2346 &((PCCERT_CONTEXT)pvIssuer)->pCertInfo->SubjectPublicKeyInfo,
2347 signedCert);
2348 break;
2349 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN:
2350 FIXME("CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: stub\n");
2351 ret = FALSE;
2352 break;
2353 case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL:
2354 if (pvIssuer)
2355 {
2356 SetLastError(E_INVALIDARG);
2357 ret = FALSE;
2358 }
2359 else
2360 {
2361 FIXME("unimplemented for NULL signer\n");
2362 SetLastError(E_INVALIDARG);
2363 ret = FALSE;
2364 }
2365 break;
2366 default:
2367 SetLastError(E_INVALIDARG);
2368 ret = FALSE;
2369 }
2370 LocalFree(signedCert);
2371 }
2372 }
2373 return ret;
2374 }
2375
2376 BOOL WINAPI CertGetIntendedKeyUsage(DWORD dwCertEncodingType,
2377 PCERT_INFO pCertInfo, BYTE *pbKeyUsage, DWORD cbKeyUsage)
2378 {
2379 PCERT_EXTENSION ext;
2380 BOOL ret = FALSE;
2381
2382 TRACE("(%08x, %p, %p, %d)\n", dwCertEncodingType, pCertInfo, pbKeyUsage,
2383 cbKeyUsage);
2384
2385 ext = CertFindExtension(szOID_KEY_USAGE, pCertInfo->cExtension,
2386 pCertInfo->rgExtension);
2387 if (ext)
2388 {
2389 CRYPT_BIT_BLOB usage;
2390 DWORD size = sizeof(usage);
2391
2392 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS,
2393 ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL,
2394 &usage, &size);
2395 if (ret)
2396 {
2397 if (cbKeyUsage < usage.cbData)
2398 ret = FALSE;
2399 else
2400 {
2401 memcpy(pbKeyUsage, usage.pbData, usage.cbData);
2402 if (cbKeyUsage > usage.cbData)
2403 memset(pbKeyUsage + usage.cbData, 0,
2404 cbKeyUsage - usage.cbData);
2405 }
2406 }
2407 }
2408 else
2409 SetLastError(0);
2410 return ret;
2411 }
2412
2413 BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags,
2414 PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage)
2415 {
2416 PCERT_ENHKEY_USAGE usage = NULL;
2417 DWORD bytesNeeded;
2418 BOOL ret = TRUE;
2419
2420 if (!pCertContext || !pcbUsage)
2421 {
2422 SetLastError(ERROR_INVALID_PARAMETER);
2423 return FALSE;
2424 }
2425
2426 TRACE("(%p, %08x, %p, %d)\n", pCertContext, dwFlags, pUsage, *pcbUsage);
2427
2428 if (!(dwFlags & CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG))
2429 {
2430 DWORD propSize = 0;
2431
2432 if (CertGetCertificateContextProperty(pCertContext,
2433 CERT_ENHKEY_USAGE_PROP_ID, NULL, &propSize))
2434 {
2435 LPBYTE buf = CryptMemAlloc(propSize);
2436
2437 if (buf)
2438 {
2439 if (CertGetCertificateContextProperty(pCertContext,
2440 CERT_ENHKEY_USAGE_PROP_ID, buf, &propSize))
2441 {
2442 ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
2443 X509_ENHANCED_KEY_USAGE, buf, propSize,
2444 CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
2445 }
2446 CryptMemFree(buf);
2447 }
2448 }
2449 }
2450 if (!usage && !(dwFlags & CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG))
2451 {
2452 PCERT_EXTENSION ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
2453 pCertContext->pCertInfo->cExtension,
2454 pCertContext->pCertInfo->rgExtension);
2455
2456 if (ext)
2457 {
2458 ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
2459 X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
2460 CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
2461 }
2462 }
2463 if (!usage)
2464 {
2465 /* If a particular location is specified, this should fail. Otherwise
2466 * it should succeed with an empty usage. (This is true on Win2k and
2467 * later, which we emulate.)
2468 */
2469 if (dwFlags)
2470 {
2471 SetLastError(CRYPT_E_NOT_FOUND);
2472 ret = FALSE;
2473 }
2474 else
2475 bytesNeeded = sizeof(CERT_ENHKEY_USAGE);
2476 }
2477
2478 if (ret)
2479 {
2480 if (!pUsage)
2481 *pcbUsage = bytesNeeded;
2482 else if (*pcbUsage < bytesNeeded)
2483 {
2484 SetLastError(ERROR_MORE_DATA);
2485 *pcbUsage = bytesNeeded;
2486 ret = FALSE;
2487 }
2488 else
2489 {
2490 *pcbUsage = bytesNeeded;
2491 if (usage)
2492 {
2493 DWORD i;
2494 LPSTR nextOID = (LPSTR)((LPBYTE)pUsage +
2495 sizeof(CERT_ENHKEY_USAGE) +
2496 usage->cUsageIdentifier * sizeof(LPSTR));
2497
2498 pUsage->cUsageIdentifier = usage->cUsageIdentifier;
2499 pUsage->rgpszUsageIdentifier = (LPSTR *)((LPBYTE)pUsage +
2500 sizeof(CERT_ENHKEY_USAGE));
2501 for (i = 0; i < usage->cUsageIdentifier; i++)
2502 {
2503 pUsage->rgpszUsageIdentifier[i] = nextOID;
2504 strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
2505 nextOID += strlen(nextOID) + 1;
2506 }
2507 }
2508 else
2509 pUsage->cUsageIdentifier = 0;
2510 }
2511 }
2512 if (usage)
2513 LocalFree(usage);
2514 TRACE("returning %d\n", ret);
2515 return ret;
2516 }
2517
2518 BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext,
2519 PCERT_ENHKEY_USAGE pUsage)
2520 {
2521 BOOL ret;
2522
2523 TRACE("(%p, %p)\n", pCertContext, pUsage);
2524
2525 if (pUsage)
2526 {
2527 CRYPT_DATA_BLOB blob = { 0, NULL };
2528
2529 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
2530 pUsage, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData, &blob.cbData);
2531 if (ret)
2532 {
2533 ret = CertSetCertificateContextProperty(pCertContext,
2534 CERT_ENHKEY_USAGE_PROP_ID, 0, &blob);
2535 LocalFree(blob.pbData);
2536 }
2537 }
2538 else
2539 ret = CertSetCertificateContextProperty(pCertContext,
2540 CERT_ENHKEY_USAGE_PROP_ID, 0, NULL);
2541 return ret;
2542 }
2543
2544 BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
2545 LPCSTR pszUsageIdentifier)
2546 {
2547 BOOL ret;
2548 DWORD size;
2549
2550 TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
2551
2552 if (CertGetEnhancedKeyUsage(pCertContext,
2553 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size))
2554 {
2555 PCERT_ENHKEY_USAGE usage = CryptMemAlloc(size);
2556
2557 if (usage)
2558 {
2559 ret = CertGetEnhancedKeyUsage(pCertContext,
2560 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size);
2561 if (ret)
2562 {
2563 DWORD i;
2564 BOOL exists = FALSE;
2565
2566 /* Make sure usage doesn't already exist */
2567 for (i = 0; !exists && i < usage->cUsageIdentifier; i++)
2568 {
2569 if (!strcmp(usage->rgpszUsageIdentifier[i],
2570 pszUsageIdentifier))
2571 exists = TRUE;
2572 }
2573 if (!exists)
2574 {
2575 PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size +
2576 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
2577
2578 if (newUsage)
2579 {
2580 LPSTR nextOID;
2581
2582 newUsage->rgpszUsageIdentifier = (LPSTR *)
2583 ((LPBYTE)newUsage + sizeof(CERT_ENHKEY_USAGE));
2584 nextOID = (LPSTR)((LPBYTE)newUsage->rgpszUsageIdentifier
2585 + (usage->cUsageIdentifier + 1) * sizeof(LPSTR));
2586 for (i = 0; i < usage->cUsageIdentifier; i++)
2587 {
2588 newUsage->rgpszUsageIdentifier[i] = nextOID;
2589 strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
2590 nextOID += strlen(nextOID) + 1;
2591 }
2592 newUsage->rgpszUsageIdentifier[i] = nextOID;
2593 strcpy(nextOID, pszUsageIdentifier);
2594 newUsage->cUsageIdentifier = i + 1;
2595 ret = CertSetEnhancedKeyUsage(pCertContext, newUsage);
2596 CryptMemFree(newUsage);
2597 }
2598 else
2599 ret = FALSE;
2600 }
2601 }
2602 CryptMemFree(usage);
2603 }
2604 else
2605 ret = FALSE;
2606 }
2607 else
2608 {
2609 PCERT_ENHKEY_USAGE usage = CryptMemAlloc(sizeof(CERT_ENHKEY_USAGE) +
2610 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
2611
2612 if (usage)
2613 {
2614 usage->rgpszUsageIdentifier =
2615 (LPSTR *)((LPBYTE)usage + sizeof(CERT_ENHKEY_USAGE));
2616 usage->rgpszUsageIdentifier[0] = (LPSTR)((LPBYTE)usage +
2617 sizeof(CERT_ENHKEY_USAGE) + sizeof(LPSTR));
2618 strcpy(usage->rgpszUsageIdentifier[0], pszUsageIdentifier);
2619 usage->cUsageIdentifier = 1;
2620 ret = CertSetEnhancedKeyUsage(pCertContext, usage);
2621 CryptMemFree(usage);
2622 }
2623 else
2624 ret = FALSE;
2625 }
2626 return ret;
2627 }
2628
2629 BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
2630 LPCSTR pszUsageIdentifier)
2631 {
2632 BOOL ret;
2633 DWORD size;
2634 CERT_ENHKEY_USAGE usage;
2635
2636 TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
2637
2638 size = sizeof(usage);
2639 ret = CertGetEnhancedKeyUsage(pCertContext,
2640 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, &usage, &size);
2641 if (!ret && GetLastError() == ERROR_MORE_DATA)
2642 {
2643 PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
2644
2645 if (pUsage)
2646 {
2647 ret = CertGetEnhancedKeyUsage(pCertContext,
2648 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
2649 if (ret)
2650 {
2651 if (pUsage->cUsageIdentifier)
2652 {
2653 DWORD i;
2654 BOOL found = FALSE;
2655
2656 for (i = 0; i < pUsage->cUsageIdentifier; i++)
2657 {
2658 if (!strcmp(pUsage->rgpszUsageIdentifier[i],
2659 pszUsageIdentifier))
2660 found = TRUE;
2661 if (found && i < pUsage->cUsageIdentifier - 1)
2662 pUsage->rgpszUsageIdentifier[i] =
2663 pUsage->rgpszUsageIdentifier[i + 1];
2664 }
2665 pUsage->cUsageIdentifier--;
2666 /* Remove the usage if it's empty */
2667 if (pUsage->cUsageIdentifier)
2668 ret = CertSetEnhancedKeyUsage(pCertContext, pUsage);
2669 else
2670 ret = CertSetEnhancedKeyUsage(pCertContext, NULL);
2671 }
2672 }
2673 CryptMemFree(pUsage);
2674 }
2675 else
2676 ret = FALSE;
2677 }
2678 else
2679 {
2680 /* it fit in an empty usage, therefore there's nothing to remove */
2681 ret = TRUE;
2682 }
2683 return ret;
2684 }
2685
2686 struct BitField
2687 {
2688 DWORD cIndexes;
2689 DWORD *indexes;
2690 };
2691
2692 #define BITS_PER_DWORD (sizeof(DWORD) * 8)
2693
2694 static void CRYPT_SetBitInField(struct BitField *field, DWORD bit)
2695 {
2696 DWORD indexIndex = bit / BITS_PER_DWORD;
2697
2698 if (indexIndex + 1 > field->cIndexes)
2699 {
2700 if (field->cIndexes)
2701 field->indexes = CryptMemRealloc(field->indexes,
2702 (indexIndex + 1) * sizeof(DWORD));
2703 else
2704 field->indexes = CryptMemAlloc(sizeof(DWORD));
2705 if (field->indexes)
2706 {
2707 field->indexes[indexIndex] = 0;
2708 field->cIndexes = indexIndex + 1;
2709 }
2710 }
2711 if (field->indexes)
2712 field->indexes[indexIndex] |= 1 << (bit % BITS_PER_DWORD);
2713 }
2714
2715 static BOOL CRYPT_IsBitInFieldSet(const struct BitField *field, DWORD bit)
2716 {
2717 BOOL set = FALSE;
2718 DWORD indexIndex = bit / BITS_PER_DWORD;
2719
2720 assert(field->cIndexes);
2721 set = field->indexes[indexIndex] & (1 << (bit % BITS_PER_DWORD));
2722 return set;
2723 }
2724
2725 BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts,
2726 int *cNumOIDs, LPSTR *rghOIDs, DWORD *pcbOIDs)
2727 {
2728 BOOL ret = TRUE;
2729 DWORD i, cbOIDs = 0;
2730 BOOL allUsagesValid = TRUE;
2731 CERT_ENHKEY_USAGE validUsages = { 0, NULL };
2732
2733 TRACE("(%d, %p, %d, %p, %d)\n", cCerts, rghCerts, *cNumOIDs,
2734 rghOIDs, *pcbOIDs);
2735
2736 for (i = 0; i < cCerts; i++)
2737 {
2738 CERT_ENHKEY_USAGE usage;
2739 DWORD size = sizeof(usage);
2740
2741 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, &usage, &size);
2742 /* Success is deliberately ignored: it implies all usages are valid */
2743 if (!ret && GetLastError() == ERROR_MORE_DATA)
2744 {
2745 PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
2746
2747 allUsagesValid = FALSE;
2748 if (pUsage)
2749 {
2750 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, pUsage, &size);
2751 if (ret)
2752 {
2753 if (!validUsages.cUsageIdentifier)
2754 {
2755 DWORD j;
2756
2757 cbOIDs = pUsage->cUsageIdentifier * sizeof(LPSTR);
2758 validUsages.cUsageIdentifier = pUsage->cUsageIdentifier;
2759 for (j = 0; j < validUsages.cUsageIdentifier; j++)
2760 cbOIDs += lstrlenA(pUsage->rgpszUsageIdentifier[j])
2761 + 1;
2762 validUsages.rgpszUsageIdentifier =
2763 CryptMemAlloc(cbOIDs);
2764 if (validUsages.rgpszUsageIdentifier)
2765 {
2766 LPSTR nextOID = (LPSTR)
2767 ((LPBYTE)validUsages.rgpszUsageIdentifier +
2768 validUsages.cUsageIdentifier * sizeof(LPSTR));
2769
2770 for (j = 0; j < validUsages.cUsageIdentifier; j++)
2771 {
2772 validUsages.rgpszUsageIdentifier[j] = nextOID;
2773 lstrcpyA(validUsages.rgpszUsageIdentifier[j],
2774 pUsage->rgpszUsageIdentifier[j]);
2775 nextOID += lstrlenA(nextOID) + 1;
2776 }
2777 }
2778 }
2779 else
2780 {
2781 struct BitField validIndexes = { 0, NULL };
2782 DWORD j, k, numRemoved = 0;
2783
2784 /* Merge: build a bitmap of all the indexes of
2785 * validUsages.rgpszUsageIdentifier that are in pUsage.
2786 */
2787 for (j = 0; j < pUsage->cUsageIdentifier; j++)
2788 {
2789 for (k = 0; k < validUsages.cUsageIdentifier; k++)
2790 {
2791 if (!strcmp(pUsage->rgpszUsageIdentifier[j],
2792 validUsages.rgpszUsageIdentifier[k]))
2793 {
2794 CRYPT_SetBitInField(&validIndexes, k);
2795 break;
2796 }
2797 }
2798 }
2799 /* Merge by removing from validUsages those that are
2800 * not in the bitmap.
2801 */
2802 for (j = 0; j < validUsages.cUsageIdentifier; j++)
2803 {
2804 if (!CRYPT_IsBitInFieldSet(&validIndexes, j))
2805 {
2806 if (j < validUsages.cUsageIdentifier - 1)
2807 {
2808 memmove(&validUsages.rgpszUsageIdentifier[j],
2809 &validUsages.rgpszUsageIdentifier[j +
2810 numRemoved + 1],
2811 (validUsages.cUsageIdentifier - numRemoved
2812 - j - 1) * sizeof(LPSTR));
2813 cbOIDs -= lstrlenA(
2814 validUsages.rgpszUsageIdentifier[j]) + 1 +
2815 sizeof(LPSTR);
2816 validUsages.cUsageIdentifier--;
2817 numRemoved++;
2818 }
2819 else
2820 validUsages.cUsageIdentifier--;
2821 }
2822 }
2823 CryptMemFree(validIndexes.indexes);
2824 }
2825 }
2826 CryptMemFree(pUsage);
2827 }
2828 }
2829 }
2830 ret = TRUE;
2831 if (allUsagesValid)
2832 {
2833 *cNumOIDs = -1;
2834 *pcbOIDs = 0;
2835 }
2836 else
2837 {
2838 *cNumOIDs = validUsages.cUsageIdentifier;
2839 if (!rghOIDs)
2840 *pcbOIDs = cbOIDs;
2841 else if (*pcbOIDs < cbOIDs)
2842 {
2843 *pcbOIDs = cbOIDs;
2844 SetLastError(ERROR_MORE_DATA);
2845 ret = FALSE;
2846 }
2847 else
2848 {
2849 LPSTR nextOID = (LPSTR)((LPBYTE)rghOIDs +
2850 validUsages.cUsageIdentifier * sizeof(LPSTR));
2851
2852 *pcbOIDs = cbOIDs;
2853 for (i = 0; i < validUsages.cUsageIdentifier; i++)
2854 {
2855 rghOIDs[i] = nextOID;
2856 lstrcpyA(nextOID, validUsages.rgpszUsageIdentifier[i]);
2857 nextOID += lstrlenA(nextOID) + 1;
2858 }
2859 }
2860 }
2861 CryptMemFree(validUsages.rgpszUsageIdentifier);
2862 TRACE("cNumOIDs: %d\n", *cNumOIDs);
2863 TRACE("returning %d\n", ret);
2864 return ret;
2865 }
2866
2867 /* Sets the CERT_KEY_PROV_INFO_PROP_ID property of context from pInfo, or, if
2868 * pInfo is NULL, from the attributes of hProv.
2869 */
2870 static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context,
2871 const CRYPT_KEY_PROV_INFO *pInfo, HCRYPTPROV hProv)
2872 {
2873 CRYPT_KEY_PROV_INFO info = { 0 };
2874 BOOL ret;
2875
2876 if (!pInfo)
2877 {
2878 DWORD size;
2879 int len;
2880
2881 ret = CryptGetProvParam(hProv, PP_CONTAINER, NULL, &size, 0);
2882 if (ret)
2883 {
2884 LPSTR szContainer = CryptMemAlloc(size);
2885
2886 if (szContainer)
2887 {
2888 ret = CryptGetProvParam(hProv, PP_CONTAINER,
2889 (BYTE *)szContainer, &size, 0);
2890 if (ret)
2891 {
2892 len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
2893 NULL, 0);
2894 if (len)
2895 {
2896 info.pwszContainerName = CryptMemAlloc(len *
2897 sizeof(WCHAR));
2898 MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
2899 info.pwszContainerName, len);
2900 }
2901 }
2902 CryptMemFree(szContainer);
2903 }
2904 }
2905 ret = CryptGetProvParam(hProv, PP_NAME, NULL, &size, 0);
2906 if (ret)
2907 {
2908 LPSTR szProvider = CryptMemAlloc(size);
2909
2910 if (szProvider)
2911 {
2912 ret = CryptGetProvParam(hProv, PP_NAME, (BYTE *)szProvider,
2913 &size, 0);
2914 if (ret)
2915 {
2916 len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
2917 NULL, 0);
2918 if (len)
2919 {
2920 info.pwszProvName = CryptMemAlloc(len *
2921 sizeof(WCHAR));
2922 MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
2923 info.pwszProvName, len);
2924 }
2925 }
2926 CryptMemFree(szProvider);
2927 }
2928 }
2929 size = sizeof(info.dwKeySpec);
2930 /* in case no CRYPT_KEY_PROV_INFO given,
2931 * we always use AT_SIGNATURE key spec
2932 */
2933 info.dwKeySpec = AT_SIGNATURE;
2934 size = sizeof(info.dwProvType);
2935 ret = CryptGetProvParam(hProv, PP_PROVTYPE, (LPBYTE)&info.dwProvType,
2936 &size, 0);
2937 if (!ret)
2938 info.dwProvType = PROV_RSA_FULL;
2939 pInfo = &info;
2940 }
2941
2942 CertSetCertificateContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID,
2943 0, pInfo);
2944
2945 if (pInfo == &info)
2946 {
2947 CryptMemFree(info.pwszContainerName);
2948 CryptMemFree(info.pwszProvName);
2949 }
2950 }
2951
2952 /* Creates a signed certificate context from the unsigned, encoded certificate
2953 * in blob, using the crypto provider hProv and the signature algorithm sigAlgo.
2954 */
2955 static PCCERT_CONTEXT CRYPT_CreateSignedCert(const CRYPT_DER_BLOB *blob,
2956 HCRYPTPROV hProv, DWORD dwKeySpec, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo)
2957 {
2958 PCCERT_CONTEXT context = NULL;
2959 BOOL ret;
2960 DWORD sigSize = 0;
2961
2962 ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
2963 blob->pbData, blob->cbData, sigAlgo, NULL, NULL, &sigSize);
2964 if (ret)
2965 {
2966 LPBYTE sig = CryptMemAlloc(sigSize);
2967
2968 ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
2969 blob->pbData, blob->cbData, sigAlgo, NULL, sig, &sigSize);
2970 if (ret)
2971 {
2972 CERT_SIGNED_CONTENT_INFO signedInfo;
2973 BYTE *encodedSignedCert = NULL;
2974 DWORD encodedSignedCertSize = 0;
2975
2976 signedInfo.ToBeSigned.cbData = blob->cbData;
2977 signedInfo.ToBeSigned.pbData = blob->pbData;
2978 signedInfo.SignatureAlgorithm = *sigAlgo;
2979 signedInfo.Signature.cbData = sigSize;
2980 signedInfo.Signature.pbData = sig;
2981 signedInfo.Signature.cUnusedBits = 0;
2982 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT,
2983 &signedInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
2984 &encodedSignedCert, &encodedSignedCertSize);
2985 if (ret)
2986 {
2987 context = CertCreateCertificateContext(X509_ASN_ENCODING,
2988 encodedSignedCert, encodedSignedCertSize);
2989 LocalFree(encodedSignedCert);
2990 }
2991 }
2992 CryptMemFree(sig);
2993 }
2994 return context;
2995 }
2996
2997 /* Copies data from the parameters into info, where:
2998 * pSerialNumber: The serial number. Must not be NULL.
2999 * pSubjectIssuerBlob: Specifies both the subject and issuer for info.
3000 * Must not be NULL
3001 * pSignatureAlgorithm: Optional.
3002 * pStartTime: The starting time of the certificate. If NULL, the current
3003 * system time is used.
3004 * pEndTime: The ending time of the certificate. If NULL, one year past the
3005 * starting time is used.
3006 * pubKey: The public key of the certificate. Must not be NULL.
3007 * pExtensions: Extensions to be included with the certificate. Optional.
3008 */
3009 static void CRYPT_MakeCertInfo(PCERT_INFO info, const CRYPT_DATA_BLOB *pSerialNumber,
3010 const CERT_NAME_BLOB *pSubjectIssuerBlob,
3011 const CRYPT_ALGORITHM_IDENTIFIER *pSignatureAlgorithm, const SYSTEMTIME *pStartTime,
3012 const SYSTEMTIME *pEndTime, const CERT_PUBLIC_KEY_INFO *pubKey,
3013 const CERT_EXTENSIONS *pExtensions)
3014 {
3015 static CHAR oid[] = szOID_RSA_SHA1RSA;
3016
3017 assert(info);
3018 assert(pSerialNumber);
3019 assert(pSubjectIssuerBlob);
3020 assert(pubKey);
3021
3022 if (pExtensions && pExtensions->cExtension)
3023 info->dwVersion = CERT_V3;
3024 else
3025 info->dwVersion = CERT_V1;
3026 info->SerialNumber.cbData = pSerialNumber->cbData;
3027 info->SerialNumber.pbData = pSerialNumber->pbData;
3028 if (pSignatureAlgorithm)
3029 info->SignatureAlgorithm = *pSignatureAlgorithm;
3030 else
3031 {
3032 info->SignatureAlgorithm.pszObjId = oid;
3033 info->SignatureAlgorithm.Parameters.cbData = 0;
3034 info->SignatureAlgorithm.Parameters.pbData = NULL;
3035 }
3036 info->Issuer.cbData = pSubjectIssuerBlob->cbData;
3037 info->Issuer.pbData = pSubjectIssuerBlob->pbData;
3038 if (pStartTime)
3039 SystemTimeToFileTime(pStartTime, &info->NotBefore);
3040 else
3041 GetSystemTimeAsFileTime(&info->NotBefore);
3042 if (pEndTime)
3043 SystemTimeToFileTime(pEndTime, &info->NotAfter);
3044 else
3045 {
3046 SYSTEMTIME endTime;
3047
3048 if (FileTimeToSystemTime(&info->NotBefore, &endTime))
3049 {
3050 endTime.wYear++;
3051 SystemTimeToFileTime(&endTime, &info->NotAfter);
3052 }
3053 }
3054 info->Subject.cbData = pSubjectIssuerBlob->cbData;
3055 info->Subject.pbData = pSubjectIssuerBlob->pbData;
3056 info->SubjectPublicKeyInfo = *pubKey;
3057 if (pExtensions)
3058 {
3059 info->cExtension = pExtensions->cExtension;
3060 info->rgExtension = pExtensions->rgExtension;
3061 }
3062 else
3063 {
3064 info->cExtension = 0;
3065 info->rgExtension = NULL;
3066 }
3067 }
3068
3069 typedef RPC_STATUS (RPC_ENTRY *UuidCreateFunc)(UUID *);
3070 typedef RPC_STATUS (RPC_ENTRY *UuidToStringFunc)(UUID *, unsigned char **);
3071 typedef RPC_STATUS (RPC_ENTRY *RpcStringFreeFunc)(unsigned char **);
3072
3073 static HCRYPTPROV CRYPT_CreateKeyProv(void)
3074 {
3075 HCRYPTPROV hProv = 0;
3076 HMODULE rpcrt = LoadLibraryA("rpcrt4");
3077
3078 if (rpcrt)
3079 {
3080 UuidCreateFunc uuidCreate = (UuidCreateFunc)GetProcAddress(rpcrt,
3081 "UuidCreate");
3082 UuidToStringFunc uuidToString = (UuidToStringFunc)GetProcAddress(rpcrt,
3083 "UuidToStringA");
3084 RpcStringFreeFunc rpcStringFree = (RpcStringFreeFunc)GetProcAddress(
3085 rpcrt, "RpcStringFreeA");
3086
3087 if (uuidCreate && uuidToString && rpcStringFree)
3088 {
3089 UUID uuid;
3090 RPC_STATUS status = uuidCreate(&uuid);
3091
3092 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY)
3093 {
3094 unsigned char *uuidStr;
3095
3096 status = uuidToString(&uuid, &uuidStr);
3097 if (status == RPC_S_OK)
3098 {
3099 BOOL ret = CryptAcquireContextA(&hProv, (LPCSTR)uuidStr,
3100 MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_NEWKEYSET);
3101
3102 if (ret)
3103 {
3104 HCRYPTKEY key;
3105
3106 ret = CryptGenKey(hProv, AT_SIGNATURE, 0, &key);
3107 if (ret)
3108 CryptDestroyKey(key);
3109 }
3110 rpcStringFree(&uuidStr);
3111 }
3112 }
3113 }
3114 FreeLibrary(rpcrt);
3115 }
3116 return hProv;
3117 }
3118
3119 PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hProv,
3120 PCERT_NAME_BLOB pSubjectIssuerBlob, DWORD dwFlags,
3121 PCRYPT_KEY_PROV_INFO pKeyProvInfo,
3122 PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime,
3123 PSYSTEMTIME pEndTime, PCERT_EXTENSIONS pExtensions)
3124 {
3125 PCCERT_CONTEXT context = NULL;
3126 BOOL ret, releaseContext = FALSE;
3127 PCERT_PUBLIC_KEY_INFO pubKey = NULL;
3128 DWORD pubKeySize = 0, dwKeySpec;
3129
3130 TRACE("(%08lx, %p, %08x, %p, %p, %p, %p, %p)\n", hProv,
3131 pSubjectIssuerBlob, dwFlags, pKeyProvInfo, pSignatureAlgorithm, pStartTime,
3132 pExtensions, pExtensions);
3133
3134 if(!pSubjectIssuerBlob)
3135 {
3136 SetLastError(ERROR_INVALID_PARAMETER);
3137 return NULL;
3138 }
3139
3140 dwKeySpec = pKeyProvInfo ? pKeyProvInfo->dwKeySpec : AT_SIGNATURE;
3141 if (!hProv)
3142 {
3143 if (!pKeyProvInfo)
3144 {
3145 hProv = CRYPT_CreateKeyProv();
3146 releaseContext = TRUE;
3147 }
3148 else if (pKeyProvInfo->dwFlags & CERT_SET_KEY_PROV_HANDLE_PROP_ID)
3149 {
3150 SetLastError(NTE_BAD_FLAGS);
3151 return NULL;
3152 }
3153 else
3154 {
3155 HCRYPTKEY hKey = 0;
3156 /* acquire the context using the given information*/
3157 ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
3158 pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
3159 pKeyProvInfo->dwFlags);
3160 if (!ret)
3161 {
3162 if(GetLastError() != NTE_BAD_KEYSET)
3163 return NULL;
3164 /* create the key set */
3165 ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
3166 pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
3167 pKeyProvInfo->dwFlags|CRYPT_NEWKEYSET);
3168 if (!ret)
3169 return NULL;
3170 }
3171 /* check if the key is here */
3172 ret = CryptGetUserKey(hProv,dwKeySpec,&hKey);
3173 if(!ret)
3174 {
3175 if (NTE_NO_KEY == GetLastError())
3176 { /* generate the key */
3177 ret = CryptGenKey(hProv,dwKeySpec,0,&hKey);
3178 }
3179 if (!ret)
3180 {
3181 CryptReleaseContext(hProv,0);
3182 SetLastError(NTE_BAD_KEYSET);
3183 return NULL;
3184 }
3185 }
3186 CryptDestroyKey(hKey);
3187 releaseContext = TRUE;
3188 }
3189 }
3190
3191 ret = CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING, NULL,
3192 &pubKeySize);
3193 if (!ret)
3194 goto end;
3195 pubKey = CryptMemAlloc(pubKeySize);
3196 if (pubKey)
3197 {
3198 ret = CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING,
3199 pubKey, &pubKeySize);
3200 if (ret)
3201 {
3202 CERT_INFO info = { 0 };
3203 CRYPT_DER_BLOB blob = { 0, NULL };
3204 BYTE serial[16];
3205 CRYPT_DATA_BLOB serialBlob = { sizeof(serial), serial };
3206
3207 CryptGenRandom(hProv, sizeof(serial), serial);
3208 CRYPT_MakeCertInfo(&info, &serialBlob, pSubjectIssuerBlob,
3209 pSignatureAlgorithm, pStartTime, pEndTime, pubKey, pExtensions);
3210 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
3211 &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData,
3212 &blob.cbData);
3213 if (ret)
3214 {
3215 if (!(dwFlags & CERT_CREATE_SELFSIGN_NO_SIGN))
3216 context = CRYPT_CreateSignedCert(&blob, hProv,dwKeySpec,
3217 &info.SignatureAlgorithm);
3218 else
3219 context = CertCreateCertificateContext(X509_ASN_ENCODING,
3220 blob.pbData, blob.cbData);
3221 if (context && !(dwFlags & CERT_CREATE_SELFSIGN_NO_KEY_INFO))
3222 CertContext_SetKeyProvInfo(context, pKeyProvInfo, hProv);
3223 LocalFree(blob.pbData);
3224 }
3225 }
3226 CryptMemFree(pubKey);
3227 }
3228 end:
3229 if (releaseContext)
3230 CryptReleaseContext(hProv, 0);
3231 return context;
3232 }
3233
3234 BOOL WINAPI CertVerifyCTLUsage(DWORD dwEncodingType, DWORD dwSubjectType,
3235 void *pvSubject, PCTL_USAGE pSubjectUsage, DWORD dwFlags,
3236 PCTL_VERIFY_USAGE_PARA pVerifyUsagePara,
3237 PCTL_VERIFY_USAGE_STATUS pVerifyUsageStatus)
3238 {
3239 FIXME("(0x%x, %d, %p, %p, 0x%x, %p, %p): stub\n", dwEncodingType,
3240 dwSubjectType, pvSubject, pSubjectUsage, dwFlags, pVerifyUsagePara,
3241 pVerifyUsageStatus);
3242 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3243 return FALSE;
3244 }
3245
3246 const void * WINAPI CertCreateContext(DWORD dwContextType, DWORD dwEncodingType,
3247 const BYTE *pbEncoded, DWORD cbEncoded,
3248 DWORD dwFlags, PCERT_CREATE_CONTEXT_PARA pCreatePara)
3249 {
3250 TRACE("(0x%x, 0x%x, %p, %d, 0x%08x, %p)\n", dwContextType, dwEncodingType,
3251 pbEncoded, cbEncoded, dwFlags, pCreatePara);
3252
3253 if (dwFlags)
3254 {
3255 FIXME("dwFlags 0x%08x not handled\n", dwFlags);
3256 return NULL;
3257 }
3258 if (pCreatePara)
3259 {
3260 FIXME("pCreatePara not handled\n");
3261 return NULL;
3262 }
3263
3264 switch (dwContextType)
3265 {
3266 case CERT_STORE_CERTIFICATE_CONTEXT:
3267 return CertCreateCertificateContext(dwEncodingType, pbEncoded, cbEncoded);
3268 case CERT_STORE_CRL_CONTEXT:
3269 return CertCreateCRLContext(dwEncodingType, pbEncoded, cbEncoded);
3270 case CERT_STORE_CTL_CONTEXT:
3271 return CertCreateCTLContext(dwEncodingType, pbEncoded, cbEncoded);
3272 default:
3273 WARN("unknown context type: 0x%x\n", dwContextType);
3274 return NULL;
3275 }
3276 }