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