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