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