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