wintrust: Use path in WIN_TRUST_SUBJECT_FILE structure rather than assuming a path...
[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     switch (GET_CERT_ENCODING_TYPE(dwCertEncodingType))
792     {
793     case 0:     /* Seems to mean "raw binary bits" */
794         if (pPublicKey1->PublicKey.cbData == pPublicKey2->PublicKey.cbData &&
795          pPublicKey1->PublicKey.cUnusedBits == pPublicKey2->PublicKey.cUnusedBits)
796         {
797           if (pPublicKey2->PublicKey.cbData)
798               ret = !memcmp(pPublicKey1->PublicKey.pbData,
799                pPublicKey2->PublicKey.pbData, pPublicKey1->PublicKey.cbData);
800           else
801               ret = TRUE;
802         }
803         else
804             ret = FALSE;
805         break;
806     default:
807         WARN("Unknown encoding type %08x\n", dwCertEncodingType);
808         /* FALLTHROUGH */
809     case X509_ASN_ENCODING:
810     {
811         BLOBHEADER *pblob1, *pblob2;
812         DWORD length;
813         ret = FALSE;
814         if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
815                     pPublicKey1->PublicKey.pbData, pPublicKey1->PublicKey.cbData,
816                     0, NULL, &length))
817         {
818             pblob1 = CryptMemAlloc(length);
819             if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
820                     pPublicKey1->PublicKey.pbData, pPublicKey1->PublicKey.cbData,
821                     0, pblob1, &length))
822             {
823                 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
824                             pPublicKey2->PublicKey.pbData, pPublicKey2->PublicKey.cbData,
825                             0, NULL, &length))
826                 {
827                     pblob2 = CryptMemAlloc(length);
828                     if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
829                             pPublicKey2->PublicKey.pbData, pPublicKey2->PublicKey.cbData,
830                             0, pblob2, &length))
831                     {
832                         /* The RSAPUBKEY structure directly follows the BLOBHEADER */
833                         RSAPUBKEY *pk1 = (LPVOID)(pblob1 + 1),
834                                   *pk2 = (LPVOID)(pblob2 + 1);
835                         ret = (pk1->bitlen == pk2->bitlen) && (pk1->pubexp == pk2->pubexp)
836                                  && !memcmp(pk1 + 1, pk2 + 1, pk1->bitlen/8);
837                     }
838                     CryptMemFree(pblob2);
839                 }
840             }
841             CryptMemFree(pblob1);
842         }
843
844         break;
845     }
846     }
847     return ret;
848 }
849
850 DWORD WINAPI CertGetPublicKeyLength(DWORD dwCertEncodingType,
851  PCERT_PUBLIC_KEY_INFO pPublicKey)
852 {
853     DWORD len = 0;
854
855     TRACE("(%08x, %p)\n", dwCertEncodingType, pPublicKey);
856
857     if (GET_CERT_ENCODING_TYPE(dwCertEncodingType) != X509_ASN_ENCODING)
858     {
859         SetLastError(ERROR_FILE_NOT_FOUND);
860         return 0;
861     }
862     if (pPublicKey->Algorithm.pszObjId &&
863      !strcmp(pPublicKey->Algorithm.pszObjId, szOID_RSA_DH))
864     {
865         FIXME("unimplemented for DH public keys\n");
866         SetLastError(CRYPT_E_ASN1_BADTAG);
867     }
868     else
869     {
870         DWORD size;
871         PBYTE buf;
872         BOOL ret = CryptDecodeObjectEx(dwCertEncodingType,
873          RSA_CSP_PUBLICKEYBLOB, pPublicKey->PublicKey.pbData,
874          pPublicKey->PublicKey.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf,
875          &size);
876
877         if (ret)
878         {
879             RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
880
881             len = rsaPubKey->bitlen;
882             LocalFree(buf);
883         }
884     }
885     return len;
886 }
887
888 typedef BOOL (*CertCompareFunc)(PCCERT_CONTEXT pCertContext, DWORD dwType,
889  DWORD dwFlags, const void *pvPara);
890
891 static BOOL compare_cert_any(PCCERT_CONTEXT pCertContext, DWORD dwType,
892  DWORD dwFlags, const void *pvPara)
893 {
894     return TRUE;
895 }
896
897 static BOOL compare_cert_by_md5_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
898  DWORD dwFlags, const void *pvPara)
899 {
900     BOOL ret;
901     BYTE hash[16];
902     DWORD size = sizeof(hash);
903
904     ret = CertGetCertificateContextProperty(pCertContext,
905      CERT_MD5_HASH_PROP_ID, hash, &size);
906     if (ret)
907     {
908         const CRYPT_HASH_BLOB *pHash = (const CRYPT_HASH_BLOB *)pvPara;
909
910         if (size == pHash->cbData)
911             ret = !memcmp(pHash->pbData, hash, size);
912         else
913             ret = FALSE;
914     }
915     return ret;
916 }
917
918 static BOOL compare_cert_by_sha1_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
919  DWORD dwFlags, const void *pvPara)
920 {
921     BOOL ret;
922     BYTE hash[20];
923     DWORD size = sizeof(hash);
924
925     ret = CertGetCertificateContextProperty(pCertContext,
926      CERT_SHA1_HASH_PROP_ID, hash, &size);
927     if (ret)
928     {
929         const CRYPT_HASH_BLOB *pHash = (const CRYPT_HASH_BLOB *)pvPara;
930
931         if (size == pHash->cbData)
932             ret = !memcmp(pHash->pbData, hash, size);
933         else
934             ret = FALSE;
935     }
936     return ret;
937 }
938
939 static BOOL compare_cert_by_name(PCCERT_CONTEXT pCertContext, DWORD dwType,
940  DWORD dwFlags, const void *pvPara)
941 {
942     CERT_NAME_BLOB *blob = (CERT_NAME_BLOB *)pvPara, *toCompare;
943     BOOL ret;
944
945     if (dwType & CERT_INFO_SUBJECT_FLAG)
946         toCompare = &pCertContext->pCertInfo->Subject;
947     else
948         toCompare = &pCertContext->pCertInfo->Issuer;
949     ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
950      toCompare, blob);
951     return ret;
952 }
953
954 static BOOL compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext,
955  DWORD dwType, DWORD dwFlags, const void *pvPara)
956 {
957     CERT_INFO *pCertInfo = (CERT_INFO *)pvPara;
958     BOOL ret;
959
960     /* Matching serial number and subject match.. */
961     ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
962      &pCertInfo->Issuer, &pCertContext->pCertInfo->Subject);
963     if (ret)
964         ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
965          &pCertInfo->SerialNumber);
966     else
967     {
968         /* failing that, if the serial number and issuer match, we match */
969         ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
970          &pCertInfo->SerialNumber);
971         if (ret)
972             ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
973              &pCertInfo->Issuer, &pCertContext->pCertInfo->Issuer);
974     }
975     TRACE("returning %d\n", ret);
976     return ret;
977 }
978
979 static BOOL compare_cert_by_cert_id(PCCERT_CONTEXT pCertContext, DWORD dwType,
980  DWORD dwFlags, const void *pvPara)
981 {
982     CERT_ID *id = (CERT_ID *)pvPara;
983     BOOL ret;
984
985     switch (id->dwIdChoice)
986     {
987     case CERT_ID_ISSUER_SERIAL_NUMBER:
988         ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
989          &pCertContext->pCertInfo->Issuer, &id->u.IssuerSerialNumber.Issuer);
990         if (ret)
991             ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
992              &id->u.IssuerSerialNumber.SerialNumber);
993         break;
994     case CERT_ID_SHA1_HASH:
995         ret = compare_cert_by_sha1_hash(pCertContext, dwType, dwFlags,
996          &id->u.HashId);
997         break;
998     case CERT_ID_KEY_IDENTIFIER:
999     {
1000         DWORD size = 0;
1001
1002         ret = CertGetCertificateContextProperty(pCertContext,
1003          CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
1004         if (ret && size == id->u.KeyId.cbData)
1005         {
1006             LPBYTE buf = CryptMemAlloc(size);
1007
1008             if (buf)
1009             {
1010                 CertGetCertificateContextProperty(pCertContext,
1011                  CERT_KEY_IDENTIFIER_PROP_ID, buf, &size);
1012                 ret = !memcmp(buf, id->u.KeyId.pbData, size);
1013                 CryptMemFree(buf);
1014             }
1015         }
1016         else
1017             ret = FALSE;
1018         break;
1019     }
1020     default:
1021         ret = FALSE;
1022         break;
1023     }
1024     return ret;
1025 }
1026
1027 static BOOL compare_cert_by_issuer(PCCERT_CONTEXT pCertContext, DWORD dwType,
1028  DWORD dwFlags, const void *pvPara)
1029 {
1030     BOOL ret = FALSE;
1031     PCCERT_CONTEXT subject = (PCCERT_CONTEXT)pvPara;
1032     PCERT_EXTENSION ext;
1033     DWORD size;
1034
1035     if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER,
1036      subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
1037     {
1038         CERT_AUTHORITY_KEY_ID_INFO *info;
1039
1040         ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
1041          X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData,
1042          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1043          &info, &size);
1044         if (ret)
1045         {
1046             CERT_ID id;
1047
1048             if (info->CertIssuer.cbData && info->CertSerialNumber.cbData)
1049             {
1050                 id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
1051                 memcpy(&id.u.IssuerSerialNumber.Issuer, &info->CertIssuer,
1052                  sizeof(CERT_NAME_BLOB));
1053                 memcpy(&id.u.IssuerSerialNumber.SerialNumber,
1054                  &info->CertSerialNumber, sizeof(CRYPT_INTEGER_BLOB));
1055                 ret = compare_cert_by_cert_id(pCertContext, dwType, dwFlags,
1056                  &id);
1057             }
1058             else if (info->KeyId.cbData)
1059             {
1060                 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
1061                 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
1062                 ret = compare_cert_by_cert_id(pCertContext, dwType, dwFlags,
1063                  &id);
1064             }
1065             else
1066                 ret = FALSE;
1067             LocalFree(info);
1068         }
1069     }
1070     else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2,
1071      subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
1072     {
1073         CERT_AUTHORITY_KEY_ID2_INFO *info;
1074
1075         ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
1076          X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData,
1077          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1078          &info, &size);
1079         if (ret)
1080         {
1081             CERT_ID id;
1082
1083             if (info->AuthorityCertIssuer.cAltEntry &&
1084              info->AuthorityCertSerialNumber.cbData)
1085             {
1086                 PCERT_ALT_NAME_ENTRY directoryName = NULL;
1087                 DWORD i;
1088
1089                 for (i = 0; !directoryName &&
1090                  i < info->AuthorityCertIssuer.cAltEntry; i++)
1091                     if (info->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice
1092                      == CERT_ALT_NAME_DIRECTORY_NAME)
1093                         directoryName =
1094                          &info->AuthorityCertIssuer.rgAltEntry[i];
1095                 if (directoryName)
1096                 {
1097                     id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
1098                     memcpy(&id.u.IssuerSerialNumber.Issuer,
1099                      &directoryName->u.DirectoryName, sizeof(CERT_NAME_BLOB));
1100                     memcpy(&id.u.IssuerSerialNumber.SerialNumber,
1101                      &info->AuthorityCertSerialNumber,
1102                      sizeof(CRYPT_INTEGER_BLOB));
1103                     ret = compare_cert_by_cert_id(pCertContext, dwType, dwFlags,
1104                      &id);
1105                 }
1106                 else
1107                 {
1108                     FIXME("no supported name type in authority key id2\n");
1109                     ret = FALSE;
1110                 }
1111             }
1112             else if (info->KeyId.cbData)
1113             {
1114                 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
1115                 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
1116                 ret = compare_cert_by_cert_id(pCertContext, dwType, dwFlags,
1117                  &id);
1118             }
1119             else
1120                 ret = FALSE;
1121             LocalFree(info);
1122         }
1123     }
1124     else
1125        ret = compare_cert_by_name(pCertContext,
1126         CERT_COMPARE_NAME | CERT_COMPARE_SUBJECT_CERT, dwFlags,
1127         &subject->pCertInfo->Issuer);
1128     return ret;
1129 }
1130
1131 static BOOL compare_existing_cert(PCCERT_CONTEXT pCertContext, DWORD dwType,
1132  DWORD dwFlags, const void *pvPara)
1133 {
1134     PCCERT_CONTEXT toCompare = (PCCERT_CONTEXT)pvPara;
1135     return CertCompareCertificate(pCertContext->dwCertEncodingType,
1136      pCertContext->pCertInfo, toCompare->pCertInfo);
1137 }
1138
1139 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
1140  DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType, const void *pvPara,
1141  PCCERT_CONTEXT pPrevCertContext)
1142 {
1143     PCCERT_CONTEXT ret;
1144     CertCompareFunc compare;
1145
1146     TRACE("(%p, %08x, %08x, %08x, %p, %p)\n", hCertStore, dwCertEncodingType,
1147          dwFlags, dwType, pvPara, pPrevCertContext);
1148
1149     switch (dwType >> CERT_COMPARE_SHIFT)
1150     {
1151     case CERT_COMPARE_ANY:
1152         compare = compare_cert_any;
1153         break;
1154     case CERT_COMPARE_MD5_HASH:
1155         compare = compare_cert_by_md5_hash;
1156         break;
1157     case CERT_COMPARE_SHA1_HASH:
1158         compare = compare_cert_by_sha1_hash;
1159         break;
1160     case CERT_COMPARE_NAME:
1161         compare = compare_cert_by_name;
1162         break;
1163     case CERT_COMPARE_SUBJECT_CERT:
1164         compare = compare_cert_by_subject_cert;
1165         break;
1166     case CERT_COMPARE_CERT_ID:
1167         compare = compare_cert_by_cert_id;
1168         break;
1169     case CERT_COMPARE_ISSUER_OF:
1170         compare = compare_cert_by_issuer;
1171         break;
1172     case CERT_COMPARE_EXISTING:
1173         compare = compare_existing_cert;
1174         break;
1175     default:
1176         FIXME("find type %08x unimplemented\n", dwType);
1177         compare = NULL;
1178     }
1179
1180     if (compare)
1181     {
1182         BOOL matches = FALSE;
1183
1184         ret = pPrevCertContext;
1185         do {
1186             ret = CertEnumCertificatesInStore(hCertStore, ret);
1187             if (ret)
1188                 matches = compare(ret, dwType, dwFlags, pvPara);
1189         } while (ret != NULL && !matches);
1190         if (!ret)
1191             SetLastError(CRYPT_E_NOT_FOUND);
1192     }
1193     else
1194     {
1195         SetLastError(CRYPT_E_NOT_FOUND);
1196         ret = NULL;
1197     }
1198     TRACE("returning %p\n", ret);
1199     return ret;
1200 }
1201
1202 PCCERT_CONTEXT WINAPI CertGetSubjectCertificateFromStore(HCERTSTORE hCertStore,
1203  DWORD dwCertEncodingType, PCERT_INFO pCertId)
1204 {
1205     TRACE("(%p, %08x, %p)\n", hCertStore, dwCertEncodingType, pCertId);
1206
1207     if (!pCertId)
1208     {
1209         SetLastError(E_INVALIDARG);
1210         return NULL;
1211     }
1212     return CertFindCertificateInStore(hCertStore, dwCertEncodingType, 0,
1213      CERT_FIND_SUBJECT_CERT, pCertId, NULL);
1214 }
1215
1216 BOOL WINAPI CertVerifySubjectCertificateContext(PCCERT_CONTEXT pSubject,
1217  PCCERT_CONTEXT pIssuer, DWORD *pdwFlags)
1218 {
1219     static const DWORD supportedFlags = CERT_STORE_REVOCATION_FLAG |
1220      CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG;
1221
1222     if (*pdwFlags & ~supportedFlags)
1223     {
1224         SetLastError(E_INVALIDARG);
1225         return FALSE;
1226     }
1227     if (*pdwFlags & CERT_STORE_REVOCATION_FLAG)
1228     {
1229         DWORD flags = 0;
1230         PCCRL_CONTEXT crl = CertGetCRLFromStore(pSubject->hCertStore, pSubject,
1231          NULL, &flags);
1232
1233         /* FIXME: what if the CRL has expired? */
1234         if (crl)
1235         {
1236             if (CertVerifyCRLRevocation(pSubject->dwCertEncodingType,
1237              pSubject->pCertInfo, 1, (PCRL_INFO *)&crl->pCrlInfo))
1238                 *pdwFlags &= CERT_STORE_REVOCATION_FLAG;
1239         }
1240         else
1241             *pdwFlags |= CERT_STORE_NO_CRL_FLAG;
1242     }
1243     if (*pdwFlags & CERT_STORE_TIME_VALIDITY_FLAG)
1244     {
1245         if (0 == CertVerifyTimeValidity(NULL, pSubject->pCertInfo))
1246             *pdwFlags &= ~CERT_STORE_TIME_VALIDITY_FLAG;
1247     }
1248     if (*pdwFlags & CERT_STORE_SIGNATURE_FLAG)
1249     {
1250         if (CryptVerifyCertificateSignatureEx(0, pSubject->dwCertEncodingType,
1251          CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)pSubject,
1252          CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)pIssuer, 0, NULL))
1253             *pdwFlags &= ~CERT_STORE_SIGNATURE_FLAG;
1254     }
1255     return TRUE;
1256 }
1257
1258 PCCERT_CONTEXT WINAPI CertGetIssuerCertificateFromStore(HCERTSTORE hCertStore,
1259  PCCERT_CONTEXT pSubjectContext, PCCERT_CONTEXT pPrevIssuerContext,
1260  DWORD *pdwFlags)
1261 {
1262     PCCERT_CONTEXT ret;
1263
1264     TRACE("(%p, %p, %p, %08x)\n", hCertStore, pSubjectContext,
1265      pPrevIssuerContext, *pdwFlags);
1266
1267     if (!pSubjectContext)
1268     {
1269         SetLastError(E_INVALIDARG);
1270         return NULL;
1271     }
1272
1273     ret = CertFindCertificateInStore(hCertStore,
1274      pSubjectContext->dwCertEncodingType, 0, CERT_FIND_ISSUER_OF,
1275      pSubjectContext, pPrevIssuerContext);
1276     if (ret)
1277     {
1278         if (!CertVerifySubjectCertificateContext(pSubjectContext, ret,
1279          pdwFlags))
1280         {
1281             CertFreeCertificateContext(ret);
1282             ret = NULL;
1283         }
1284     }
1285     TRACE("returning %p\n", ret);
1286     return ret;
1287 }
1288
1289 typedef struct _OLD_CERT_REVOCATION_STATUS {
1290     DWORD cbSize;
1291     DWORD dwIndex;
1292     DWORD dwError;
1293     DWORD dwReason;
1294 } OLD_CERT_REVOCATION_STATUS, *POLD_CERT_REVOCATION_STATUS;
1295
1296 typedef BOOL (WINAPI *CertVerifyRevocationFunc)(DWORD, DWORD, DWORD,
1297  void **, DWORD, PCERT_REVOCATION_PARA, PCERT_REVOCATION_STATUS);
1298
1299 BOOL WINAPI CertVerifyRevocation(DWORD dwEncodingType, DWORD dwRevType,
1300  DWORD cContext, PVOID rgpvContext[], DWORD dwFlags,
1301  PCERT_REVOCATION_PARA pRevPara, PCERT_REVOCATION_STATUS pRevStatus)
1302 {
1303     BOOL ret;
1304
1305     TRACE("(%08x, %d, %d, %p, %08x, %p, %p)\n", dwEncodingType, dwRevType,
1306      cContext, rgpvContext, dwFlags, pRevPara, pRevStatus);
1307
1308     if (pRevStatus->cbSize != sizeof(OLD_CERT_REVOCATION_STATUS) &&
1309      pRevStatus->cbSize != sizeof(CERT_REVOCATION_STATUS))
1310     {
1311         SetLastError(E_INVALIDARG);
1312         return FALSE;
1313     }
1314     if (cContext)
1315     {
1316         static HCRYPTOIDFUNCSET set = NULL;
1317         DWORD size;
1318
1319         if (!set)
1320             set = CryptInitOIDFunctionSet(CRYPT_OID_VERIFY_REVOCATION_FUNC, 0);
1321         ret = CryptGetDefaultOIDDllList(set, dwEncodingType, NULL, &size);
1322         if (ret)
1323         {
1324             if (size == 1)
1325             {
1326                 /* empty list */
1327                 SetLastError(CRYPT_E_NO_REVOCATION_DLL);
1328                 ret = FALSE;
1329             }
1330             else
1331             {
1332                 LPWSTR dllList = CryptMemAlloc(size * sizeof(WCHAR)), ptr;
1333
1334                 if (dllList)
1335                 {
1336                     ret = CryptGetDefaultOIDDllList(set, dwEncodingType,
1337                      dllList, &size);
1338                     if (ret)
1339                     {
1340                         for (ptr = dllList; ret && *ptr;
1341                          ptr += lstrlenW(ptr) + 1)
1342                         {
1343                             CertVerifyRevocationFunc func;
1344                             HCRYPTOIDFUNCADDR hFunc;
1345
1346                             ret = CryptGetDefaultOIDFunctionAddress(set,
1347                              dwEncodingType, ptr, 0, (void **)&func, &hFunc);
1348                             if (ret)
1349                             {
1350                                 ret = func(dwEncodingType, dwRevType, cContext,
1351                                  rgpvContext, dwFlags, pRevPara, pRevStatus);
1352                                 CryptFreeOIDFunctionAddress(hFunc, 0);
1353                             }
1354                         }
1355                     }
1356                     CryptMemFree(dllList);
1357                 }
1358                 else
1359                 {
1360                     SetLastError(ERROR_OUTOFMEMORY);
1361                     ret = FALSE;
1362                 }
1363             }
1364         }
1365     }
1366     else
1367         ret = TRUE;
1368     return ret;
1369 }
1370
1371 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
1372  CRYPT_ATTRIBUTE rgAttr[])
1373 {
1374     PCRYPT_ATTRIBUTE ret = NULL;
1375     DWORD i;
1376
1377     TRACE("%s %d %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
1378
1379     if (!cAttr)
1380         return NULL;
1381     if (!pszObjId)
1382     {
1383         SetLastError(ERROR_INVALID_PARAMETER);
1384         return NULL;
1385     }
1386
1387     for (i = 0; !ret && i < cAttr; i++)
1388         if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
1389             ret = &rgAttr[i];
1390     return ret;
1391 }
1392
1393 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
1394  CERT_EXTENSION rgExtensions[])
1395 {
1396     PCERT_EXTENSION ret = NULL;
1397     DWORD i;
1398
1399     TRACE("%s %d %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
1400
1401     if (!cExtensions)
1402         return NULL;
1403     if (!pszObjId)
1404     {
1405         SetLastError(ERROR_INVALID_PARAMETER);
1406         return NULL;
1407     }
1408
1409     for (i = 0; !ret && i < cExtensions; i++)
1410         if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
1411          rgExtensions[i].pszObjId))
1412             ret = &rgExtensions[i];
1413     return ret;
1414 }
1415
1416 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
1417 {
1418     PCERT_RDN_ATTR ret = NULL;
1419     DWORD i, j;
1420
1421     TRACE("%s %p\n", debugstr_a(pszObjId), pName);
1422
1423     if (!pszObjId)
1424     {
1425         SetLastError(ERROR_INVALID_PARAMETER);
1426         return NULL;
1427     }
1428
1429     for (i = 0; !ret && i < pName->cRDN; i++)
1430         for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
1431             if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
1432              pName->rgRDN[i].rgRDNAttr[j].pszObjId))
1433                 ret = &pName->rgRDN[i].rgRDNAttr[j];
1434     return ret;
1435 }
1436
1437 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
1438  PCERT_INFO pCertInfo)
1439 {
1440     FILETIME fileTime;
1441     LONG ret;
1442
1443     if (!pTimeToVerify)
1444     {
1445         GetSystemTimeAsFileTime(&fileTime);
1446         pTimeToVerify = &fileTime;
1447     }
1448     if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
1449     {
1450         ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
1451         if (ret < 0)
1452             ret = 0;
1453     }
1454     return ret;
1455 }
1456
1457 BOOL WINAPI CertVerifyValidityNesting(PCERT_INFO pSubjectInfo,
1458  PCERT_INFO pIssuerInfo)
1459 {
1460     TRACE("(%p, %p)\n", pSubjectInfo, pIssuerInfo);
1461
1462     return CertVerifyTimeValidity(&pSubjectInfo->NotBefore, pIssuerInfo) == 0
1463      && CertVerifyTimeValidity(&pSubjectInfo->NotAfter, pIssuerInfo) == 0;
1464 }
1465
1466 BOOL WINAPI CryptHashCertificate(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
1467  DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
1468  DWORD *pcbComputedHash)
1469 {
1470     BOOL ret = TRUE;
1471     HCRYPTHASH hHash = 0;
1472
1473     TRACE("(%08lx, %d, %08x, %p, %d, %p, %p)\n", hCryptProv, Algid, dwFlags,
1474      pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
1475
1476     if (!hCryptProv)
1477         hCryptProv = CRYPT_GetDefaultProvider();
1478     if (!Algid)
1479         Algid = CALG_SHA1;
1480     if (ret)
1481     {
1482         ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
1483         if (ret)
1484         {
1485             ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
1486             if (ret)
1487                 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
1488                  pcbComputedHash, 0);
1489             CryptDestroyHash(hHash);
1490         }
1491     }
1492     return ret;
1493 }
1494
1495 BOOL WINAPI CryptHashPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
1496  DWORD dwFlags, DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo,
1497  BYTE *pbComputedHash, DWORD *pcbComputedHash)
1498 {
1499     BOOL ret = TRUE;
1500     HCRYPTHASH hHash = 0;
1501
1502     TRACE("(%08lx, %d, %08x, %d, %p, %p, %p)\n", hCryptProv, Algid, dwFlags,
1503      dwCertEncodingType, pInfo, pbComputedHash, pcbComputedHash);
1504
1505     if (!hCryptProv)
1506         hCryptProv = CRYPT_GetDefaultProvider();
1507     if (!Algid)
1508         Algid = CALG_MD5;
1509     if (ret)
1510     {
1511         BYTE *buf;
1512         DWORD size = 0;
1513
1514         ret = CryptEncodeObjectEx(dwCertEncodingType, X509_PUBLIC_KEY_INFO,
1515          pInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
1516         if (ret)
1517         {
1518             ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
1519             if (ret)
1520             {
1521                 ret = CryptHashData(hHash, buf, size, 0);
1522                 if (ret)
1523                     ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
1524                      pcbComputedHash, 0);
1525                 CryptDestroyHash(hHash);
1526             }
1527             LocalFree(buf);
1528         }
1529     }
1530     return ret;
1531 }
1532
1533 BOOL WINAPI CryptSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
1534  DWORD dwKeySpec, DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned,
1535  DWORD cbEncodedToBeSigned, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
1536  const void *pvHashAuxInfo, BYTE *pbSignature, DWORD *pcbSignature)
1537 {
1538     BOOL ret;
1539     PCCRYPT_OID_INFO info;
1540     HCRYPTHASH hHash;
1541
1542     TRACE("(%08lx, %d, %d, %p, %d, %p, %p, %p, %p)\n", hCryptProv,
1543      dwKeySpec, dwCertEncodingType, pbEncodedToBeSigned, cbEncodedToBeSigned,
1544      pSignatureAlgorithm, pvHashAuxInfo, pbSignature, pcbSignature);
1545
1546     info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1547      pSignatureAlgorithm->pszObjId, 0);
1548     if (!info)
1549     {
1550         SetLastError(NTE_BAD_ALGID);
1551         return FALSE;
1552     }
1553     if (info->dwGroupId == CRYPT_HASH_ALG_OID_GROUP_ID)
1554     {
1555         if (!hCryptProv)
1556             hCryptProv = CRYPT_GetDefaultProvider();
1557         ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
1558         if (ret)
1559         {
1560             ret = CryptHashData(hHash, pbEncodedToBeSigned,
1561              cbEncodedToBeSigned, 0);
1562             if (ret)
1563                 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbSignature,
1564                  pcbSignature, 0);
1565             CryptDestroyHash(hHash);
1566         }
1567     }
1568     else
1569     {
1570         if (!hCryptProv)
1571         {
1572             SetLastError(ERROR_INVALID_PARAMETER);
1573             ret = FALSE;
1574         }
1575         else
1576         {
1577             ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
1578             if (ret)
1579             {
1580                 ret = CryptHashData(hHash, pbEncodedToBeSigned,
1581                  cbEncodedToBeSigned, 0);
1582                 if (ret)
1583                     ret = CryptSignHashW(hHash, dwKeySpec, NULL, 0, pbSignature,
1584                      pcbSignature);
1585                 CryptDestroyHash(hHash);
1586             }
1587         }
1588     }
1589     return ret;
1590 }
1591
1592 BOOL WINAPI CryptSignAndEncodeCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
1593  DWORD dwKeySpec, DWORD dwCertEncodingType, LPCSTR lpszStructType,
1594  const void *pvStructInfo, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
1595  const void *pvHashAuxInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
1596 {
1597     BOOL ret;
1598     DWORD encodedSize, hashSize;
1599
1600     TRACE("(%08lx, %d, %d, %s, %p, %p, %p, %p, %p)\n", hCryptProv, dwKeySpec,
1601      dwCertEncodingType, debugstr_a(lpszStructType), pvStructInfo,
1602      pSignatureAlgorithm, pvHashAuxInfo, pbEncoded, pcbEncoded);
1603
1604     ret = CryptEncodeObject(dwCertEncodingType, lpszStructType, pvStructInfo,
1605      NULL, &encodedSize);
1606     if (ret)
1607     {
1608         PBYTE encoded = CryptMemAlloc(encodedSize);
1609
1610         if (encoded)
1611         {
1612             ret = CryptEncodeObject(dwCertEncodingType, lpszStructType,
1613              pvStructInfo, encoded, &encodedSize);
1614             if (ret)
1615             {
1616                 ret = CryptSignCertificate(hCryptProv, dwKeySpec,
1617                  dwCertEncodingType, encoded, encodedSize, pSignatureAlgorithm,
1618                  pvHashAuxInfo, NULL, &hashSize);
1619                 if (ret)
1620                 {
1621                     PBYTE hash = CryptMemAlloc(hashSize);
1622
1623                     if (hash)
1624                     {
1625                         ret = CryptSignCertificate(hCryptProv, dwKeySpec,
1626                          dwCertEncodingType, encoded, encodedSize,
1627                          pSignatureAlgorithm, pvHashAuxInfo, hash, &hashSize);
1628                         if (ret)
1629                         {
1630                             CERT_SIGNED_CONTENT_INFO info = { { 0 } };
1631
1632                             info.ToBeSigned.cbData = encodedSize;
1633                             info.ToBeSigned.pbData = encoded;
1634                             memcpy(&info.SignatureAlgorithm,
1635                              pSignatureAlgorithm,
1636                              sizeof(info.SignatureAlgorithm));
1637                             info.Signature.cbData = hashSize;
1638                             info.Signature.pbData = hash;
1639                             info.Signature.cUnusedBits = 0;
1640                             ret = CryptEncodeObject(dwCertEncodingType,
1641                              X509_CERT, &info, pbEncoded, pcbEncoded);
1642                         }
1643                         CryptMemFree(hash);
1644                     }
1645                 }
1646             }
1647             CryptMemFree(encoded);
1648         }
1649     }
1650     return ret;
1651 }
1652
1653 BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV_LEGACY hCryptProv,
1654  DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
1655  PCERT_PUBLIC_KEY_INFO pPublicKey)
1656 {
1657     return CryptVerifyCertificateSignatureEx(hCryptProv, dwCertEncodingType,
1658      CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, (void *)pbEncoded,
1659      CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
1660 }
1661
1662 static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv,
1663  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pubKeyInfo,
1664  const CERT_SIGNED_CONTENT_INFO *signedCert)
1665 {
1666     BOOL ret;
1667     HCRYPTKEY key;
1668     PCCRYPT_OID_INFO info;
1669     ALG_ID pubKeyID, hashID;
1670
1671     info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1672      signedCert->SignatureAlgorithm.pszObjId, 0);
1673     if (!info || info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID)
1674     {
1675         SetLastError(NTE_BAD_ALGID);
1676         return FALSE;
1677     }
1678     hashID = info->u.Algid;
1679     if (info->ExtraInfo.cbData >= sizeof(ALG_ID))
1680         pubKeyID = *(ALG_ID *)info->ExtraInfo.pbData;
1681     else
1682         pubKeyID = hashID;
1683     /* Load the default provider if necessary */
1684     if (!hCryptProv)
1685         hCryptProv = CRYPT_GetDefaultProvider();
1686     ret = CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType,
1687      pubKeyInfo, pubKeyID, 0, NULL, &key);
1688     if (ret)
1689     {
1690         HCRYPTHASH hash;
1691
1692         ret = CryptCreateHash(hCryptProv, hashID, 0, 0, &hash);
1693         if (ret)
1694         {
1695             ret = CryptHashData(hash, signedCert->ToBeSigned.pbData,
1696              signedCert->ToBeSigned.cbData, 0);
1697             if (ret)
1698                 ret = CryptVerifySignatureW(hash, signedCert->Signature.pbData,
1699                  signedCert->Signature.cbData, key, NULL, 0);
1700             CryptDestroyHash(hash);
1701         }
1702         CryptDestroyKey(key);
1703     }
1704     return ret;
1705 }
1706
1707 BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV_LEGACY hCryptProv,
1708  DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
1709  DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
1710 {
1711     BOOL ret = TRUE;
1712     CRYPT_DATA_BLOB subjectBlob;
1713
1714     TRACE("(%08lx, %d, %d, %p, %d, %p, %08x, %p)\n", hCryptProv,
1715      dwCertEncodingType, dwSubjectType, pvSubject, dwIssuerType, pvIssuer,
1716      dwFlags, pvReserved);
1717
1718     switch (dwSubjectType)
1719     {
1720     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB:
1721     {
1722         PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvSubject;
1723
1724         subjectBlob.pbData = blob->pbData;
1725         subjectBlob.cbData = blob->cbData;
1726         break;
1727     }
1728     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT:
1729     {
1730         PCERT_CONTEXT context = (PCERT_CONTEXT)pvSubject;
1731
1732         subjectBlob.pbData = context->pbCertEncoded;
1733         subjectBlob.cbData = context->cbCertEncoded;
1734         break;
1735     }
1736     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL:
1737     {
1738         PCRL_CONTEXT context = (PCRL_CONTEXT)pvSubject;
1739
1740         subjectBlob.pbData = context->pbCrlEncoded;
1741         subjectBlob.cbData = context->cbCrlEncoded;
1742         break;
1743     }
1744     default:
1745         SetLastError(E_INVALIDARG);
1746         ret = FALSE;
1747     }
1748
1749     if (ret)
1750     {
1751         PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
1752         DWORD size = 0;
1753
1754         ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
1755          subjectBlob.pbData, subjectBlob.cbData,
1756          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1757          (BYTE *)&signedCert, &size);
1758         if (ret)
1759         {
1760             switch (dwIssuerType)
1761             {
1762             case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY:
1763                 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
1764                  dwCertEncodingType, (PCERT_PUBLIC_KEY_INFO)pvIssuer,
1765                  signedCert);
1766                 break;
1767             case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT:
1768                 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
1769                  dwCertEncodingType,
1770                  &((PCCERT_CONTEXT)pvIssuer)->pCertInfo->SubjectPublicKeyInfo,
1771                  signedCert);
1772                 break;
1773             case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN:
1774                 FIXME("CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: stub\n");
1775                 ret = FALSE;
1776                 break;
1777             case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL:
1778                 if (pvIssuer)
1779                 {
1780                     SetLastError(E_INVALIDARG);
1781                     ret = FALSE;
1782                 }
1783                 else
1784                 {
1785                     FIXME("unimplemented for NULL signer\n");
1786                     SetLastError(E_INVALIDARG);
1787                     ret = FALSE;
1788                 }
1789                 break;
1790             default:
1791                 SetLastError(E_INVALIDARG);
1792                 ret = FALSE;
1793             }
1794             LocalFree(signedCert);
1795         }
1796     }
1797     return ret;
1798 }
1799
1800 BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags,
1801  PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage)
1802 {
1803     PCERT_ENHKEY_USAGE usage = NULL;
1804     DWORD bytesNeeded;
1805     BOOL ret = TRUE;
1806
1807     if (!pCertContext || !pcbUsage)
1808     {
1809         SetLastError(ERROR_INVALID_PARAMETER);
1810         return FALSE;
1811     }
1812
1813     TRACE("(%p, %08x, %p, %d)\n", pCertContext, dwFlags, pUsage, *pcbUsage);
1814
1815     if (!(dwFlags & CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG))
1816     {
1817         DWORD propSize = 0;
1818
1819         if (CertGetCertificateContextProperty(pCertContext,
1820          CERT_ENHKEY_USAGE_PROP_ID, NULL, &propSize))
1821         {
1822             LPBYTE buf = CryptMemAlloc(propSize);
1823
1824             if (buf)
1825             {
1826                 if (CertGetCertificateContextProperty(pCertContext,
1827                  CERT_ENHKEY_USAGE_PROP_ID, buf, &propSize))
1828                 {
1829                     ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
1830                      X509_ENHANCED_KEY_USAGE, buf, propSize,
1831                      CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
1832                 }
1833                 CryptMemFree(buf);
1834             }
1835         }
1836     }
1837     if (!usage && !(dwFlags & CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG))
1838     {
1839         PCERT_EXTENSION ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
1840          pCertContext->pCertInfo->cExtension,
1841          pCertContext->pCertInfo->rgExtension);
1842
1843         if (ext)
1844         {
1845             ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
1846              X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
1847              CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
1848         }
1849     }
1850     if (!usage)
1851     {
1852         /* If a particular location is specified, this should fail.  Otherwise
1853          * it should succeed with an empty usage.  (This is true on Win2k and
1854          * later, which we emulate.)
1855          */
1856         if (dwFlags)
1857         {
1858             SetLastError(CRYPT_E_NOT_FOUND);
1859             ret = FALSE;
1860         }
1861         else
1862             bytesNeeded = sizeof(CERT_ENHKEY_USAGE);
1863     }
1864
1865     if (ret)
1866     {
1867         if (!pUsage)
1868             *pcbUsage = bytesNeeded;
1869         else if (*pcbUsage < bytesNeeded)
1870         {
1871             SetLastError(ERROR_MORE_DATA);
1872             *pcbUsage = bytesNeeded;
1873             ret = FALSE;
1874         }
1875         else
1876         {
1877             *pcbUsage = bytesNeeded;
1878             if (usage)
1879             {
1880                 DWORD i;
1881                 LPSTR nextOID = (LPSTR)((LPBYTE)pUsage +
1882                  sizeof(CERT_ENHKEY_USAGE) +
1883                  usage->cUsageIdentifier * sizeof(LPSTR));
1884
1885                 pUsage->cUsageIdentifier = usage->cUsageIdentifier;
1886                 pUsage->rgpszUsageIdentifier = (LPSTR *)((LPBYTE)pUsage +
1887                  sizeof(CERT_ENHKEY_USAGE));
1888                 for (i = 0; i < usage->cUsageIdentifier; i++)
1889                 {
1890                     pUsage->rgpszUsageIdentifier[i] = nextOID;
1891                     strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
1892                     nextOID += strlen(nextOID) + 1;
1893                 }
1894             }
1895             else
1896                 pUsage->cUsageIdentifier = 0;
1897         }
1898     }
1899     if (usage)
1900         LocalFree(usage);
1901     TRACE("returning %d\n", ret);
1902     return ret;
1903 }
1904
1905 BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext,
1906  PCERT_ENHKEY_USAGE pUsage)
1907 {
1908     BOOL ret;
1909
1910     TRACE("(%p, %p)\n", pCertContext, pUsage);
1911
1912     if (pUsage)
1913     {
1914         CRYPT_DATA_BLOB blob = { 0, NULL };
1915
1916         ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
1917          pUsage, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData, &blob.cbData);
1918         if (ret)
1919         {
1920             ret = CertSetCertificateContextProperty(pCertContext,
1921              CERT_ENHKEY_USAGE_PROP_ID, 0, &blob);
1922             LocalFree(blob.pbData);
1923         }
1924     }
1925     else
1926         ret = CertSetCertificateContextProperty(pCertContext,
1927          CERT_ENHKEY_USAGE_PROP_ID, 0, NULL);
1928     return ret;
1929 }
1930
1931 BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
1932  LPCSTR pszUsageIdentifier)
1933 {
1934     BOOL ret;
1935     DWORD size;
1936
1937     TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
1938
1939     if (CertGetEnhancedKeyUsage(pCertContext,
1940      CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size))
1941     {
1942         PCERT_ENHKEY_USAGE usage = CryptMemAlloc(size);
1943
1944         if (usage)
1945         {
1946             ret = CertGetEnhancedKeyUsage(pCertContext,
1947              CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size);
1948             if (ret)
1949             {
1950                 DWORD i;
1951                 BOOL exists = FALSE;
1952
1953                 /* Make sure usage doesn't already exist */
1954                 for (i = 0; !exists && i < usage->cUsageIdentifier; i++)
1955                 {
1956                     if (!strcmp(usage->rgpszUsageIdentifier[i],
1957                      pszUsageIdentifier))
1958                         exists = TRUE;
1959                 }
1960                 if (!exists)
1961                 {
1962                     PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size +
1963                      sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
1964
1965                     if (newUsage)
1966                     {
1967                         LPSTR nextOID;
1968
1969                         newUsage->rgpszUsageIdentifier = (LPSTR *)
1970                          ((LPBYTE)newUsage + sizeof(CERT_ENHKEY_USAGE));
1971                         nextOID = (LPSTR)((LPBYTE)newUsage->rgpszUsageIdentifier
1972                           + (usage->cUsageIdentifier + 1) * sizeof(LPSTR));
1973                         for (i = 0; i < usage->cUsageIdentifier; i++)
1974                         {
1975                             newUsage->rgpszUsageIdentifier[i] = nextOID;
1976                             strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
1977                             nextOID += strlen(nextOID) + 1;
1978                         }
1979                         newUsage->rgpszUsageIdentifier[i] = nextOID;
1980                         strcpy(nextOID, pszUsageIdentifier);
1981                         newUsage->cUsageIdentifier = i + 1;
1982                         ret = CertSetEnhancedKeyUsage(pCertContext, newUsage);
1983                         CryptMemFree(newUsage);
1984                     }
1985                     else
1986                         ret = FALSE;
1987                 }
1988             }
1989             CryptMemFree(usage);
1990         }
1991         else
1992             ret = FALSE;
1993     }
1994     else
1995     {
1996         PCERT_ENHKEY_USAGE usage = CryptMemAlloc(sizeof(CERT_ENHKEY_USAGE) +
1997          sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
1998
1999         if (usage)
2000         {
2001             usage->rgpszUsageIdentifier =
2002              (LPSTR *)((LPBYTE)usage + sizeof(CERT_ENHKEY_USAGE));
2003             usage->rgpszUsageIdentifier[0] = (LPSTR)((LPBYTE)usage +
2004              sizeof(CERT_ENHKEY_USAGE) + sizeof(LPSTR));
2005             strcpy(usage->rgpszUsageIdentifier[0], pszUsageIdentifier);
2006             usage->cUsageIdentifier = 1;
2007             ret = CertSetEnhancedKeyUsage(pCertContext, usage);
2008             CryptMemFree(usage);
2009         }
2010         else
2011             ret = FALSE;
2012     }
2013     return ret;
2014 }
2015
2016 BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
2017  LPCSTR pszUsageIdentifier)
2018 {
2019     BOOL ret;
2020     DWORD size;
2021     CERT_ENHKEY_USAGE usage;
2022
2023     TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
2024
2025     size = sizeof(usage);
2026     ret = CertGetEnhancedKeyUsage(pCertContext,
2027      CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, &usage, &size);
2028     if (!ret && GetLastError() == ERROR_MORE_DATA)
2029     {
2030         PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
2031
2032         if (pUsage)
2033         {
2034             ret = CertGetEnhancedKeyUsage(pCertContext,
2035              CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
2036             if (ret)
2037             {
2038                 if (pUsage->cUsageIdentifier)
2039                 {
2040                     DWORD i;
2041                     BOOL found = FALSE;
2042
2043                     for (i = 0; i < pUsage->cUsageIdentifier; i++)
2044                     {
2045                         if (!strcmp(pUsage->rgpszUsageIdentifier[i],
2046                          pszUsageIdentifier))
2047                             found = TRUE;
2048                         if (found && i < pUsage->cUsageIdentifier - 1)
2049                             pUsage->rgpszUsageIdentifier[i] =
2050                              pUsage->rgpszUsageIdentifier[i + 1];
2051                     }
2052                     pUsage->cUsageIdentifier--;
2053                     /* Remove the usage if it's empty */
2054                     if (pUsage->cUsageIdentifier)
2055                         ret = CertSetEnhancedKeyUsage(pCertContext, pUsage);
2056                     else
2057                         ret = CertSetEnhancedKeyUsage(pCertContext, NULL);
2058                 }
2059             }
2060             CryptMemFree(pUsage);
2061         }
2062         else
2063             ret = FALSE;
2064     }
2065     else
2066     {
2067         /* it fit in an empty usage, therefore there's nothing to remove */
2068         ret = TRUE;
2069     }
2070     return ret;
2071 }
2072
2073 struct BitField
2074 {
2075     DWORD  cIndexes;
2076     DWORD *indexes;
2077 };
2078
2079 #define BITS_PER_DWORD (sizeof(DWORD) * 8)
2080
2081 static void CRYPT_SetBitInField(struct BitField *field, DWORD bit)
2082 {
2083     DWORD indexIndex = bit / BITS_PER_DWORD;
2084
2085     if (indexIndex + 1 > field->cIndexes)
2086     {
2087         if (field->cIndexes)
2088             field->indexes = CryptMemRealloc(field->indexes,
2089              (indexIndex + 1) * sizeof(DWORD));
2090         else
2091             field->indexes = CryptMemAlloc(sizeof(DWORD));
2092         if (field->indexes)
2093         {
2094             field->indexes[indexIndex] = 0;
2095             field->cIndexes = indexIndex + 1;
2096         }
2097     }
2098     if (field->indexes)
2099         field->indexes[indexIndex] |= 1 << (bit % BITS_PER_DWORD);
2100 }
2101
2102 static BOOL CRYPT_IsBitInFieldSet(struct BitField *field, DWORD bit)
2103 {
2104     BOOL set = FALSE;
2105     DWORD indexIndex = bit / BITS_PER_DWORD;
2106
2107     assert(field->cIndexes);
2108     set = field->indexes[indexIndex] & (1 << (bit % BITS_PER_DWORD));
2109     return set;
2110 }
2111
2112 BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts,
2113  int *cNumOIDs, LPSTR *rghOIDs, DWORD *pcbOIDs)
2114 {
2115     BOOL ret = TRUE;
2116     DWORD i, cbOIDs = 0;
2117     BOOL allUsagesValid = TRUE;
2118     CERT_ENHKEY_USAGE validUsages = { 0, NULL };
2119
2120     TRACE("(%d, %p, %d, %p, %d)\n", cCerts, rghCerts, *cNumOIDs,
2121      rghOIDs, *pcbOIDs);
2122
2123     for (i = 0; i < cCerts; i++)
2124     {
2125         CERT_ENHKEY_USAGE usage;
2126         DWORD size = sizeof(usage);
2127
2128         ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, &usage, &size);
2129         /* Success is deliberately ignored: it implies all usages are valid */
2130         if (!ret && GetLastError() == ERROR_MORE_DATA)
2131         {
2132             PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
2133
2134             allUsagesValid = FALSE;
2135             if (pUsage)
2136             {
2137                 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, pUsage, &size);
2138                 if (ret)
2139                 {
2140                     if (!validUsages.cUsageIdentifier)
2141                     {
2142                         DWORD j;
2143
2144                         cbOIDs = pUsage->cUsageIdentifier * sizeof(LPSTR);
2145                         validUsages.cUsageIdentifier = pUsage->cUsageIdentifier;
2146                         for (j = 0; j < validUsages.cUsageIdentifier; j++)
2147                             cbOIDs += lstrlenA(pUsage->rgpszUsageIdentifier[j])
2148                              + 1;
2149                         validUsages.rgpszUsageIdentifier =
2150                          CryptMemAlloc(cbOIDs);
2151                         if (validUsages.rgpszUsageIdentifier)
2152                         {
2153                             LPSTR nextOID = (LPSTR)
2154                              ((LPBYTE)validUsages.rgpszUsageIdentifier +
2155                              validUsages.cUsageIdentifier * sizeof(LPSTR));
2156
2157                             for (j = 0; j < validUsages.cUsageIdentifier; j++)
2158                             {
2159                                 validUsages.rgpszUsageIdentifier[j] = nextOID;
2160                                 lstrcpyA(validUsages.rgpszUsageIdentifier[j],
2161                                  pUsage->rgpszUsageIdentifier[j]);
2162                                 nextOID += lstrlenA(nextOID) + 1;
2163                             }
2164                         }
2165                     }
2166                     else
2167                     {
2168                         struct BitField validIndexes = { 0, NULL };
2169                         DWORD j, k, numRemoved = 0;
2170
2171                         /* Merge: build a bitmap of all the indexes of
2172                          * validUsages.rgpszUsageIdentifier that are in pUsage.
2173                          */
2174                         for (j = 0; j < pUsage->cUsageIdentifier; j++)
2175                         {
2176                             for (k = 0; k < validUsages.cUsageIdentifier; k++)
2177                             {
2178                                 if (!strcmp(pUsage->rgpszUsageIdentifier[j],
2179                                  validUsages.rgpszUsageIdentifier[k]))
2180                                 {
2181                                     CRYPT_SetBitInField(&validIndexes, k);
2182                                     break;
2183                                 }
2184                             }
2185                         }
2186                         /* Merge by removing from validUsages those that are
2187                          * not in the bitmap.
2188                          */
2189                         for (j = 0; j < validUsages.cUsageIdentifier; j++)
2190                         {
2191                             if (!CRYPT_IsBitInFieldSet(&validIndexes, j))
2192                             {
2193                                 if (j < validUsages.cUsageIdentifier - 1)
2194                                 {
2195                                     memmove(&validUsages.rgpszUsageIdentifier[j],
2196                                      &validUsages.rgpszUsageIdentifier[j +
2197                                      numRemoved + 1],
2198                                      (validUsages.cUsageIdentifier - numRemoved
2199                                      - j - 1) * sizeof(LPSTR));
2200                                     cbOIDs -= lstrlenA(
2201                                      validUsages.rgpszUsageIdentifier[j]) + 1 +
2202                                      sizeof(LPSTR);
2203                                     validUsages.cUsageIdentifier--;
2204                                     numRemoved++;
2205                                 }
2206                                 else
2207                                     validUsages.cUsageIdentifier--;
2208                             }
2209                         }
2210                         CryptMemFree(validIndexes.indexes);
2211                     }
2212                 }
2213                 CryptMemFree(pUsage);
2214             }
2215         }
2216     }
2217     ret = TRUE;
2218     if (allUsagesValid)
2219     {
2220         *cNumOIDs = -1;
2221         *pcbOIDs = 0;
2222     }
2223     else
2224     {
2225         *cNumOIDs = validUsages.cUsageIdentifier;
2226         if (!rghOIDs)
2227             *pcbOIDs = cbOIDs;
2228         else if (*pcbOIDs < cbOIDs)
2229         {
2230             *pcbOIDs = cbOIDs;
2231             SetLastError(ERROR_MORE_DATA);
2232             ret = FALSE;
2233         }
2234         else
2235         {
2236             LPSTR nextOID = (LPSTR)((LPBYTE)rghOIDs +
2237              validUsages.cUsageIdentifier * sizeof(LPSTR));
2238
2239             *pcbOIDs = cbOIDs;
2240             for (i = 0; i < validUsages.cUsageIdentifier; i++)
2241             {
2242                 rghOIDs[i] = nextOID;
2243                 lstrcpyA(nextOID, validUsages.rgpszUsageIdentifier[i]);
2244                 nextOID += lstrlenA(nextOID) + 1;
2245             }
2246         }
2247     }
2248     CryptMemFree(validUsages.rgpszUsageIdentifier);
2249     TRACE("cNumOIDs: %d\n", *cNumOIDs);
2250     TRACE("returning %d\n", ret);
2251     return ret;
2252 }
2253
2254 /* Sets the CERT_KEY_PROV_INFO_PROP_ID property of context from pInfo, or, if
2255  * pInfo is NULL, from the attributes of hProv.
2256  */
2257 static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context,
2258  const CRYPT_KEY_PROV_INFO *pInfo, HCRYPTPROV hProv)
2259 {
2260     CRYPT_KEY_PROV_INFO info = { 0 };
2261     BOOL ret;
2262
2263     if (!pInfo)
2264     {
2265         DWORD size;
2266         int len;
2267
2268         ret = CryptGetProvParam(hProv, PP_CONTAINER, NULL, &size, 0);
2269         if (ret)
2270         {
2271             LPSTR szContainer = CryptMemAlloc(size);
2272
2273             if (szContainer)
2274             {
2275                 ret = CryptGetProvParam(hProv, PP_CONTAINER,
2276                  (BYTE *)szContainer, &size, 0);
2277                 if (ret)
2278                 {
2279                     len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
2280                      NULL, 0);
2281                     if (len)
2282                     {
2283                         info.pwszContainerName = CryptMemAlloc(len *
2284                          sizeof(WCHAR));
2285                         len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
2286                          info.pwszContainerName, len);
2287                     }
2288                 }
2289                 CryptMemFree(szContainer);
2290             }
2291         }
2292         ret = CryptGetProvParam(hProv, PP_NAME, NULL, &size, 0);
2293         if (ret)
2294         {
2295             LPSTR szProvider = CryptMemAlloc(size);
2296
2297             if (szProvider)
2298             {
2299                 ret = CryptGetProvParam(hProv, PP_NAME, (BYTE *)szProvider,
2300                  &size, 0);
2301                 if (ret)
2302                 {
2303                     len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
2304                      NULL, 0);
2305                     if (len)
2306                     {
2307                         info.pwszProvName = CryptMemAlloc(len *
2308                          sizeof(WCHAR));
2309                         len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
2310                          info.pwszProvName, len);
2311                     }
2312                 }
2313                 CryptMemFree(szProvider);
2314             }
2315         }
2316         size = sizeof(info.dwKeySpec);
2317         /* in case no CRYPT_KEY_PROV_INFO given,
2318          *  we always use AT_SIGNATURE key spec
2319          */
2320         info.dwKeySpec = AT_SIGNATURE;
2321         size = sizeof(info.dwProvType);
2322         ret = CryptGetProvParam(hProv, PP_PROVTYPE, (LPBYTE)&info.dwProvType,
2323          &size, 0);
2324         if (!ret)
2325             info.dwProvType = PROV_RSA_FULL;
2326         pInfo = &info;
2327     }
2328
2329     ret = CertSetCertificateContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID,
2330      0, pInfo);
2331
2332     if (pInfo == &info)
2333     {
2334         CryptMemFree(info.pwszContainerName);
2335         CryptMemFree(info.pwszProvName);
2336     }
2337 }
2338
2339 /* Creates a signed certificate context from the unsigned, encoded certificate
2340  * in blob, using the crypto provider hProv and the signature algorithm sigAlgo.
2341  */
2342 static PCCERT_CONTEXT CRYPT_CreateSignedCert(const CRYPT_DER_BLOB *blob,
2343  HCRYPTPROV hProv, DWORD dwKeySpec, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo)
2344 {
2345     PCCERT_CONTEXT context = NULL;
2346     BOOL ret;
2347     DWORD sigSize = 0;
2348
2349     ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
2350      blob->pbData, blob->cbData, sigAlgo, NULL, NULL, &sigSize);
2351     if (ret)
2352     {
2353         LPBYTE sig = CryptMemAlloc(sigSize);
2354
2355         ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
2356          blob->pbData, blob->cbData, sigAlgo, NULL, sig, &sigSize);
2357         if (ret)
2358         {
2359             CERT_SIGNED_CONTENT_INFO signedInfo;
2360             BYTE *encodedSignedCert = NULL;
2361             DWORD encodedSignedCertSize = 0;
2362
2363             signedInfo.ToBeSigned.cbData = blob->cbData;
2364             signedInfo.ToBeSigned.pbData = blob->pbData;
2365             memcpy(&signedInfo.SignatureAlgorithm, sigAlgo,
2366              sizeof(signedInfo.SignatureAlgorithm));
2367             signedInfo.Signature.cbData = sigSize;
2368             signedInfo.Signature.pbData = sig;
2369             signedInfo.Signature.cUnusedBits = 0;
2370             ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT,
2371              &signedInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
2372              (BYTE *)&encodedSignedCert, &encodedSignedCertSize);
2373             if (ret)
2374             {
2375                 context = CertCreateCertificateContext(X509_ASN_ENCODING,
2376                  encodedSignedCert, encodedSignedCertSize);
2377                 LocalFree(encodedSignedCert);
2378             }
2379         }
2380         CryptMemFree(sig);
2381     }
2382     return context;
2383 }
2384
2385 /* Copies data from the parameters into info, where:
2386  * pSerialNumber: The serial number.  Must not be NULL.
2387  * pSubjectIssuerBlob: Specifies both the subject and issuer for info.
2388  *                     Must not be NULL
2389  * pSignatureAlgorithm: Optional.
2390  * pStartTime: The starting time of the certificate.  If NULL, the current
2391  *             system time is used.
2392  * pEndTime: The ending time of the certificate.  If NULL, one year past the
2393  *           starting time is used.
2394  * pubKey: The public key of the certificate.  Must not be NULL.
2395  * pExtensions: Extensions to be included with the certificate.  Optional.
2396  */
2397 static void CRYPT_MakeCertInfo(PCERT_INFO info, const CRYPT_DATA_BLOB *pSerialNumber,
2398  const CERT_NAME_BLOB *pSubjectIssuerBlob,
2399  const CRYPT_ALGORITHM_IDENTIFIER *pSignatureAlgorithm, const SYSTEMTIME *pStartTime,
2400  const SYSTEMTIME *pEndTime, const CERT_PUBLIC_KEY_INFO *pubKey,
2401  const CERT_EXTENSIONS *pExtensions)
2402 {
2403     static CHAR oid[] = szOID_RSA_SHA1RSA;
2404
2405     assert(info);
2406     assert(pSerialNumber);
2407     assert(pSubjectIssuerBlob);
2408     assert(pubKey);
2409
2410     info->dwVersion = CERT_V3;
2411     info->SerialNumber.cbData = pSerialNumber->cbData;
2412     info->SerialNumber.pbData = pSerialNumber->pbData;
2413     if (pSignatureAlgorithm)
2414         memcpy(&info->SignatureAlgorithm, pSignatureAlgorithm,
2415          sizeof(info->SignatureAlgorithm));
2416     else
2417     {
2418         info->SignatureAlgorithm.pszObjId = oid;
2419         info->SignatureAlgorithm.Parameters.cbData = 0;
2420         info->SignatureAlgorithm.Parameters.pbData = NULL;
2421     }
2422     info->Issuer.cbData = pSubjectIssuerBlob->cbData;
2423     info->Issuer.pbData = pSubjectIssuerBlob->pbData;
2424     if (pStartTime)
2425         SystemTimeToFileTime(pStartTime, &info->NotBefore);
2426     else
2427         GetSystemTimeAsFileTime(&info->NotBefore);
2428     if (pEndTime)
2429         SystemTimeToFileTime(pEndTime, &info->NotAfter);
2430     else
2431     {
2432         SYSTEMTIME endTime;
2433
2434         if (FileTimeToSystemTime(&info->NotBefore, &endTime))
2435         {
2436             endTime.wYear++;
2437             SystemTimeToFileTime(&endTime, &info->NotAfter);
2438         }
2439     }
2440     info->Subject.cbData = pSubjectIssuerBlob->cbData;
2441     info->Subject.pbData = pSubjectIssuerBlob->pbData;
2442     memcpy(&info->SubjectPublicKeyInfo, pubKey,
2443      sizeof(info->SubjectPublicKeyInfo));
2444     if (pExtensions)
2445     {
2446         info->cExtension = pExtensions->cExtension;
2447         info->rgExtension = pExtensions->rgExtension;
2448     }
2449     else
2450     {
2451         info->cExtension = 0;
2452         info->rgExtension = NULL;
2453     }
2454 }
2455  
2456 typedef RPC_STATUS (RPC_ENTRY *UuidCreateFunc)(UUID *);
2457 typedef RPC_STATUS (RPC_ENTRY *UuidToStringFunc)(UUID *, unsigned char **);
2458 typedef RPC_STATUS (RPC_ENTRY *RpcStringFreeFunc)(unsigned char **);
2459
2460 static HCRYPTPROV CRYPT_CreateKeyProv(void)
2461 {
2462     HCRYPTPROV hProv = 0;
2463     HMODULE rpcrt = LoadLibraryA("rpcrt4");
2464
2465     if (rpcrt)
2466     {
2467         UuidCreateFunc uuidCreate = (UuidCreateFunc)GetProcAddress(rpcrt,
2468          "UuidCreate");
2469         UuidToStringFunc uuidToString = (UuidToStringFunc)GetProcAddress(rpcrt,
2470          "UuidToStringA");
2471         RpcStringFreeFunc rpcStringFree = (RpcStringFreeFunc)GetProcAddress(
2472          rpcrt, "RpcStringFreeA");
2473
2474         if (uuidCreate && uuidToString && rpcStringFree)
2475         {
2476             UUID uuid;
2477             RPC_STATUS status = uuidCreate(&uuid);
2478
2479             if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY)
2480             {
2481                 unsigned char *uuidStr;
2482
2483                 status = uuidToString(&uuid, &uuidStr);
2484                 if (status == RPC_S_OK)
2485                 {
2486                     BOOL ret = CryptAcquireContextA(&hProv, (LPCSTR)uuidStr,
2487                      MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_NEWKEYSET);
2488
2489                     if (ret)
2490                     {
2491                         HCRYPTKEY key;
2492
2493                         ret = CryptGenKey(hProv, AT_SIGNATURE, 0, &key);
2494                         if (ret)
2495                             CryptDestroyKey(key);
2496                     }
2497                     rpcStringFree(&uuidStr);
2498                 }
2499             }
2500         }
2501         FreeLibrary(rpcrt);
2502     }
2503     return hProv;
2504 }
2505
2506 PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hProv,
2507  PCERT_NAME_BLOB pSubjectIssuerBlob, DWORD dwFlags,
2508  PCRYPT_KEY_PROV_INFO pKeyProvInfo,
2509  PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime,
2510  PSYSTEMTIME pEndTime, PCERT_EXTENSIONS pExtensions)
2511 {
2512     PCCERT_CONTEXT context = NULL;
2513     BOOL ret, releaseContext = FALSE;
2514     PCERT_PUBLIC_KEY_INFO pubKey = NULL;
2515     DWORD pubKeySize = 0,dwKeySpec = AT_SIGNATURE;
2516
2517     TRACE("(%08lx, %p, %08x, %p, %p, %p, %p, %p)\n", hProv,
2518      pSubjectIssuerBlob, dwFlags, pKeyProvInfo, pSignatureAlgorithm, pStartTime,
2519      pExtensions, pExtensions);
2520
2521     if(!pSubjectIssuerBlob)
2522     {
2523         SetLastError(ERROR_INVALID_PARAMETER);
2524         return NULL;
2525     }
2526
2527     if (!hProv)
2528     {
2529         if (!pKeyProvInfo)
2530         {
2531             hProv = CRYPT_CreateKeyProv();
2532             releaseContext = TRUE;
2533         }
2534         else if (pKeyProvInfo->dwFlags & CERT_SET_KEY_PROV_HANDLE_PROP_ID)
2535         {
2536             SetLastError(NTE_BAD_FLAGS);
2537             return NULL;
2538         }
2539         else
2540         {
2541             HCRYPTKEY hKey = 0;
2542             /* acquire the context using the given information*/
2543             ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
2544                     pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
2545                     pKeyProvInfo->dwFlags);
2546             if (!ret)
2547             {
2548                 if(GetLastError() != NTE_BAD_KEYSET)
2549                     return NULL;
2550                 /* create the key set */
2551                 ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
2552                     pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
2553                     pKeyProvInfo->dwFlags|CRYPT_NEWKEYSET);
2554                 if (!ret)
2555                     return NULL;
2556             }
2557             dwKeySpec = pKeyProvInfo->dwKeySpec;
2558             /* check if the key is here */
2559             ret = CryptGetUserKey(hProv,dwKeySpec,&hKey);
2560             if(!ret)
2561             {
2562                 if (NTE_NO_KEY == GetLastError())
2563                 { /* generate the key */
2564                     ret = CryptGenKey(hProv,dwKeySpec,0,&hKey);
2565                 }
2566                 if (!ret)
2567                 {
2568                     CryptReleaseContext(hProv,0);
2569                     SetLastError(NTE_BAD_KEYSET);
2570                     return NULL;
2571                 }
2572             }
2573             CryptDestroyKey(hKey);
2574             releaseContext = TRUE;
2575         }
2576     }
2577     else if (pKeyProvInfo)
2578     {
2579         SetLastError(ERROR_INVALID_PARAMETER);
2580         return NULL;
2581     }
2582
2583     CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING, NULL,
2584      &pubKeySize);
2585     pubKey = CryptMemAlloc(pubKeySize);
2586     if (pubKey)
2587     {
2588         ret = CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING,
2589          pubKey, &pubKeySize);
2590         if (ret)
2591         {
2592             CERT_INFO info = { 0 };
2593             CRYPT_DER_BLOB blob = { 0, NULL };
2594             BYTE serial[16];
2595             CRYPT_DATA_BLOB serialBlob = { sizeof(serial), serial };
2596
2597             CryptGenRandom(hProv, sizeof(serial), serial);
2598             CRYPT_MakeCertInfo(&info, &serialBlob, pSubjectIssuerBlob,
2599              pSignatureAlgorithm, pStartTime, pEndTime, pubKey, pExtensions);
2600             ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
2601              &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&blob.pbData,
2602              &blob.cbData);
2603             if (ret)
2604             {
2605                 if (!(dwFlags & CERT_CREATE_SELFSIGN_NO_SIGN))
2606                     context = CRYPT_CreateSignedCert(&blob, hProv,dwKeySpec,
2607                      &info.SignatureAlgorithm);
2608                 else
2609                     context = CertCreateCertificateContext(X509_ASN_ENCODING,
2610                      blob.pbData, blob.cbData);
2611                 if (context && !(dwFlags & CERT_CREATE_SELFSIGN_NO_KEY_INFO))
2612                     CertContext_SetKeyProvInfo(context, pKeyProvInfo, hProv);
2613                 LocalFree(blob.pbData);
2614             }
2615         }
2616         CryptMemFree(pubKey);
2617     }
2618     if (releaseContext)
2619         CryptReleaseContext(hProv, 0);
2620     return context;
2621 }
2622
2623 BOOL WINAPI CertVerifyCTLUsage(DWORD dwEncodingType, DWORD dwSubjectType,
2624                                void *pvSubject, PCTL_USAGE pSubjectUsage, DWORD dwFlags,
2625                                PCTL_VERIFY_USAGE_PARA pVerifyUsagePara,
2626                                PCTL_VERIFY_USAGE_STATUS pVerifyUsageStatus)
2627 {
2628     FIXME("(0x%x, %d, %p, %p, 0x%x, %p, %p): stub\n", dwEncodingType,
2629           dwSubjectType, pvSubject, pSubjectUsage, dwFlags, pVerifyUsagePara,
2630           pVerifyUsageStatus);
2631     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2632     return FALSE;
2633 }