wined3d: Get rid of the local_constant typedef.
[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     return CryptVerifyCertificateSignatureEx(hCryptProv, dwCertEncodingType,
2243      CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, (void *)pbEncoded,
2244      CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
2245 }
2246
2247 static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv,
2248  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pubKeyInfo,
2249  const CERT_SIGNED_CONTENT_INFO *signedCert)
2250 {
2251     BOOL ret;
2252     HCRYPTKEY key;
2253     PCCRYPT_OID_INFO info;
2254     ALG_ID pubKeyID, hashID;
2255
2256     info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2257      signedCert->SignatureAlgorithm.pszObjId, 0);
2258     if (!info || info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID)
2259     {
2260         SetLastError(NTE_BAD_ALGID);
2261         return FALSE;
2262     }
2263     hashID = info->u.Algid;
2264     if (info->ExtraInfo.cbData >= sizeof(ALG_ID))
2265         pubKeyID = *(ALG_ID *)info->ExtraInfo.pbData;
2266     else
2267         pubKeyID = hashID;
2268     /* Load the default provider if necessary */
2269     if (!hCryptProv)
2270         hCryptProv = CRYPT_GetDefaultProvider();
2271     ret = CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType,
2272      pubKeyInfo, pubKeyID, 0, NULL, &key);
2273     if (ret)
2274     {
2275         HCRYPTHASH hash;
2276
2277         ret = CryptCreateHash(hCryptProv, hashID, 0, 0, &hash);
2278         if (ret)
2279         {
2280             ret = CryptHashData(hash, signedCert->ToBeSigned.pbData,
2281              signedCert->ToBeSigned.cbData, 0);
2282             if (ret)
2283                 ret = CryptVerifySignatureW(hash, signedCert->Signature.pbData,
2284                  signedCert->Signature.cbData, key, NULL, 0);
2285             CryptDestroyHash(hash);
2286         }
2287         CryptDestroyKey(key);
2288     }
2289     return ret;
2290 }
2291
2292 BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV_LEGACY hCryptProv,
2293  DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
2294  DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
2295 {
2296     BOOL ret = TRUE;
2297     CRYPT_DATA_BLOB subjectBlob;
2298
2299     TRACE("(%08lx, %d, %d, %p, %d, %p, %08x, %p)\n", hCryptProv,
2300      dwCertEncodingType, dwSubjectType, pvSubject, dwIssuerType, pvIssuer,
2301      dwFlags, pvReserved);
2302
2303     switch (dwSubjectType)
2304     {
2305     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB:
2306     {
2307         PCRYPT_DATA_BLOB blob = pvSubject;
2308
2309         subjectBlob.pbData = blob->pbData;
2310         subjectBlob.cbData = blob->cbData;
2311         break;
2312     }
2313     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT:
2314     {
2315         PCERT_CONTEXT context = pvSubject;
2316
2317         subjectBlob.pbData = context->pbCertEncoded;
2318         subjectBlob.cbData = context->cbCertEncoded;
2319         break;
2320     }
2321     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL:
2322     {
2323         PCRL_CONTEXT context = pvSubject;
2324
2325         subjectBlob.pbData = context->pbCrlEncoded;
2326         subjectBlob.cbData = context->cbCrlEncoded;
2327         break;
2328     }
2329     default:
2330         SetLastError(E_INVALIDARG);
2331         ret = FALSE;
2332     }
2333
2334     if (ret)
2335     {
2336         PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
2337         DWORD size = 0;
2338
2339         ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
2340          subjectBlob.pbData, subjectBlob.cbData,
2341          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
2342          &signedCert, &size);
2343         if (ret)
2344         {
2345             switch (dwIssuerType)
2346             {
2347             case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY:
2348                 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
2349                  dwCertEncodingType, pvIssuer,
2350                  signedCert);
2351                 break;
2352             case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT:
2353                 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
2354                  dwCertEncodingType,
2355                  &((PCCERT_CONTEXT)pvIssuer)->pCertInfo->SubjectPublicKeyInfo,
2356                  signedCert);
2357                 break;
2358             case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN:
2359                 FIXME("CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: stub\n");
2360                 ret = FALSE;
2361                 break;
2362             case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL:
2363                 if (pvIssuer)
2364                 {
2365                     SetLastError(E_INVALIDARG);
2366                     ret = FALSE;
2367                 }
2368                 else
2369                 {
2370                     FIXME("unimplemented for NULL signer\n");
2371                     SetLastError(E_INVALIDARG);
2372                     ret = FALSE;
2373                 }
2374                 break;
2375             default:
2376                 SetLastError(E_INVALIDARG);
2377                 ret = FALSE;
2378             }
2379             LocalFree(signedCert);
2380         }
2381     }
2382     return ret;
2383 }
2384
2385 BOOL WINAPI CertGetIntendedKeyUsage(DWORD dwCertEncodingType,
2386  PCERT_INFO pCertInfo, BYTE *pbKeyUsage, DWORD cbKeyUsage)
2387 {
2388     PCERT_EXTENSION ext;
2389     BOOL ret = FALSE;
2390
2391     TRACE("(%08x, %p, %p, %d)\n", dwCertEncodingType, pCertInfo, pbKeyUsage,
2392      cbKeyUsage);
2393
2394     ext = CertFindExtension(szOID_KEY_USAGE, pCertInfo->cExtension,
2395      pCertInfo->rgExtension);
2396     if (ext)
2397     {
2398         CRYPT_BIT_BLOB usage;
2399         DWORD size = sizeof(usage);
2400
2401         ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS,
2402          ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL,
2403          &usage, &size);
2404         if (ret)
2405         {
2406             if (cbKeyUsage < usage.cbData)
2407                 ret = FALSE;
2408             else
2409             {
2410                 memcpy(pbKeyUsage, usage.pbData, usage.cbData);
2411                 if (cbKeyUsage > usage.cbData)
2412                     memset(pbKeyUsage + usage.cbData, 0,
2413                      cbKeyUsage - usage.cbData);
2414             }
2415         }
2416     }
2417     else
2418         SetLastError(0);
2419     return ret;
2420 }
2421
2422 BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags,
2423  PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage)
2424 {
2425     PCERT_ENHKEY_USAGE usage = NULL;
2426     DWORD bytesNeeded;
2427     BOOL ret = TRUE;
2428
2429     if (!pCertContext || !pcbUsage)
2430     {
2431         SetLastError(ERROR_INVALID_PARAMETER);
2432         return FALSE;
2433     }
2434
2435     TRACE("(%p, %08x, %p, %d)\n", pCertContext, dwFlags, pUsage, *pcbUsage);
2436
2437     if (!(dwFlags & CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG))
2438     {
2439         DWORD propSize = 0;
2440
2441         if (CertGetCertificateContextProperty(pCertContext,
2442          CERT_ENHKEY_USAGE_PROP_ID, NULL, &propSize))
2443         {
2444             LPBYTE buf = CryptMemAlloc(propSize);
2445
2446             if (buf)
2447             {
2448                 if (CertGetCertificateContextProperty(pCertContext,
2449                  CERT_ENHKEY_USAGE_PROP_ID, buf, &propSize))
2450                 {
2451                     ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
2452                      X509_ENHANCED_KEY_USAGE, buf, propSize,
2453                      CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
2454                 }
2455                 CryptMemFree(buf);
2456             }
2457         }
2458     }
2459     if (!usage && !(dwFlags & CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG))
2460     {
2461         PCERT_EXTENSION ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
2462          pCertContext->pCertInfo->cExtension,
2463          pCertContext->pCertInfo->rgExtension);
2464
2465         if (ext)
2466         {
2467             ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
2468              X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
2469              CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
2470         }
2471     }
2472     if (!usage)
2473     {
2474         /* If a particular location is specified, this should fail.  Otherwise
2475          * it should succeed with an empty usage.  (This is true on Win2k and
2476          * later, which we emulate.)
2477          */
2478         if (dwFlags)
2479         {
2480             SetLastError(CRYPT_E_NOT_FOUND);
2481             ret = FALSE;
2482         }
2483         else
2484             bytesNeeded = sizeof(CERT_ENHKEY_USAGE);
2485     }
2486
2487     if (ret)
2488     {
2489         if (!pUsage)
2490             *pcbUsage = bytesNeeded;
2491         else if (*pcbUsage < bytesNeeded)
2492         {
2493             SetLastError(ERROR_MORE_DATA);
2494             *pcbUsage = bytesNeeded;
2495             ret = FALSE;
2496         }
2497         else
2498         {
2499             *pcbUsage = bytesNeeded;
2500             if (usage)
2501             {
2502                 DWORD i;
2503                 LPSTR nextOID = (LPSTR)((LPBYTE)pUsage +
2504                  sizeof(CERT_ENHKEY_USAGE) +
2505                  usage->cUsageIdentifier * sizeof(LPSTR));
2506
2507                 pUsage->cUsageIdentifier = usage->cUsageIdentifier;
2508                 pUsage->rgpszUsageIdentifier = (LPSTR *)((LPBYTE)pUsage +
2509                  sizeof(CERT_ENHKEY_USAGE));
2510                 for (i = 0; i < usage->cUsageIdentifier; i++)
2511                 {
2512                     pUsage->rgpszUsageIdentifier[i] = nextOID;
2513                     strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
2514                     nextOID += strlen(nextOID) + 1;
2515                 }
2516             }
2517             else
2518                 pUsage->cUsageIdentifier = 0;
2519         }
2520     }
2521     if (usage)
2522         LocalFree(usage);
2523     TRACE("returning %d\n", ret);
2524     return ret;
2525 }
2526
2527 BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext,
2528  PCERT_ENHKEY_USAGE pUsage)
2529 {
2530     BOOL ret;
2531
2532     TRACE("(%p, %p)\n", pCertContext, pUsage);
2533
2534     if (pUsage)
2535     {
2536         CRYPT_DATA_BLOB blob = { 0, NULL };
2537
2538         ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
2539          pUsage, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData, &blob.cbData);
2540         if (ret)
2541         {
2542             ret = CertSetCertificateContextProperty(pCertContext,
2543              CERT_ENHKEY_USAGE_PROP_ID, 0, &blob);
2544             LocalFree(blob.pbData);
2545         }
2546     }
2547     else
2548         ret = CertSetCertificateContextProperty(pCertContext,
2549          CERT_ENHKEY_USAGE_PROP_ID, 0, NULL);
2550     return ret;
2551 }
2552
2553 BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
2554  LPCSTR pszUsageIdentifier)
2555 {
2556     BOOL ret;
2557     DWORD size;
2558
2559     TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
2560
2561     if (CertGetEnhancedKeyUsage(pCertContext,
2562      CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size))
2563     {
2564         PCERT_ENHKEY_USAGE usage = CryptMemAlloc(size);
2565
2566         if (usage)
2567         {
2568             ret = CertGetEnhancedKeyUsage(pCertContext,
2569              CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size);
2570             if (ret)
2571             {
2572                 DWORD i;
2573                 BOOL exists = FALSE;
2574
2575                 /* Make sure usage doesn't already exist */
2576                 for (i = 0; !exists && i < usage->cUsageIdentifier; i++)
2577                 {
2578                     if (!strcmp(usage->rgpszUsageIdentifier[i],
2579                      pszUsageIdentifier))
2580                         exists = TRUE;
2581                 }
2582                 if (!exists)
2583                 {
2584                     PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size +
2585                      sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
2586
2587                     if (newUsage)
2588                     {
2589                         LPSTR nextOID;
2590
2591                         newUsage->rgpszUsageIdentifier = (LPSTR *)
2592                          ((LPBYTE)newUsage + sizeof(CERT_ENHKEY_USAGE));
2593                         nextOID = (LPSTR)((LPBYTE)newUsage->rgpszUsageIdentifier
2594                           + (usage->cUsageIdentifier + 1) * sizeof(LPSTR));
2595                         for (i = 0; i < usage->cUsageIdentifier; i++)
2596                         {
2597                             newUsage->rgpszUsageIdentifier[i] = nextOID;
2598                             strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
2599                             nextOID += strlen(nextOID) + 1;
2600                         }
2601                         newUsage->rgpszUsageIdentifier[i] = nextOID;
2602                         strcpy(nextOID, pszUsageIdentifier);
2603                         newUsage->cUsageIdentifier = i + 1;
2604                         ret = CertSetEnhancedKeyUsage(pCertContext, newUsage);
2605                         CryptMemFree(newUsage);
2606                     }
2607                     else
2608                         ret = FALSE;
2609                 }
2610             }
2611             CryptMemFree(usage);
2612         }
2613         else
2614             ret = FALSE;
2615     }
2616     else
2617     {
2618         PCERT_ENHKEY_USAGE usage = CryptMemAlloc(sizeof(CERT_ENHKEY_USAGE) +
2619          sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
2620
2621         if (usage)
2622         {
2623             usage->rgpszUsageIdentifier =
2624              (LPSTR *)((LPBYTE)usage + sizeof(CERT_ENHKEY_USAGE));
2625             usage->rgpszUsageIdentifier[0] = (LPSTR)((LPBYTE)usage +
2626              sizeof(CERT_ENHKEY_USAGE) + sizeof(LPSTR));
2627             strcpy(usage->rgpszUsageIdentifier[0], pszUsageIdentifier);
2628             usage->cUsageIdentifier = 1;
2629             ret = CertSetEnhancedKeyUsage(pCertContext, usage);
2630             CryptMemFree(usage);
2631         }
2632         else
2633             ret = FALSE;
2634     }
2635     return ret;
2636 }
2637
2638 BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
2639  LPCSTR pszUsageIdentifier)
2640 {
2641     BOOL ret;
2642     DWORD size;
2643     CERT_ENHKEY_USAGE usage;
2644
2645     TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
2646
2647     size = sizeof(usage);
2648     ret = CertGetEnhancedKeyUsage(pCertContext,
2649      CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, &usage, &size);
2650     if (!ret && GetLastError() == ERROR_MORE_DATA)
2651     {
2652         PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
2653
2654         if (pUsage)
2655         {
2656             ret = CertGetEnhancedKeyUsage(pCertContext,
2657              CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
2658             if (ret)
2659             {
2660                 if (pUsage->cUsageIdentifier)
2661                 {
2662                     DWORD i;
2663                     BOOL found = FALSE;
2664
2665                     for (i = 0; i < pUsage->cUsageIdentifier; i++)
2666                     {
2667                         if (!strcmp(pUsage->rgpszUsageIdentifier[i],
2668                          pszUsageIdentifier))
2669                             found = TRUE;
2670                         if (found && i < pUsage->cUsageIdentifier - 1)
2671                             pUsage->rgpszUsageIdentifier[i] =
2672                              pUsage->rgpszUsageIdentifier[i + 1];
2673                     }
2674                     pUsage->cUsageIdentifier--;
2675                     /* Remove the usage if it's empty */
2676                     if (pUsage->cUsageIdentifier)
2677                         ret = CertSetEnhancedKeyUsage(pCertContext, pUsage);
2678                     else
2679                         ret = CertSetEnhancedKeyUsage(pCertContext, NULL);
2680                 }
2681             }
2682             CryptMemFree(pUsage);
2683         }
2684         else
2685             ret = FALSE;
2686     }
2687     else
2688     {
2689         /* it fit in an empty usage, therefore there's nothing to remove */
2690         ret = TRUE;
2691     }
2692     return ret;
2693 }
2694
2695 struct BitField
2696 {
2697     DWORD  cIndexes;
2698     DWORD *indexes;
2699 };
2700
2701 #define BITS_PER_DWORD (sizeof(DWORD) * 8)
2702
2703 static void CRYPT_SetBitInField(struct BitField *field, DWORD bit)
2704 {
2705     DWORD indexIndex = bit / BITS_PER_DWORD;
2706
2707     if (indexIndex + 1 > field->cIndexes)
2708     {
2709         if (field->cIndexes)
2710             field->indexes = CryptMemRealloc(field->indexes,
2711              (indexIndex + 1) * sizeof(DWORD));
2712         else
2713             field->indexes = CryptMemAlloc(sizeof(DWORD));
2714         if (field->indexes)
2715         {
2716             field->indexes[indexIndex] = 0;
2717             field->cIndexes = indexIndex + 1;
2718         }
2719     }
2720     if (field->indexes)
2721         field->indexes[indexIndex] |= 1 << (bit % BITS_PER_DWORD);
2722 }
2723
2724 static BOOL CRYPT_IsBitInFieldSet(const struct BitField *field, DWORD bit)
2725 {
2726     BOOL set = FALSE;
2727     DWORD indexIndex = bit / BITS_PER_DWORD;
2728
2729     assert(field->cIndexes);
2730     set = field->indexes[indexIndex] & (1 << (bit % BITS_PER_DWORD));
2731     return set;
2732 }
2733
2734 BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts,
2735  int *cNumOIDs, LPSTR *rghOIDs, DWORD *pcbOIDs)
2736 {
2737     BOOL ret = TRUE;
2738     DWORD i, cbOIDs = 0;
2739     BOOL allUsagesValid = TRUE;
2740     CERT_ENHKEY_USAGE validUsages = { 0, NULL };
2741
2742     TRACE("(%d, %p, %d, %p, %d)\n", cCerts, rghCerts, *cNumOIDs,
2743      rghOIDs, *pcbOIDs);
2744
2745     for (i = 0; i < cCerts; i++)
2746     {
2747         CERT_ENHKEY_USAGE usage;
2748         DWORD size = sizeof(usage);
2749
2750         ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, &usage, &size);
2751         /* Success is deliberately ignored: it implies all usages are valid */
2752         if (!ret && GetLastError() == ERROR_MORE_DATA)
2753         {
2754             PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
2755
2756             allUsagesValid = FALSE;
2757             if (pUsage)
2758             {
2759                 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, pUsage, &size);
2760                 if (ret)
2761                 {
2762                     if (!validUsages.cUsageIdentifier)
2763                     {
2764                         DWORD j;
2765
2766                         cbOIDs = pUsage->cUsageIdentifier * sizeof(LPSTR);
2767                         validUsages.cUsageIdentifier = pUsage->cUsageIdentifier;
2768                         for (j = 0; j < validUsages.cUsageIdentifier; j++)
2769                             cbOIDs += lstrlenA(pUsage->rgpszUsageIdentifier[j])
2770                              + 1;
2771                         validUsages.rgpszUsageIdentifier =
2772                          CryptMemAlloc(cbOIDs);
2773                         if (validUsages.rgpszUsageIdentifier)
2774                         {
2775                             LPSTR nextOID = (LPSTR)
2776                              ((LPBYTE)validUsages.rgpszUsageIdentifier +
2777                              validUsages.cUsageIdentifier * sizeof(LPSTR));
2778
2779                             for (j = 0; j < validUsages.cUsageIdentifier; j++)
2780                             {
2781                                 validUsages.rgpszUsageIdentifier[j] = nextOID;
2782                                 lstrcpyA(validUsages.rgpszUsageIdentifier[j],
2783                                  pUsage->rgpszUsageIdentifier[j]);
2784                                 nextOID += lstrlenA(nextOID) + 1;
2785                             }
2786                         }
2787                     }
2788                     else
2789                     {
2790                         struct BitField validIndexes = { 0, NULL };
2791                         DWORD j, k, numRemoved = 0;
2792
2793                         /* Merge: build a bitmap of all the indexes of
2794                          * validUsages.rgpszUsageIdentifier that are in pUsage.
2795                          */
2796                         for (j = 0; j < pUsage->cUsageIdentifier; j++)
2797                         {
2798                             for (k = 0; k < validUsages.cUsageIdentifier; k++)
2799                             {
2800                                 if (!strcmp(pUsage->rgpszUsageIdentifier[j],
2801                                  validUsages.rgpszUsageIdentifier[k]))
2802                                 {
2803                                     CRYPT_SetBitInField(&validIndexes, k);
2804                                     break;
2805                                 }
2806                             }
2807                         }
2808                         /* Merge by removing from validUsages those that are
2809                          * not in the bitmap.
2810                          */
2811                         for (j = 0; j < validUsages.cUsageIdentifier; j++)
2812                         {
2813                             if (!CRYPT_IsBitInFieldSet(&validIndexes, j))
2814                             {
2815                                 if (j < validUsages.cUsageIdentifier - 1)
2816                                 {
2817                                     memmove(&validUsages.rgpszUsageIdentifier[j],
2818                                      &validUsages.rgpszUsageIdentifier[j +
2819                                      numRemoved + 1],
2820                                      (validUsages.cUsageIdentifier - numRemoved
2821                                      - j - 1) * sizeof(LPSTR));
2822                                     cbOIDs -= lstrlenA(
2823                                      validUsages.rgpszUsageIdentifier[j]) + 1 +
2824                                      sizeof(LPSTR);
2825                                     validUsages.cUsageIdentifier--;
2826                                     numRemoved++;
2827                                 }
2828                                 else
2829                                     validUsages.cUsageIdentifier--;
2830                             }
2831                         }
2832                         CryptMemFree(validIndexes.indexes);
2833                     }
2834                 }
2835                 CryptMemFree(pUsage);
2836             }
2837         }
2838     }
2839     ret = TRUE;
2840     if (allUsagesValid)
2841     {
2842         *cNumOIDs = -1;
2843         *pcbOIDs = 0;
2844     }
2845     else
2846     {
2847         *cNumOIDs = validUsages.cUsageIdentifier;
2848         if (!rghOIDs)
2849             *pcbOIDs = cbOIDs;
2850         else if (*pcbOIDs < cbOIDs)
2851         {
2852             *pcbOIDs = cbOIDs;
2853             SetLastError(ERROR_MORE_DATA);
2854             ret = FALSE;
2855         }
2856         else
2857         {
2858             LPSTR nextOID = (LPSTR)((LPBYTE)rghOIDs +
2859              validUsages.cUsageIdentifier * sizeof(LPSTR));
2860
2861             *pcbOIDs = cbOIDs;
2862             for (i = 0; i < validUsages.cUsageIdentifier; i++)
2863             {
2864                 rghOIDs[i] = nextOID;
2865                 lstrcpyA(nextOID, validUsages.rgpszUsageIdentifier[i]);
2866                 nextOID += lstrlenA(nextOID) + 1;
2867             }
2868         }
2869     }
2870     CryptMemFree(validUsages.rgpszUsageIdentifier);
2871     TRACE("cNumOIDs: %d\n", *cNumOIDs);
2872     TRACE("returning %d\n", ret);
2873     return ret;
2874 }
2875
2876 /* Sets the CERT_KEY_PROV_INFO_PROP_ID property of context from pInfo, or, if
2877  * pInfo is NULL, from the attributes of hProv.
2878  */
2879 static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context,
2880  const CRYPT_KEY_PROV_INFO *pInfo, HCRYPTPROV hProv)
2881 {
2882     CRYPT_KEY_PROV_INFO info = { 0 };
2883     BOOL ret;
2884
2885     if (!pInfo)
2886     {
2887         DWORD size;
2888         int len;
2889
2890         ret = CryptGetProvParam(hProv, PP_CONTAINER, NULL, &size, 0);
2891         if (ret)
2892         {
2893             LPSTR szContainer = CryptMemAlloc(size);
2894
2895             if (szContainer)
2896             {
2897                 ret = CryptGetProvParam(hProv, PP_CONTAINER,
2898                  (BYTE *)szContainer, &size, 0);
2899                 if (ret)
2900                 {
2901                     len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
2902                      NULL, 0);
2903                     if (len)
2904                     {
2905                         info.pwszContainerName = CryptMemAlloc(len *
2906                          sizeof(WCHAR));
2907                         MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
2908                          info.pwszContainerName, len);
2909                     }
2910                 }
2911                 CryptMemFree(szContainer);
2912             }
2913         }
2914         ret = CryptGetProvParam(hProv, PP_NAME, NULL, &size, 0);
2915         if (ret)
2916         {
2917             LPSTR szProvider = CryptMemAlloc(size);
2918
2919             if (szProvider)
2920             {
2921                 ret = CryptGetProvParam(hProv, PP_NAME, (BYTE *)szProvider,
2922                  &size, 0);
2923                 if (ret)
2924                 {
2925                     len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
2926                      NULL, 0);
2927                     if (len)
2928                     {
2929                         info.pwszProvName = CryptMemAlloc(len *
2930                          sizeof(WCHAR));
2931                         MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
2932                          info.pwszProvName, len);
2933                     }
2934                 }
2935                 CryptMemFree(szProvider);
2936             }
2937         }
2938         size = sizeof(info.dwKeySpec);
2939         /* in case no CRYPT_KEY_PROV_INFO given,
2940          *  we always use AT_SIGNATURE key spec
2941          */
2942         info.dwKeySpec = AT_SIGNATURE;
2943         size = sizeof(info.dwProvType);
2944         ret = CryptGetProvParam(hProv, PP_PROVTYPE, (LPBYTE)&info.dwProvType,
2945          &size, 0);
2946         if (!ret)
2947             info.dwProvType = PROV_RSA_FULL;
2948         pInfo = &info;
2949     }
2950
2951     CertSetCertificateContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID,
2952      0, pInfo);
2953
2954     if (pInfo == &info)
2955     {
2956         CryptMemFree(info.pwszContainerName);
2957         CryptMemFree(info.pwszProvName);
2958     }
2959 }
2960
2961 /* Creates a signed certificate context from the unsigned, encoded certificate
2962  * in blob, using the crypto provider hProv and the signature algorithm sigAlgo.
2963  */
2964 static PCCERT_CONTEXT CRYPT_CreateSignedCert(const CRYPT_DER_BLOB *blob,
2965  HCRYPTPROV hProv, DWORD dwKeySpec, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo)
2966 {
2967     PCCERT_CONTEXT context = NULL;
2968     BOOL ret;
2969     DWORD sigSize = 0;
2970
2971     ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
2972      blob->pbData, blob->cbData, sigAlgo, NULL, NULL, &sigSize);
2973     if (ret)
2974     {
2975         LPBYTE sig = CryptMemAlloc(sigSize);
2976
2977         ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
2978          blob->pbData, blob->cbData, sigAlgo, NULL, sig, &sigSize);
2979         if (ret)
2980         {
2981             CERT_SIGNED_CONTENT_INFO signedInfo;
2982             BYTE *encodedSignedCert = NULL;
2983             DWORD encodedSignedCertSize = 0;
2984
2985             signedInfo.ToBeSigned.cbData = blob->cbData;
2986             signedInfo.ToBeSigned.pbData = blob->pbData;
2987             memcpy(&signedInfo.SignatureAlgorithm, sigAlgo,
2988              sizeof(signedInfo.SignatureAlgorithm));
2989             signedInfo.Signature.cbData = sigSize;
2990             signedInfo.Signature.pbData = sig;
2991             signedInfo.Signature.cUnusedBits = 0;
2992             ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT,
2993              &signedInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
2994              &encodedSignedCert, &encodedSignedCertSize);
2995             if (ret)
2996             {
2997                 context = CertCreateCertificateContext(X509_ASN_ENCODING,
2998                  encodedSignedCert, encodedSignedCertSize);
2999                 LocalFree(encodedSignedCert);
3000             }
3001         }
3002         CryptMemFree(sig);
3003     }
3004     return context;
3005 }
3006
3007 /* Copies data from the parameters into info, where:
3008  * pSerialNumber: The serial number.  Must not be NULL.
3009  * pSubjectIssuerBlob: Specifies both the subject and issuer for info.
3010  *                     Must not be NULL
3011  * pSignatureAlgorithm: Optional.
3012  * pStartTime: The starting time of the certificate.  If NULL, the current
3013  *             system time is used.
3014  * pEndTime: The ending time of the certificate.  If NULL, one year past the
3015  *           starting time is used.
3016  * pubKey: The public key of the certificate.  Must not be NULL.
3017  * pExtensions: Extensions to be included with the certificate.  Optional.
3018  */
3019 static void CRYPT_MakeCertInfo(PCERT_INFO info, const CRYPT_DATA_BLOB *pSerialNumber,
3020  const CERT_NAME_BLOB *pSubjectIssuerBlob,
3021  const CRYPT_ALGORITHM_IDENTIFIER *pSignatureAlgorithm, const SYSTEMTIME *pStartTime,
3022  const SYSTEMTIME *pEndTime, const CERT_PUBLIC_KEY_INFO *pubKey,
3023  const CERT_EXTENSIONS *pExtensions)
3024 {
3025     static CHAR oid[] = szOID_RSA_SHA1RSA;
3026
3027     assert(info);
3028     assert(pSerialNumber);
3029     assert(pSubjectIssuerBlob);
3030     assert(pubKey);
3031
3032     if (pExtensions && pExtensions->cExtension)
3033         info->dwVersion = CERT_V3;
3034     else
3035         info->dwVersion = CERT_V1;
3036     info->SerialNumber.cbData = pSerialNumber->cbData;
3037     info->SerialNumber.pbData = pSerialNumber->pbData;
3038     if (pSignatureAlgorithm)
3039         memcpy(&info->SignatureAlgorithm, pSignatureAlgorithm,
3040          sizeof(info->SignatureAlgorithm));
3041     else
3042     {
3043         info->SignatureAlgorithm.pszObjId = oid;
3044         info->SignatureAlgorithm.Parameters.cbData = 0;
3045         info->SignatureAlgorithm.Parameters.pbData = NULL;
3046     }
3047     info->Issuer.cbData = pSubjectIssuerBlob->cbData;
3048     info->Issuer.pbData = pSubjectIssuerBlob->pbData;
3049     if (pStartTime)
3050         SystemTimeToFileTime(pStartTime, &info->NotBefore);
3051     else
3052         GetSystemTimeAsFileTime(&info->NotBefore);
3053     if (pEndTime)
3054         SystemTimeToFileTime(pEndTime, &info->NotAfter);
3055     else
3056     {
3057         SYSTEMTIME endTime;
3058
3059         if (FileTimeToSystemTime(&info->NotBefore, &endTime))
3060         {
3061             endTime.wYear++;
3062             SystemTimeToFileTime(&endTime, &info->NotAfter);
3063         }
3064     }
3065     info->Subject.cbData = pSubjectIssuerBlob->cbData;
3066     info->Subject.pbData = pSubjectIssuerBlob->pbData;
3067     memcpy(&info->SubjectPublicKeyInfo, pubKey,
3068      sizeof(info->SubjectPublicKeyInfo));
3069     if (pExtensions)
3070     {
3071         info->cExtension = pExtensions->cExtension;
3072         info->rgExtension = pExtensions->rgExtension;
3073     }
3074     else
3075     {
3076         info->cExtension = 0;
3077         info->rgExtension = NULL;
3078     }
3079 }
3080  
3081 typedef RPC_STATUS (RPC_ENTRY *UuidCreateFunc)(UUID *);
3082 typedef RPC_STATUS (RPC_ENTRY *UuidToStringFunc)(UUID *, unsigned char **);
3083 typedef RPC_STATUS (RPC_ENTRY *RpcStringFreeFunc)(unsigned char **);
3084
3085 static HCRYPTPROV CRYPT_CreateKeyProv(void)
3086 {
3087     HCRYPTPROV hProv = 0;
3088     HMODULE rpcrt = LoadLibraryA("rpcrt4");
3089
3090     if (rpcrt)
3091     {
3092         UuidCreateFunc uuidCreate = (UuidCreateFunc)GetProcAddress(rpcrt,
3093          "UuidCreate");
3094         UuidToStringFunc uuidToString = (UuidToStringFunc)GetProcAddress(rpcrt,
3095          "UuidToStringA");
3096         RpcStringFreeFunc rpcStringFree = (RpcStringFreeFunc)GetProcAddress(
3097          rpcrt, "RpcStringFreeA");
3098
3099         if (uuidCreate && uuidToString && rpcStringFree)
3100         {
3101             UUID uuid;
3102             RPC_STATUS status = uuidCreate(&uuid);
3103
3104             if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY)
3105             {
3106                 unsigned char *uuidStr;
3107
3108                 status = uuidToString(&uuid, &uuidStr);
3109                 if (status == RPC_S_OK)
3110                 {
3111                     BOOL ret = CryptAcquireContextA(&hProv, (LPCSTR)uuidStr,
3112                      MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_NEWKEYSET);
3113
3114                     if (ret)
3115                     {
3116                         HCRYPTKEY key;
3117
3118                         ret = CryptGenKey(hProv, AT_SIGNATURE, 0, &key);
3119                         if (ret)
3120                             CryptDestroyKey(key);
3121                     }
3122                     rpcStringFree(&uuidStr);
3123                 }
3124             }
3125         }
3126         FreeLibrary(rpcrt);
3127     }
3128     return hProv;
3129 }
3130
3131 PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hProv,
3132  PCERT_NAME_BLOB pSubjectIssuerBlob, DWORD dwFlags,
3133  PCRYPT_KEY_PROV_INFO pKeyProvInfo,
3134  PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime,
3135  PSYSTEMTIME pEndTime, PCERT_EXTENSIONS pExtensions)
3136 {
3137     PCCERT_CONTEXT context = NULL;
3138     BOOL ret, releaseContext = FALSE;
3139     PCERT_PUBLIC_KEY_INFO pubKey = NULL;
3140     DWORD pubKeySize = 0,dwKeySpec = AT_SIGNATURE;
3141
3142     TRACE("(%08lx, %p, %08x, %p, %p, %p, %p, %p)\n", hProv,
3143      pSubjectIssuerBlob, dwFlags, pKeyProvInfo, pSignatureAlgorithm, pStartTime,
3144      pExtensions, pExtensions);
3145
3146     if(!pSubjectIssuerBlob)
3147     {
3148         SetLastError(ERROR_INVALID_PARAMETER);
3149         return NULL;
3150     }
3151
3152     if (!hProv)
3153     {
3154         if (!pKeyProvInfo)
3155         {
3156             hProv = CRYPT_CreateKeyProv();
3157             releaseContext = TRUE;
3158         }
3159         else if (pKeyProvInfo->dwFlags & CERT_SET_KEY_PROV_HANDLE_PROP_ID)
3160         {
3161             SetLastError(NTE_BAD_FLAGS);
3162             return NULL;
3163         }
3164         else
3165         {
3166             HCRYPTKEY hKey = 0;
3167             /* acquire the context using the given information*/
3168             ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
3169                     pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
3170                     pKeyProvInfo->dwFlags);
3171             if (!ret)
3172             {
3173                 if(GetLastError() != NTE_BAD_KEYSET)
3174                     return NULL;
3175                 /* create the key set */
3176                 ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
3177                     pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
3178                     pKeyProvInfo->dwFlags|CRYPT_NEWKEYSET);
3179                 if (!ret)
3180                     return NULL;
3181             }
3182             dwKeySpec = pKeyProvInfo->dwKeySpec;
3183             /* check if the key is here */
3184             ret = CryptGetUserKey(hProv,dwKeySpec,&hKey);
3185             if(!ret)
3186             {
3187                 if (NTE_NO_KEY == GetLastError())
3188                 { /* generate the key */
3189                     ret = CryptGenKey(hProv,dwKeySpec,0,&hKey);
3190                 }
3191                 if (!ret)
3192                 {
3193                     CryptReleaseContext(hProv,0);
3194                     SetLastError(NTE_BAD_KEYSET);
3195                     return NULL;
3196                 }
3197             }
3198             CryptDestroyKey(hKey);
3199             releaseContext = TRUE;
3200         }
3201     }
3202     else if (pKeyProvInfo)
3203     {
3204         SetLastError(ERROR_INVALID_PARAMETER);
3205         return NULL;
3206     }
3207
3208     CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING, NULL,
3209      &pubKeySize);
3210     pubKey = CryptMemAlloc(pubKeySize);
3211     if (pubKey)
3212     {
3213         ret = CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING,
3214          pubKey, &pubKeySize);
3215         if (ret)
3216         {
3217             CERT_INFO info = { 0 };
3218             CRYPT_DER_BLOB blob = { 0, NULL };
3219             BYTE serial[16];
3220             CRYPT_DATA_BLOB serialBlob = { sizeof(serial), serial };
3221
3222             CryptGenRandom(hProv, sizeof(serial), serial);
3223             CRYPT_MakeCertInfo(&info, &serialBlob, pSubjectIssuerBlob,
3224              pSignatureAlgorithm, pStartTime, pEndTime, pubKey, pExtensions);
3225             ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
3226              &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData,
3227              &blob.cbData);
3228             if (ret)
3229             {
3230                 if (!(dwFlags & CERT_CREATE_SELFSIGN_NO_SIGN))
3231                     context = CRYPT_CreateSignedCert(&blob, hProv,dwKeySpec,
3232                      &info.SignatureAlgorithm);
3233                 else
3234                     context = CertCreateCertificateContext(X509_ASN_ENCODING,
3235                      blob.pbData, blob.cbData);
3236                 if (context && !(dwFlags & CERT_CREATE_SELFSIGN_NO_KEY_INFO))
3237                     CertContext_SetKeyProvInfo(context, pKeyProvInfo, hProv);
3238                 LocalFree(blob.pbData);
3239             }
3240         }
3241         CryptMemFree(pubKey);
3242     }
3243     if (releaseContext)
3244         CryptReleaseContext(hProv, 0);
3245     return context;
3246 }
3247
3248 BOOL WINAPI CertVerifyCTLUsage(DWORD dwEncodingType, DWORD dwSubjectType,
3249                                void *pvSubject, PCTL_USAGE pSubjectUsage, DWORD dwFlags,
3250                                PCTL_VERIFY_USAGE_PARA pVerifyUsagePara,
3251                                PCTL_VERIFY_USAGE_STATUS pVerifyUsageStatus)
3252 {
3253     FIXME("(0x%x, %d, %p, %p, 0x%x, %p, %p): stub\n", dwEncodingType,
3254           dwSubjectType, pvSubject, pSubjectUsage, dwFlags, pVerifyUsagePara,
3255           pVerifyUsageStatus);
3256     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3257     return FALSE;
3258 }
3259
3260 const void * WINAPI CertCreateContext(DWORD dwContextType, DWORD dwEncodingType,
3261                                       const BYTE *pbEncoded, DWORD cbEncoded,
3262                                       DWORD dwFlags, PCERT_CREATE_CONTEXT_PARA pCreatePara)
3263 {
3264     TRACE("(0x%x, 0x%x, %p, %d, 0x%08x, %p)\n", dwContextType, dwEncodingType,
3265           pbEncoded, cbEncoded, dwFlags, pCreatePara);
3266
3267     if (dwFlags)
3268     {
3269         FIXME("dwFlags 0x%08x not handled\n", dwFlags);
3270         return NULL;
3271     }
3272     if (pCreatePara)
3273     {
3274         FIXME("pCreatePara not handled\n");
3275         return NULL;
3276     }
3277
3278     switch (dwContextType)
3279     {
3280     case CERT_STORE_CERTIFICATE_CONTEXT:
3281         return CertCreateCertificateContext(dwEncodingType, pbEncoded, cbEncoded);
3282     case CERT_STORE_CRL_CONTEXT:
3283         return CertCreateCRLContext(dwEncodingType, pbEncoded, cbEncoded);
3284     case CERT_STORE_CTL_CONTEXT:
3285         return CertCreateCTLContext(dwEncodingType, pbEncoded, cbEncoded);
3286     default:
3287         WARN("unknown context type: 0x%x\n", dwContextType);
3288         return NULL;
3289     }
3290 }