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