dbghelp: Write-strings warning fix.
[wine] / dlls / crypt32 / cert.c
1 /*
2  * Copyright 2004-2006 Juan Lang
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  *
18  */
19
20 #include <assert.h>
21 #include <stdarg.h>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wincrypt.h"
25 #include "winnls.h"
26 #include "rpc.h"
27 #include "wine/debug.h"
28 #include "crypt32_private.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
31
32 /* Internal version of CertGetCertificateContextProperty that gets properties
33  * directly from the context (or the context it's linked to, depending on its
34  * type.) Doesn't handle special-case properties, since they are handled by
35  * CertGetCertificateContextProperty, and are particular to the store in which
36  * the property exists (which is separate from the context.)
37  */
38 static BOOL WINAPI CertContext_GetProperty(void *context, DWORD dwPropId,
39  void *pvData, DWORD *pcbData);
40
41 /* Internal version of CertSetCertificateContextProperty that sets properties
42  * directly on the context (or the context it's linked to, depending on its
43  * type.) Doesn't handle special cases, since they're handled by
44  * CertSetCertificateContextProperty anyway.
45  */
46 static BOOL WINAPI CertContext_SetProperty(void *context, DWORD dwPropId,
47  DWORD dwFlags, const void *pvData);
48
49 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
50  DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
51  DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
52 {
53     PCCERT_CONTEXT cert = CertCreateCertificateContext(dwCertEncodingType,
54      pbCertEncoded, cbCertEncoded);
55     BOOL ret;
56
57     TRACE("(%p, %08lx, %p, %ld, %08lx, %p)\n", hCertStore, dwCertEncodingType,
58      pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
59
60     if (cert)
61     {
62         ret = CertAddCertificateContextToStore(hCertStore, cert,
63          dwAddDisposition, ppCertContext);
64         CertFreeCertificateContext(cert);
65     }
66     else
67         ret = FALSE;
68     return ret;
69 }
70
71 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
72  const BYTE *pbCertEncoded, DWORD cbCertEncoded)
73 {
74     PCERT_CONTEXT cert = NULL;
75     BOOL ret;
76     PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
77     PCERT_INFO certInfo = NULL;
78     DWORD size = 0;
79
80     TRACE("(%08lx, %p, %ld)\n", dwCertEncodingType, pbCertEncoded,
81      cbCertEncoded);
82
83     /* First try to decode it as a signed cert. */
84     ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT, pbCertEncoded,
85      cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&signedCert, &size);
86     if (ret)
87     {
88         size = 0;
89         ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT_TO_BE_SIGNED,
90          signedCert->ToBeSigned.pbData, signedCert->ToBeSigned.cbData,
91          CRYPT_DECODE_ALLOC_FLAG, NULL, (BYTE *)&certInfo, &size);
92         LocalFree(signedCert);
93     }
94     /* Failing that, try it as an unsigned cert */
95     if (!ret)
96     {
97         size = 0;
98         ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT_TO_BE_SIGNED,
99          pbCertEncoded, cbCertEncoded,
100          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
101          (BYTE *)&certInfo, &size);
102     }
103     if (ret)
104     {
105         BYTE *data = NULL;
106
107         cert = (PCERT_CONTEXT)Context_CreateDataContext(sizeof(CERT_CONTEXT));
108         if (!cert)
109             goto end;
110         data = CryptMemAlloc(cbCertEncoded);
111         if (!data)
112         {
113             CryptMemFree(cert);
114             cert = NULL;
115             goto end;
116         }
117         memcpy(data, pbCertEncoded, cbCertEncoded);
118         cert->dwCertEncodingType = dwCertEncodingType;
119         cert->pbCertEncoded      = data;
120         cert->cbCertEncoded      = cbCertEncoded;
121         cert->pCertInfo          = certInfo;
122         cert->hCertStore         = 0;
123     }
124
125 end:
126     return (PCCERT_CONTEXT)cert;
127 }
128
129 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
130  PCCERT_CONTEXT pCertContext)
131 {
132     TRACE("(%p)\n", pCertContext);
133     Context_AddRef((void *)pCertContext, sizeof(CERT_CONTEXT));
134     return pCertContext;
135 }
136
137 static void CertDataContext_Free(void *context)
138 {
139     PCERT_CONTEXT certContext = (PCERT_CONTEXT)context;
140
141     CryptMemFree(certContext->pbCertEncoded);
142     LocalFree(certContext->pCertInfo);
143 }
144
145 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
146 {
147     TRACE("(%p)\n", pCertContext);
148
149     if (pCertContext)
150         Context_Release((void *)pCertContext, sizeof(CERT_CONTEXT),
151          CertDataContext_Free);
152     return TRUE;
153 }
154
155 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
156  DWORD dwPropId)
157 {
158     PCONTEXT_PROPERTY_LIST properties = Context_GetProperties(
159      (void *)pCertContext, sizeof(CERT_CONTEXT));
160     DWORD ret;
161
162     TRACE("(%p, %ld)\n", pCertContext, dwPropId);
163
164     if (properties)
165         ret = ContextPropertyList_EnumPropIDs(properties, dwPropId);
166     else
167         ret = 0;
168     return ret;
169 }
170
171 static BOOL CertContext_GetHashProp(void *context, DWORD dwPropId,
172  ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
173  DWORD *pcbData)
174 {
175     BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
176      pcbData);
177     if (ret)
178     {
179         CRYPT_DATA_BLOB blob = { *pcbData, pvData };
180
181         ret = CertContext_SetProperty(context, dwPropId, 0, &blob);
182     }
183     return ret;
184 }
185
186 static BOOL WINAPI CertContext_GetProperty(void *context, DWORD dwPropId,
187  void *pvData, DWORD *pcbData)
188 {
189     PCCERT_CONTEXT pCertContext = (PCCERT_CONTEXT)context;
190     PCONTEXT_PROPERTY_LIST properties =
191      Context_GetProperties(context, sizeof(CERT_CONTEXT));
192     BOOL ret;
193     CRYPT_DATA_BLOB blob;
194
195     TRACE("(%p, %ld, %p, %p)\n", context, dwPropId, pvData, pcbData);
196
197     if (properties)
198         ret = ContextPropertyList_FindProperty(properties, dwPropId, &blob);
199     else
200         ret = FALSE;
201     if (ret)
202     {
203         if (!pvData)
204         {
205             *pcbData = blob.cbData;
206             ret = TRUE;
207         }
208         else if (*pcbData < blob.cbData)
209         {
210             SetLastError(ERROR_MORE_DATA);
211             *pcbData = blob.cbData;
212         }
213         else
214         {
215             memcpy(pvData, blob.pbData, blob.cbData);
216             *pcbData = blob.cbData;
217             ret = TRUE;
218         }
219     }
220     else
221     {
222         /* Implicit properties */
223         switch (dwPropId)
224         {
225         case CERT_SHA1_HASH_PROP_ID:
226             ret = CertContext_GetHashProp(context, dwPropId, CALG_SHA1,
227              pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData,
228              pcbData);
229             break;
230         case CERT_MD5_HASH_PROP_ID:
231             ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
232              pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData,
233              pcbData);
234             break;
235         case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
236             ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
237              pCertContext->pCertInfo->Subject.pbData,
238              pCertContext->pCertInfo->Subject.cbData,
239              pvData, pcbData);
240             break;
241         case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
242             ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
243              pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
244              pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
245              pvData, pcbData);
246             break;
247         case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
248             ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
249              pCertContext->pCertInfo->SerialNumber.pbData,
250              pCertContext->pCertInfo->SerialNumber.cbData,
251              pvData, pcbData);
252             break;
253         case CERT_SIGNATURE_HASH_PROP_ID:
254             FIXME("CERT_SIGNATURE_HASH_PROP_ID unimplemented\n");
255             SetLastError(CRYPT_E_NOT_FOUND);
256             break;
257         default:
258             SetLastError(CRYPT_E_NOT_FOUND);
259         }
260     }
261     TRACE("returning %d\n", ret);
262     return ret;
263 }
264
265 /* info is assumed to be a CRYPT_KEY_PROV_INFO, followed by its container name,
266  * provider name, and any provider parameters, in a contiguous buffer, but
267  * where info's pointers are assumed to be invalid.  Upon return, info's
268  * pointers point to the appropriate memory locations.
269  */
270 static void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info)
271 {
272     DWORD i, containerLen, provNameLen;
273     LPBYTE data = (LPBYTE)info + sizeof(CRYPT_KEY_PROV_INFO);
274
275     info->pwszContainerName = (LPWSTR)data;
276     containerLen = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
277     data += containerLen;
278
279     info->pwszProvName = (LPWSTR)data;
280     provNameLen = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
281     data += provNameLen;
282
283     info->rgProvParam = (PCRYPT_KEY_PROV_PARAM)data;
284     data += info->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
285
286     for (i = 0; i < info->cProvParam; i++)
287     {
288         info->rgProvParam[i].pbData = data;
289         data += info->rgProvParam[i].cbData;
290     }
291 }
292
293 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
294  DWORD dwPropId, void *pvData, DWORD *pcbData)
295 {
296     BOOL ret;
297
298     TRACE("(%p, %ld, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
299
300     switch (dwPropId)
301     {
302     case 0:
303     case CERT_CERT_PROP_ID:
304     case CERT_CRL_PROP_ID:
305     case CERT_CTL_PROP_ID:
306         SetLastError(E_INVALIDARG);
307         ret = FALSE;
308         break;
309     case CERT_ACCESS_STATE_PROP_ID:
310         if (!pvData)
311         {
312             *pcbData = sizeof(DWORD);
313             ret = TRUE;
314         }
315         else if (*pcbData < sizeof(DWORD))
316         {
317             SetLastError(ERROR_MORE_DATA);
318             *pcbData = sizeof(DWORD);
319             ret = FALSE;
320         }
321         else
322         {
323             *(DWORD *)pvData =
324              CertStore_GetAccessState(pCertContext->hCertStore);
325             ret = TRUE;
326         }
327         break;
328     case CERT_KEY_PROV_INFO_PROP_ID:
329         ret = CertContext_GetProperty((void *)pCertContext, dwPropId, pvData,
330          pcbData);
331         if (ret && pvData)
332             CRYPT_FixKeyProvInfoPointers((PCRYPT_KEY_PROV_INFO)pvData);
333         break;
334     default:
335         ret = CertContext_GetProperty((void *)pCertContext, dwPropId, pvData,
336          pcbData);
337     }
338
339     TRACE("returning %d\n", ret);
340     return ret;
341 }
342
343 /* Copies key provider info from from into to, where to is assumed to be a
344  * contiguous buffer of memory large enough for from and all its associated
345  * data, but whose pointers are uninitialized.
346  * Upon return, to contains a contiguous copy of from, packed in the following
347  * order:
348  * - CRYPT_KEY_PROV_INFO
349  * - pwszContainerName
350  * - pwszProvName
351  * - rgProvParam[0]...
352  */
353 static void CRYPT_CopyKeyProvInfo(PCRYPT_KEY_PROV_INFO to,
354  PCRYPT_KEY_PROV_INFO from)
355 {
356     DWORD i;
357     LPBYTE nextData = (LPBYTE)to + sizeof(CRYPT_KEY_PROV_INFO);
358
359     to->pwszContainerName = (LPWSTR)nextData;
360     lstrcpyW(to->pwszContainerName, from->pwszContainerName);
361     nextData += (lstrlenW(from->pwszContainerName) + 1) * sizeof(WCHAR);
362     to->pwszProvName = (LPWSTR)nextData;
363     lstrcpyW(to->pwszProvName, from->pwszProvName);
364     nextData += (lstrlenW(from->pwszProvName) + 1) * sizeof(WCHAR);
365     to->dwProvType = from->dwProvType;
366     to->dwFlags = from->dwFlags;
367     to->cProvParam = from->cProvParam;
368     to->rgProvParam = (PCRYPT_KEY_PROV_PARAM)nextData;
369     nextData += to->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
370     to->dwKeySpec = from->dwKeySpec;
371     for (i = 0; i < to->cProvParam; i++)
372     {
373         memcpy(&to->rgProvParam[i], &from->rgProvParam[i],
374          sizeof(CRYPT_KEY_PROV_PARAM));
375         to->rgProvParam[i].pbData = nextData;
376         memcpy(to->rgProvParam[i].pbData, from->rgProvParam[i].pbData,
377          from->rgProvParam[i].cbData);
378         nextData += from->rgProvParam[i].cbData;
379     }
380 }
381
382 static BOOL CertContext_SetKeyProvInfoProperty(PCONTEXT_PROPERTY_LIST properties,
383  PCRYPT_KEY_PROV_INFO info)
384 {
385     BOOL ret;
386     LPBYTE buf = NULL;
387     DWORD size = sizeof(CRYPT_KEY_PROV_INFO), i, containerSize, provNameSize;
388
389     containerSize = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
390     provNameSize = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
391     size += containerSize + provNameSize;
392     for (i = 0; i < info->cProvParam; i++)
393         size += sizeof(CRYPT_KEY_PROV_PARAM) + info->rgProvParam[i].cbData;
394     buf = CryptMemAlloc(size);
395     if (buf)
396     {
397         CRYPT_CopyKeyProvInfo((PCRYPT_KEY_PROV_INFO)buf, info);
398         ret = ContextPropertyList_SetProperty(properties,
399          CERT_KEY_PROV_INFO_PROP_ID, buf, size);
400         CryptMemFree(buf);
401     }
402     else
403         ret = FALSE;
404     return ret;
405 }
406
407 static BOOL WINAPI CertContext_SetProperty(void *context, DWORD dwPropId,
408  DWORD dwFlags, const void *pvData)
409 {
410     PCONTEXT_PROPERTY_LIST properties =
411      Context_GetProperties(context, sizeof(CERT_CONTEXT));
412     BOOL ret;
413
414     TRACE("(%p, %ld, %08lx, %p)\n", context, dwPropId, dwFlags, pvData);
415
416     if (!properties)
417         ret = FALSE;
418     else if (!pvData)
419     {
420         ContextPropertyList_RemoveProperty(properties, dwPropId);
421         ret = TRUE;
422     }
423     else
424     {
425         switch (dwPropId)
426         {
427         case CERT_AUTO_ENROLL_PROP_ID:
428         case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */
429         case CERT_DESCRIPTION_PROP_ID:
430         case CERT_FRIENDLY_NAME_PROP_ID:
431         case CERT_HASH_PROP_ID:
432         case CERT_KEY_IDENTIFIER_PROP_ID:
433         case CERT_MD5_HASH_PROP_ID:
434         case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
435         case CERT_PUBKEY_ALG_PARA_PROP_ID:
436         case CERT_PVK_FILE_PROP_ID:
437         case CERT_SIGNATURE_HASH_PROP_ID:
438         case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
439         case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
440         case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
441         case CERT_ENROLLMENT_PROP_ID:
442         case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
443         case CERT_RENEWAL_PROP_ID:
444         {
445             PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData;
446
447             ret = ContextPropertyList_SetProperty(properties, dwPropId,
448              blob->pbData, blob->cbData);
449             break;
450         }
451         case CERT_DATE_STAMP_PROP_ID:
452             ret = ContextPropertyList_SetProperty(properties, dwPropId,
453              (LPBYTE)pvData, sizeof(FILETIME));
454             break;
455         case CERT_KEY_PROV_INFO_PROP_ID:
456             ret = CertContext_SetKeyProvInfoProperty(properties,
457              (PCRYPT_KEY_PROV_INFO)pvData);
458             break;
459         default:
460             FIXME("%ld: stub\n", dwPropId);
461             ret = FALSE;
462         }
463     }
464     TRACE("returning %d\n", ret);
465     return ret;
466 }
467
468 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
469  DWORD dwPropId, DWORD dwFlags, const void *pvData)
470 {
471     BOOL ret;
472
473     TRACE("(%p, %ld, %08lx, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
474
475     /* Handle special cases for "read-only"/invalid prop IDs.  Windows just
476      * crashes on most of these, I'll be safer.
477      */
478     switch (dwPropId)
479     {
480     case 0:
481     case CERT_ACCESS_STATE_PROP_ID:
482     case CERT_CERT_PROP_ID:
483     case CERT_CRL_PROP_ID:
484     case CERT_CTL_PROP_ID:
485         SetLastError(E_INVALIDARG);
486         return FALSE;
487     }
488     ret = CertContext_SetProperty((void *)pCertContext, dwPropId, dwFlags,
489      pvData);
490     TRACE("returning %d\n", ret);
491     return ret;
492 }
493
494 BOOL WINAPI CertCompareCertificate(DWORD dwCertEncodingType,
495  PCERT_INFO pCertId1, PCERT_INFO pCertId2)
496 {
497     TRACE("(%08lx, %p, %p)\n", dwCertEncodingType, pCertId1, pCertId2);
498
499     return CertCompareCertificateName(dwCertEncodingType, &pCertId1->Issuer,
500      &pCertId2->Issuer) && CertCompareIntegerBlob(&pCertId1->SerialNumber,
501      &pCertId2->SerialNumber);
502 }
503
504 BOOL WINAPI CertCompareCertificateName(DWORD dwCertEncodingType,
505  PCERT_NAME_BLOB pCertName1, PCERT_NAME_BLOB pCertName2)
506 {
507     BOOL ret;
508
509     TRACE("(%08lx, %p, %p)\n", dwCertEncodingType, pCertName1, pCertName2);
510
511     if (pCertName1->cbData == pCertName2->cbData)
512     {
513         if (pCertName1->cbData)
514             ret = !memcmp(pCertName1->pbData, pCertName2->pbData,
515              pCertName1->cbData);
516         else
517             ret = TRUE;
518     }
519     else
520         ret = FALSE;
521     return ret;
522 }
523
524 /* Returns the number of significant bytes in pInt, where a byte is
525  * insignificant if it's a leading 0 for positive numbers or a leading 0xff
526  * for negative numbers.  pInt is assumed to be little-endian.
527  */
528 static DWORD CRYPT_significantBytes(PCRYPT_INTEGER_BLOB pInt)
529 {
530     DWORD ret = pInt->cbData;
531
532     while (ret > 1)
533     {
534         if (pInt->pbData[ret - 2] <= 0x7f && pInt->pbData[ret - 1] == 0)
535             ret--;
536         else if (pInt->pbData[ret - 2] >= 0x80 && pInt->pbData[ret - 1] == 0xff)
537             ret--;
538         else
539             break;
540     }
541     return ret;
542 }
543
544 BOOL WINAPI CertCompareIntegerBlob(PCRYPT_INTEGER_BLOB pInt1,
545  PCRYPT_INTEGER_BLOB pInt2)
546 {
547     BOOL ret;
548     DWORD cb1, cb2;
549
550     TRACE("(%p, %p)\n", pInt1, pInt2);
551
552     cb1 = CRYPT_significantBytes(pInt1);
553     cb2 = CRYPT_significantBytes(pInt2);
554     if (cb1 == cb2)
555     {
556         if (cb1)
557             ret = !memcmp(pInt1->pbData, pInt1->pbData, cb1);
558         else
559             ret = TRUE;
560     }
561     else
562         ret = FALSE;
563     return ret;
564 }
565
566 BOOL WINAPI CertComparePublicKeyInfo(DWORD dwCertEncodingType,
567  PCERT_PUBLIC_KEY_INFO pPublicKey1, PCERT_PUBLIC_KEY_INFO pPublicKey2)
568 {
569     BOOL ret;
570
571     TRACE("(%08lx, %p, %p)\n", dwCertEncodingType, pPublicKey1, pPublicKey2);
572
573     if (pPublicKey1->PublicKey.cbData == pPublicKey2->PublicKey.cbData &&
574      pPublicKey1->PublicKey.cUnusedBits == pPublicKey2->PublicKey.cUnusedBits)
575     {
576         if (pPublicKey2->PublicKey.cbData)
577             ret = !memcmp(pPublicKey1->PublicKey.pbData,
578              pPublicKey2->PublicKey.pbData, pPublicKey1->PublicKey.cbData);
579         else
580             ret = TRUE;
581     }
582     else
583         ret = FALSE;
584     return ret;
585 }
586
587 typedef BOOL (*CertCompareFunc)(PCCERT_CONTEXT pCertContext, DWORD dwType,
588  DWORD dwFlags, const void *pvPara);
589
590 static BOOL compare_cert_any(PCCERT_CONTEXT pCertContext, DWORD dwType,
591  DWORD dwFlags, const void *pvPara)
592 {
593     return TRUE;
594 }
595
596 static BOOL compare_cert_by_md5_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
597  DWORD dwFlags, const void *pvPara)
598 {
599     BOOL ret;
600     BYTE hash[16];
601     DWORD size = sizeof(hash);
602
603     ret = CertGetCertificateContextProperty(pCertContext,
604      CERT_MD5_HASH_PROP_ID, hash, &size);
605     if (ret)
606     {
607         const CRYPT_HASH_BLOB *pHash = (const CRYPT_HASH_BLOB *)pvPara;
608
609         if (size == pHash->cbData)
610             ret = !memcmp(pHash->pbData, hash, size);
611         else
612             ret = FALSE;
613     }
614     return ret;
615 }
616
617 static BOOL compare_cert_by_sha1_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
618  DWORD dwFlags, const void *pvPara)
619 {
620     BOOL ret;
621     BYTE hash[20];
622     DWORD size = sizeof(hash);
623
624     ret = CertGetCertificateContextProperty(pCertContext,
625      CERT_SHA1_HASH_PROP_ID, hash, &size);
626     if (ret)
627     {
628         const CRYPT_HASH_BLOB *pHash = (const CRYPT_HASH_BLOB *)pvPara;
629
630         if (size == pHash->cbData)
631             ret = !memcmp(pHash->pbData, hash, size);
632         else
633             ret = FALSE;
634     }
635     return ret;
636 }
637
638 static BOOL compare_cert_by_name(PCCERT_CONTEXT pCertContext, DWORD dwType,
639  DWORD dwFlags, const void *pvPara)
640 {
641     CERT_NAME_BLOB *blob = (CERT_NAME_BLOB *)pvPara, *toCompare;
642     BOOL ret;
643
644     if (dwType & CERT_INFO_SUBJECT_FLAG)
645         toCompare = &pCertContext->pCertInfo->Subject;
646     else
647         toCompare = &pCertContext->pCertInfo->Issuer;
648     ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
649      toCompare, blob);
650     return ret;
651 }
652
653 static BOOL compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext,
654  DWORD dwType, DWORD dwFlags, const void *pvPara)
655 {
656     CERT_INFO *pCertInfo = (CERT_INFO *)pvPara;
657
658     return CertCompareCertificateName(pCertContext->dwCertEncodingType,
659      &pCertInfo->Issuer, &pCertContext->pCertInfo->Subject);
660 }
661
662 static BOOL compare_cert_by_issuer(PCCERT_CONTEXT pCertContext,
663  DWORD dwType, DWORD dwFlags, const void *pvPara)
664 {
665     return compare_cert_by_subject_cert(pCertContext, dwType, dwFlags,
666      ((PCCERT_CONTEXT)pvPara)->pCertInfo);
667 }
668
669 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
670  DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType, const void *pvPara,
671  PCCERT_CONTEXT pPrevCertContext)
672 {
673     PCCERT_CONTEXT ret;
674     CertCompareFunc compare;
675
676     TRACE("(%p, %ld, %ld, %ld, %p, %p)\n", hCertStore, dwCertEncodingType,
677          dwFlags, dwType, pvPara, pPrevCertContext);
678
679     switch (dwType >> CERT_COMPARE_SHIFT)
680     {
681     case CERT_COMPARE_ANY:
682         compare = compare_cert_any;
683         break;
684     case CERT_COMPARE_MD5_HASH:
685         compare = compare_cert_by_md5_hash;
686         break;
687     case CERT_COMPARE_SHA1_HASH:
688         compare = compare_cert_by_sha1_hash;
689         break;
690     case CERT_COMPARE_NAME:
691         compare = compare_cert_by_name;
692         break;
693     case CERT_COMPARE_SUBJECT_CERT:
694         compare = compare_cert_by_subject_cert;
695         break;
696     case CERT_COMPARE_ISSUER_OF:
697         compare = compare_cert_by_issuer;
698         break;
699     default:
700         FIXME("find type %08lx unimplemented\n", dwType);
701         compare = NULL;
702     }
703
704     if (compare)
705     {
706         BOOL matches = FALSE;
707
708         ret = pPrevCertContext;
709         do {
710             ret = CertEnumCertificatesInStore(hCertStore, ret);
711             if (ret)
712                 matches = compare(ret, dwType, dwFlags, pvPara);
713         } while (ret != NULL && !matches);
714         if (!ret)
715             SetLastError(CRYPT_E_NOT_FOUND);
716     }
717     else
718     {
719         SetLastError(CRYPT_E_NOT_FOUND);
720         ret = NULL;
721     }
722     return ret;
723 }
724
725 PCCERT_CONTEXT WINAPI CertGetSubjectCertificateFromStore(HCERTSTORE hCertStore,
726  DWORD dwCertEncodingType, PCERT_INFO pCertId)
727 {
728     TRACE("(%p, %08lx, %p)\n", hCertStore, dwCertEncodingType, pCertId);
729
730     if (!pCertId)
731     {
732         SetLastError(E_INVALIDARG);
733         return NULL;
734     }
735     return CertFindCertificateInStore(hCertStore, dwCertEncodingType, 0,
736      CERT_FIND_SUBJECT_CERT, pCertId, NULL);
737 }
738
739 BOOL WINAPI CertVerifySubjectCertificateContext(PCCERT_CONTEXT pSubject,
740  PCCERT_CONTEXT pIssuer, DWORD *pdwFlags)
741 {
742     static const DWORD supportedFlags = CERT_STORE_REVOCATION_FLAG |
743      CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG;
744
745     if (*pdwFlags & ~supportedFlags)
746     {
747         SetLastError(E_INVALIDARG);
748         return FALSE;
749     }
750     if (*pdwFlags & CERT_STORE_REVOCATION_FLAG)
751     {
752         PCCRL_CONTEXT crl = CertFindCRLInStore(pSubject->hCertStore,
753          pSubject->dwCertEncodingType, 0, CRL_FIND_ISSUED_BY, pSubject, NULL);
754
755         if (crl)
756         {
757             FIXME("check CRL for subject\n");
758         }
759         else
760             *pdwFlags |= CERT_STORE_NO_CRL_FLAG;
761     }
762     if (*pdwFlags & CERT_STORE_TIME_VALIDITY_FLAG)
763     {
764         if (0 == CertVerifyTimeValidity(NULL, pSubject->pCertInfo))
765             *pdwFlags &= ~CERT_STORE_TIME_VALIDITY_FLAG;
766     }
767     if (*pdwFlags & CERT_STORE_SIGNATURE_FLAG)
768     {
769         if (CryptVerifyCertificateSignatureEx(0, pSubject->dwCertEncodingType,
770          CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)pSubject,
771          CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)pIssuer, 0, NULL))
772             *pdwFlags &= ~CERT_STORE_SIGNATURE_FLAG;
773     }
774     return TRUE;
775 }
776
777 PCCERT_CONTEXT WINAPI CertGetIssuerCertificateFromStore(HCERTSTORE hCertStore,
778  PCCERT_CONTEXT pSubjectContext, PCCERT_CONTEXT pPrevIssuerContext,
779  DWORD *pdwFlags)
780 {
781     PCCERT_CONTEXT ret;
782
783     TRACE("(%p, %p, %p, %08lx)\n", hCertStore, pSubjectContext,
784      pPrevIssuerContext, *pdwFlags);
785
786     if (!pSubjectContext)
787     {
788         SetLastError(E_INVALIDARG);
789         return NULL;
790     }
791
792     ret = CertFindCertificateInStore(hCertStore,
793      pSubjectContext->dwCertEncodingType, 0, CERT_FIND_ISSUER_OF,
794      pSubjectContext, pPrevIssuerContext);
795     if (ret)
796     {
797         if (!CertVerifySubjectCertificateContext(pSubjectContext, ret,
798          pdwFlags))
799         {
800             CertFreeCertificateContext(ret);
801             ret = NULL;
802         }
803     }
804
805     return ret;
806 }
807
808 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
809  CRYPT_ATTRIBUTE rgAttr[])
810 {
811     PCRYPT_ATTRIBUTE ret = NULL;
812     DWORD i;
813
814     TRACE("%s %ld %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
815
816     if (!cAttr)
817         return NULL;
818     if (!pszObjId)
819     {
820         SetLastError(ERROR_INVALID_PARAMETER);
821         return NULL;
822     }
823
824     for (i = 0; !ret && i < cAttr; i++)
825         if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
826             ret = &rgAttr[i];
827     return ret;
828 }
829
830 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
831  CERT_EXTENSION rgExtensions[])
832 {
833     PCERT_EXTENSION ret = NULL;
834     DWORD i;
835
836     TRACE("%s %ld %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
837
838     if (!cExtensions)
839         return NULL;
840     if (!pszObjId)
841     {
842         SetLastError(ERROR_INVALID_PARAMETER);
843         return NULL;
844     }
845
846     for (i = 0; !ret && i < cExtensions; i++)
847         if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
848          rgExtensions[i].pszObjId))
849             ret = &rgExtensions[i];
850     return ret;
851 }
852
853 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
854 {
855     PCERT_RDN_ATTR ret = NULL;
856     DWORD i, j;
857
858     TRACE("%s %p\n", debugstr_a(pszObjId), pName);
859
860     if (!pszObjId)
861     {
862         SetLastError(ERROR_INVALID_PARAMETER);
863         return NULL;
864     }
865
866     for (i = 0; !ret && i < pName->cRDN; i++)
867         for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
868             if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
869              pName->rgRDN[i].rgRDNAttr[j].pszObjId))
870                 ret = &pName->rgRDN[i].rgRDNAttr[j];
871     return ret;
872 }
873
874 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
875  PCERT_INFO pCertInfo)
876 {
877     FILETIME fileTime;
878     LONG ret;
879
880     if (!pTimeToVerify)
881     {
882         SYSTEMTIME sysTime;
883
884         GetSystemTime(&sysTime);
885         SystemTimeToFileTime(&sysTime, &fileTime);
886         pTimeToVerify = &fileTime;
887     }
888     if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
889     {
890         ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
891         if (ret < 0)
892             ret = 0;
893     }
894     return ret;
895 }
896
897 BOOL WINAPI CryptHashCertificate(HCRYPTPROV hCryptProv, ALG_ID Algid,
898  DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
899  DWORD *pcbComputedHash)
900 {
901     BOOL ret = TRUE;
902     HCRYPTHASH hHash = 0;
903
904     TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv, Algid, dwFlags,
905      pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
906
907     if (!hCryptProv)
908         hCryptProv = CRYPT_GetDefaultProvider();
909     if (!Algid)
910         Algid = CALG_SHA1;
911     if (ret)
912     {
913         ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
914         if (ret)
915         {
916             ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
917             if (ret)
918                 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
919                  pcbComputedHash, 0);
920             CryptDestroyHash(hHash);
921         }
922     }
923     return ret;
924 }
925
926 BOOL WINAPI CryptSignCertificate(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
927  DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned,
928  DWORD cbEncodedToBeSigned, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
929  const void *pvHashAuxInfo, BYTE *pbSignature, DWORD *pcbSignature)
930 {
931     BOOL ret;
932     ALG_ID algID;
933     HCRYPTHASH hHash;
934
935     TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %p, %p, %p)\n", hCryptProv,
936      dwKeySpec, dwCertEncodingType, pbEncodedToBeSigned, cbEncodedToBeSigned,
937      pSignatureAlgorithm, pvHashAuxInfo, pbSignature, pcbSignature);
938
939     algID = CertOIDToAlgId(pSignatureAlgorithm->pszObjId);
940     if (!algID)
941     {
942         SetLastError(NTE_BAD_ALGID);
943         return FALSE;
944     }
945     if (!hCryptProv)
946     {
947         SetLastError(ERROR_INVALID_PARAMETER);
948         return FALSE;
949     }
950
951     ret = CryptCreateHash(hCryptProv, algID, 0, 0, &hHash);
952     if (ret)
953     {
954         ret = CryptHashData(hHash, pbEncodedToBeSigned, cbEncodedToBeSigned, 0);
955         if (ret)
956             ret = CryptSignHashW(hHash, dwKeySpec, NULL, 0, pbSignature,
957              pcbSignature);
958         CryptDestroyHash(hHash);
959     }
960     return ret;
961 }
962
963 BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV hCryptProv,
964  DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
965  PCERT_PUBLIC_KEY_INFO pPublicKey)
966 {
967     return CryptVerifyCertificateSignatureEx(hCryptProv, dwCertEncodingType,
968      CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, (void *)pbEncoded,
969      CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
970 }
971
972 static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV hCryptProv,
973  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pubKeyInfo,
974  PCERT_SIGNED_CONTENT_INFO signedCert)
975 {
976     BOOL ret;
977     ALG_ID algID = CertOIDToAlgId(pubKeyInfo->Algorithm.pszObjId);
978     HCRYPTKEY key;
979
980     /* Load the default provider if necessary */
981     if (!hCryptProv)
982         hCryptProv = CRYPT_GetDefaultProvider();
983     ret = CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType,
984      pubKeyInfo, algID, 0, NULL, &key);
985     if (ret)
986     {
987         HCRYPTHASH hash;
988
989         /* Some key algorithms aren't hash algorithms, so map them */
990         if (algID == CALG_RSA_SIGN || algID == CALG_RSA_KEYX)
991             algID = CALG_SHA1;
992         ret = CryptCreateHash(hCryptProv, algID, 0, 0, &hash);
993         if (ret)
994         {
995             ret = CryptHashData(hash, signedCert->ToBeSigned.pbData,
996              signedCert->ToBeSigned.cbData, 0);
997             if (ret)
998                 ret = CryptVerifySignatureW(hash, signedCert->Signature.pbData,
999                  signedCert->Signature.cbData, key, NULL, 0);
1000             CryptDestroyHash(hash);
1001         }
1002         CryptDestroyKey(key);
1003     }
1004     return ret;
1005 }
1006
1007 BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV hCryptProv,
1008  DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
1009  DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
1010 {
1011     BOOL ret = TRUE;
1012     CRYPT_DATA_BLOB subjectBlob;
1013
1014     TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %08lx, %p)\n", hCryptProv,
1015      dwCertEncodingType, dwSubjectType, pvSubject, dwIssuerType, pvIssuer,
1016      dwFlags, pvReserved);
1017
1018     switch (dwSubjectType)
1019     {
1020     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB:
1021     {
1022         PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvSubject;
1023
1024         subjectBlob.pbData = blob->pbData;
1025         subjectBlob.cbData = blob->cbData;
1026         break;
1027     }
1028     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT:
1029     {
1030         PCERT_CONTEXT context = (PCERT_CONTEXT)pvSubject;
1031
1032         subjectBlob.pbData = context->pbCertEncoded;
1033         subjectBlob.cbData = context->cbCertEncoded;
1034         break;
1035     }
1036     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL:
1037     {
1038         PCRL_CONTEXT context = (PCRL_CONTEXT)pvSubject;
1039
1040         subjectBlob.pbData = context->pbCrlEncoded;
1041         subjectBlob.cbData = context->cbCrlEncoded;
1042         break;
1043     }
1044     default:
1045         SetLastError(E_INVALIDARG);
1046         ret = FALSE;
1047     }
1048
1049     if (ret)
1050     {
1051         PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
1052         DWORD size = 0;
1053
1054         ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
1055          subjectBlob.pbData, subjectBlob.cbData,
1056          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1057          (BYTE *)&signedCert, &size);
1058         if (ret)
1059         {
1060             switch (dwIssuerType)
1061             {
1062             case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY:
1063                 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
1064                  dwCertEncodingType, (PCERT_PUBLIC_KEY_INFO)pvIssuer,
1065                  signedCert);
1066                 break;
1067             case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT:
1068                 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
1069                  dwCertEncodingType,
1070                  &((PCCERT_CONTEXT)pvIssuer)->pCertInfo->SubjectPublicKeyInfo,
1071                  signedCert);
1072                 break;
1073             case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN:
1074                 FIXME("CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: stub\n");
1075                 ret = FALSE;
1076                 break;
1077             case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL:
1078                 if (pvIssuer)
1079                 {
1080                     SetLastError(E_INVALIDARG);
1081                     ret = FALSE;
1082                 }
1083                 else
1084                 {
1085                     FIXME("unimplemented for NULL signer\n");
1086                     SetLastError(E_INVALIDARG);
1087                     ret = FALSE;
1088                 }
1089                 break;
1090             default:
1091                 SetLastError(E_INVALIDARG);
1092                 ret = FALSE;
1093             }
1094             LocalFree(signedCert);
1095         }
1096     }
1097     return ret;
1098 }
1099
1100 BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags,
1101  PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage)
1102 {
1103     PCERT_ENHKEY_USAGE usage = NULL;
1104     DWORD bytesNeeded;
1105     BOOL ret = TRUE;
1106
1107     if (!pCertContext || !pcbUsage)
1108     {
1109         SetLastError(ERROR_INVALID_PARAMETER);
1110         return FALSE;
1111     }
1112
1113     TRACE("(%p, %08lx, %p, %ld)\n", pCertContext, dwFlags, pUsage, *pcbUsage);
1114
1115     if (!(dwFlags & CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG))
1116     {
1117         DWORD propSize = 0;
1118
1119         if (CertGetCertificateContextProperty(pCertContext,
1120          CERT_ENHKEY_USAGE_PROP_ID, NULL, &propSize))
1121         {
1122             LPBYTE buf = CryptMemAlloc(propSize);
1123
1124             if (buf)
1125             {
1126                 if (CertGetCertificateContextProperty(pCertContext,
1127                  CERT_ENHKEY_USAGE_PROP_ID, buf, &propSize))
1128                 {
1129                     ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
1130                      X509_ENHANCED_KEY_USAGE, buf, propSize,
1131                      CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
1132                 }
1133                 CryptMemFree(buf);
1134             }
1135         }
1136     }
1137     if (!usage && !(dwFlags & CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG))
1138     {
1139         PCERT_EXTENSION ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
1140          pCertContext->pCertInfo->cExtension,
1141          pCertContext->pCertInfo->rgExtension);
1142
1143         if (ext)
1144         {
1145             ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
1146              X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
1147              CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
1148         }
1149     }
1150     if (!usage)
1151     {
1152         /* If a particular location is specified, this should fail.  Otherwise
1153          * it should succeed with an empty usage.  (This is true on Win2k and
1154          * later, which we emulate.)
1155          */
1156         if (dwFlags)
1157         {
1158             SetLastError(CRYPT_E_NOT_FOUND);
1159             ret = FALSE;
1160         }
1161         else
1162             bytesNeeded = sizeof(CERT_ENHKEY_USAGE);
1163     }
1164
1165     if (ret)
1166     {
1167         if (!pUsage)
1168             *pcbUsage = bytesNeeded;
1169         else if (*pcbUsage < bytesNeeded)
1170         {
1171             SetLastError(ERROR_MORE_DATA);
1172             *pcbUsage = bytesNeeded;
1173             ret = FALSE;
1174         }
1175         else
1176         {
1177             *pcbUsage = bytesNeeded;
1178             if (usage)
1179             {
1180                 DWORD i;
1181                 LPSTR nextOID = (LPSTR)((LPBYTE)pUsage +
1182                  sizeof(CERT_ENHKEY_USAGE) +
1183                  usage->cUsageIdentifier * sizeof(LPSTR));
1184
1185                 pUsage->cUsageIdentifier = usage->cUsageIdentifier;
1186                 pUsage->rgpszUsageIdentifier = (LPSTR *)((LPBYTE)pUsage +
1187                  sizeof(CERT_ENHKEY_USAGE));
1188                 for (i = 0; i < usage->cUsageIdentifier; i++)
1189                 {
1190                     pUsage->rgpszUsageIdentifier[i] = nextOID;
1191                     strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
1192                     nextOID += strlen(nextOID) + 1;
1193                 }
1194             }
1195             else
1196                 pUsage->cUsageIdentifier = 0;
1197         }
1198     }
1199     if (usage)
1200         LocalFree(usage);
1201     TRACE("returning %d\n", ret);
1202     return ret;
1203 }
1204
1205 BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext,
1206  PCERT_ENHKEY_USAGE pUsage)
1207 {
1208     BOOL ret;
1209
1210     TRACE("(%p, %p)\n", pCertContext, pUsage);
1211
1212     if (pUsage)
1213     {
1214         CRYPT_DATA_BLOB blob = { 0, NULL };
1215
1216         ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
1217          pUsage, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData, &blob.cbData);
1218         if (ret)
1219         {
1220             ret = CertSetCertificateContextProperty(pCertContext,
1221              CERT_ENHKEY_USAGE_PROP_ID, 0, &blob);
1222             LocalFree(blob.pbData);
1223         }
1224     }
1225     else
1226         ret = CertSetCertificateContextProperty(pCertContext,
1227          CERT_ENHKEY_USAGE_PROP_ID, 0, NULL);
1228     return ret;
1229 }
1230
1231 BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
1232  LPCSTR pszUsageIdentifier)
1233 {
1234     BOOL ret;
1235     DWORD size;
1236
1237     TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
1238
1239     if (CertGetEnhancedKeyUsage(pCertContext,
1240      CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size))
1241     {
1242         PCERT_ENHKEY_USAGE usage = CryptMemAlloc(size);
1243
1244         if (usage)
1245         {
1246             ret = CertGetEnhancedKeyUsage(pCertContext,
1247              CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size);
1248             if (ret)
1249             {
1250                 PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size +
1251                  sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
1252
1253                 if (newUsage)
1254                 {
1255                     LPSTR nextOID;
1256                     DWORD i;
1257
1258                     newUsage->rgpszUsageIdentifier =
1259                      (LPSTR *)((LPBYTE)newUsage + sizeof(CERT_ENHKEY_USAGE));
1260                     nextOID = (LPSTR)((LPBYTE)newUsage->rgpszUsageIdentifier +
1261                      (usage->cUsageIdentifier + 1) * sizeof(LPSTR));
1262                     for (i = 0; i < usage->cUsageIdentifier; i++)
1263                     {
1264                         newUsage->rgpszUsageIdentifier[i] = nextOID;
1265                         strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
1266                         nextOID += strlen(nextOID) + 1;
1267                     }
1268                     newUsage->rgpszUsageIdentifier[i] = nextOID;
1269                     strcpy(nextOID, pszUsageIdentifier);
1270                     newUsage->cUsageIdentifier = i + 1;
1271                     ret = CertSetEnhancedKeyUsage(pCertContext, newUsage);
1272                     CryptMemFree(newUsage);
1273                 }
1274             }
1275             CryptMemFree(usage);
1276         }
1277         else
1278             ret = FALSE;
1279     }
1280     else
1281     {
1282         PCERT_ENHKEY_USAGE usage = CryptMemAlloc(sizeof(CERT_ENHKEY_USAGE) +
1283          sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
1284
1285         if (usage)
1286         {
1287             usage->rgpszUsageIdentifier =
1288              (LPSTR *)((LPBYTE)usage + sizeof(CERT_ENHKEY_USAGE));
1289             usage->rgpszUsageIdentifier[0] = (LPSTR)((LPBYTE)usage +
1290              sizeof(CERT_ENHKEY_USAGE) + sizeof(LPSTR));
1291             strcpy(usage->rgpszUsageIdentifier[0], pszUsageIdentifier);
1292             usage->cUsageIdentifier = 1;
1293             ret = CertSetEnhancedKeyUsage(pCertContext, usage);
1294             CryptMemFree(usage);
1295         }
1296         else
1297             ret = FALSE;
1298     }
1299     return ret;
1300 }
1301
1302 BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
1303  LPCSTR pszUsageIdentifier)
1304 {
1305     BOOL ret;
1306     DWORD size;
1307     CERT_ENHKEY_USAGE usage;
1308
1309     TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
1310
1311     size = sizeof(usage);
1312     ret = CertGetEnhancedKeyUsage(pCertContext,
1313      CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, &usage, &size);
1314     if (!ret && GetLastError() == ERROR_MORE_DATA)
1315     {
1316         PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
1317
1318         if (pUsage)
1319         {
1320             ret = CertGetEnhancedKeyUsage(pCertContext,
1321              CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
1322             if (ret)
1323             {
1324                 if (pUsage->cUsageIdentifier)
1325                 {
1326                     DWORD i;
1327                     BOOL found = FALSE;
1328
1329                     for (i = 0; i < pUsage->cUsageIdentifier; i++)
1330                     {
1331                         if (!strcmp(pUsage->rgpszUsageIdentifier[i],
1332                          pszUsageIdentifier))
1333                             found = TRUE;
1334                         if (found && i < pUsage->cUsageIdentifier - 1)
1335                             pUsage->rgpszUsageIdentifier[i] =
1336                              pUsage->rgpszUsageIdentifier[i + 1];
1337                     }
1338                     pUsage->cUsageIdentifier--;
1339                     /* Remove the usage if it's empty */
1340                     if (pUsage->cUsageIdentifier)
1341                         ret = CertSetEnhancedKeyUsage(pCertContext, pUsage);
1342                     else
1343                         ret = CertSetEnhancedKeyUsage(pCertContext, NULL);
1344                 }
1345             }
1346             CryptMemFree(pUsage);
1347         }
1348         else
1349             ret = FALSE;
1350     }
1351     else
1352     {
1353         /* it fit in an empty usage, therefore there's nothing to remove */
1354         ret = TRUE;
1355     }
1356     return ret;
1357 }
1358
1359 BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts,
1360  int *cNumOIDSs, LPSTR *rghOIDs, DWORD *pcbOIDs)
1361 {
1362     BOOL ret = TRUE;
1363     DWORD i, cbOIDs = 0;
1364     BOOL allUsagesValid = TRUE;
1365     CERT_ENHKEY_USAGE validUsages = { 0, NULL };
1366
1367     TRACE("(%ld, %p, %p, %p, %ld)\n", cCerts, *rghCerts, cNumOIDSs,
1368      rghOIDs, *pcbOIDs);
1369
1370     for (i = 0; ret && i < cCerts; i++)
1371     {
1372         CERT_ENHKEY_USAGE usage;
1373         DWORD size = sizeof(usage);
1374
1375         ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, &usage, &size);
1376         /* Success is deliberately ignored: it implies all usages are valid */
1377         if (!ret && GetLastError() == ERROR_MORE_DATA)
1378         {
1379             PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
1380
1381             allUsagesValid = FALSE;
1382             if (pUsage)
1383             {
1384                 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, pUsage, &size);
1385                 if (ret)
1386                 {
1387                     if (!validUsages.cUsageIdentifier)
1388                     {
1389                         DWORD j;
1390
1391                         cbOIDs = pUsage->cUsageIdentifier * sizeof(LPSTR);
1392                         validUsages.cUsageIdentifier = pUsage->cUsageIdentifier;
1393                         for (j = 0; j < validUsages.cUsageIdentifier; j++)
1394                             cbOIDs += lstrlenA(pUsage->rgpszUsageIdentifier[j])
1395                              + 1;
1396                         validUsages.rgpszUsageIdentifier =
1397                          CryptMemAlloc(cbOIDs);
1398                         if (validUsages.rgpszUsageIdentifier)
1399                         {
1400                             LPSTR nextOID = (LPSTR)
1401                              ((LPBYTE)validUsages.rgpszUsageIdentifier +
1402                              validUsages.cUsageIdentifier * sizeof(LPSTR));
1403
1404                             for (j = 0; j < validUsages.cUsageIdentifier; j++)
1405                             {
1406                                 validUsages.rgpszUsageIdentifier[j] = nextOID;
1407                                 lstrcpyA(validUsages.rgpszUsageIdentifier[j],
1408                                  pUsage->rgpszUsageIdentifier[j]);
1409                                 nextOID += lstrlenA(nextOID) + 1;
1410                             }
1411                         }
1412                         else
1413                             ret = FALSE;
1414                     }
1415                     else
1416                     {
1417                         DWORD j, k, validIndexes = 0, numRemoved = 0;
1418
1419                         /* Merge: build a bitmap of all the indexes of
1420                          * validUsages.rgpszUsageIdentifier that are in pUsage.
1421                          */
1422                         for (j = 0; j < pUsage->cUsageIdentifier; j++)
1423                         {
1424                             for (k = 0; k < validUsages.cUsageIdentifier; k++)
1425                             {
1426                                 if (!strcmp(pUsage->rgpszUsageIdentifier[j],
1427                                  validUsages.rgpszUsageIdentifier[k]))
1428                                 {
1429                                     validIndexes |= (1 << k);
1430                                     break;
1431                                 }
1432                             }
1433                         }
1434                         /* Merge by removing from validUsages those that are
1435                          * not in the bitmap.
1436                          */
1437                         for (j = 0; j < validUsages.cUsageIdentifier; j++)
1438                         {
1439                             if (!(validIndexes & (1 << j)))
1440                             {
1441                                 if (j < validUsages.cUsageIdentifier - 1)
1442                                 {
1443                                     memcpy(&validUsages.rgpszUsageIdentifier[j],
1444                                      &validUsages.rgpszUsageIdentifier[j +
1445                                      numRemoved + 1],
1446                                      (validUsages.cUsageIdentifier - numRemoved
1447                                      - j - 1) * sizeof(LPSTR));
1448                                     cbOIDs -= lstrlenA(
1449                                      validUsages.rgpszUsageIdentifier[j]) + 1 +
1450                                      sizeof(LPSTR);
1451                                     numRemoved++;
1452                                 }
1453                                 else
1454                                     validUsages.cUsageIdentifier--;
1455                             }
1456                         }
1457                     }
1458                 }
1459                 CryptMemFree(pUsage);
1460             }
1461             else
1462                 ret = FALSE;
1463         }
1464     }
1465     if (ret)
1466     {
1467         if (allUsagesValid)
1468         {
1469             *cNumOIDSs = -1;
1470             *pcbOIDs = 0;
1471         }
1472         else
1473         {
1474             if (!rghOIDs || *pcbOIDs < cbOIDs)
1475             {
1476                 *pcbOIDs = cbOIDs;
1477                 SetLastError(ERROR_MORE_DATA);
1478                 ret = FALSE;
1479             }
1480             else
1481             {
1482                 LPSTR nextOID = (LPSTR)((LPBYTE)rghOIDs +
1483                  validUsages.cUsageIdentifier * sizeof(LPSTR));
1484
1485                 *pcbOIDs = cbOIDs;
1486                 *cNumOIDSs = validUsages.cUsageIdentifier;
1487                 for (i = 0; i < validUsages.cUsageIdentifier; i++)
1488                 {
1489                     rghOIDs[i] = nextOID;
1490                     lstrcpyA(nextOID, validUsages.rgpszUsageIdentifier[i]);
1491                     nextOID += lstrlenA(nextOID) + 1;
1492                 }
1493             }
1494         }
1495     }
1496     CryptMemFree(validUsages.rgpszUsageIdentifier);
1497     return ret;
1498 }
1499
1500 /* Sets the CERT_KEY_PROV_INFO_PROP_ID property of context from pInfo, or, if
1501  * pInfo is NULL, from the attributes of hProv.
1502  */
1503 static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context,
1504  PCRYPT_KEY_PROV_INFO pInfo, HCRYPTPROV hProv)
1505 {
1506     CRYPT_KEY_PROV_INFO info = { 0 };
1507     BOOL ret;
1508
1509     if (!pInfo)
1510     {
1511         DWORD size;
1512         int len;
1513
1514         ret = CryptGetProvParam(hProv, PP_CONTAINER, NULL, &size, 0);
1515         if (ret)
1516         {
1517             LPSTR szContainer = CryptMemAlloc(size);
1518
1519             if (szContainer)
1520             {
1521                 ret = CryptGetProvParam(hProv, PP_CONTAINER,
1522                  (BYTE *)szContainer, &size, 0);
1523                 if (ret)
1524                 {
1525                     len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
1526                      NULL, 0);
1527                     if (len)
1528                     {
1529                         info.pwszContainerName = CryptMemAlloc(len *
1530                          sizeof(WCHAR));
1531                         len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
1532                          info.pwszContainerName, len);
1533                     }
1534                 }
1535                 CryptMemFree(szContainer);
1536             }
1537         }
1538         ret = CryptGetProvParam(hProv, PP_NAME, NULL, &size, 0);
1539         if (ret)
1540         {
1541             LPSTR szProvider = CryptMemAlloc(size);
1542
1543             if (szProvider)
1544             {
1545                 ret = CryptGetProvParam(hProv, PP_NAME, (BYTE *)szProvider,
1546                  &size, 0);
1547                 if (ret)
1548                 {
1549                     len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
1550                      NULL, 0);
1551                     if (len)
1552                     {
1553                         info.pwszProvName = CryptMemAlloc(len *
1554                          sizeof(WCHAR));
1555                         len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
1556                          info.pwszProvName, len);
1557                     }
1558                 }
1559                 CryptMemFree(szProvider);
1560             }
1561         }
1562         size = sizeof(info.dwKeySpec);
1563         ret = CryptGetProvParam(hProv, PP_KEYSPEC, (LPBYTE)&info.dwKeySpec,
1564          &size, 0);
1565         if (!ret)
1566             info.dwKeySpec = AT_SIGNATURE;
1567         size = sizeof(info.dwProvType);
1568         ret = CryptGetProvParam(hProv, PP_PROVTYPE, (LPBYTE)&info.dwProvType,
1569          &size, 0);
1570         if (!ret)
1571             info.dwProvType = PROV_RSA_FULL;
1572         pInfo = &info;
1573     }
1574
1575     ret = CertSetCertificateContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID,
1576      0, pInfo);
1577
1578     if (pInfo == &info)
1579     {
1580         CryptMemFree(info.pwszContainerName);
1581         CryptMemFree(info.pwszProvName);
1582     }
1583 }
1584
1585 /* Creates a signed certificate context from the unsigned, encoded certificate
1586  * in blob, using the crypto provider hProv and the signature algorithm sigAlgo.
1587  */
1588 static PCCERT_CONTEXT CRYPT_CreateSignedCert(PCRYPT_DER_BLOB blob,
1589  HCRYPTPROV hProv, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo)
1590 {
1591     PCCERT_CONTEXT context = NULL;
1592     BOOL ret;
1593     DWORD sigSize = 0;
1594
1595     ret = CryptSignCertificate(hProv, AT_SIGNATURE, X509_ASN_ENCODING,
1596      blob->pbData, blob->cbData, sigAlgo, NULL, NULL, &sigSize);
1597     if (ret)
1598     {
1599         LPBYTE sig = CryptMemAlloc(sigSize);
1600
1601         ret = CryptSignCertificate(hProv, AT_SIGNATURE, X509_ASN_ENCODING,
1602          blob->pbData, blob->cbData, sigAlgo, NULL, sig, &sigSize);
1603         if (ret)
1604         {
1605             CERT_SIGNED_CONTENT_INFO signedInfo;
1606             BYTE *encodedSignedCert = NULL;
1607             DWORD encodedSignedCertSize = 0;
1608
1609             signedInfo.ToBeSigned.cbData = blob->cbData;
1610             signedInfo.ToBeSigned.pbData = blob->pbData;
1611             memcpy(&signedInfo.SignatureAlgorithm, sigAlgo,
1612              sizeof(signedInfo.SignatureAlgorithm));
1613             signedInfo.Signature.cbData = sigSize;
1614             signedInfo.Signature.pbData = sig;
1615             signedInfo.Signature.cUnusedBits = 0;
1616             ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT,
1617              &signedInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
1618              (BYTE *)&encodedSignedCert, &encodedSignedCertSize);
1619             if (ret)
1620             {
1621                 context = CertCreateCertificateContext(X509_ASN_ENCODING,
1622                  encodedSignedCert, encodedSignedCertSize);
1623                 LocalFree(encodedSignedCert);
1624             }
1625         }
1626         CryptMemFree(sig);
1627     }
1628     return context;
1629 }
1630
1631 /* Copies data from the parameters into info, where:
1632  * pSubjectIssuerBlob: Specifies both the subject and issuer for info.
1633  *                     Must not be NULL
1634  * pSignatureAlgorithm: Optional.
1635  * pStartTime: The starting time of the certificate.  If NULL, the current
1636  *             system time is used.
1637  * pEndTime: The ending time of the certificate.  If NULL, one year past the
1638  *           starting time is used.
1639  * pubKey: The public key of the certificate.  Must not be NULL.
1640  * pExtensions: Extensions to be included with the certificate.  Optional.
1641  */
1642 static void CRYPT_MakeCertInfo(PCERT_INFO info,
1643  PCERT_NAME_BLOB pSubjectIssuerBlob,
1644  PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime,
1645  PSYSTEMTIME pEndTime, PCERT_PUBLIC_KEY_INFO pubKey,
1646  PCERT_EXTENSIONS pExtensions)
1647 {
1648     /* FIXME: what serial number to use? */
1649     static const BYTE serialNum[] = { 1 };
1650     static CHAR oid[] = szOID_RSA_SHA1RSA;
1651
1652     assert(info);
1653     assert(pSubjectIssuerBlob);
1654     assert(pubKey);
1655
1656     info->dwVersion = CERT_V3;
1657     info->SerialNumber.cbData = sizeof(serialNum);
1658     info->SerialNumber.pbData = (LPBYTE)serialNum;
1659     if (pSignatureAlgorithm)
1660         memcpy(&info->SignatureAlgorithm, pSignatureAlgorithm,
1661          sizeof(info->SignatureAlgorithm));
1662     else
1663     {
1664         info->SignatureAlgorithm.pszObjId = oid;
1665         info->SignatureAlgorithm.Parameters.cbData = 0;
1666         info->SignatureAlgorithm.Parameters.pbData = NULL;
1667     }
1668     info->Issuer.cbData = pSubjectIssuerBlob->cbData;
1669     info->Issuer.pbData = pSubjectIssuerBlob->pbData;
1670     if (pStartTime)
1671         SystemTimeToFileTime(pStartTime, &info->NotBefore);
1672     else
1673         GetSystemTimeAsFileTime(&info->NotBefore);
1674     if (pEndTime)
1675         SystemTimeToFileTime(pStartTime, &info->NotAfter);
1676     else
1677     {
1678         SYSTEMTIME endTime;
1679
1680         if (FileTimeToSystemTime(&info->NotBefore, &endTime))
1681         {
1682             endTime.wYear++;
1683             SystemTimeToFileTime(&endTime, &info->NotAfter);
1684         }
1685     }
1686     info->Subject.cbData = pSubjectIssuerBlob->cbData;
1687     info->Subject.pbData = pSubjectIssuerBlob->pbData;
1688     memcpy(&info->SubjectPublicKeyInfo, pubKey,
1689      sizeof(info->SubjectPublicKeyInfo));
1690     if (pExtensions)
1691     {
1692         info->cExtension = pExtensions->cExtension;
1693         info->rgExtension = pExtensions->rgExtension;
1694     }
1695     else
1696     {
1697         info->cExtension = 0;
1698         info->rgExtension = NULL;
1699     }
1700 }
1701  
1702 typedef RPC_STATUS (RPC_ENTRY *UuidCreateFunc)(UUID *);
1703 typedef RPC_STATUS (RPC_ENTRY *UuidToStringFunc)(UUID *, unsigned char **);
1704 typedef RPC_STATUS (RPC_ENTRY *RpcStringFreeFunc)(unsigned char **);
1705
1706 static HCRYPTPROV CRYPT_CreateKeyProv(void)
1707 {
1708     HCRYPTPROV hProv = 0;
1709     HMODULE rpcrt = LoadLibraryA("rpcrt4");
1710
1711     if (rpcrt)
1712     {
1713         UuidCreateFunc uuidCreate = (UuidCreateFunc)GetProcAddress(rpcrt,
1714          "UuidCreate");
1715         UuidToStringFunc uuidToString = (UuidToStringFunc)GetProcAddress(rpcrt,
1716          "UuidToString");
1717         RpcStringFreeFunc rpcStringFree = (RpcStringFreeFunc)GetProcAddress(
1718          rpcrt, "RpcStringFree");
1719
1720         if (uuidCreate && uuidToString && rpcStringFree)
1721         {
1722             UUID uuid;
1723             RPC_STATUS status = uuidCreate(&uuid);
1724
1725             if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY)
1726             {
1727                 unsigned char *uuidStr;
1728
1729                 status = uuidToString(&uuid, &uuidStr);
1730                 if (status == RPC_S_OK)
1731                 {
1732                     BOOL ret = CryptAcquireContextA(&hProv, (LPCSTR)uuidStr,
1733                      MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_NEWKEYSET);
1734
1735                     if (ret)
1736                     {
1737                         HCRYPTKEY key;
1738
1739                         ret = CryptGenKey(hProv, AT_SIGNATURE, 0, &key);
1740                         if (ret)
1741                             CryptDestroyKey(key);
1742                     }
1743                     rpcStringFree(&uuidStr);
1744                 }
1745             }
1746         }
1747         FreeLibrary(rpcrt);
1748     }
1749     return hProv;
1750 }
1751
1752 PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV hProv,
1753  PCERT_NAME_BLOB pSubjectIssuerBlob, DWORD dwFlags,
1754  PCRYPT_KEY_PROV_INFO pKeyProvInfo,
1755  PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime,
1756  PSYSTEMTIME pEndTime, PCERT_EXTENSIONS pExtensions)
1757 {
1758     PCCERT_CONTEXT context = NULL;
1759     BOOL ret, releaseContext = FALSE;
1760     PCERT_PUBLIC_KEY_INFO pubKey = NULL;
1761     DWORD pubKeySize = 0;
1762
1763     TRACE("(0x%08lx, %p, %08lx, %p, %p, %p, %p, %p)\n", hProv,
1764      pSubjectIssuerBlob, dwFlags, pKeyProvInfo, pSignatureAlgorithm, pStartTime,
1765      pExtensions, pExtensions);
1766
1767     if (!hProv)
1768     {
1769         hProv = CRYPT_CreateKeyProv();
1770         releaseContext = TRUE;
1771     }
1772
1773     CryptExportPublicKeyInfo(hProv, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
1774      &pubKeySize);
1775     pubKey = CryptMemAlloc(pubKeySize);
1776     if (pubKey)
1777     {
1778         ret = CryptExportPublicKeyInfo(hProv, AT_SIGNATURE, X509_ASN_ENCODING,
1779          pubKey, &pubKeySize);
1780         if (ret)
1781         {
1782             CERT_INFO info = { 0 };
1783             CRYPT_DER_BLOB blob = { 0, NULL };
1784             BOOL ret;
1785
1786             CRYPT_MakeCertInfo(&info, pSubjectIssuerBlob, pSignatureAlgorithm,
1787              pStartTime, pEndTime, pubKey, pExtensions);
1788             ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
1789              &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&blob.pbData,
1790              &blob.cbData);
1791             if (ret)
1792             {
1793                 if (!(dwFlags & CERT_CREATE_SELFSIGN_NO_SIGN))
1794                     context = CRYPT_CreateSignedCert(&blob, hProv,
1795                      &info.SignatureAlgorithm);
1796                 else
1797                     context = CertCreateCertificateContext(X509_ASN_ENCODING,
1798                      blob.pbData, blob.cbData);
1799                 if (context && !(dwFlags & CERT_CREATE_SELFSIGN_NO_KEY_INFO))
1800                     CertContext_SetKeyProvInfo(context, pKeyProvInfo, hProv);
1801                 LocalFree(blob.pbData);
1802             }
1803         }
1804         CryptMemFree(pubKey);
1805     }
1806     if (releaseContext)
1807         CryptReleaseContext(hProv, 0);
1808     return context;
1809 }