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