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