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