crypt32: Fix test failures on multiple Windows versions.
[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 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
1836  PCERT_INFO pCertInfo)
1837 {
1838     FILETIME fileTime;
1839     LONG ret;
1840
1841     if (!pTimeToVerify)
1842     {
1843         GetSystemTimeAsFileTime(&fileTime);
1844         pTimeToVerify = &fileTime;
1845     }
1846     if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
1847     {
1848         ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
1849         if (ret < 0)
1850             ret = 0;
1851     }
1852     return ret;
1853 }
1854
1855 BOOL WINAPI CertVerifyValidityNesting(PCERT_INFO pSubjectInfo,
1856  PCERT_INFO pIssuerInfo)
1857 {
1858     TRACE("(%p, %p)\n", pSubjectInfo, pIssuerInfo);
1859
1860     return CertVerifyTimeValidity(&pSubjectInfo->NotBefore, pIssuerInfo) == 0
1861      && CertVerifyTimeValidity(&pSubjectInfo->NotAfter, pIssuerInfo) == 0;
1862 }
1863
1864 BOOL WINAPI CryptHashCertificate(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
1865  DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
1866  DWORD *pcbComputedHash)
1867 {
1868     BOOL ret = TRUE;
1869     HCRYPTHASH hHash = 0;
1870
1871     TRACE("(%08lx, %d, %08x, %p, %d, %p, %p)\n", hCryptProv, Algid, dwFlags,
1872      pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
1873
1874     if (!hCryptProv)
1875         hCryptProv = CRYPT_GetDefaultProvider();
1876     if (!Algid)
1877         Algid = CALG_SHA1;
1878     if (ret)
1879     {
1880         ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
1881         if (ret)
1882         {
1883             ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
1884             if (ret)
1885                 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
1886                  pcbComputedHash, 0);
1887             CryptDestroyHash(hHash);
1888         }
1889     }
1890     return ret;
1891 }
1892
1893 BOOL WINAPI CryptHashPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
1894  DWORD dwFlags, DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo,
1895  BYTE *pbComputedHash, DWORD *pcbComputedHash)
1896 {
1897     BOOL ret = TRUE;
1898     HCRYPTHASH hHash = 0;
1899
1900     TRACE("(%08lx, %d, %08x, %d, %p, %p, %p)\n", hCryptProv, Algid, dwFlags,
1901      dwCertEncodingType, pInfo, pbComputedHash, pcbComputedHash);
1902
1903     if (!hCryptProv)
1904         hCryptProv = CRYPT_GetDefaultProvider();
1905     if (!Algid)
1906         Algid = CALG_MD5;
1907     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
1908     {
1909         SetLastError(ERROR_FILE_NOT_FOUND);
1910         return FALSE;
1911     }
1912     if (ret)
1913     {
1914         BYTE *buf;
1915         DWORD size = 0;
1916
1917         ret = CRYPT_AsnEncodePubKeyInfoNoNull(dwCertEncodingType,
1918          X509_PUBLIC_KEY_INFO, pInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
1919          (LPBYTE)&buf, &size);
1920         if (ret)
1921         {
1922             ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
1923             if (ret)
1924             {
1925                 ret = CryptHashData(hHash, buf, size, 0);
1926                 if (ret)
1927                     ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
1928                      pcbComputedHash, 0);
1929                 CryptDestroyHash(hHash);
1930             }
1931             LocalFree(buf);
1932         }
1933     }
1934     return ret;
1935 }
1936
1937 BOOL WINAPI CryptHashToBeSigned(HCRYPTPROV_LEGACY hCryptProv,
1938  DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
1939  BYTE *pbComputedHash, DWORD *pcbComputedHash)
1940 {
1941     BOOL ret;
1942     CERT_SIGNED_CONTENT_INFO *info;
1943     DWORD size;
1944
1945     TRACE("(%08lx, %08x, %p, %d, %p, %d)\n", hCryptProv, dwCertEncodingType,
1946      pbEncoded, cbEncoded, pbComputedHash, *pcbComputedHash);
1947
1948     ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
1949      pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size);
1950     if (ret)
1951     {
1952         PCCRYPT_OID_INFO oidInfo;
1953         HCRYPTHASH hHash;
1954
1955         if (!hCryptProv)
1956             hCryptProv = CRYPT_GetDefaultProvider();
1957         oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1958          info->SignatureAlgorithm.pszObjId, 0);
1959         if (!oidInfo)
1960         {
1961             SetLastError(NTE_BAD_ALGID);
1962             ret = FALSE;
1963         }
1964         else
1965         {
1966             ret = CryptCreateHash(hCryptProv, oidInfo->u.Algid, 0, 0, &hHash);
1967             if (ret)
1968             {
1969                 ret = CryptHashData(hHash, info->ToBeSigned.pbData,
1970                  info->ToBeSigned.cbData, 0);
1971                 if (ret)
1972                     ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
1973                      pcbComputedHash, 0);
1974                 CryptDestroyHash(hHash);
1975             }
1976         }
1977         LocalFree(info);
1978     }
1979     return ret;
1980 }
1981
1982 BOOL WINAPI CryptSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
1983  DWORD dwKeySpec, DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned,
1984  DWORD cbEncodedToBeSigned, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
1985  const void *pvHashAuxInfo, BYTE *pbSignature, DWORD *pcbSignature)
1986 {
1987     BOOL ret;
1988     PCCRYPT_OID_INFO info;
1989     HCRYPTHASH hHash;
1990
1991     TRACE("(%08lx, %d, %d, %p, %d, %p, %p, %p, %p)\n", hCryptProv,
1992      dwKeySpec, dwCertEncodingType, pbEncodedToBeSigned, cbEncodedToBeSigned,
1993      pSignatureAlgorithm, pvHashAuxInfo, pbSignature, pcbSignature);
1994
1995     info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1996      pSignatureAlgorithm->pszObjId, 0);
1997     if (!info)
1998     {
1999         SetLastError(NTE_BAD_ALGID);
2000         return FALSE;
2001     }
2002     if (info->dwGroupId == CRYPT_HASH_ALG_OID_GROUP_ID)
2003     {
2004         if (!hCryptProv)
2005             hCryptProv = CRYPT_GetDefaultProvider();
2006         ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
2007         if (ret)
2008         {
2009             ret = CryptHashData(hHash, pbEncodedToBeSigned,
2010              cbEncodedToBeSigned, 0);
2011             if (ret)
2012                 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbSignature,
2013                  pcbSignature, 0);
2014             CryptDestroyHash(hHash);
2015         }
2016     }
2017     else
2018     {
2019         if (!hCryptProv)
2020         {
2021             SetLastError(ERROR_INVALID_PARAMETER);
2022             ret = FALSE;
2023         }
2024         else
2025         {
2026             ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
2027             if (ret)
2028             {
2029                 ret = CryptHashData(hHash, pbEncodedToBeSigned,
2030                  cbEncodedToBeSigned, 0);
2031                 if (ret)
2032                     ret = CryptSignHashW(hHash, dwKeySpec, NULL, 0, pbSignature,
2033                      pcbSignature);
2034                 CryptDestroyHash(hHash);
2035             }
2036         }
2037     }
2038     return ret;
2039 }
2040
2041 BOOL WINAPI CryptSignAndEncodeCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
2042  DWORD dwKeySpec, DWORD dwCertEncodingType, LPCSTR lpszStructType,
2043  const void *pvStructInfo, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
2044  const void *pvHashAuxInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
2045 {
2046     BOOL ret;
2047     DWORD encodedSize, hashSize;
2048
2049     TRACE("(%08lx, %d, %d, %s, %p, %p, %p, %p, %p)\n", hCryptProv, dwKeySpec,
2050      dwCertEncodingType, debugstr_a(lpszStructType), pvStructInfo,
2051      pSignatureAlgorithm, pvHashAuxInfo, pbEncoded, pcbEncoded);
2052
2053     ret = CryptEncodeObject(dwCertEncodingType, lpszStructType, pvStructInfo,
2054      NULL, &encodedSize);
2055     if (ret)
2056     {
2057         PBYTE encoded = CryptMemAlloc(encodedSize);
2058
2059         if (encoded)
2060         {
2061             ret = CryptEncodeObject(dwCertEncodingType, lpszStructType,
2062              pvStructInfo, encoded, &encodedSize);
2063             if (ret)
2064             {
2065                 ret = CryptSignCertificate(hCryptProv, dwKeySpec,
2066                  dwCertEncodingType, encoded, encodedSize, pSignatureAlgorithm,
2067                  pvHashAuxInfo, NULL, &hashSize);
2068                 if (ret)
2069                 {
2070                     PBYTE hash = CryptMemAlloc(hashSize);
2071
2072                     if (hash)
2073                     {
2074                         ret = CryptSignCertificate(hCryptProv, dwKeySpec,
2075                          dwCertEncodingType, encoded, encodedSize,
2076                          pSignatureAlgorithm, pvHashAuxInfo, hash, &hashSize);
2077                         if (ret)
2078                         {
2079                             CERT_SIGNED_CONTENT_INFO info = { { 0 } };
2080
2081                             info.ToBeSigned.cbData = encodedSize;
2082                             info.ToBeSigned.pbData = encoded;
2083                             memcpy(&info.SignatureAlgorithm,
2084                              pSignatureAlgorithm,
2085                              sizeof(info.SignatureAlgorithm));
2086                             info.Signature.cbData = hashSize;
2087                             info.Signature.pbData = hash;
2088                             info.Signature.cUnusedBits = 0;
2089                             ret = CryptEncodeObject(dwCertEncodingType,
2090                              X509_CERT, &info, pbEncoded, pcbEncoded);
2091                         }
2092                         CryptMemFree(hash);
2093                     }
2094                 }
2095             }
2096             CryptMemFree(encoded);
2097         }
2098     }
2099     return ret;
2100 }
2101
2102 BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV_LEGACY hCryptProv,
2103  DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
2104  PCERT_PUBLIC_KEY_INFO pPublicKey)
2105 {
2106     return CryptVerifyCertificateSignatureEx(hCryptProv, dwCertEncodingType,
2107      CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, (void *)pbEncoded,
2108      CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
2109 }
2110
2111 static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv,
2112  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pubKeyInfo,
2113  const CERT_SIGNED_CONTENT_INFO *signedCert)
2114 {
2115     BOOL ret;
2116     HCRYPTKEY key;
2117     PCCRYPT_OID_INFO info;
2118     ALG_ID pubKeyID, hashID;
2119
2120     info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
2121      signedCert->SignatureAlgorithm.pszObjId, 0);
2122     if (!info || info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID)
2123     {
2124         SetLastError(NTE_BAD_ALGID);
2125         return FALSE;
2126     }
2127     hashID = info->u.Algid;
2128     if (info->ExtraInfo.cbData >= sizeof(ALG_ID))
2129         pubKeyID = *(ALG_ID *)info->ExtraInfo.pbData;
2130     else
2131         pubKeyID = hashID;
2132     /* Load the default provider if necessary */
2133     if (!hCryptProv)
2134         hCryptProv = CRYPT_GetDefaultProvider();
2135     ret = CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType,
2136      pubKeyInfo, pubKeyID, 0, NULL, &key);
2137     if (ret)
2138     {
2139         HCRYPTHASH hash;
2140
2141         ret = CryptCreateHash(hCryptProv, hashID, 0, 0, &hash);
2142         if (ret)
2143         {
2144             ret = CryptHashData(hash, signedCert->ToBeSigned.pbData,
2145              signedCert->ToBeSigned.cbData, 0);
2146             if (ret)
2147                 ret = CryptVerifySignatureW(hash, signedCert->Signature.pbData,
2148                  signedCert->Signature.cbData, key, NULL, 0);
2149             CryptDestroyHash(hash);
2150         }
2151         CryptDestroyKey(key);
2152     }
2153     return ret;
2154 }
2155
2156 BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV_LEGACY hCryptProv,
2157  DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
2158  DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
2159 {
2160     BOOL ret = TRUE;
2161     CRYPT_DATA_BLOB subjectBlob;
2162
2163     TRACE("(%08lx, %d, %d, %p, %d, %p, %08x, %p)\n", hCryptProv,
2164      dwCertEncodingType, dwSubjectType, pvSubject, dwIssuerType, pvIssuer,
2165      dwFlags, pvReserved);
2166
2167     switch (dwSubjectType)
2168     {
2169     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB:
2170     {
2171         PCRYPT_DATA_BLOB blob = pvSubject;
2172
2173         subjectBlob.pbData = blob->pbData;
2174         subjectBlob.cbData = blob->cbData;
2175         break;
2176     }
2177     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT:
2178     {
2179         PCERT_CONTEXT context = pvSubject;
2180
2181         subjectBlob.pbData = context->pbCertEncoded;
2182         subjectBlob.cbData = context->cbCertEncoded;
2183         break;
2184     }
2185     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL:
2186     {
2187         PCRL_CONTEXT context = pvSubject;
2188
2189         subjectBlob.pbData = context->pbCrlEncoded;
2190         subjectBlob.cbData = context->cbCrlEncoded;
2191         break;
2192     }
2193     default:
2194         SetLastError(E_INVALIDARG);
2195         ret = FALSE;
2196     }
2197
2198     if (ret)
2199     {
2200         PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
2201         DWORD size = 0;
2202
2203         ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
2204          subjectBlob.pbData, subjectBlob.cbData,
2205          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
2206          &signedCert, &size);
2207         if (ret)
2208         {
2209             switch (dwIssuerType)
2210             {
2211             case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY:
2212                 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
2213                  dwCertEncodingType, pvIssuer,
2214                  signedCert);
2215                 break;
2216             case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT:
2217                 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
2218                  dwCertEncodingType,
2219                  &((PCCERT_CONTEXT)pvIssuer)->pCertInfo->SubjectPublicKeyInfo,
2220                  signedCert);
2221                 break;
2222             case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN:
2223                 FIXME("CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: stub\n");
2224                 ret = FALSE;
2225                 break;
2226             case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL:
2227                 if (pvIssuer)
2228                 {
2229                     SetLastError(E_INVALIDARG);
2230                     ret = FALSE;
2231                 }
2232                 else
2233                 {
2234                     FIXME("unimplemented for NULL signer\n");
2235                     SetLastError(E_INVALIDARG);
2236                     ret = FALSE;
2237                 }
2238                 break;
2239             default:
2240                 SetLastError(E_INVALIDARG);
2241                 ret = FALSE;
2242             }
2243             LocalFree(signedCert);
2244         }
2245     }
2246     return ret;
2247 }
2248
2249 BOOL WINAPI CertGetIntendedKeyUsage(DWORD dwCertEncodingType,
2250  PCERT_INFO pCertInfo, BYTE *pbKeyUsage, DWORD cbKeyUsage)
2251 {
2252     PCERT_EXTENSION ext;
2253     BOOL ret = FALSE;
2254
2255     TRACE("(%08x, %p, %p, %d)\n", dwCertEncodingType, pCertInfo, pbKeyUsage,
2256      cbKeyUsage);
2257
2258     ext = CertFindExtension(szOID_KEY_USAGE, pCertInfo->cExtension,
2259      pCertInfo->rgExtension);
2260     if (ext)
2261     {
2262         CRYPT_BIT_BLOB usage;
2263         DWORD size = sizeof(usage);
2264
2265         ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS,
2266          ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL,
2267          &usage, &size);
2268         if (ret)
2269         {
2270             if (cbKeyUsage < usage.cbData)
2271                 ret = FALSE;
2272             else
2273             {
2274                 memcpy(pbKeyUsage, usage.pbData, usage.cbData);
2275                 if (cbKeyUsage > usage.cbData)
2276                     memset(pbKeyUsage + usage.cbData, 0,
2277                      cbKeyUsage - usage.cbData);
2278             }
2279         }
2280     }
2281     else
2282         SetLastError(0);
2283     return ret;
2284 }
2285
2286 BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags,
2287  PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage)
2288 {
2289     PCERT_ENHKEY_USAGE usage = NULL;
2290     DWORD bytesNeeded;
2291     BOOL ret = TRUE;
2292
2293     if (!pCertContext || !pcbUsage)
2294     {
2295         SetLastError(ERROR_INVALID_PARAMETER);
2296         return FALSE;
2297     }
2298
2299     TRACE("(%p, %08x, %p, %d)\n", pCertContext, dwFlags, pUsage, *pcbUsage);
2300
2301     if (!(dwFlags & CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG))
2302     {
2303         DWORD propSize = 0;
2304
2305         if (CertGetCertificateContextProperty(pCertContext,
2306          CERT_ENHKEY_USAGE_PROP_ID, NULL, &propSize))
2307         {
2308             LPBYTE buf = CryptMemAlloc(propSize);
2309
2310             if (buf)
2311             {
2312                 if (CertGetCertificateContextProperty(pCertContext,
2313                  CERT_ENHKEY_USAGE_PROP_ID, buf, &propSize))
2314                 {
2315                     ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
2316                      X509_ENHANCED_KEY_USAGE, buf, propSize,
2317                      CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
2318                 }
2319                 CryptMemFree(buf);
2320             }
2321         }
2322     }
2323     if (!usage && !(dwFlags & CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG))
2324     {
2325         PCERT_EXTENSION ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
2326          pCertContext->pCertInfo->cExtension,
2327          pCertContext->pCertInfo->rgExtension);
2328
2329         if (ext)
2330         {
2331             ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
2332              X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
2333              CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
2334         }
2335     }
2336     if (!usage)
2337     {
2338         /* If a particular location is specified, this should fail.  Otherwise
2339          * it should succeed with an empty usage.  (This is true on Win2k and
2340          * later, which we emulate.)
2341          */
2342         if (dwFlags)
2343         {
2344             SetLastError(CRYPT_E_NOT_FOUND);
2345             ret = FALSE;
2346         }
2347         else
2348             bytesNeeded = sizeof(CERT_ENHKEY_USAGE);
2349     }
2350
2351     if (ret)
2352     {
2353         if (!pUsage)
2354             *pcbUsage = bytesNeeded;
2355         else if (*pcbUsage < bytesNeeded)
2356         {
2357             SetLastError(ERROR_MORE_DATA);
2358             *pcbUsage = bytesNeeded;
2359             ret = FALSE;
2360         }
2361         else
2362         {
2363             *pcbUsage = bytesNeeded;
2364             if (usage)
2365             {
2366                 DWORD i;
2367                 LPSTR nextOID = (LPSTR)((LPBYTE)pUsage +
2368                  sizeof(CERT_ENHKEY_USAGE) +
2369                  usage->cUsageIdentifier * sizeof(LPSTR));
2370
2371                 pUsage->cUsageIdentifier = usage->cUsageIdentifier;
2372                 pUsage->rgpszUsageIdentifier = (LPSTR *)((LPBYTE)pUsage +
2373                  sizeof(CERT_ENHKEY_USAGE));
2374                 for (i = 0; i < usage->cUsageIdentifier; i++)
2375                 {
2376                     pUsage->rgpszUsageIdentifier[i] = nextOID;
2377                     strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
2378                     nextOID += strlen(nextOID) + 1;
2379                 }
2380             }
2381             else
2382                 pUsage->cUsageIdentifier = 0;
2383         }
2384     }
2385     if (usage)
2386         LocalFree(usage);
2387     TRACE("returning %d\n", ret);
2388     return ret;
2389 }
2390
2391 BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext,
2392  PCERT_ENHKEY_USAGE pUsage)
2393 {
2394     BOOL ret;
2395
2396     TRACE("(%p, %p)\n", pCertContext, pUsage);
2397
2398     if (pUsage)
2399     {
2400         CRYPT_DATA_BLOB blob = { 0, NULL };
2401
2402         ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
2403          pUsage, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData, &blob.cbData);
2404         if (ret)
2405         {
2406             ret = CertSetCertificateContextProperty(pCertContext,
2407              CERT_ENHKEY_USAGE_PROP_ID, 0, &blob);
2408             LocalFree(blob.pbData);
2409         }
2410     }
2411     else
2412         ret = CertSetCertificateContextProperty(pCertContext,
2413          CERT_ENHKEY_USAGE_PROP_ID, 0, NULL);
2414     return ret;
2415 }
2416
2417 BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
2418  LPCSTR pszUsageIdentifier)
2419 {
2420     BOOL ret;
2421     DWORD size;
2422
2423     TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
2424
2425     if (CertGetEnhancedKeyUsage(pCertContext,
2426      CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size))
2427     {
2428         PCERT_ENHKEY_USAGE usage = CryptMemAlloc(size);
2429
2430         if (usage)
2431         {
2432             ret = CertGetEnhancedKeyUsage(pCertContext,
2433              CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size);
2434             if (ret)
2435             {
2436                 DWORD i;
2437                 BOOL exists = FALSE;
2438
2439                 /* Make sure usage doesn't already exist */
2440                 for (i = 0; !exists && i < usage->cUsageIdentifier; i++)
2441                 {
2442                     if (!strcmp(usage->rgpszUsageIdentifier[i],
2443                      pszUsageIdentifier))
2444                         exists = TRUE;
2445                 }
2446                 if (!exists)
2447                 {
2448                     PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size +
2449                      sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
2450
2451                     if (newUsage)
2452                     {
2453                         LPSTR nextOID;
2454
2455                         newUsage->rgpszUsageIdentifier = (LPSTR *)
2456                          ((LPBYTE)newUsage + sizeof(CERT_ENHKEY_USAGE));
2457                         nextOID = (LPSTR)((LPBYTE)newUsage->rgpszUsageIdentifier
2458                           + (usage->cUsageIdentifier + 1) * sizeof(LPSTR));
2459                         for (i = 0; i < usage->cUsageIdentifier; i++)
2460                         {
2461                             newUsage->rgpszUsageIdentifier[i] = nextOID;
2462                             strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
2463                             nextOID += strlen(nextOID) + 1;
2464                         }
2465                         newUsage->rgpszUsageIdentifier[i] = nextOID;
2466                         strcpy(nextOID, pszUsageIdentifier);
2467                         newUsage->cUsageIdentifier = i + 1;
2468                         ret = CertSetEnhancedKeyUsage(pCertContext, newUsage);
2469                         CryptMemFree(newUsage);
2470                     }
2471                     else
2472                         ret = FALSE;
2473                 }
2474             }
2475             CryptMemFree(usage);
2476         }
2477         else
2478             ret = FALSE;
2479     }
2480     else
2481     {
2482         PCERT_ENHKEY_USAGE usage = CryptMemAlloc(sizeof(CERT_ENHKEY_USAGE) +
2483          sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
2484
2485         if (usage)
2486         {
2487             usage->rgpszUsageIdentifier =
2488              (LPSTR *)((LPBYTE)usage + sizeof(CERT_ENHKEY_USAGE));
2489             usage->rgpszUsageIdentifier[0] = (LPSTR)((LPBYTE)usage +
2490              sizeof(CERT_ENHKEY_USAGE) + sizeof(LPSTR));
2491             strcpy(usage->rgpszUsageIdentifier[0], pszUsageIdentifier);
2492             usage->cUsageIdentifier = 1;
2493             ret = CertSetEnhancedKeyUsage(pCertContext, usage);
2494             CryptMemFree(usage);
2495         }
2496         else
2497             ret = FALSE;
2498     }
2499     return ret;
2500 }
2501
2502 BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
2503  LPCSTR pszUsageIdentifier)
2504 {
2505     BOOL ret;
2506     DWORD size;
2507     CERT_ENHKEY_USAGE usage;
2508
2509     TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
2510
2511     size = sizeof(usage);
2512     ret = CertGetEnhancedKeyUsage(pCertContext,
2513      CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, &usage, &size);
2514     if (!ret && GetLastError() == ERROR_MORE_DATA)
2515     {
2516         PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
2517
2518         if (pUsage)
2519         {
2520             ret = CertGetEnhancedKeyUsage(pCertContext,
2521              CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
2522             if (ret)
2523             {
2524                 if (pUsage->cUsageIdentifier)
2525                 {
2526                     DWORD i;
2527                     BOOL found = FALSE;
2528
2529                     for (i = 0; i < pUsage->cUsageIdentifier; i++)
2530                     {
2531                         if (!strcmp(pUsage->rgpszUsageIdentifier[i],
2532                          pszUsageIdentifier))
2533                             found = TRUE;
2534                         if (found && i < pUsage->cUsageIdentifier - 1)
2535                             pUsage->rgpszUsageIdentifier[i] =
2536                              pUsage->rgpszUsageIdentifier[i + 1];
2537                     }
2538                     pUsage->cUsageIdentifier--;
2539                     /* Remove the usage if it's empty */
2540                     if (pUsage->cUsageIdentifier)
2541                         ret = CertSetEnhancedKeyUsage(pCertContext, pUsage);
2542                     else
2543                         ret = CertSetEnhancedKeyUsage(pCertContext, NULL);
2544                 }
2545             }
2546             CryptMemFree(pUsage);
2547         }
2548         else
2549             ret = FALSE;
2550     }
2551     else
2552     {
2553         /* it fit in an empty usage, therefore there's nothing to remove */
2554         ret = TRUE;
2555     }
2556     return ret;
2557 }
2558
2559 struct BitField
2560 {
2561     DWORD  cIndexes;
2562     DWORD *indexes;
2563 };
2564
2565 #define BITS_PER_DWORD (sizeof(DWORD) * 8)
2566
2567 static void CRYPT_SetBitInField(struct BitField *field, DWORD bit)
2568 {
2569     DWORD indexIndex = bit / BITS_PER_DWORD;
2570
2571     if (indexIndex + 1 > field->cIndexes)
2572     {
2573         if (field->cIndexes)
2574             field->indexes = CryptMemRealloc(field->indexes,
2575              (indexIndex + 1) * sizeof(DWORD));
2576         else
2577             field->indexes = CryptMemAlloc(sizeof(DWORD));
2578         if (field->indexes)
2579         {
2580             field->indexes[indexIndex] = 0;
2581             field->cIndexes = indexIndex + 1;
2582         }
2583     }
2584     if (field->indexes)
2585         field->indexes[indexIndex] |= 1 << (bit % BITS_PER_DWORD);
2586 }
2587
2588 static BOOL CRYPT_IsBitInFieldSet(const struct BitField *field, DWORD bit)
2589 {
2590     BOOL set = FALSE;
2591     DWORD indexIndex = bit / BITS_PER_DWORD;
2592
2593     assert(field->cIndexes);
2594     set = field->indexes[indexIndex] & (1 << (bit % BITS_PER_DWORD));
2595     return set;
2596 }
2597
2598 BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts,
2599  int *cNumOIDs, LPSTR *rghOIDs, DWORD *pcbOIDs)
2600 {
2601     BOOL ret = TRUE;
2602     DWORD i, cbOIDs = 0;
2603     BOOL allUsagesValid = TRUE;
2604     CERT_ENHKEY_USAGE validUsages = { 0, NULL };
2605
2606     TRACE("(%d, %p, %d, %p, %d)\n", cCerts, rghCerts, *cNumOIDs,
2607      rghOIDs, *pcbOIDs);
2608
2609     for (i = 0; i < cCerts; i++)
2610     {
2611         CERT_ENHKEY_USAGE usage;
2612         DWORD size = sizeof(usage);
2613
2614         ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, &usage, &size);
2615         /* Success is deliberately ignored: it implies all usages are valid */
2616         if (!ret && GetLastError() == ERROR_MORE_DATA)
2617         {
2618             PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
2619
2620             allUsagesValid = FALSE;
2621             if (pUsage)
2622             {
2623                 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, pUsage, &size);
2624                 if (ret)
2625                 {
2626                     if (!validUsages.cUsageIdentifier)
2627                     {
2628                         DWORD j;
2629
2630                         cbOIDs = pUsage->cUsageIdentifier * sizeof(LPSTR);
2631                         validUsages.cUsageIdentifier = pUsage->cUsageIdentifier;
2632                         for (j = 0; j < validUsages.cUsageIdentifier; j++)
2633                             cbOIDs += lstrlenA(pUsage->rgpszUsageIdentifier[j])
2634                              + 1;
2635                         validUsages.rgpszUsageIdentifier =
2636                          CryptMemAlloc(cbOIDs);
2637                         if (validUsages.rgpszUsageIdentifier)
2638                         {
2639                             LPSTR nextOID = (LPSTR)
2640                              ((LPBYTE)validUsages.rgpszUsageIdentifier +
2641                              validUsages.cUsageIdentifier * sizeof(LPSTR));
2642
2643                             for (j = 0; j < validUsages.cUsageIdentifier; j++)
2644                             {
2645                                 validUsages.rgpszUsageIdentifier[j] = nextOID;
2646                                 lstrcpyA(validUsages.rgpszUsageIdentifier[j],
2647                                  pUsage->rgpszUsageIdentifier[j]);
2648                                 nextOID += lstrlenA(nextOID) + 1;
2649                             }
2650                         }
2651                     }
2652                     else
2653                     {
2654                         struct BitField validIndexes = { 0, NULL };
2655                         DWORD j, k, numRemoved = 0;
2656
2657                         /* Merge: build a bitmap of all the indexes of
2658                          * validUsages.rgpszUsageIdentifier that are in pUsage.
2659                          */
2660                         for (j = 0; j < pUsage->cUsageIdentifier; j++)
2661                         {
2662                             for (k = 0; k < validUsages.cUsageIdentifier; k++)
2663                             {
2664                                 if (!strcmp(pUsage->rgpszUsageIdentifier[j],
2665                                  validUsages.rgpszUsageIdentifier[k]))
2666                                 {
2667                                     CRYPT_SetBitInField(&validIndexes, k);
2668                                     break;
2669                                 }
2670                             }
2671                         }
2672                         /* Merge by removing from validUsages those that are
2673                          * not in the bitmap.
2674                          */
2675                         for (j = 0; j < validUsages.cUsageIdentifier; j++)
2676                         {
2677                             if (!CRYPT_IsBitInFieldSet(&validIndexes, j))
2678                             {
2679                                 if (j < validUsages.cUsageIdentifier - 1)
2680                                 {
2681                                     memmove(&validUsages.rgpszUsageIdentifier[j],
2682                                      &validUsages.rgpszUsageIdentifier[j +
2683                                      numRemoved + 1],
2684                                      (validUsages.cUsageIdentifier - numRemoved
2685                                      - j - 1) * sizeof(LPSTR));
2686                                     cbOIDs -= lstrlenA(
2687                                      validUsages.rgpszUsageIdentifier[j]) + 1 +
2688                                      sizeof(LPSTR);
2689                                     validUsages.cUsageIdentifier--;
2690                                     numRemoved++;
2691                                 }
2692                                 else
2693                                     validUsages.cUsageIdentifier--;
2694                             }
2695                         }
2696                         CryptMemFree(validIndexes.indexes);
2697                     }
2698                 }
2699                 CryptMemFree(pUsage);
2700             }
2701         }
2702     }
2703     ret = TRUE;
2704     if (allUsagesValid)
2705     {
2706         *cNumOIDs = -1;
2707         *pcbOIDs = 0;
2708     }
2709     else
2710     {
2711         *cNumOIDs = validUsages.cUsageIdentifier;
2712         if (!rghOIDs)
2713             *pcbOIDs = cbOIDs;
2714         else if (*pcbOIDs < cbOIDs)
2715         {
2716             *pcbOIDs = cbOIDs;
2717             SetLastError(ERROR_MORE_DATA);
2718             ret = FALSE;
2719         }
2720         else
2721         {
2722             LPSTR nextOID = (LPSTR)((LPBYTE)rghOIDs +
2723              validUsages.cUsageIdentifier * sizeof(LPSTR));
2724
2725             *pcbOIDs = cbOIDs;
2726             for (i = 0; i < validUsages.cUsageIdentifier; i++)
2727             {
2728                 rghOIDs[i] = nextOID;
2729                 lstrcpyA(nextOID, validUsages.rgpszUsageIdentifier[i]);
2730                 nextOID += lstrlenA(nextOID) + 1;
2731             }
2732         }
2733     }
2734     CryptMemFree(validUsages.rgpszUsageIdentifier);
2735     TRACE("cNumOIDs: %d\n", *cNumOIDs);
2736     TRACE("returning %d\n", ret);
2737     return ret;
2738 }
2739
2740 /* Sets the CERT_KEY_PROV_INFO_PROP_ID property of context from pInfo, or, if
2741  * pInfo is NULL, from the attributes of hProv.
2742  */
2743 static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context,
2744  const CRYPT_KEY_PROV_INFO *pInfo, HCRYPTPROV hProv)
2745 {
2746     CRYPT_KEY_PROV_INFO info = { 0 };
2747     BOOL ret;
2748
2749     if (!pInfo)
2750     {
2751         DWORD size;
2752         int len;
2753
2754         ret = CryptGetProvParam(hProv, PP_CONTAINER, NULL, &size, 0);
2755         if (ret)
2756         {
2757             LPSTR szContainer = CryptMemAlloc(size);
2758
2759             if (szContainer)
2760             {
2761                 ret = CryptGetProvParam(hProv, PP_CONTAINER,
2762                  (BYTE *)szContainer, &size, 0);
2763                 if (ret)
2764                 {
2765                     len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
2766                      NULL, 0);
2767                     if (len)
2768                     {
2769                         info.pwszContainerName = CryptMemAlloc(len *
2770                          sizeof(WCHAR));
2771                         len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
2772                          info.pwszContainerName, len);
2773                     }
2774                 }
2775                 CryptMemFree(szContainer);
2776             }
2777         }
2778         ret = CryptGetProvParam(hProv, PP_NAME, NULL, &size, 0);
2779         if (ret)
2780         {
2781             LPSTR szProvider = CryptMemAlloc(size);
2782
2783             if (szProvider)
2784             {
2785                 ret = CryptGetProvParam(hProv, PP_NAME, (BYTE *)szProvider,
2786                  &size, 0);
2787                 if (ret)
2788                 {
2789                     len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
2790                      NULL, 0);
2791                     if (len)
2792                     {
2793                         info.pwszProvName = CryptMemAlloc(len *
2794                          sizeof(WCHAR));
2795                         len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
2796                          info.pwszProvName, len);
2797                     }
2798                 }
2799                 CryptMemFree(szProvider);
2800             }
2801         }
2802         size = sizeof(info.dwKeySpec);
2803         /* in case no CRYPT_KEY_PROV_INFO given,
2804          *  we always use AT_SIGNATURE key spec
2805          */
2806         info.dwKeySpec = AT_SIGNATURE;
2807         size = sizeof(info.dwProvType);
2808         ret = CryptGetProvParam(hProv, PP_PROVTYPE, (LPBYTE)&info.dwProvType,
2809          &size, 0);
2810         if (!ret)
2811             info.dwProvType = PROV_RSA_FULL;
2812         pInfo = &info;
2813     }
2814
2815     ret = CertSetCertificateContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID,
2816      0, pInfo);
2817
2818     if (pInfo == &info)
2819     {
2820         CryptMemFree(info.pwszContainerName);
2821         CryptMemFree(info.pwszProvName);
2822     }
2823 }
2824
2825 /* Creates a signed certificate context from the unsigned, encoded certificate
2826  * in blob, using the crypto provider hProv and the signature algorithm sigAlgo.
2827  */
2828 static PCCERT_CONTEXT CRYPT_CreateSignedCert(const CRYPT_DER_BLOB *blob,
2829  HCRYPTPROV hProv, DWORD dwKeySpec, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo)
2830 {
2831     PCCERT_CONTEXT context = NULL;
2832     BOOL ret;
2833     DWORD sigSize = 0;
2834
2835     ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
2836      blob->pbData, blob->cbData, sigAlgo, NULL, NULL, &sigSize);
2837     if (ret)
2838     {
2839         LPBYTE sig = CryptMemAlloc(sigSize);
2840
2841         ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
2842          blob->pbData, blob->cbData, sigAlgo, NULL, sig, &sigSize);
2843         if (ret)
2844         {
2845             CERT_SIGNED_CONTENT_INFO signedInfo;
2846             BYTE *encodedSignedCert = NULL;
2847             DWORD encodedSignedCertSize = 0;
2848
2849             signedInfo.ToBeSigned.cbData = blob->cbData;
2850             signedInfo.ToBeSigned.pbData = blob->pbData;
2851             memcpy(&signedInfo.SignatureAlgorithm, sigAlgo,
2852              sizeof(signedInfo.SignatureAlgorithm));
2853             signedInfo.Signature.cbData = sigSize;
2854             signedInfo.Signature.pbData = sig;
2855             signedInfo.Signature.cUnusedBits = 0;
2856             ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT,
2857              &signedInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
2858              &encodedSignedCert, &encodedSignedCertSize);
2859             if (ret)
2860             {
2861                 context = CertCreateCertificateContext(X509_ASN_ENCODING,
2862                  encodedSignedCert, encodedSignedCertSize);
2863                 LocalFree(encodedSignedCert);
2864             }
2865         }
2866         CryptMemFree(sig);
2867     }
2868     return context;
2869 }
2870
2871 /* Copies data from the parameters into info, where:
2872  * pSerialNumber: The serial number.  Must not be NULL.
2873  * pSubjectIssuerBlob: Specifies both the subject and issuer for info.
2874  *                     Must not be NULL
2875  * pSignatureAlgorithm: Optional.
2876  * pStartTime: The starting time of the certificate.  If NULL, the current
2877  *             system time is used.
2878  * pEndTime: The ending time of the certificate.  If NULL, one year past the
2879  *           starting time is used.
2880  * pubKey: The public key of the certificate.  Must not be NULL.
2881  * pExtensions: Extensions to be included with the certificate.  Optional.
2882  */
2883 static void CRYPT_MakeCertInfo(PCERT_INFO info, const CRYPT_DATA_BLOB *pSerialNumber,
2884  const CERT_NAME_BLOB *pSubjectIssuerBlob,
2885  const CRYPT_ALGORITHM_IDENTIFIER *pSignatureAlgorithm, const SYSTEMTIME *pStartTime,
2886  const SYSTEMTIME *pEndTime, const CERT_PUBLIC_KEY_INFO *pubKey,
2887  const CERT_EXTENSIONS *pExtensions)
2888 {
2889     static CHAR oid[] = szOID_RSA_SHA1RSA;
2890
2891     assert(info);
2892     assert(pSerialNumber);
2893     assert(pSubjectIssuerBlob);
2894     assert(pubKey);
2895
2896     if (pExtensions && pExtensions->cExtension)
2897         info->dwVersion = CERT_V3;
2898     else
2899         info->dwVersion = CERT_V1;
2900     info->SerialNumber.cbData = pSerialNumber->cbData;
2901     info->SerialNumber.pbData = pSerialNumber->pbData;
2902     if (pSignatureAlgorithm)
2903         memcpy(&info->SignatureAlgorithm, pSignatureAlgorithm,
2904          sizeof(info->SignatureAlgorithm));
2905     else
2906     {
2907         info->SignatureAlgorithm.pszObjId = oid;
2908         info->SignatureAlgorithm.Parameters.cbData = 0;
2909         info->SignatureAlgorithm.Parameters.pbData = NULL;
2910     }
2911     info->Issuer.cbData = pSubjectIssuerBlob->cbData;
2912     info->Issuer.pbData = pSubjectIssuerBlob->pbData;
2913     if (pStartTime)
2914         SystemTimeToFileTime(pStartTime, &info->NotBefore);
2915     else
2916         GetSystemTimeAsFileTime(&info->NotBefore);
2917     if (pEndTime)
2918         SystemTimeToFileTime(pEndTime, &info->NotAfter);
2919     else
2920     {
2921         SYSTEMTIME endTime;
2922
2923         if (FileTimeToSystemTime(&info->NotBefore, &endTime))
2924         {
2925             endTime.wYear++;
2926             SystemTimeToFileTime(&endTime, &info->NotAfter);
2927         }
2928     }
2929     info->Subject.cbData = pSubjectIssuerBlob->cbData;
2930     info->Subject.pbData = pSubjectIssuerBlob->pbData;
2931     memcpy(&info->SubjectPublicKeyInfo, pubKey,
2932      sizeof(info->SubjectPublicKeyInfo));
2933     if (pExtensions)
2934     {
2935         info->cExtension = pExtensions->cExtension;
2936         info->rgExtension = pExtensions->rgExtension;
2937     }
2938     else
2939     {
2940         info->cExtension = 0;
2941         info->rgExtension = NULL;
2942     }
2943 }
2944  
2945 typedef RPC_STATUS (RPC_ENTRY *UuidCreateFunc)(UUID *);
2946 typedef RPC_STATUS (RPC_ENTRY *UuidToStringFunc)(UUID *, unsigned char **);
2947 typedef RPC_STATUS (RPC_ENTRY *RpcStringFreeFunc)(unsigned char **);
2948
2949 static HCRYPTPROV CRYPT_CreateKeyProv(void)
2950 {
2951     HCRYPTPROV hProv = 0;
2952     HMODULE rpcrt = LoadLibraryA("rpcrt4");
2953
2954     if (rpcrt)
2955     {
2956         UuidCreateFunc uuidCreate = (UuidCreateFunc)GetProcAddress(rpcrt,
2957          "UuidCreate");
2958         UuidToStringFunc uuidToString = (UuidToStringFunc)GetProcAddress(rpcrt,
2959          "UuidToStringA");
2960         RpcStringFreeFunc rpcStringFree = (RpcStringFreeFunc)GetProcAddress(
2961          rpcrt, "RpcStringFreeA");
2962
2963         if (uuidCreate && uuidToString && rpcStringFree)
2964         {
2965             UUID uuid;
2966             RPC_STATUS status = uuidCreate(&uuid);
2967
2968             if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY)
2969             {
2970                 unsigned char *uuidStr;
2971
2972                 status = uuidToString(&uuid, &uuidStr);
2973                 if (status == RPC_S_OK)
2974                 {
2975                     BOOL ret = CryptAcquireContextA(&hProv, (LPCSTR)uuidStr,
2976                      MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_NEWKEYSET);
2977
2978                     if (ret)
2979                     {
2980                         HCRYPTKEY key;
2981
2982                         ret = CryptGenKey(hProv, AT_SIGNATURE, 0, &key);
2983                         if (ret)
2984                             CryptDestroyKey(key);
2985                     }
2986                     rpcStringFree(&uuidStr);
2987                 }
2988             }
2989         }
2990         FreeLibrary(rpcrt);
2991     }
2992     return hProv;
2993 }
2994
2995 PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hProv,
2996  PCERT_NAME_BLOB pSubjectIssuerBlob, DWORD dwFlags,
2997  PCRYPT_KEY_PROV_INFO pKeyProvInfo,
2998  PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime,
2999  PSYSTEMTIME pEndTime, PCERT_EXTENSIONS pExtensions)
3000 {
3001     PCCERT_CONTEXT context = NULL;
3002     BOOL ret, releaseContext = FALSE;
3003     PCERT_PUBLIC_KEY_INFO pubKey = NULL;
3004     DWORD pubKeySize = 0,dwKeySpec = AT_SIGNATURE;
3005
3006     TRACE("(%08lx, %p, %08x, %p, %p, %p, %p, %p)\n", hProv,
3007      pSubjectIssuerBlob, dwFlags, pKeyProvInfo, pSignatureAlgorithm, pStartTime,
3008      pExtensions, pExtensions);
3009
3010     if(!pSubjectIssuerBlob)
3011     {
3012         SetLastError(ERROR_INVALID_PARAMETER);
3013         return NULL;
3014     }
3015
3016     if (!hProv)
3017     {
3018         if (!pKeyProvInfo)
3019         {
3020             hProv = CRYPT_CreateKeyProv();
3021             releaseContext = TRUE;
3022         }
3023         else if (pKeyProvInfo->dwFlags & CERT_SET_KEY_PROV_HANDLE_PROP_ID)
3024         {
3025             SetLastError(NTE_BAD_FLAGS);
3026             return NULL;
3027         }
3028         else
3029         {
3030             HCRYPTKEY hKey = 0;
3031             /* acquire the context using the given information*/
3032             ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
3033                     pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
3034                     pKeyProvInfo->dwFlags);
3035             if (!ret)
3036             {
3037                 if(GetLastError() != NTE_BAD_KEYSET)
3038                     return NULL;
3039                 /* create the key set */
3040                 ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
3041                     pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
3042                     pKeyProvInfo->dwFlags|CRYPT_NEWKEYSET);
3043                 if (!ret)
3044                     return NULL;
3045             }
3046             dwKeySpec = pKeyProvInfo->dwKeySpec;
3047             /* check if the key is here */
3048             ret = CryptGetUserKey(hProv,dwKeySpec,&hKey);
3049             if(!ret)
3050             {
3051                 if (NTE_NO_KEY == GetLastError())
3052                 { /* generate the key */
3053                     ret = CryptGenKey(hProv,dwKeySpec,0,&hKey);
3054                 }
3055                 if (!ret)
3056                 {
3057                     CryptReleaseContext(hProv,0);
3058                     SetLastError(NTE_BAD_KEYSET);
3059                     return NULL;
3060                 }
3061             }
3062             CryptDestroyKey(hKey);
3063             releaseContext = TRUE;
3064         }
3065     }
3066     else if (pKeyProvInfo)
3067     {
3068         SetLastError(ERROR_INVALID_PARAMETER);
3069         return NULL;
3070     }
3071
3072     CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING, NULL,
3073      &pubKeySize);
3074     pubKey = CryptMemAlloc(pubKeySize);
3075     if (pubKey)
3076     {
3077         ret = CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING,
3078          pubKey, &pubKeySize);
3079         if (ret)
3080         {
3081             CERT_INFO info = { 0 };
3082             CRYPT_DER_BLOB blob = { 0, NULL };
3083             BYTE serial[16];
3084             CRYPT_DATA_BLOB serialBlob = { sizeof(serial), serial };
3085
3086             CryptGenRandom(hProv, sizeof(serial), serial);
3087             CRYPT_MakeCertInfo(&info, &serialBlob, pSubjectIssuerBlob,
3088              pSignatureAlgorithm, pStartTime, pEndTime, pubKey, pExtensions);
3089             ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
3090              &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData,
3091              &blob.cbData);
3092             if (ret)
3093             {
3094                 if (!(dwFlags & CERT_CREATE_SELFSIGN_NO_SIGN))
3095                     context = CRYPT_CreateSignedCert(&blob, hProv,dwKeySpec,
3096                      &info.SignatureAlgorithm);
3097                 else
3098                     context = CertCreateCertificateContext(X509_ASN_ENCODING,
3099                      blob.pbData, blob.cbData);
3100                 if (context && !(dwFlags & CERT_CREATE_SELFSIGN_NO_KEY_INFO))
3101                     CertContext_SetKeyProvInfo(context, pKeyProvInfo, hProv);
3102                 LocalFree(blob.pbData);
3103             }
3104         }
3105         CryptMemFree(pubKey);
3106     }
3107     if (releaseContext)
3108         CryptReleaseContext(hProv, 0);
3109     return context;
3110 }
3111
3112 BOOL WINAPI CertVerifyCTLUsage(DWORD dwEncodingType, DWORD dwSubjectType,
3113                                void *pvSubject, PCTL_USAGE pSubjectUsage, DWORD dwFlags,
3114                                PCTL_VERIFY_USAGE_PARA pVerifyUsagePara,
3115                                PCTL_VERIFY_USAGE_STATUS pVerifyUsageStatus)
3116 {
3117     FIXME("(0x%x, %d, %p, %p, 0x%x, %p, %p): stub\n", dwEncodingType,
3118           dwSubjectType, pvSubject, pSubjectUsage, dwFlags, pVerifyUsagePara,
3119           pVerifyUsageStatus);
3120     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3121     return FALSE;
3122 }
3123
3124 const void * WINAPI CertCreateContext(DWORD dwContextType, DWORD dwEncodingType,
3125                                       const BYTE *pbEncoded, DWORD cbEncoded,
3126                                       DWORD dwFlags, PCERT_CREATE_CONTEXT_PARA pCreatePara)
3127 {
3128     TRACE("(0x%x, 0x%x, %p, %d, 0x%08x, %p)\n", dwContextType, dwEncodingType,
3129           pbEncoded, cbEncoded, dwFlags, pCreatePara);
3130
3131     if (dwFlags)
3132     {
3133         FIXME("dwFlags 0x%08x not handled\n", dwFlags);
3134         return NULL;
3135     }
3136     if (pCreatePara)
3137     {
3138         FIXME("pCreatePara not handled\n");
3139         return NULL;
3140     }
3141
3142     switch (dwContextType)
3143     {
3144     case CERT_STORE_CERTIFICATE_CONTEXT:
3145         return CertCreateCertificateContext(dwEncodingType, pbEncoded, cbEncoded);
3146     case CERT_STORE_CRL_CONTEXT:
3147         return CertCreateCRLContext(dwEncodingType, pbEncoded, cbEncoded);
3148     case CERT_STORE_CTL_CONTEXT:
3149         return CertCreateCTLContext(dwEncodingType, pbEncoded, cbEncoded);
3150     default:
3151         WARN("unknown context type: 0x%x\n", dwContextType);
3152         return NULL;
3153     }
3154 }