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