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