crypt32: Add base message type and use it to implement CryptMsgDuplicate and CryptMsg...
[wine] / dlls / crypt32 / cert.c
1 /*
2  * Copyright 2004-2006 Juan Lang
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  *
18  */
19
20 #include <assert.h>
21 #include <stdarg.h>
22
23 #define NONAMELESSUNION
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wincrypt.h"
27 #include "winnls.h"
28 #include "rpc.h"
29 #include "wine/debug.h"
30 #include "crypt32_private.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
33
34 /* Internal version of CertGetCertificateContextProperty that gets properties
35  * directly from the context (or the context it's linked to, depending on its
36  * type.) Doesn't handle special-case properties, since they are handled by
37  * CertGetCertificateContextProperty, and are particular to the store in which
38  * the property exists (which is separate from the context.)
39  */
40 static BOOL WINAPI CertContext_GetProperty(void *context, DWORD dwPropId,
41  void *pvData, DWORD *pcbData);
42
43 /* Internal version of CertSetCertificateContextProperty that sets properties
44  * directly on the context (or the context it's linked to, depending on its
45  * type.) Doesn't handle special cases, since they're handled by
46  * CertSetCertificateContextProperty anyway.
47  */
48 static BOOL WINAPI CertContext_SetProperty(void *context, DWORD dwPropId,
49  DWORD dwFlags, const void *pvData);
50
51 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
52  DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
53  DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
54 {
55     PCCERT_CONTEXT cert = CertCreateCertificateContext(dwCertEncodingType,
56      pbCertEncoded, cbCertEncoded);
57     BOOL ret;
58
59     TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore, dwCertEncodingType,
60      pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
61
62     if (cert)
63     {
64         ret = CertAddCertificateContextToStore(hCertStore, cert,
65          dwAddDisposition, ppCertContext);
66         CertFreeCertificateContext(cert);
67     }
68     else
69         ret = FALSE;
70     return ret;
71 }
72
73 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
74  const BYTE *pbCertEncoded, DWORD cbCertEncoded)
75 {
76     PCERT_CONTEXT cert = NULL;
77     BOOL ret;
78     PCERT_INFO certInfo = NULL;
79     DWORD size = 0;
80
81     TRACE("(%08x, %p, %d)\n", dwCertEncodingType, pbCertEncoded,
82      cbCertEncoded);
83
84     ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT_TO_BE_SIGNED,
85      pbCertEncoded, cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL,
86      (BYTE *)&certInfo, &size);
87     if (ret)
88     {
89         BYTE *data = NULL;
90
91         cert = (PCERT_CONTEXT)Context_CreateDataContext(sizeof(CERT_CONTEXT));
92         if (!cert)
93             goto end;
94         data = CryptMemAlloc(cbCertEncoded);
95         if (!data)
96         {
97             CryptMemFree(cert);
98             cert = NULL;
99             goto end;
100         }
101         memcpy(data, pbCertEncoded, cbCertEncoded);
102         cert->dwCertEncodingType = dwCertEncodingType;
103         cert->pbCertEncoded      = data;
104         cert->cbCertEncoded      = cbCertEncoded;
105         cert->pCertInfo          = certInfo;
106         cert->hCertStore         = 0;
107     }
108
109 end:
110     return (PCCERT_CONTEXT)cert;
111 }
112
113 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
114  PCCERT_CONTEXT pCertContext)
115 {
116     TRACE("(%p)\n", pCertContext);
117     Context_AddRef((void *)pCertContext, sizeof(CERT_CONTEXT));
118     return pCertContext;
119 }
120
121 static void CertDataContext_Free(void *context)
122 {
123     PCERT_CONTEXT certContext = (PCERT_CONTEXT)context;
124
125     CryptMemFree(certContext->pbCertEncoded);
126     LocalFree(certContext->pCertInfo);
127 }
128
129 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
130 {
131     TRACE("(%p)\n", pCertContext);
132
133     if (pCertContext)
134         Context_Release((void *)pCertContext, sizeof(CERT_CONTEXT),
135          CertDataContext_Free);
136     return TRUE;
137 }
138
139 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
140  DWORD dwPropId)
141 {
142     PCONTEXT_PROPERTY_LIST properties = Context_GetProperties(
143      (void *)pCertContext, sizeof(CERT_CONTEXT));
144     DWORD ret;
145
146     TRACE("(%p, %d)\n", pCertContext, dwPropId);
147
148     if (properties)
149         ret = ContextPropertyList_EnumPropIDs(properties, dwPropId);
150     else
151         ret = 0;
152     return ret;
153 }
154
155 static BOOL CertContext_GetHashProp(void *context, DWORD dwPropId,
156  ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
157  DWORD *pcbData)
158 {
159     BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
160      pcbData);
161     if (ret && pvData)
162     {
163         CRYPT_DATA_BLOB blob = { *pcbData, pvData };
164
165         ret = CertContext_SetProperty(context, dwPropId, 0, &blob);
166     }
167     return ret;
168 }
169
170 static BOOL WINAPI CertContext_GetProperty(void *context, DWORD dwPropId,
171  void *pvData, DWORD *pcbData)
172 {
173     PCCERT_CONTEXT pCertContext = (PCCERT_CONTEXT)context;
174     PCONTEXT_PROPERTY_LIST properties =
175      Context_GetProperties(context, sizeof(CERT_CONTEXT));
176     BOOL ret;
177     CRYPT_DATA_BLOB blob;
178
179     TRACE("(%p, %d, %p, %p)\n", context, dwPropId, pvData, pcbData);
180
181     if (properties)
182         ret = ContextPropertyList_FindProperty(properties, dwPropId, &blob);
183     else
184         ret = FALSE;
185     if (ret)
186     {
187         if (!pvData)
188             *pcbData = blob.cbData;
189         else if (*pcbData < blob.cbData)
190         {
191             SetLastError(ERROR_MORE_DATA);
192             *pcbData = blob.cbData;
193             ret = FALSE;
194         }
195         else
196         {
197             memcpy(pvData, blob.pbData, blob.cbData);
198             *pcbData = blob.cbData;
199         }
200     }
201     else
202     {
203         /* Implicit properties */
204         switch (dwPropId)
205         {
206         case CERT_SHA1_HASH_PROP_ID:
207             ret = CertContext_GetHashProp(context, dwPropId, CALG_SHA1,
208              pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData,
209              pcbData);
210             break;
211         case CERT_MD5_HASH_PROP_ID:
212             ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
213              pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData,
214              pcbData);
215             break;
216         case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
217             ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
218              pCertContext->pCertInfo->Subject.pbData,
219              pCertContext->pCertInfo->Subject.cbData,
220              pvData, pcbData);
221             break;
222         case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
223             ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
224              pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
225              pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
226              pvData, pcbData);
227             break;
228         case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
229             ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
230              pCertContext->pCertInfo->SerialNumber.pbData,
231              pCertContext->pCertInfo->SerialNumber.cbData,
232              pvData, pcbData);
233             break;
234         case CERT_SIGNATURE_HASH_PROP_ID:
235             FIXME("CERT_SIGNATURE_HASH_PROP_ID unimplemented\n");
236             SetLastError(CRYPT_E_NOT_FOUND);
237             break;
238         default:
239             SetLastError(CRYPT_E_NOT_FOUND);
240         }
241     }
242     TRACE("returning %d\n", ret);
243     return ret;
244 }
245
246 void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info)
247 {
248     DWORD i, containerLen, provNameLen;
249     LPBYTE data = (LPBYTE)info + sizeof(CRYPT_KEY_PROV_INFO);
250
251     info->pwszContainerName = (LPWSTR)data;
252     containerLen = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
253     data += containerLen;
254
255     info->pwszProvName = (LPWSTR)data;
256     provNameLen = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
257     data += provNameLen;
258
259     info->rgProvParam = (PCRYPT_KEY_PROV_PARAM)data;
260     data += info->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
261
262     for (i = 0; i < info->cProvParam; i++)
263     {
264         info->rgProvParam[i].pbData = data;
265         data += info->rgProvParam[i].cbData;
266     }
267 }
268
269 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
270  DWORD dwPropId, void *pvData, DWORD *pcbData)
271 {
272     BOOL ret;
273
274     TRACE("(%p, %d, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
275
276     switch (dwPropId)
277     {
278     case 0:
279     case CERT_CERT_PROP_ID:
280     case CERT_CRL_PROP_ID:
281     case CERT_CTL_PROP_ID:
282         SetLastError(E_INVALIDARG);
283         ret = FALSE;
284         break;
285     case CERT_ACCESS_STATE_PROP_ID:
286         if (!pvData)
287         {
288             *pcbData = sizeof(DWORD);
289             ret = TRUE;
290         }
291         else if (*pcbData < sizeof(DWORD))
292         {
293             SetLastError(ERROR_MORE_DATA);
294             *pcbData = sizeof(DWORD);
295             ret = FALSE;
296         }
297         else
298         {
299             if (pCertContext->hCertStore)
300                 ret = CertGetStoreProperty(pCertContext->hCertStore, dwPropId,
301                  pvData, pcbData);
302             else
303                 *(DWORD *)pvData = 0;
304             ret = TRUE;
305         }
306         break;
307     case CERT_KEY_IDENTIFIER_PROP_ID:
308         ret = CertContext_GetProperty((void *)pCertContext, dwPropId,
309          pvData, pcbData);
310         if (!ret)
311             SetLastError(ERROR_INVALID_DATA);
312         break;
313     case CERT_KEY_PROV_HANDLE_PROP_ID:
314     {
315         CERT_KEY_CONTEXT keyContext;
316         DWORD size = sizeof(keyContext);
317
318         ret = CertContext_GetProperty((void *)pCertContext,
319          CERT_KEY_CONTEXT_PROP_ID, &keyContext, &size);
320         if (ret)
321         {
322             if (!pvData)
323                 *pcbData = sizeof(HCRYPTPROV);
324             else if (*pcbData < sizeof(HCRYPTPROV))
325             {
326                 SetLastError(ERROR_MORE_DATA);
327                 *pcbData = sizeof(HCRYPTPROV);
328                 ret = FALSE;
329             }
330             else
331                 *(HCRYPTPROV *)pvData = keyContext.hCryptProv;
332         }
333         break;
334     }
335     case CERT_KEY_PROV_INFO_PROP_ID:
336         ret = CertContext_GetProperty((void *)pCertContext, dwPropId, pvData,
337          pcbData);
338         if (ret && pvData)
339             CRYPT_FixKeyProvInfoPointers((PCRYPT_KEY_PROV_INFO)pvData);
340         break;
341     default:
342         ret = CertContext_GetProperty((void *)pCertContext, dwPropId, pvData,
343          pcbData);
344     }
345
346     TRACE("returning %d\n", ret);
347     return ret;
348 }
349
350 /* Copies key provider info from from into to, where to is assumed to be a
351  * contiguous buffer of memory large enough for from and all its associated
352  * data, but whose pointers are uninitialized.
353  * Upon return, to contains a contiguous copy of from, packed in the following
354  * order:
355  * - CRYPT_KEY_PROV_INFO
356  * - pwszContainerName
357  * - pwszProvName
358  * - rgProvParam[0]...
359  */
360 static void CRYPT_CopyKeyProvInfo(PCRYPT_KEY_PROV_INFO to,
361  const CRYPT_KEY_PROV_INFO *from)
362 {
363     DWORD i;
364     LPBYTE nextData = (LPBYTE)to + sizeof(CRYPT_KEY_PROV_INFO);
365
366     if (from->pwszContainerName)
367     {
368         to->pwszContainerName = (LPWSTR)nextData;
369         lstrcpyW(to->pwszContainerName, from->pwszContainerName);
370         nextData += (lstrlenW(from->pwszContainerName) + 1) * sizeof(WCHAR);
371     }
372     else
373         to->pwszContainerName = NULL;
374     if (from->pwszProvName)
375     {
376         to->pwszProvName = (LPWSTR)nextData;
377         lstrcpyW(to->pwszProvName, from->pwszProvName);
378         nextData += (lstrlenW(from->pwszProvName) + 1) * sizeof(WCHAR);
379     }
380     else
381         to->pwszProvName = NULL;
382     to->dwProvType = from->dwProvType;
383     to->dwFlags = from->dwFlags;
384     to->cProvParam = from->cProvParam;
385     to->rgProvParam = (PCRYPT_KEY_PROV_PARAM)nextData;
386     nextData += to->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
387     to->dwKeySpec = from->dwKeySpec;
388     for (i = 0; i < to->cProvParam; i++)
389     {
390         memcpy(&to->rgProvParam[i], &from->rgProvParam[i],
391          sizeof(CRYPT_KEY_PROV_PARAM));
392         to->rgProvParam[i].pbData = nextData;
393         memcpy(to->rgProvParam[i].pbData, from->rgProvParam[i].pbData,
394          from->rgProvParam[i].cbData);
395         nextData += from->rgProvParam[i].cbData;
396     }
397 }
398
399 static BOOL CertContext_SetKeyProvInfoProperty(PCONTEXT_PROPERTY_LIST properties,
400  const CRYPT_KEY_PROV_INFO *info)
401 {
402     BOOL ret;
403     LPBYTE buf = NULL;
404     DWORD size = sizeof(CRYPT_KEY_PROV_INFO), i, containerSize, provNameSize;
405
406     if (info->pwszContainerName)
407         containerSize = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
408     else
409         containerSize = 0;
410     if (info->pwszProvName)
411         provNameSize = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
412     else
413         provNameSize = 0;
414     size += containerSize + provNameSize;
415     for (i = 0; i < info->cProvParam; i++)
416         size += sizeof(CRYPT_KEY_PROV_PARAM) + info->rgProvParam[i].cbData;
417     buf = CryptMemAlloc(size);
418     if (buf)
419     {
420         CRYPT_CopyKeyProvInfo((PCRYPT_KEY_PROV_INFO)buf, info);
421         ret = ContextPropertyList_SetProperty(properties,
422          CERT_KEY_PROV_INFO_PROP_ID, buf, size);
423         CryptMemFree(buf);
424     }
425     else
426         ret = FALSE;
427     return ret;
428 }
429
430 static BOOL WINAPI CertContext_SetProperty(void *context, DWORD dwPropId,
431  DWORD dwFlags, const void *pvData)
432 {
433     PCONTEXT_PROPERTY_LIST properties =
434      Context_GetProperties(context, sizeof(CERT_CONTEXT));
435     BOOL ret;
436
437     TRACE("(%p, %d, %08x, %p)\n", context, dwPropId, dwFlags, pvData);
438
439     if (!properties)
440         ret = FALSE;
441     else
442     {
443         switch (dwPropId)
444         {
445         case CERT_AUTO_ENROLL_PROP_ID:
446         case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */
447         case CERT_DESCRIPTION_PROP_ID:
448         case CERT_FRIENDLY_NAME_PROP_ID:
449         case CERT_HASH_PROP_ID:
450         case CERT_KEY_IDENTIFIER_PROP_ID:
451         case CERT_MD5_HASH_PROP_ID:
452         case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
453         case CERT_PUBKEY_ALG_PARA_PROP_ID:
454         case CERT_PVK_FILE_PROP_ID:
455         case CERT_SIGNATURE_HASH_PROP_ID:
456         case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
457         case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
458         case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
459         case CERT_ENROLLMENT_PROP_ID:
460         case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
461         case CERT_RENEWAL_PROP_ID:
462         {
463             if (pvData)
464             {
465                 const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvData;
466
467                 ret = ContextPropertyList_SetProperty(properties, dwPropId,
468                  blob->pbData, blob->cbData);
469             }
470             else
471             {
472                 ContextPropertyList_RemoveProperty(properties, dwPropId);
473                 ret = TRUE;
474             }
475             break;
476         }
477         case CERT_DATE_STAMP_PROP_ID:
478             if (pvData)
479                 ret = ContextPropertyList_SetProperty(properties, dwPropId,
480                  (const BYTE *)pvData, sizeof(FILETIME));
481             else
482             {
483                 ContextPropertyList_RemoveProperty(properties, dwPropId);
484                 ret = TRUE;
485             }
486             break;
487         case CERT_KEY_CONTEXT_PROP_ID:
488         {
489             if (pvData)
490             {
491                 const CERT_KEY_CONTEXT *keyContext = (const CERT_KEY_CONTEXT *)pvData;
492
493                 ret = ContextPropertyList_SetProperty(properties, dwPropId,
494                  (const BYTE *)keyContext, keyContext->cbSize);
495             }
496             else
497             {
498                 ContextPropertyList_RemoveProperty(properties, dwPropId);
499                 ret = TRUE;
500             }
501             break;
502         }
503         case CERT_KEY_PROV_INFO_PROP_ID:
504             if (pvData)
505                 ret = CertContext_SetKeyProvInfoProperty(properties,
506                  (const CRYPT_KEY_PROV_INFO *)pvData);
507             else
508             {
509                 ContextPropertyList_RemoveProperty(properties, dwPropId);
510                 ret = TRUE;
511             }
512             break;
513         case CERT_KEY_PROV_HANDLE_PROP_ID:
514         {
515             CERT_KEY_CONTEXT keyContext;
516             DWORD size = sizeof(keyContext);
517
518             ret = CertContext_GetProperty(context, CERT_KEY_CONTEXT_PROP_ID,
519              &keyContext, &size);
520             if (ret)
521             {
522                 if (!(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
523                     CryptReleaseContext(keyContext.hCryptProv, 0);
524                 if (pvData)
525                     keyContext.hCryptProv = *(const HCRYPTPROV *)pvData;
526                 else
527                     keyContext.hCryptProv = 0;
528                 ret = CertContext_SetProperty(context, CERT_KEY_CONTEXT_PROP_ID,
529                  0, &keyContext);
530             }
531             break;
532         }
533         default:
534             FIXME("%d: stub\n", dwPropId);
535             ret = FALSE;
536         }
537     }
538     TRACE("returning %d\n", ret);
539     return ret;
540 }
541
542 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
543  DWORD dwPropId, DWORD dwFlags, const void *pvData)
544 {
545     BOOL ret;
546
547     TRACE("(%p, %d, %08x, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
548
549     /* Handle special cases for "read-only"/invalid prop IDs.  Windows just
550      * crashes on most of these, I'll be safer.
551      */
552     switch (dwPropId)
553     {
554     case 0:
555     case CERT_ACCESS_STATE_PROP_ID:
556     case CERT_CERT_PROP_ID:
557     case CERT_CRL_PROP_ID:
558     case CERT_CTL_PROP_ID:
559         SetLastError(E_INVALIDARG);
560         return FALSE;
561     }
562     ret = CertContext_SetProperty((void *)pCertContext, dwPropId, dwFlags,
563      pvData);
564     TRACE("returning %d\n", ret);
565     return ret;
566 }
567
568 /* Acquires the private key using the key provider info, retrieving info from
569  * the certificate if info is NULL.  The acquired provider is returned in
570  * *phCryptProv, and the key spec for the provider is returned in *pdwKeySpec.
571  */
572 static BOOL CRYPT_AcquirePrivateKeyFromProvInfo(PCCERT_CONTEXT pCert,
573  PCRYPT_KEY_PROV_INFO info, HCRYPTPROV *phCryptProv, DWORD *pdwKeySpec)
574 {
575     DWORD size = 0;
576     BOOL allocated = FALSE, ret = TRUE;
577
578     if (!info)
579     {
580         ret = CertGetCertificateContextProperty(pCert,
581          CERT_KEY_PROV_INFO_PROP_ID, 0, &size);
582         if (ret)
583         {
584             info = (PCRYPT_KEY_PROV_INFO)HeapAlloc(GetProcessHeap(), 0, size);
585             if (info)
586             {
587                 ret = CertGetCertificateContextProperty(pCert,
588                  CERT_KEY_PROV_INFO_PROP_ID, info, &size);
589                 allocated = TRUE;
590             }
591         }
592         else
593             SetLastError(CRYPT_E_NO_KEY_PROPERTY);
594     }
595     if (ret)
596     {
597         ret = CryptAcquireContextW(phCryptProv, info->pwszContainerName,
598          info->pwszProvName, info->dwProvType, 0);
599         if (ret)
600         {
601             DWORD i;
602
603             for (i = 0; i < info->cProvParam; i++)
604             {
605                 CryptSetProvParam(*phCryptProv,
606                  info->rgProvParam[i].dwParam, info->rgProvParam[i].pbData,
607                  info->rgProvParam[i].dwFlags);
608             }
609             *pdwKeySpec = info->dwKeySpec;
610         }
611         else
612             SetLastError(CRYPT_E_NO_KEY_PROPERTY);
613     }
614     if (allocated)
615         HeapFree(GetProcessHeap(), 0, info);
616     return ret;
617 }
618
619 BOOL WINAPI CryptAcquireCertificatePrivateKey(PCCERT_CONTEXT pCert,
620  DWORD dwFlags, void *pvReserved, HCRYPTPROV *phCryptProv, DWORD *pdwKeySpec,
621  BOOL *pfCallerFreeProv)
622 {
623     BOOL ret = FALSE, cache = FALSE;
624     PCRYPT_KEY_PROV_INFO info = NULL;
625     CERT_KEY_CONTEXT keyContext;
626     DWORD size;
627
628     TRACE("(%p, %08x, %p, %p, %p, %p)\n", pCert, dwFlags, pvReserved,
629      phCryptProv, pdwKeySpec, pfCallerFreeProv);
630
631     if (dwFlags & CRYPT_ACQUIRE_USE_PROV_INFO_FLAG)
632     {
633         DWORD size = 0;
634
635         ret = CertGetCertificateContextProperty(pCert,
636          CERT_KEY_PROV_INFO_PROP_ID, 0, &size);
637         if (ret)
638         {
639             info = (PCRYPT_KEY_PROV_INFO)HeapAlloc(
640              GetProcessHeap(), 0, size);
641             ret = CertGetCertificateContextProperty(pCert,
642              CERT_KEY_PROV_INFO_PROP_ID, info, &size);
643             if (ret)
644                 cache = info->dwFlags & CERT_SET_KEY_CONTEXT_PROP_ID;
645         }
646     }
647     else if (dwFlags & CRYPT_ACQUIRE_CACHE_FLAG)
648         cache = TRUE;
649     *phCryptProv = 0;
650     if (cache)
651     {
652         size = sizeof(keyContext);
653         ret = CertGetCertificateContextProperty(pCert, CERT_KEY_CONTEXT_PROP_ID,
654          &keyContext, &size);
655         if (ret)
656         {
657             *phCryptProv = keyContext.hCryptProv;
658             if (pdwKeySpec)
659                 *pdwKeySpec = keyContext.dwKeySpec;
660             if (pfCallerFreeProv)
661                 *pfCallerFreeProv = !cache;
662         }
663     }
664     if (!*phCryptProv)
665     {
666         ret = CRYPT_AcquirePrivateKeyFromProvInfo(pCert, info,
667          &keyContext.hCryptProv, &keyContext.dwKeySpec);
668         if (ret)
669         {
670             *phCryptProv = keyContext.hCryptProv;
671             if (pdwKeySpec)
672                 *pdwKeySpec = keyContext.dwKeySpec;
673             if (cache)
674             {
675                 keyContext.cbSize = sizeof(keyContext);
676                 if (CertSetCertificateContextProperty(pCert,
677                  CERT_KEY_CONTEXT_PROP_ID, 0, &keyContext))
678                 {
679                     if (pfCallerFreeProv)
680                         *pfCallerFreeProv = FALSE;
681                 }
682             }
683             else
684             {
685                 if (pfCallerFreeProv)
686                     *pfCallerFreeProv = TRUE;
687             }
688         }
689     }
690     HeapFree(GetProcessHeap(), 0, info);
691     return ret;
692 }
693
694 BOOL WINAPI CertCompareCertificate(DWORD dwCertEncodingType,
695  PCERT_INFO pCertId1, PCERT_INFO pCertId2)
696 {
697     TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertId1, pCertId2);
698
699     return CertCompareCertificateName(dwCertEncodingType, &pCertId1->Issuer,
700      &pCertId2->Issuer) && CertCompareIntegerBlob(&pCertId1->SerialNumber,
701      &pCertId2->SerialNumber);
702 }
703
704 BOOL WINAPI CertCompareCertificateName(DWORD dwCertEncodingType,
705  PCERT_NAME_BLOB pCertName1, PCERT_NAME_BLOB pCertName2)
706 {
707     BOOL ret;
708
709     TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertName1, pCertName2);
710
711     if (pCertName1->cbData == pCertName2->cbData)
712     {
713         if (pCertName1->cbData)
714             ret = !memcmp(pCertName1->pbData, pCertName2->pbData,
715              pCertName1->cbData);
716         else
717             ret = TRUE;
718     }
719     else
720         ret = FALSE;
721     return ret;
722 }
723
724 /* Returns the number of significant bytes in pInt, where a byte is
725  * insignificant if it's a leading 0 for positive numbers or a leading 0xff
726  * for negative numbers.  pInt is assumed to be little-endian.
727  */
728 static DWORD CRYPT_significantBytes(const CRYPT_INTEGER_BLOB *pInt)
729 {
730     DWORD ret = pInt->cbData;
731
732     while (ret > 1)
733     {
734         if (pInt->pbData[ret - 2] <= 0x7f && pInt->pbData[ret - 1] == 0)
735             ret--;
736         else if (pInt->pbData[ret - 2] >= 0x80 && pInt->pbData[ret - 1] == 0xff)
737             ret--;
738         else
739             break;
740     }
741     return ret;
742 }
743
744 BOOL WINAPI CertCompareIntegerBlob(PCRYPT_INTEGER_BLOB pInt1,
745  PCRYPT_INTEGER_BLOB pInt2)
746 {
747     BOOL ret;
748     DWORD cb1, cb2;
749
750     TRACE("(%p, %p)\n", pInt1, pInt2);
751
752     cb1 = CRYPT_significantBytes(pInt1);
753     cb2 = CRYPT_significantBytes(pInt2);
754     if (cb1 == cb2)
755     {
756         if (cb1)
757             ret = !memcmp(pInt1->pbData, pInt1->pbData, cb1);
758         else
759             ret = TRUE;
760     }
761     else
762         ret = FALSE;
763     return ret;
764 }
765
766 BOOL WINAPI CertComparePublicKeyInfo(DWORD dwCertEncodingType,
767  PCERT_PUBLIC_KEY_INFO pPublicKey1, PCERT_PUBLIC_KEY_INFO pPublicKey2)
768 {
769     BOOL ret;
770
771     TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pPublicKey1, pPublicKey2);
772
773     if (pPublicKey1->PublicKey.cbData == pPublicKey2->PublicKey.cbData &&
774      pPublicKey1->PublicKey.cUnusedBits == pPublicKey2->PublicKey.cUnusedBits)
775     {
776         if (pPublicKey2->PublicKey.cbData)
777             ret = !memcmp(pPublicKey1->PublicKey.pbData,
778              pPublicKey2->PublicKey.pbData, pPublicKey1->PublicKey.cbData);
779         else
780             ret = TRUE;
781     }
782     else
783         ret = FALSE;
784     return ret;
785 }
786
787 DWORD WINAPI CertGetPublicKeyLength(DWORD dwCertEncodingType,
788  PCERT_PUBLIC_KEY_INFO pPublicKey)
789 {
790     DWORD len = 0;
791
792     TRACE("(%08x, %p)\n", dwCertEncodingType, pPublicKey);
793
794     if (dwCertEncodingType != X509_ASN_ENCODING)
795     {
796         SetLastError(ERROR_FILE_NOT_FOUND);
797         return 0;
798     }
799     if (pPublicKey->Algorithm.pszObjId &&
800      !strcmp(pPublicKey->Algorithm.pszObjId, szOID_RSA_DH))
801     {
802         FIXME("unimplemented for DH public keys\n");
803         SetLastError(CRYPT_E_ASN1_BADTAG);
804     }
805     else
806     {
807         DWORD size;
808         PBYTE buf;
809         BOOL ret = CryptDecodeObjectEx(dwCertEncodingType,
810          RSA_CSP_PUBLICKEYBLOB, pPublicKey->PublicKey.pbData,
811          pPublicKey->PublicKey.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf,
812          &size);
813
814         if (ret)
815         {
816             RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)((LPBYTE)buf +
817              sizeof(BLOBHEADER));
818
819             len = rsaPubKey->bitlen;
820             LocalFree(buf);
821         }
822     }
823     return len;
824 }
825
826 typedef BOOL (*CertCompareFunc)(PCCERT_CONTEXT pCertContext, DWORD dwType,
827  DWORD dwFlags, const void *pvPara);
828
829 static BOOL compare_cert_any(PCCERT_CONTEXT pCertContext, DWORD dwType,
830  DWORD dwFlags, const void *pvPara)
831 {
832     return TRUE;
833 }
834
835 static BOOL compare_cert_by_md5_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
836  DWORD dwFlags, const void *pvPara)
837 {
838     BOOL ret;
839     BYTE hash[16];
840     DWORD size = sizeof(hash);
841
842     ret = CertGetCertificateContextProperty(pCertContext,
843      CERT_MD5_HASH_PROP_ID, hash, &size);
844     if (ret)
845     {
846         const CRYPT_HASH_BLOB *pHash = (const CRYPT_HASH_BLOB *)pvPara;
847
848         if (size == pHash->cbData)
849             ret = !memcmp(pHash->pbData, hash, size);
850         else
851             ret = FALSE;
852     }
853     return ret;
854 }
855
856 static BOOL compare_cert_by_sha1_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
857  DWORD dwFlags, const void *pvPara)
858 {
859     BOOL ret;
860     BYTE hash[20];
861     DWORD size = sizeof(hash);
862
863     ret = CertGetCertificateContextProperty(pCertContext,
864      CERT_SHA1_HASH_PROP_ID, hash, &size);
865     if (ret)
866     {
867         const CRYPT_HASH_BLOB *pHash = (const CRYPT_HASH_BLOB *)pvPara;
868
869         if (size == pHash->cbData)
870             ret = !memcmp(pHash->pbData, hash, size);
871         else
872             ret = FALSE;
873     }
874     return ret;
875 }
876
877 static BOOL compare_cert_by_name(PCCERT_CONTEXT pCertContext, DWORD dwType,
878  DWORD dwFlags, const void *pvPara)
879 {
880     CERT_NAME_BLOB *blob = (CERT_NAME_BLOB *)pvPara, *toCompare;
881     BOOL ret;
882
883     if (dwType & CERT_INFO_SUBJECT_FLAG)
884         toCompare = &pCertContext->pCertInfo->Subject;
885     else
886         toCompare = &pCertContext->pCertInfo->Issuer;
887     ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
888      toCompare, blob);
889     return ret;
890 }
891
892 static BOOL compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext,
893  DWORD dwType, DWORD dwFlags, const void *pvPara)
894 {
895     CERT_INFO *pCertInfo = (CERT_INFO *)pvPara;
896
897     return CertCompareCertificateName(pCertContext->dwCertEncodingType,
898      &pCertInfo->Issuer, &pCertContext->pCertInfo->Subject);
899 }
900
901 static BOOL compare_cert_by_issuer(PCCERT_CONTEXT pCertContext,
902  DWORD dwType, DWORD dwFlags, const void *pvPara)
903 {
904     return compare_cert_by_subject_cert(pCertContext, dwType, dwFlags,
905      ((PCCERT_CONTEXT)pvPara)->pCertInfo);
906 }
907
908 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
909  DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType, const void *pvPara,
910  PCCERT_CONTEXT pPrevCertContext)
911 {
912     PCCERT_CONTEXT ret;
913     CertCompareFunc compare;
914
915     TRACE("(%p, %d, %d, %d, %p, %p)\n", hCertStore, dwCertEncodingType,
916          dwFlags, dwType, pvPara, pPrevCertContext);
917
918     switch (dwType >> CERT_COMPARE_SHIFT)
919     {
920     case CERT_COMPARE_ANY:
921         compare = compare_cert_any;
922         break;
923     case CERT_COMPARE_MD5_HASH:
924         compare = compare_cert_by_md5_hash;
925         break;
926     case CERT_COMPARE_SHA1_HASH:
927         compare = compare_cert_by_sha1_hash;
928         break;
929     case CERT_COMPARE_NAME:
930         compare = compare_cert_by_name;
931         break;
932     case CERT_COMPARE_SUBJECT_CERT:
933         compare = compare_cert_by_subject_cert;
934         break;
935     case CERT_COMPARE_ISSUER_OF:
936         compare = compare_cert_by_issuer;
937         break;
938     default:
939         FIXME("find type %08x unimplemented\n", dwType);
940         compare = NULL;
941     }
942
943     if (compare)
944     {
945         BOOL matches = FALSE;
946
947         ret = pPrevCertContext;
948         do {
949             ret = CertEnumCertificatesInStore(hCertStore, ret);
950             if (ret)
951                 matches = compare(ret, dwType, dwFlags, pvPara);
952         } while (ret != NULL && !matches);
953         if (!ret)
954             SetLastError(CRYPT_E_NOT_FOUND);
955     }
956     else
957     {
958         SetLastError(CRYPT_E_NOT_FOUND);
959         ret = NULL;
960     }
961     return ret;
962 }
963
964 PCCERT_CONTEXT WINAPI CertGetSubjectCertificateFromStore(HCERTSTORE hCertStore,
965  DWORD dwCertEncodingType, PCERT_INFO pCertId)
966 {
967     TRACE("(%p, %08x, %p)\n", hCertStore, dwCertEncodingType, pCertId);
968
969     if (!pCertId)
970     {
971         SetLastError(E_INVALIDARG);
972         return NULL;
973     }
974     return CertFindCertificateInStore(hCertStore, dwCertEncodingType, 0,
975      CERT_FIND_SUBJECT_CERT, pCertId, NULL);
976 }
977
978 BOOL WINAPI CertVerifySubjectCertificateContext(PCCERT_CONTEXT pSubject,
979  PCCERT_CONTEXT pIssuer, DWORD *pdwFlags)
980 {
981     static const DWORD supportedFlags = CERT_STORE_REVOCATION_FLAG |
982      CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG;
983
984     if (*pdwFlags & ~supportedFlags)
985     {
986         SetLastError(E_INVALIDARG);
987         return FALSE;
988     }
989     if (*pdwFlags & CERT_STORE_REVOCATION_FLAG)
990     {
991         DWORD flags = 0;
992         PCCRL_CONTEXT crl = CertGetCRLFromStore(pSubject->hCertStore, pSubject,
993          NULL, &flags);
994
995         /* FIXME: what if the CRL has expired? */
996         if (crl)
997         {
998             if (CertVerifyCRLRevocation(pSubject->dwCertEncodingType,
999              pSubject->pCertInfo, 1, (PCRL_INFO *)&crl->pCrlInfo))
1000                 *pdwFlags &= CERT_STORE_REVOCATION_FLAG;
1001         }
1002         else
1003             *pdwFlags |= CERT_STORE_NO_CRL_FLAG;
1004     }
1005     if (*pdwFlags & CERT_STORE_TIME_VALIDITY_FLAG)
1006     {
1007         if (0 == CertVerifyTimeValidity(NULL, pSubject->pCertInfo))
1008             *pdwFlags &= ~CERT_STORE_TIME_VALIDITY_FLAG;
1009     }
1010     if (*pdwFlags & CERT_STORE_SIGNATURE_FLAG)
1011     {
1012         if (CryptVerifyCertificateSignatureEx(0, pSubject->dwCertEncodingType,
1013          CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)pSubject,
1014          CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)pIssuer, 0, NULL))
1015             *pdwFlags &= ~CERT_STORE_SIGNATURE_FLAG;
1016     }
1017     return TRUE;
1018 }
1019
1020 PCCERT_CONTEXT WINAPI CertGetIssuerCertificateFromStore(HCERTSTORE hCertStore,
1021  PCCERT_CONTEXT pSubjectContext, PCCERT_CONTEXT pPrevIssuerContext,
1022  DWORD *pdwFlags)
1023 {
1024     PCCERT_CONTEXT ret;
1025
1026     TRACE("(%p, %p, %p, %08x)\n", hCertStore, pSubjectContext,
1027      pPrevIssuerContext, *pdwFlags);
1028
1029     if (!pSubjectContext)
1030     {
1031         SetLastError(E_INVALIDARG);
1032         return NULL;
1033     }
1034
1035     ret = CertFindCertificateInStore(hCertStore,
1036      pSubjectContext->dwCertEncodingType, 0, CERT_FIND_ISSUER_OF,
1037      pSubjectContext, pPrevIssuerContext);
1038     if (ret)
1039     {
1040         if (!CertVerifySubjectCertificateContext(pSubjectContext, ret,
1041          pdwFlags))
1042         {
1043             CertFreeCertificateContext(ret);
1044             ret = NULL;
1045         }
1046     }
1047
1048     return ret;
1049 }
1050
1051 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
1052  CRYPT_ATTRIBUTE rgAttr[])
1053 {
1054     PCRYPT_ATTRIBUTE ret = NULL;
1055     DWORD i;
1056
1057     TRACE("%s %d %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
1058
1059     if (!cAttr)
1060         return NULL;
1061     if (!pszObjId)
1062     {
1063         SetLastError(ERROR_INVALID_PARAMETER);
1064         return NULL;
1065     }
1066
1067     for (i = 0; !ret && i < cAttr; i++)
1068         if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
1069             ret = &rgAttr[i];
1070     return ret;
1071 }
1072
1073 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
1074  CERT_EXTENSION rgExtensions[])
1075 {
1076     PCERT_EXTENSION ret = NULL;
1077     DWORD i;
1078
1079     TRACE("%s %d %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
1080
1081     if (!cExtensions)
1082         return NULL;
1083     if (!pszObjId)
1084     {
1085         SetLastError(ERROR_INVALID_PARAMETER);
1086         return NULL;
1087     }
1088
1089     for (i = 0; !ret && i < cExtensions; i++)
1090         if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
1091          rgExtensions[i].pszObjId))
1092             ret = &rgExtensions[i];
1093     return ret;
1094 }
1095
1096 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
1097 {
1098     PCERT_RDN_ATTR ret = NULL;
1099     DWORD i, j;
1100
1101     TRACE("%s %p\n", debugstr_a(pszObjId), pName);
1102
1103     if (!pszObjId)
1104     {
1105         SetLastError(ERROR_INVALID_PARAMETER);
1106         return NULL;
1107     }
1108
1109     for (i = 0; !ret && i < pName->cRDN; i++)
1110         for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
1111             if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
1112              pName->rgRDN[i].rgRDNAttr[j].pszObjId))
1113                 ret = &pName->rgRDN[i].rgRDNAttr[j];
1114     return ret;
1115 }
1116
1117 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
1118  PCERT_INFO pCertInfo)
1119 {
1120     FILETIME fileTime;
1121     LONG ret;
1122
1123     if (!pTimeToVerify)
1124     {
1125         SYSTEMTIME sysTime;
1126
1127         GetSystemTime(&sysTime);
1128         SystemTimeToFileTime(&sysTime, &fileTime);
1129         pTimeToVerify = &fileTime;
1130     }
1131     if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
1132     {
1133         ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
1134         if (ret < 0)
1135             ret = 0;
1136     }
1137     return ret;
1138 }
1139
1140 BOOL WINAPI CertVerifyValidityNesting(PCERT_INFO pSubjectInfo,
1141  PCERT_INFO pIssuerInfo)
1142 {
1143     TRACE("(%p, %p)\n", pSubjectInfo, pIssuerInfo);
1144
1145     return CertVerifyTimeValidity(&pSubjectInfo->NotBefore, pIssuerInfo) == 0
1146      && CertVerifyTimeValidity(&pSubjectInfo->NotAfter, pIssuerInfo) == 0;
1147 }
1148
1149 BOOL WINAPI CryptHashCertificate(HCRYPTPROV hCryptProv, ALG_ID Algid,
1150  DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
1151  DWORD *pcbComputedHash)
1152 {
1153     BOOL ret = TRUE;
1154     HCRYPTHASH hHash = 0;
1155
1156     TRACE("(%08lx, %d, %08x, %p, %d, %p, %p)\n", hCryptProv, Algid, dwFlags,
1157      pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
1158
1159     if (!hCryptProv)
1160         hCryptProv = CRYPT_GetDefaultProvider();
1161     if (!Algid)
1162         Algid = CALG_SHA1;
1163     if (ret)
1164     {
1165         ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
1166         if (ret)
1167         {
1168             ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
1169             if (ret)
1170                 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
1171                  pcbComputedHash, 0);
1172             CryptDestroyHash(hHash);
1173         }
1174     }
1175     return ret;
1176 }
1177
1178 BOOL WINAPI CryptHashPublicKeyInfo(HCRYPTPROV hCryptProv, ALG_ID Algid,
1179  DWORD dwFlags, DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo,
1180  BYTE *pbComputedHash, DWORD *pcbComputedHash)
1181 {
1182     BOOL ret = TRUE;
1183     HCRYPTHASH hHash = 0;
1184
1185     TRACE("(%08lx, %d, %08x, %d, %p, %p, %p)\n", hCryptProv, Algid, dwFlags,
1186      dwCertEncodingType, pInfo, pbComputedHash, pcbComputedHash);
1187
1188     if (!hCryptProv)
1189         hCryptProv = CRYPT_GetDefaultProvider();
1190     if (!Algid)
1191         Algid = CALG_MD5;
1192     if (ret)
1193     {
1194         BYTE *buf;
1195         DWORD size = 0;
1196
1197         ret = CryptEncodeObjectEx(dwCertEncodingType, X509_PUBLIC_KEY_INFO,
1198          pInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL, &buf, &size);
1199         if (ret)
1200         {
1201             ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
1202             if (ret)
1203             {
1204                 ret = CryptHashData(hHash, buf, size, 0);
1205                 if (ret)
1206                     ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
1207                      pcbComputedHash, 0);
1208                 CryptDestroyHash(hHash);
1209             }
1210             LocalFree(buf);
1211         }
1212     }
1213     return ret;
1214 }
1215
1216 BOOL WINAPI CryptSignCertificate(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
1217  DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned,
1218  DWORD cbEncodedToBeSigned, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
1219  const void *pvHashAuxInfo, BYTE *pbSignature, DWORD *pcbSignature)
1220 {
1221     BOOL ret;
1222     PCCRYPT_OID_INFO info;
1223     HCRYPTHASH hHash;
1224
1225     TRACE("(%08lx, %d, %d, %p, %d, %p, %p, %p, %p)\n", hCryptProv,
1226      dwKeySpec, dwCertEncodingType, pbEncodedToBeSigned, cbEncodedToBeSigned,
1227      pSignatureAlgorithm, pvHashAuxInfo, pbSignature, pcbSignature);
1228
1229     info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1230      pSignatureAlgorithm->pszObjId, 0);
1231     if (!info)
1232     {
1233         SetLastError(NTE_BAD_ALGID);
1234         return FALSE;
1235     }
1236     if (info->dwGroupId == CRYPT_HASH_ALG_OID_GROUP_ID)
1237     {
1238         if (!hCryptProv)
1239             hCryptProv = CRYPT_GetDefaultProvider();
1240         ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
1241         if (ret)
1242         {
1243             ret = CryptHashData(hHash, pbEncodedToBeSigned,
1244              cbEncodedToBeSigned, 0);
1245             if (ret)
1246                 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbSignature,
1247                  pcbSignature, 0);
1248             CryptDestroyHash(hHash);
1249         }
1250     }
1251     else
1252     {
1253         if (!hCryptProv)
1254         {
1255             SetLastError(ERROR_INVALID_PARAMETER);
1256             ret = FALSE;
1257         }
1258         else
1259         {
1260             ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
1261             if (ret)
1262             {
1263                 ret = CryptHashData(hHash, pbEncodedToBeSigned,
1264                  cbEncodedToBeSigned, 0);
1265                 if (ret)
1266                     ret = CryptSignHashW(hHash, dwKeySpec, NULL, 0, pbSignature,
1267                      pcbSignature);
1268                 CryptDestroyHash(hHash);
1269             }
1270         }
1271     }
1272     return ret;
1273 }
1274
1275 BOOL WINAPI CryptSignAndEncodeCertificate(HCRYPTPROV hCryptProv,
1276  DWORD dwKeySpec, DWORD dwCertEncodingType, LPCSTR lpszStructType,
1277  const void *pvStructInfo, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
1278  const void *pvHashAuxInfo, PBYTE pbEncoded, DWORD *pcbEncoded)
1279 {
1280     BOOL ret;
1281     DWORD encodedSize, hashSize;
1282
1283     TRACE("(%08lx, %d, %d, %s, %p, %p, %p, %p, %p)\n", hCryptProv, dwKeySpec,
1284      dwCertEncodingType, debugstr_a(lpszStructType), pvStructInfo,
1285      pSignatureAlgorithm, pvHashAuxInfo, pbEncoded, pcbEncoded);
1286
1287     ret = CryptEncodeObject(dwCertEncodingType, lpszStructType, pvStructInfo,
1288      NULL, &encodedSize);
1289     if (ret)
1290     {
1291         PBYTE encoded = CryptMemAlloc(encodedSize);
1292
1293         if (encoded)
1294         {
1295             ret = CryptEncodeObject(dwCertEncodingType, lpszStructType,
1296              pvStructInfo, encoded, &encodedSize);
1297             if (ret)
1298             {
1299                 ret = CryptSignCertificate(hCryptProv, dwKeySpec,
1300                  dwCertEncodingType, encoded, encodedSize, pSignatureAlgorithm,
1301                  pvHashAuxInfo, NULL, &hashSize);
1302                 if (ret)
1303                 {
1304                     PBYTE hash = CryptMemAlloc(hashSize);
1305
1306                     if (hash)
1307                     {
1308                         ret = CryptSignCertificate(hCryptProv, dwKeySpec,
1309                          dwCertEncodingType, encoded, encodedSize,
1310                          pSignatureAlgorithm, pvHashAuxInfo, hash, &hashSize);
1311                         if (ret)
1312                         {
1313                             CERT_SIGNED_CONTENT_INFO info = { { 0 } };
1314
1315                             info.ToBeSigned.cbData = encodedSize;
1316                             info.ToBeSigned.pbData = encoded;
1317                             memcpy(&info.SignatureAlgorithm,
1318                              pSignatureAlgorithm,
1319                              sizeof(info.SignatureAlgorithm));
1320                             info.Signature.cbData = hashSize;
1321                             info.Signature.pbData = hash;
1322                             info.Signature.cUnusedBits = 0;
1323                             ret = CryptEncodeObject(dwCertEncodingType,
1324                              X509_CERT, &info, pbEncoded, pcbEncoded);
1325                         }
1326                         CryptMemFree(hash);
1327                     }
1328                 }
1329             }
1330             CryptMemFree(encoded);
1331         }
1332     }
1333     return ret;
1334 }
1335
1336 BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV hCryptProv,
1337  DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
1338  PCERT_PUBLIC_KEY_INFO pPublicKey)
1339 {
1340     return CryptVerifyCertificateSignatureEx(hCryptProv, dwCertEncodingType,
1341      CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, (void *)pbEncoded,
1342      CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
1343 }
1344
1345 static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV hCryptProv,
1346  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pubKeyInfo,
1347  const CERT_SIGNED_CONTENT_INFO *signedCert)
1348 {
1349     BOOL ret;
1350     HCRYPTKEY key;
1351     PCCRYPT_OID_INFO info;
1352     ALG_ID pubKeyID, hashID;
1353
1354     info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
1355      pubKeyInfo->Algorithm.pszObjId, 0);
1356     if (!info || (info->dwGroupId != CRYPT_PUBKEY_ALG_OID_GROUP_ID &&
1357      info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID))
1358     {
1359         SetLastError(NTE_BAD_ALGID);
1360         return FALSE;
1361     }
1362     if (info->dwGroupId == CRYPT_PUBKEY_ALG_OID_GROUP_ID)
1363     {
1364         switch (info->u.Algid)
1365         {
1366             case CALG_RSA_KEYX:
1367                 pubKeyID = CALG_RSA_SIGN;
1368                 hashID = CALG_SHA1;
1369                 break;
1370             case CALG_RSA_SIGN:
1371                 pubKeyID = CALG_RSA_SIGN;
1372                 hashID = CALG_SHA1;
1373                 break;
1374             default:
1375                 FIXME("unimplemented for %s\n", pubKeyInfo->Algorithm.pszObjId);
1376                 return FALSE;
1377         }
1378     }
1379     else
1380     {
1381         hashID = info->u.Algid;
1382         if (info->ExtraInfo.cbData >= sizeof(ALG_ID))
1383             pubKeyID = *(ALG_ID *)info->ExtraInfo.pbData;
1384         else
1385             pubKeyID = hashID;
1386     }
1387     /* Load the default provider if necessary */
1388     if (!hCryptProv)
1389         hCryptProv = CRYPT_GetDefaultProvider();
1390     ret = CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType,
1391      pubKeyInfo, pubKeyID, 0, NULL, &key);
1392     if (ret)
1393     {
1394         HCRYPTHASH hash;
1395
1396         ret = CryptCreateHash(hCryptProv, hashID, 0, 0, &hash);
1397         if (ret)
1398         {
1399             ret = CryptHashData(hash, signedCert->ToBeSigned.pbData,
1400              signedCert->ToBeSigned.cbData, 0);
1401             if (ret)
1402                 ret = CryptVerifySignatureW(hash, signedCert->Signature.pbData,
1403                  signedCert->Signature.cbData, key, NULL, 0);
1404             CryptDestroyHash(hash);
1405         }
1406         CryptDestroyKey(key);
1407     }
1408     return ret;
1409 }
1410
1411 BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV hCryptProv,
1412  DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
1413  DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
1414 {
1415     BOOL ret = TRUE;
1416     CRYPT_DATA_BLOB subjectBlob;
1417
1418     TRACE("(%08lx, %d, %d, %p, %d, %p, %08x, %p)\n", hCryptProv,
1419      dwCertEncodingType, dwSubjectType, pvSubject, dwIssuerType, pvIssuer,
1420      dwFlags, pvReserved);
1421
1422     switch (dwSubjectType)
1423     {
1424     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB:
1425     {
1426         PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvSubject;
1427
1428         subjectBlob.pbData = blob->pbData;
1429         subjectBlob.cbData = blob->cbData;
1430         break;
1431     }
1432     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT:
1433     {
1434         PCERT_CONTEXT context = (PCERT_CONTEXT)pvSubject;
1435
1436         subjectBlob.pbData = context->pbCertEncoded;
1437         subjectBlob.cbData = context->cbCertEncoded;
1438         break;
1439     }
1440     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL:
1441     {
1442         PCRL_CONTEXT context = (PCRL_CONTEXT)pvSubject;
1443
1444         subjectBlob.pbData = context->pbCrlEncoded;
1445         subjectBlob.cbData = context->cbCrlEncoded;
1446         break;
1447     }
1448     default:
1449         SetLastError(E_INVALIDARG);
1450         ret = FALSE;
1451     }
1452
1453     if (ret)
1454     {
1455         PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
1456         DWORD size = 0;
1457
1458         ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
1459          subjectBlob.pbData, subjectBlob.cbData,
1460          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
1461          (BYTE *)&signedCert, &size);
1462         if (ret)
1463         {
1464             switch (dwIssuerType)
1465             {
1466             case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY:
1467                 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
1468                  dwCertEncodingType, (PCERT_PUBLIC_KEY_INFO)pvIssuer,
1469                  signedCert);
1470                 break;
1471             case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT:
1472                 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
1473                  dwCertEncodingType,
1474                  &((PCCERT_CONTEXT)pvIssuer)->pCertInfo->SubjectPublicKeyInfo,
1475                  signedCert);
1476                 break;
1477             case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN:
1478                 FIXME("CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: stub\n");
1479                 ret = FALSE;
1480                 break;
1481             case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL:
1482                 if (pvIssuer)
1483                 {
1484                     SetLastError(E_INVALIDARG);
1485                     ret = FALSE;
1486                 }
1487                 else
1488                 {
1489                     FIXME("unimplemented for NULL signer\n");
1490                     SetLastError(E_INVALIDARG);
1491                     ret = FALSE;
1492                 }
1493                 break;
1494             default:
1495                 SetLastError(E_INVALIDARG);
1496                 ret = FALSE;
1497             }
1498             LocalFree(signedCert);
1499         }
1500     }
1501     return ret;
1502 }
1503
1504 BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags,
1505  PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage)
1506 {
1507     PCERT_ENHKEY_USAGE usage = NULL;
1508     DWORD bytesNeeded;
1509     BOOL ret = TRUE;
1510
1511     if (!pCertContext || !pcbUsage)
1512     {
1513         SetLastError(ERROR_INVALID_PARAMETER);
1514         return FALSE;
1515     }
1516
1517     TRACE("(%p, %08x, %p, %d)\n", pCertContext, dwFlags, pUsage, *pcbUsage);
1518
1519     if (!(dwFlags & CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG))
1520     {
1521         DWORD propSize = 0;
1522
1523         if (CertGetCertificateContextProperty(pCertContext,
1524          CERT_ENHKEY_USAGE_PROP_ID, NULL, &propSize))
1525         {
1526             LPBYTE buf = CryptMemAlloc(propSize);
1527
1528             if (buf)
1529             {
1530                 if (CertGetCertificateContextProperty(pCertContext,
1531                  CERT_ENHKEY_USAGE_PROP_ID, buf, &propSize))
1532                 {
1533                     ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
1534                      X509_ENHANCED_KEY_USAGE, buf, propSize,
1535                      CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
1536                 }
1537                 CryptMemFree(buf);
1538             }
1539         }
1540     }
1541     if (!usage && !(dwFlags & CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG))
1542     {
1543         PCERT_EXTENSION ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
1544          pCertContext->pCertInfo->cExtension,
1545          pCertContext->pCertInfo->rgExtension);
1546
1547         if (ext)
1548         {
1549             ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
1550              X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
1551              CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
1552         }
1553     }
1554     if (!usage)
1555     {
1556         /* If a particular location is specified, this should fail.  Otherwise
1557          * it should succeed with an empty usage.  (This is true on Win2k and
1558          * later, which we emulate.)
1559          */
1560         if (dwFlags)
1561         {
1562             SetLastError(CRYPT_E_NOT_FOUND);
1563             ret = FALSE;
1564         }
1565         else
1566             bytesNeeded = sizeof(CERT_ENHKEY_USAGE);
1567     }
1568
1569     if (ret)
1570     {
1571         if (!pUsage)
1572             *pcbUsage = bytesNeeded;
1573         else if (*pcbUsage < bytesNeeded)
1574         {
1575             SetLastError(ERROR_MORE_DATA);
1576             *pcbUsage = bytesNeeded;
1577             ret = FALSE;
1578         }
1579         else
1580         {
1581             *pcbUsage = bytesNeeded;
1582             if (usage)
1583             {
1584                 DWORD i;
1585                 LPSTR nextOID = (LPSTR)((LPBYTE)pUsage +
1586                  sizeof(CERT_ENHKEY_USAGE) +
1587                  usage->cUsageIdentifier * sizeof(LPSTR));
1588
1589                 pUsage->cUsageIdentifier = usage->cUsageIdentifier;
1590                 pUsage->rgpszUsageIdentifier = (LPSTR *)((LPBYTE)pUsage +
1591                  sizeof(CERT_ENHKEY_USAGE));
1592                 for (i = 0; i < usage->cUsageIdentifier; i++)
1593                 {
1594                     pUsage->rgpszUsageIdentifier[i] = nextOID;
1595                     strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
1596                     nextOID += strlen(nextOID) + 1;
1597                 }
1598             }
1599             else
1600                 pUsage->cUsageIdentifier = 0;
1601         }
1602     }
1603     if (usage)
1604         LocalFree(usage);
1605     TRACE("returning %d\n", ret);
1606     return ret;
1607 }
1608
1609 BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext,
1610  PCERT_ENHKEY_USAGE pUsage)
1611 {
1612     BOOL ret;
1613
1614     TRACE("(%p, %p)\n", pCertContext, pUsage);
1615
1616     if (pUsage)
1617     {
1618         CRYPT_DATA_BLOB blob = { 0, NULL };
1619
1620         ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
1621          pUsage, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData, &blob.cbData);
1622         if (ret)
1623         {
1624             ret = CertSetCertificateContextProperty(pCertContext,
1625              CERT_ENHKEY_USAGE_PROP_ID, 0, &blob);
1626             LocalFree(blob.pbData);
1627         }
1628     }
1629     else
1630         ret = CertSetCertificateContextProperty(pCertContext,
1631          CERT_ENHKEY_USAGE_PROP_ID, 0, NULL);
1632     return ret;
1633 }
1634
1635 BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
1636  LPCSTR pszUsageIdentifier)
1637 {
1638     BOOL ret;
1639     DWORD size;
1640
1641     TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
1642
1643     if (CertGetEnhancedKeyUsage(pCertContext,
1644      CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size))
1645     {
1646         PCERT_ENHKEY_USAGE usage = CryptMemAlloc(size);
1647
1648         if (usage)
1649         {
1650             ret = CertGetEnhancedKeyUsage(pCertContext,
1651              CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size);
1652             if (ret)
1653             {
1654                 PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size +
1655                  sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
1656
1657                 if (newUsage)
1658                 {
1659                     LPSTR nextOID;
1660                     DWORD i;
1661
1662                     newUsage->rgpszUsageIdentifier =
1663                      (LPSTR *)((LPBYTE)newUsage + sizeof(CERT_ENHKEY_USAGE));
1664                     nextOID = (LPSTR)((LPBYTE)newUsage->rgpszUsageIdentifier +
1665                      (usage->cUsageIdentifier + 1) * sizeof(LPSTR));
1666                     for (i = 0; i < usage->cUsageIdentifier; i++)
1667                     {
1668                         newUsage->rgpszUsageIdentifier[i] = nextOID;
1669                         strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
1670                         nextOID += strlen(nextOID) + 1;
1671                     }
1672                     newUsage->rgpszUsageIdentifier[i] = nextOID;
1673                     strcpy(nextOID, pszUsageIdentifier);
1674                     newUsage->cUsageIdentifier = i + 1;
1675                     ret = CertSetEnhancedKeyUsage(pCertContext, newUsage);
1676                     CryptMemFree(newUsage);
1677                 }
1678             }
1679             CryptMemFree(usage);
1680         }
1681         else
1682             ret = FALSE;
1683     }
1684     else
1685     {
1686         PCERT_ENHKEY_USAGE usage = CryptMemAlloc(sizeof(CERT_ENHKEY_USAGE) +
1687          sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
1688
1689         if (usage)
1690         {
1691             usage->rgpszUsageIdentifier =
1692              (LPSTR *)((LPBYTE)usage + sizeof(CERT_ENHKEY_USAGE));
1693             usage->rgpszUsageIdentifier[0] = (LPSTR)((LPBYTE)usage +
1694              sizeof(CERT_ENHKEY_USAGE) + sizeof(LPSTR));
1695             strcpy(usage->rgpszUsageIdentifier[0], pszUsageIdentifier);
1696             usage->cUsageIdentifier = 1;
1697             ret = CertSetEnhancedKeyUsage(pCertContext, usage);
1698             CryptMemFree(usage);
1699         }
1700         else
1701             ret = FALSE;
1702     }
1703     return ret;
1704 }
1705
1706 BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
1707  LPCSTR pszUsageIdentifier)
1708 {
1709     BOOL ret;
1710     DWORD size;
1711     CERT_ENHKEY_USAGE usage;
1712
1713     TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
1714
1715     size = sizeof(usage);
1716     ret = CertGetEnhancedKeyUsage(pCertContext,
1717      CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, &usage, &size);
1718     if (!ret && GetLastError() == ERROR_MORE_DATA)
1719     {
1720         PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
1721
1722         if (pUsage)
1723         {
1724             ret = CertGetEnhancedKeyUsage(pCertContext,
1725              CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
1726             if (ret)
1727             {
1728                 if (pUsage->cUsageIdentifier)
1729                 {
1730                     DWORD i;
1731                     BOOL found = FALSE;
1732
1733                     for (i = 0; i < pUsage->cUsageIdentifier; i++)
1734                     {
1735                         if (!strcmp(pUsage->rgpszUsageIdentifier[i],
1736                          pszUsageIdentifier))
1737                             found = TRUE;
1738                         if (found && i < pUsage->cUsageIdentifier - 1)
1739                             pUsage->rgpszUsageIdentifier[i] =
1740                              pUsage->rgpszUsageIdentifier[i + 1];
1741                     }
1742                     pUsage->cUsageIdentifier--;
1743                     /* Remove the usage if it's empty */
1744                     if (pUsage->cUsageIdentifier)
1745                         ret = CertSetEnhancedKeyUsage(pCertContext, pUsage);
1746                     else
1747                         ret = CertSetEnhancedKeyUsage(pCertContext, NULL);
1748                 }
1749             }
1750             CryptMemFree(pUsage);
1751         }
1752         else
1753             ret = FALSE;
1754     }
1755     else
1756     {
1757         /* it fit in an empty usage, therefore there's nothing to remove */
1758         ret = TRUE;
1759     }
1760     return ret;
1761 }
1762
1763 BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts,
1764  int *cNumOIDSs, LPSTR *rghOIDs, DWORD *pcbOIDs)
1765 {
1766     BOOL ret = TRUE;
1767     DWORD i, cbOIDs = 0;
1768     BOOL allUsagesValid = TRUE;
1769     CERT_ENHKEY_USAGE validUsages = { 0, NULL };
1770
1771     TRACE("(%d, %p, %p, %p, %d)\n", cCerts, *rghCerts, cNumOIDSs,
1772      rghOIDs, *pcbOIDs);
1773
1774     for (i = 0; ret && i < cCerts; i++)
1775     {
1776         CERT_ENHKEY_USAGE usage;
1777         DWORD size = sizeof(usage);
1778
1779         ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, &usage, &size);
1780         /* Success is deliberately ignored: it implies all usages are valid */
1781         if (!ret && GetLastError() == ERROR_MORE_DATA)
1782         {
1783             PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
1784
1785             allUsagesValid = FALSE;
1786             if (pUsage)
1787             {
1788                 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, pUsage, &size);
1789                 if (ret)
1790                 {
1791                     if (!validUsages.cUsageIdentifier)
1792                     {
1793                         DWORD j;
1794
1795                         cbOIDs = pUsage->cUsageIdentifier * sizeof(LPSTR);
1796                         validUsages.cUsageIdentifier = pUsage->cUsageIdentifier;
1797                         for (j = 0; j < validUsages.cUsageIdentifier; j++)
1798                             cbOIDs += lstrlenA(pUsage->rgpszUsageIdentifier[j])
1799                              + 1;
1800                         validUsages.rgpszUsageIdentifier =
1801                          CryptMemAlloc(cbOIDs);
1802                         if (validUsages.rgpszUsageIdentifier)
1803                         {
1804                             LPSTR nextOID = (LPSTR)
1805                              ((LPBYTE)validUsages.rgpszUsageIdentifier +
1806                              validUsages.cUsageIdentifier * sizeof(LPSTR));
1807
1808                             for (j = 0; j < validUsages.cUsageIdentifier; j++)
1809                             {
1810                                 validUsages.rgpszUsageIdentifier[j] = nextOID;
1811                                 lstrcpyA(validUsages.rgpszUsageIdentifier[j],
1812                                  pUsage->rgpszUsageIdentifier[j]);
1813                                 nextOID += lstrlenA(nextOID) + 1;
1814                             }
1815                         }
1816                         else
1817                             ret = FALSE;
1818                     }
1819                     else
1820                     {
1821                         DWORD j, k, validIndexes = 0, numRemoved = 0;
1822
1823                         /* Merge: build a bitmap of all the indexes of
1824                          * validUsages.rgpszUsageIdentifier that are in pUsage.
1825                          */
1826                         for (j = 0; j < pUsage->cUsageIdentifier; j++)
1827                         {
1828                             for (k = 0; k < validUsages.cUsageIdentifier; k++)
1829                             {
1830                                 if (!strcmp(pUsage->rgpszUsageIdentifier[j],
1831                                  validUsages.rgpszUsageIdentifier[k]))
1832                                 {
1833                                     validIndexes |= (1 << k);
1834                                     break;
1835                                 }
1836                             }
1837                         }
1838                         /* Merge by removing from validUsages those that are
1839                          * not in the bitmap.
1840                          */
1841                         for (j = 0; j < validUsages.cUsageIdentifier; j++)
1842                         {
1843                             if (!(validIndexes & (1 << j)))
1844                             {
1845                                 if (j < validUsages.cUsageIdentifier - 1)
1846                                 {
1847                                     memcpy(&validUsages.rgpszUsageIdentifier[j],
1848                                      &validUsages.rgpszUsageIdentifier[j +
1849                                      numRemoved + 1],
1850                                      (validUsages.cUsageIdentifier - numRemoved
1851                                      - j - 1) * sizeof(LPSTR));
1852                                     cbOIDs -= lstrlenA(
1853                                      validUsages.rgpszUsageIdentifier[j]) + 1 +
1854                                      sizeof(LPSTR);
1855                                     numRemoved++;
1856                                 }
1857                                 else
1858                                     validUsages.cUsageIdentifier--;
1859                             }
1860                         }
1861                     }
1862                 }
1863                 CryptMemFree(pUsage);
1864             }
1865             else
1866                 ret = FALSE;
1867         }
1868     }
1869     if (ret)
1870     {
1871         if (allUsagesValid)
1872         {
1873             *cNumOIDSs = -1;
1874             *pcbOIDs = 0;
1875         }
1876         else
1877         {
1878             if (!rghOIDs || *pcbOIDs < cbOIDs)
1879             {
1880                 *pcbOIDs = cbOIDs;
1881                 SetLastError(ERROR_MORE_DATA);
1882                 ret = FALSE;
1883             }
1884             else
1885             {
1886                 LPSTR nextOID = (LPSTR)((LPBYTE)rghOIDs +
1887                  validUsages.cUsageIdentifier * sizeof(LPSTR));
1888
1889                 *pcbOIDs = cbOIDs;
1890                 *cNumOIDSs = validUsages.cUsageIdentifier;
1891                 for (i = 0; i < validUsages.cUsageIdentifier; i++)
1892                 {
1893                     rghOIDs[i] = nextOID;
1894                     lstrcpyA(nextOID, validUsages.rgpszUsageIdentifier[i]);
1895                     nextOID += lstrlenA(nextOID) + 1;
1896                 }
1897             }
1898         }
1899     }
1900     CryptMemFree(validUsages.rgpszUsageIdentifier);
1901     return ret;
1902 }
1903
1904 /* Sets the CERT_KEY_PROV_INFO_PROP_ID property of context from pInfo, or, if
1905  * pInfo is NULL, from the attributes of hProv.
1906  */
1907 static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context,
1908  const CRYPT_KEY_PROV_INFO *pInfo, HCRYPTPROV hProv)
1909 {
1910     CRYPT_KEY_PROV_INFO info = { 0 };
1911     BOOL ret;
1912
1913     if (!pInfo)
1914     {
1915         DWORD size;
1916         int len;
1917
1918         ret = CryptGetProvParam(hProv, PP_CONTAINER, NULL, &size, 0);
1919         if (ret)
1920         {
1921             LPSTR szContainer = CryptMemAlloc(size);
1922
1923             if (szContainer)
1924             {
1925                 ret = CryptGetProvParam(hProv, PP_CONTAINER,
1926                  (BYTE *)szContainer, &size, 0);
1927                 if (ret)
1928                 {
1929                     len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
1930                      NULL, 0);
1931                     if (len)
1932                     {
1933                         info.pwszContainerName = CryptMemAlloc(len *
1934                          sizeof(WCHAR));
1935                         len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
1936                          info.pwszContainerName, len);
1937                     }
1938                 }
1939                 CryptMemFree(szContainer);
1940             }
1941         }
1942         ret = CryptGetProvParam(hProv, PP_NAME, NULL, &size, 0);
1943         if (ret)
1944         {
1945             LPSTR szProvider = CryptMemAlloc(size);
1946
1947             if (szProvider)
1948             {
1949                 ret = CryptGetProvParam(hProv, PP_NAME, (BYTE *)szProvider,
1950                  &size, 0);
1951                 if (ret)
1952                 {
1953                     len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
1954                      NULL, 0);
1955                     if (len)
1956                     {
1957                         info.pwszProvName = CryptMemAlloc(len *
1958                          sizeof(WCHAR));
1959                         len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
1960                          info.pwszProvName, len);
1961                     }
1962                 }
1963                 CryptMemFree(szProvider);
1964             }
1965         }
1966         size = sizeof(info.dwKeySpec);
1967         /* in case no CRYPT_KEY_PROV_INFO given,
1968          *  we always use AT_SIGNATURE key spec
1969          */
1970         info.dwKeySpec = AT_SIGNATURE;
1971         size = sizeof(info.dwProvType);
1972         ret = CryptGetProvParam(hProv, PP_PROVTYPE, (LPBYTE)&info.dwProvType,
1973          &size, 0);
1974         if (!ret)
1975             info.dwProvType = PROV_RSA_FULL;
1976         pInfo = &info;
1977     }
1978
1979     ret = CertSetCertificateContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID,
1980      0, pInfo);
1981
1982     if (pInfo == &info)
1983     {
1984         CryptMemFree(info.pwszContainerName);
1985         CryptMemFree(info.pwszProvName);
1986     }
1987 }
1988
1989 /* Creates a signed certificate context from the unsigned, encoded certificate
1990  * in blob, using the crypto provider hProv and the signature algorithm sigAlgo.
1991  */
1992 static PCCERT_CONTEXT CRYPT_CreateSignedCert(const CRYPT_DER_BLOB *blob,
1993  HCRYPTPROV hProv, DWORD dwKeySpec, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo)
1994 {
1995     PCCERT_CONTEXT context = NULL;
1996     BOOL ret;
1997     DWORD sigSize = 0;
1998
1999     ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
2000      blob->pbData, blob->cbData, sigAlgo, NULL, NULL, &sigSize);
2001     if (ret)
2002     {
2003         LPBYTE sig = CryptMemAlloc(sigSize);
2004
2005         ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
2006          blob->pbData, blob->cbData, sigAlgo, NULL, sig, &sigSize);
2007         if (ret)
2008         {
2009             CERT_SIGNED_CONTENT_INFO signedInfo;
2010             BYTE *encodedSignedCert = NULL;
2011             DWORD encodedSignedCertSize = 0;
2012
2013             signedInfo.ToBeSigned.cbData = blob->cbData;
2014             signedInfo.ToBeSigned.pbData = blob->pbData;
2015             memcpy(&signedInfo.SignatureAlgorithm, sigAlgo,
2016              sizeof(signedInfo.SignatureAlgorithm));
2017             signedInfo.Signature.cbData = sigSize;
2018             signedInfo.Signature.pbData = sig;
2019             signedInfo.Signature.cUnusedBits = 0;
2020             ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT,
2021              &signedInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
2022              (BYTE *)&encodedSignedCert, &encodedSignedCertSize);
2023             if (ret)
2024             {
2025                 context = CertCreateCertificateContext(X509_ASN_ENCODING,
2026                  encodedSignedCert, encodedSignedCertSize);
2027                 LocalFree(encodedSignedCert);
2028             }
2029         }
2030         CryptMemFree(sig);
2031     }
2032     return context;
2033 }
2034
2035 /* Copies data from the parameters into info, where:
2036  * pSerialNumber: The serial number.  Must not be NULL.
2037  * pSubjectIssuerBlob: Specifies both the subject and issuer for info.
2038  *                     Must not be NULL
2039  * pSignatureAlgorithm: Optional.
2040  * pStartTime: The starting time of the certificate.  If NULL, the current
2041  *             system time is used.
2042  * pEndTime: The ending time of the certificate.  If NULL, one year past the
2043  *           starting time is used.
2044  * pubKey: The public key of the certificate.  Must not be NULL.
2045  * pExtensions: Extensions to be included with the certificate.  Optional.
2046  */
2047 static void CRYPT_MakeCertInfo(PCERT_INFO info, const CRYPT_DATA_BLOB *pSerialNumber,
2048  const CERT_NAME_BLOB *pSubjectIssuerBlob,
2049  const CRYPT_ALGORITHM_IDENTIFIER *pSignatureAlgorithm, const SYSTEMTIME *pStartTime,
2050  const SYSTEMTIME *pEndTime, const CERT_PUBLIC_KEY_INFO *pubKey,
2051  const CERT_EXTENSIONS *pExtensions)
2052 {
2053     static CHAR oid[] = szOID_RSA_SHA1RSA;
2054
2055     assert(info);
2056     assert(pSerialNumber);
2057     assert(pSubjectIssuerBlob);
2058     assert(pubKey);
2059
2060     info->dwVersion = CERT_V3;
2061     info->SerialNumber.cbData = pSerialNumber->cbData;
2062     info->SerialNumber.pbData = pSerialNumber->pbData;
2063     if (pSignatureAlgorithm)
2064         memcpy(&info->SignatureAlgorithm, pSignatureAlgorithm,
2065          sizeof(info->SignatureAlgorithm));
2066     else
2067     {
2068         info->SignatureAlgorithm.pszObjId = oid;
2069         info->SignatureAlgorithm.Parameters.cbData = 0;
2070         info->SignatureAlgorithm.Parameters.pbData = NULL;
2071     }
2072     info->Issuer.cbData = pSubjectIssuerBlob->cbData;
2073     info->Issuer.pbData = pSubjectIssuerBlob->pbData;
2074     if (pStartTime)
2075         SystemTimeToFileTime(pStartTime, &info->NotBefore);
2076     else
2077         GetSystemTimeAsFileTime(&info->NotBefore);
2078     if (pEndTime)
2079         SystemTimeToFileTime(pEndTime, &info->NotAfter);
2080     else
2081     {
2082         SYSTEMTIME endTime;
2083
2084         if (FileTimeToSystemTime(&info->NotBefore, &endTime))
2085         {
2086             endTime.wYear++;
2087             SystemTimeToFileTime(&endTime, &info->NotAfter);
2088         }
2089     }
2090     info->Subject.cbData = pSubjectIssuerBlob->cbData;
2091     info->Subject.pbData = pSubjectIssuerBlob->pbData;
2092     memcpy(&info->SubjectPublicKeyInfo, pubKey,
2093      sizeof(info->SubjectPublicKeyInfo));
2094     if (pExtensions)
2095     {
2096         info->cExtension = pExtensions->cExtension;
2097         info->rgExtension = pExtensions->rgExtension;
2098     }
2099     else
2100     {
2101         info->cExtension = 0;
2102         info->rgExtension = NULL;
2103     }
2104 }
2105  
2106 typedef RPC_STATUS (RPC_ENTRY *UuidCreateFunc)(UUID *);
2107 typedef RPC_STATUS (RPC_ENTRY *UuidToStringFunc)(UUID *, unsigned char **);
2108 typedef RPC_STATUS (RPC_ENTRY *RpcStringFreeFunc)(unsigned char **);
2109
2110 static HCRYPTPROV CRYPT_CreateKeyProv(void)
2111 {
2112     HCRYPTPROV hProv = 0;
2113     HMODULE rpcrt = LoadLibraryA("rpcrt4");
2114
2115     if (rpcrt)
2116     {
2117         UuidCreateFunc uuidCreate = (UuidCreateFunc)GetProcAddress(rpcrt,
2118          "UuidCreate");
2119         UuidToStringFunc uuidToString = (UuidToStringFunc)GetProcAddress(rpcrt,
2120          "UuidToStringA");
2121         RpcStringFreeFunc rpcStringFree = (RpcStringFreeFunc)GetProcAddress(
2122          rpcrt, "RpcStringFreeA");
2123
2124         if (uuidCreate && uuidToString && rpcStringFree)
2125         {
2126             UUID uuid;
2127             RPC_STATUS status = uuidCreate(&uuid);
2128
2129             if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY)
2130             {
2131                 unsigned char *uuidStr;
2132
2133                 status = uuidToString(&uuid, &uuidStr);
2134                 if (status == RPC_S_OK)
2135                 {
2136                     BOOL ret = CryptAcquireContextA(&hProv, (LPCSTR)uuidStr,
2137                      MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_NEWKEYSET);
2138
2139                     if (ret)
2140                     {
2141                         HCRYPTKEY key;
2142
2143                         ret = CryptGenKey(hProv, AT_SIGNATURE, 0, &key);
2144                         if (ret)
2145                             CryptDestroyKey(key);
2146                     }
2147                     rpcStringFree(&uuidStr);
2148                 }
2149             }
2150         }
2151         FreeLibrary(rpcrt);
2152     }
2153     return hProv;
2154 }
2155
2156 PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV hProv,
2157  PCERT_NAME_BLOB pSubjectIssuerBlob, DWORD dwFlags,
2158  PCRYPT_KEY_PROV_INFO pKeyProvInfo,
2159  PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime,
2160  PSYSTEMTIME pEndTime, PCERT_EXTENSIONS pExtensions)
2161 {
2162     PCCERT_CONTEXT context = NULL;
2163     BOOL ret, releaseContext = FALSE;
2164     PCERT_PUBLIC_KEY_INFO pubKey = NULL;
2165     DWORD pubKeySize = 0,dwKeySpec = AT_SIGNATURE;
2166
2167     TRACE("(%08lx, %p, %08x, %p, %p, %p, %p, %p)\n", hProv,
2168      pSubjectIssuerBlob, dwFlags, pKeyProvInfo, pSignatureAlgorithm, pStartTime,
2169      pExtensions, pExtensions);
2170
2171     if(!pSubjectIssuerBlob)
2172     {
2173         SetLastError(ERROR_INVALID_PARAMETER);
2174         return NULL;
2175     }
2176
2177     if (!hProv)
2178     {
2179         if (!pKeyProvInfo)
2180         {
2181             hProv = CRYPT_CreateKeyProv();
2182             releaseContext = TRUE;
2183         }
2184         else if (pKeyProvInfo->dwFlags & CERT_SET_KEY_PROV_HANDLE_PROP_ID)
2185         {
2186             SetLastError(NTE_BAD_FLAGS);
2187             return NULL;
2188         }
2189         else
2190         {
2191             HCRYPTKEY hKey = 0;
2192             /* acquire the context using the given information*/
2193             ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
2194                     pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
2195                     pKeyProvInfo->dwFlags);
2196             if (!ret)
2197             {
2198                 if(GetLastError() != NTE_BAD_KEYSET)
2199                     return NULL;
2200                 /* create the key set */
2201                 ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
2202                     pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
2203                     pKeyProvInfo->dwFlags|CRYPT_NEWKEYSET);
2204                 if (!ret)
2205                     return NULL;
2206             }
2207             dwKeySpec = pKeyProvInfo->dwKeySpec;
2208             /* check if the key is here */
2209             ret = CryptGetUserKey(hProv,dwKeySpec,&hKey);
2210             if(!ret)
2211             {
2212                 if (NTE_NO_KEY == GetLastError())
2213                 { /* generate the key */
2214                     ret = CryptGenKey(hProv,dwKeySpec,0,&hKey);
2215                 }
2216                 if (!ret)
2217                 {
2218                     CryptReleaseContext(hProv,0);
2219                     SetLastError(NTE_BAD_KEYSET);
2220                     return NULL;
2221                 }
2222             }
2223             CryptDestroyKey(hKey);
2224             releaseContext = TRUE;
2225         }
2226     }
2227     else if (pKeyProvInfo)
2228     {
2229         SetLastError(ERROR_INVALID_PARAMETER);
2230         return NULL;
2231     }
2232
2233     CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING, NULL,
2234      &pubKeySize);
2235     pubKey = CryptMemAlloc(pubKeySize);
2236     if (pubKey)
2237     {
2238         ret = CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING,
2239          pubKey, &pubKeySize);
2240         if (ret)
2241         {
2242             CERT_INFO info = { 0 };
2243             CRYPT_DER_BLOB blob = { 0, NULL };
2244             BYTE serial[16];
2245             CRYPT_DATA_BLOB serialBlob = { sizeof(serial), serial };
2246
2247             CryptGenRandom(hProv, sizeof(serial), serial);
2248             CRYPT_MakeCertInfo(&info, &serialBlob, pSubjectIssuerBlob,
2249              pSignatureAlgorithm, pStartTime, pEndTime, pubKey, pExtensions);
2250             ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
2251              &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&blob.pbData,
2252              &blob.cbData);
2253             if (ret)
2254             {
2255                 if (!(dwFlags & CERT_CREATE_SELFSIGN_NO_SIGN))
2256                     context = CRYPT_CreateSignedCert(&blob, hProv,dwKeySpec,
2257                      &info.SignatureAlgorithm);
2258                 else
2259                     context = CertCreateCertificateContext(X509_ASN_ENCODING,
2260                      blob.pbData, blob.cbData);
2261                 if (context && !(dwFlags & CERT_CREATE_SELFSIGN_NO_KEY_INFO))
2262                     CertContext_SetKeyProvInfo(context, pKeyProvInfo, hProv);
2263                 LocalFree(blob.pbData);
2264             }
2265         }
2266         CryptMemFree(pubKey);
2267     }
2268     if (releaseContext)
2269         CryptReleaseContext(hProv, 0);
2270     return context;
2271 }
2272
2273 BOOL WINAPI CertGetCertificateChain(HCERTCHAINENGINE hChainEngine,
2274     PCCERT_CONTEXT pCertContext, LPFILETIME pTime, HCERTSTORE hAdditionalStore,
2275     PCERT_CHAIN_PARA pChainPara, DWORD dwFlags, LPVOID pvReserved,
2276     PCCERT_CHAIN_CONTEXT* ppChainContext)
2277 {
2278     FIXME(" %p %p %p %p %p 0x%08X %p %p - stub\n",hChainEngine, pCertContext,
2279      pTime, hAdditionalStore, pChainPara, dwFlags, pvReserved, ppChainContext);
2280
2281     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2282     return FALSE;
2283 }