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