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