crypt32: Avoid a use-after-free bug in tests.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
33  CRYPT_ATTRIBUTE rgAttr[])
34 {
35     PCRYPT_ATTRIBUTE ret = NULL;
36     DWORD i;
37
38     TRACE("%s %ld %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
39
40     if (!cAttr)
41         return NULL;
42     if (!pszObjId)
43     {
44         SetLastError(ERROR_INVALID_PARAMETER);
45         return NULL;
46     }
47
48     for (i = 0; !ret && i < cAttr; i++)
49         if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
50             ret = &rgAttr[i];
51     return ret;
52 }
53
54 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
55  CERT_EXTENSION rgExtensions[])
56 {
57     PCERT_EXTENSION ret = NULL;
58     DWORD i;
59
60     TRACE("%s %ld %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
61
62     if (!cExtensions)
63         return NULL;
64     if (!pszObjId)
65     {
66         SetLastError(ERROR_INVALID_PARAMETER);
67         return NULL;
68     }
69
70     for (i = 0; !ret && i < cExtensions; i++)
71         if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
72          rgExtensions[i].pszObjId))
73             ret = &rgExtensions[i];
74     return ret;
75 }
76
77 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
78 {
79     PCERT_RDN_ATTR ret = NULL;
80     DWORD i, j;
81
82     TRACE("%s %p\n", debugstr_a(pszObjId), pName);
83
84     if (!pszObjId)
85     {
86         SetLastError(ERROR_INVALID_PARAMETER);
87         return NULL;
88     }
89
90     for (i = 0; !ret && i < pName->cRDN; i++)
91         for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
92             if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
93              pName->rgRDN[i].rgRDNAttr[j].pszObjId))
94                 ret = &pName->rgRDN[i].rgRDNAttr[j];
95     return ret;
96 }
97
98 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
99  PCERT_INFO pCertInfo)
100 {
101     FILETIME fileTime;
102     LONG ret;
103
104     if (!pTimeToVerify)
105     {
106         SYSTEMTIME sysTime;
107
108         GetSystemTime(&sysTime);
109         SystemTimeToFileTime(&sysTime, &fileTime);
110         pTimeToVerify = &fileTime;
111     }
112     if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
113     {
114         ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
115         if (ret < 0)
116             ret = 0;
117     }
118     return ret;
119 }
120
121 BOOL WINAPI CryptHashCertificate(HCRYPTPROV hCryptProv, ALG_ID Algid,
122  DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
123  DWORD *pcbComputedHash)
124 {
125     BOOL ret = TRUE;
126     HCRYPTHASH hHash = 0;
127
128     TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv, Algid, dwFlags,
129      pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
130
131     if (!hCryptProv)
132         hCryptProv = CRYPT_GetDefaultProvider();
133     if (!Algid)
134         Algid = CALG_SHA1;
135     if (ret)
136     {
137         ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
138         if (ret)
139         {
140             ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
141             if (ret)
142                 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
143                  pcbComputedHash, 0);
144             CryptDestroyHash(hHash);
145         }
146     }
147     return ret;
148 }
149
150 BOOL WINAPI CryptSignCertificate(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
151  DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned,
152  DWORD cbEncodedToBeSigned, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
153  const void *pvHashAuxInfo, BYTE *pbSignature, DWORD *pcbSignature)
154 {
155     BOOL ret;
156     ALG_ID algID;
157     HCRYPTHASH hHash;
158
159     TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %p, %p, %p)\n", hCryptProv,
160      dwKeySpec, dwCertEncodingType, pbEncodedToBeSigned, cbEncodedToBeSigned,
161      pSignatureAlgorithm, pvHashAuxInfo, pbSignature, pcbSignature);
162
163     algID = CertOIDToAlgId(pSignatureAlgorithm->pszObjId);
164     if (!algID)
165     {
166         SetLastError(NTE_BAD_ALGID);
167         return FALSE;
168     }
169     if (!hCryptProv)
170     {
171         SetLastError(ERROR_INVALID_PARAMETER);
172         return FALSE;
173     }
174
175     ret = CryptCreateHash(hCryptProv, algID, 0, 0, &hHash);
176     if (ret)
177     {
178         ret = CryptHashData(hHash, pbEncodedToBeSigned, cbEncodedToBeSigned, 0);
179         if (ret)
180             ret = CryptSignHashW(hHash, dwKeySpec, NULL, 0, pbSignature,
181              pcbSignature);
182         CryptDestroyHash(hHash);
183     }
184     return ret;
185 }
186
187 BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV hCryptProv,
188  DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
189  PCERT_PUBLIC_KEY_INFO pPublicKey)
190 {
191     return CryptVerifyCertificateSignatureEx(hCryptProv, dwCertEncodingType,
192      CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, (void *)pbEncoded,
193      CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
194 }
195
196 static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV hCryptProv,
197  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pubKeyInfo,
198  PCERT_SIGNED_CONTENT_INFO signedCert)
199 {
200     BOOL ret;
201     ALG_ID algID = CertOIDToAlgId(pubKeyInfo->Algorithm.pszObjId);
202     HCRYPTKEY key;
203
204     /* Load the default provider if necessary */
205     if (!hCryptProv)
206         hCryptProv = CRYPT_GetDefaultProvider();
207     ret = CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType,
208      pubKeyInfo, algID, 0, NULL, &key);
209     if (ret)
210     {
211         HCRYPTHASH hash;
212
213         /* Some key algorithms aren't hash algorithms, so map them */
214         if (algID == CALG_RSA_SIGN || algID == CALG_RSA_KEYX)
215             algID = CALG_SHA1;
216         ret = CryptCreateHash(hCryptProv, algID, 0, 0, &hash);
217         if (ret)
218         {
219             ret = CryptHashData(hash, signedCert->ToBeSigned.pbData,
220              signedCert->ToBeSigned.cbData, 0);
221             if (ret)
222                 ret = CryptVerifySignatureW(hash, signedCert->Signature.pbData,
223                  signedCert->Signature.cbData, key, NULL, 0);
224             CryptDestroyHash(hash);
225         }
226         CryptDestroyKey(key);
227     }
228     return ret;
229 }
230
231 BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV hCryptProv,
232  DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
233  DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
234 {
235     BOOL ret = TRUE;
236     CRYPT_DATA_BLOB subjectBlob;
237
238     TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %08lx, %p)\n", hCryptProv,
239      dwCertEncodingType, dwSubjectType, pvSubject, dwIssuerType, pvIssuer,
240      dwFlags, pvReserved);
241
242     switch (dwSubjectType)
243     {
244     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB:
245     {
246         PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvSubject;
247
248         subjectBlob.pbData = blob->pbData;
249         subjectBlob.cbData = blob->cbData;
250         break;
251     }
252     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT:
253     {
254         PCERT_CONTEXT context = (PCERT_CONTEXT)pvSubject;
255
256         subjectBlob.pbData = context->pbCertEncoded;
257         subjectBlob.cbData = context->cbCertEncoded;
258         break;
259     }
260     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL:
261     {
262         PCRL_CONTEXT context = (PCRL_CONTEXT)pvSubject;
263
264         subjectBlob.pbData = context->pbCrlEncoded;
265         subjectBlob.cbData = context->cbCrlEncoded;
266         break;
267     }
268     default:
269         SetLastError(E_INVALIDARG);
270         ret = FALSE;
271     }
272
273     if (ret)
274     {
275         PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
276         DWORD size = 0;
277
278         ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
279          subjectBlob.pbData, subjectBlob.cbData,
280          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
281          (BYTE *)&signedCert, &size);
282         if (ret)
283         {
284             switch (dwIssuerType)
285             {
286             case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY:
287                 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
288                  dwCertEncodingType, (PCERT_PUBLIC_KEY_INFO)pvIssuer,
289                  signedCert);
290                 break;
291             case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT:
292                 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
293                  dwCertEncodingType,
294                  &((PCCERT_CONTEXT)pvIssuer)->pCertInfo->SubjectPublicKeyInfo,
295                  signedCert);
296                 break;
297             case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN:
298                 FIXME("CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: stub\n");
299                 ret = FALSE;
300                 break;
301             case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL:
302                 if (pvIssuer)
303                 {
304                     SetLastError(E_INVALIDARG);
305                     ret = FALSE;
306                 }
307                 else
308                 {
309                     FIXME("unimplemented for NULL signer\n");
310                     SetLastError(E_INVALIDARG);
311                     ret = FALSE;
312                 }
313                 break;
314             default:
315                 SetLastError(E_INVALIDARG);
316                 ret = FALSE;
317             }
318             LocalFree(signedCert);
319         }
320     }
321     return ret;
322 }
323
324 BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags,
325  PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage)
326 {
327     PCERT_ENHKEY_USAGE usage = NULL;
328     DWORD bytesNeeded;
329     BOOL ret = TRUE;
330
331     if (!pCertContext || !pcbUsage)
332     {
333         SetLastError(ERROR_INVALID_PARAMETER);
334         return FALSE;
335     }
336
337     TRACE("(%p, %08lx, %p, %ld)\n", pCertContext, dwFlags, pUsage, *pcbUsage);
338
339     if (!(dwFlags & CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG))
340     {
341         DWORD propSize = 0;
342
343         if (CertGetCertificateContextProperty(pCertContext,
344          CERT_ENHKEY_USAGE_PROP_ID, NULL, &propSize))
345         {
346             LPBYTE buf = CryptMemAlloc(propSize);
347
348             if (buf)
349             {
350                 if (CertGetCertificateContextProperty(pCertContext,
351                  CERT_ENHKEY_USAGE_PROP_ID, buf, &propSize))
352                 {
353                     ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
354                      X509_ENHANCED_KEY_USAGE, buf, propSize,
355                      CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
356                 }
357                 CryptMemFree(buf);
358             }
359         }
360     }
361     if (!usage && !(dwFlags & CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG))
362     {
363         PCERT_EXTENSION ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
364          pCertContext->pCertInfo->cExtension,
365          pCertContext->pCertInfo->rgExtension);
366
367         if (ext)
368         {
369             ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
370              X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
371              CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
372         }
373     }
374     if (!usage)
375     {
376         /* If a particular location is specified, this should fail.  Otherwise
377          * it should succeed with an empty usage.  (This is true on Win2k and
378          * later, which we emulate.)
379          */
380         if (dwFlags)
381         {
382             SetLastError(CRYPT_E_NOT_FOUND);
383             ret = FALSE;
384         }
385         else
386             bytesNeeded = sizeof(CERT_ENHKEY_USAGE);
387     }
388
389     if (ret)
390     {
391         if (!pUsage)
392             *pcbUsage = bytesNeeded;
393         else if (*pcbUsage < bytesNeeded)
394         {
395             SetLastError(ERROR_MORE_DATA);
396             *pcbUsage = bytesNeeded;
397             ret = FALSE;
398         }
399         else
400         {
401             *pcbUsage = bytesNeeded;
402             if (usage)
403             {
404                 DWORD i;
405                 LPSTR nextOID = (LPSTR)((LPBYTE)pUsage +
406                  sizeof(CERT_ENHKEY_USAGE) +
407                  usage->cUsageIdentifier * sizeof(LPSTR));
408
409                 pUsage->cUsageIdentifier = usage->cUsageIdentifier;
410                 pUsage->rgpszUsageIdentifier = (LPSTR *)((LPBYTE)pUsage +
411                  sizeof(CERT_ENHKEY_USAGE));
412                 for (i = 0; i < usage->cUsageIdentifier; i++)
413                 {
414                     pUsage->rgpszUsageIdentifier[i] = nextOID;
415                     strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
416                     nextOID += strlen(nextOID) + 1;
417                 }
418             }
419             else
420                 pUsage->cUsageIdentifier = 0;
421         }
422     }
423     if (usage)
424         LocalFree(usage);
425     TRACE("returning %d\n", ret);
426     return ret;
427 }
428
429 BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext,
430  PCERT_ENHKEY_USAGE pUsage)
431 {
432     BOOL ret;
433
434     TRACE("(%p, %p)\n", pCertContext, pUsage);
435
436     if (pUsage)
437     {
438         CRYPT_DATA_BLOB blob = { 0, NULL };
439
440         ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
441          pUsage, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData, &blob.cbData);
442         if (ret)
443         {
444             ret = CertSetCertificateContextProperty(pCertContext,
445              CERT_ENHKEY_USAGE_PROP_ID, 0, &blob);
446             LocalFree(blob.pbData);
447         }
448     }
449     else
450         ret = CertSetCertificateContextProperty(pCertContext,
451          CERT_ENHKEY_USAGE_PROP_ID, 0, NULL);
452     return ret;
453 }
454
455 BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
456  LPCSTR pszUsageIdentifier)
457 {
458     BOOL ret;
459     DWORD size;
460
461     TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
462
463     if (CertGetEnhancedKeyUsage(pCertContext,
464      CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size))
465     {
466         PCERT_ENHKEY_USAGE usage = CryptMemAlloc(size);
467
468         if (usage)
469         {
470             ret = CertGetEnhancedKeyUsage(pCertContext,
471              CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size);
472             if (ret)
473             {
474                 PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size +
475                  sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
476
477                 if (newUsage)
478                 {
479                     LPSTR nextOID;
480                     DWORD i;
481
482                     newUsage->rgpszUsageIdentifier =
483                      (LPSTR *)((LPBYTE)newUsage + sizeof(CERT_ENHKEY_USAGE));
484                     nextOID = (LPSTR)((LPBYTE)newUsage->rgpszUsageIdentifier +
485                      (usage->cUsageIdentifier + 1) * sizeof(LPSTR));
486                     for (i = 0; i < usage->cUsageIdentifier; i++)
487                     {
488                         newUsage->rgpszUsageIdentifier[i] = nextOID;
489                         strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
490                         nextOID += strlen(nextOID) + 1;
491                     }
492                     newUsage->rgpszUsageIdentifier[i] = nextOID;
493                     strcpy(nextOID, pszUsageIdentifier);
494                     newUsage->cUsageIdentifier = i + 1;
495                     ret = CertSetEnhancedKeyUsage(pCertContext, newUsage);
496                     CryptMemFree(newUsage);
497                 }
498             }
499             CryptMemFree(usage);
500         }
501         else
502             ret = FALSE;
503     }
504     else
505     {
506         PCERT_ENHKEY_USAGE usage = CryptMemAlloc(sizeof(CERT_ENHKEY_USAGE) +
507          sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
508
509         if (usage)
510         {
511             usage->rgpszUsageIdentifier =
512              (LPSTR *)((LPBYTE)usage + sizeof(CERT_ENHKEY_USAGE));
513             usage->rgpszUsageIdentifier[0] = (LPSTR)((LPBYTE)usage +
514              sizeof(CERT_ENHKEY_USAGE) + sizeof(LPSTR));
515             strcpy(usage->rgpszUsageIdentifier[0], pszUsageIdentifier);
516             usage->cUsageIdentifier = 1;
517             ret = CertSetEnhancedKeyUsage(pCertContext, usage);
518             CryptMemFree(usage);
519         }
520         else
521             ret = FALSE;
522     }
523     return ret;
524 }
525
526 BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
527  LPCSTR pszUsageIdentifier)
528 {
529     BOOL ret;
530     DWORD size;
531     CERT_ENHKEY_USAGE usage;
532
533     TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
534
535     size = sizeof(usage);
536     ret = CertGetEnhancedKeyUsage(pCertContext,
537      CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, &usage, &size);
538     if (!ret && GetLastError() == ERROR_MORE_DATA)
539     {
540         PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
541
542         if (pUsage)
543         {
544             ret = CertGetEnhancedKeyUsage(pCertContext,
545              CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
546             if (ret)
547             {
548                 if (pUsage->cUsageIdentifier)
549                 {
550                     DWORD i;
551                     BOOL found = FALSE;
552
553                     for (i = 0; i < pUsage->cUsageIdentifier; i++)
554                     {
555                         if (!strcmp(pUsage->rgpszUsageIdentifier[i],
556                          pszUsageIdentifier))
557                             found = TRUE;
558                         if (found && i < pUsage->cUsageIdentifier - 1)
559                             pUsage->rgpszUsageIdentifier[i] =
560                              pUsage->rgpszUsageIdentifier[i + 1];
561                     }
562                     pUsage->cUsageIdentifier--;
563                     /* Remove the usage if it's empty */
564                     if (pUsage->cUsageIdentifier)
565                         ret = CertSetEnhancedKeyUsage(pCertContext, pUsage);
566                     else
567                         ret = CertSetEnhancedKeyUsage(pCertContext, NULL);
568                 }
569             }
570             CryptMemFree(pUsage);
571         }
572         else
573             ret = FALSE;
574     }
575     else
576     {
577         /* it fit in an empty usage, therefore there's nothing to remove */
578         ret = TRUE;
579     }
580     return ret;
581 }
582
583 BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts,
584  int *cNumOIDSs, LPSTR *rghOIDs, DWORD *pcbOIDs)
585 {
586     BOOL ret = TRUE;
587     DWORD i, cbOIDs = 0;
588     BOOL allUsagesValid = TRUE;
589     CERT_ENHKEY_USAGE validUsages = { 0, NULL };
590
591     TRACE("(%ld, %p, %p, %p, %ld)\n", cCerts, *rghCerts, cNumOIDSs,
592      rghOIDs, *pcbOIDs);
593
594     for (i = 0; ret && i < cCerts; i++)
595     {
596         CERT_ENHKEY_USAGE usage;
597         DWORD size = sizeof(usage);
598
599         ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, &usage, &size);
600         /* Success is deliberately ignored: it implies all usages are valid */
601         if (!ret && GetLastError() == ERROR_MORE_DATA)
602         {
603             PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
604
605             allUsagesValid = FALSE;
606             if (pUsage)
607             {
608                 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, pUsage, &size);
609                 if (ret)
610                 {
611                     if (!validUsages.cUsageIdentifier)
612                     {
613                         DWORD j;
614
615                         cbOIDs = pUsage->cUsageIdentifier * sizeof(LPSTR);
616                         validUsages.cUsageIdentifier = pUsage->cUsageIdentifier;
617                         for (j = 0; j < validUsages.cUsageIdentifier; j++)
618                             cbOIDs += lstrlenA(pUsage->rgpszUsageIdentifier[j])
619                              + 1;
620                         validUsages.rgpszUsageIdentifier =
621                          CryptMemAlloc(cbOIDs);
622                         if (validUsages.rgpszUsageIdentifier)
623                         {
624                             LPSTR nextOID = (LPSTR)
625                              ((LPBYTE)validUsages.rgpszUsageIdentifier +
626                              validUsages.cUsageIdentifier * sizeof(LPSTR));
627
628                             for (j = 0; j < validUsages.cUsageIdentifier; j++)
629                             {
630                                 validUsages.rgpszUsageIdentifier[j] = nextOID;
631                                 lstrcpyA(validUsages.rgpszUsageIdentifier[j],
632                                  pUsage->rgpszUsageIdentifier[j]);
633                                 nextOID += lstrlenA(nextOID) + 1;
634                             }
635                         }
636                         else
637                             ret = FALSE;
638                     }
639                     else
640                     {
641                         DWORD j, k, validIndexes = 0, numRemoved = 0;
642
643                         /* Merge: build a bitmap of all the indexes of
644                          * validUsages.rgpszUsageIdentifier that are in pUsage.
645                          */
646                         for (j = 0; j < pUsage->cUsageIdentifier; j++)
647                         {
648                             for (k = 0; k < validUsages.cUsageIdentifier; k++)
649                             {
650                                 if (!strcmp(pUsage->rgpszUsageIdentifier[j],
651                                  validUsages.rgpszUsageIdentifier[k]))
652                                 {
653                                     validIndexes |= (1 << k);
654                                     break;
655                                 }
656                             }
657                         }
658                         /* Merge by removing from validUsages those that are
659                          * not in the bitmap.
660                          */
661                         for (j = 0; j < validUsages.cUsageIdentifier; j++)
662                         {
663                             if (!(validIndexes & (1 << j)))
664                             {
665                                 if (j < validUsages.cUsageIdentifier - 1)
666                                 {
667                                     memcpy(&validUsages.rgpszUsageIdentifier[j],
668                                      &validUsages.rgpszUsageIdentifier[j +
669                                      numRemoved + 1],
670                                      (validUsages.cUsageIdentifier - numRemoved
671                                      - j - 1) * sizeof(LPSTR));
672                                     cbOIDs -= lstrlenA(
673                                      validUsages.rgpszUsageIdentifier[j]) + 1 +
674                                      sizeof(LPSTR);
675                                     numRemoved++;
676                                 }
677                                 else
678                                     validUsages.cUsageIdentifier--;
679                             }
680                         }
681                     }
682                 }
683                 CryptMemFree(pUsage);
684             }
685             else
686                 ret = FALSE;
687         }
688     }
689     if (ret)
690     {
691         if (allUsagesValid)
692         {
693             *cNumOIDSs = -1;
694             *pcbOIDs = 0;
695         }
696         else
697         {
698             if (!rghOIDs || *pcbOIDs < cbOIDs)
699             {
700                 *pcbOIDs = cbOIDs;
701                 SetLastError(ERROR_MORE_DATA);
702                 ret = FALSE;
703             }
704             else
705             {
706                 LPSTR nextOID = (LPSTR)((LPBYTE)rghOIDs +
707                  validUsages.cUsageIdentifier * sizeof(LPSTR));
708
709                 *pcbOIDs = cbOIDs;
710                 *cNumOIDSs = validUsages.cUsageIdentifier;
711                 for (i = 0; i < validUsages.cUsageIdentifier; i++)
712                 {
713                     rghOIDs[i] = nextOID;
714                     lstrcpyA(nextOID, validUsages.rgpszUsageIdentifier[i]);
715                     nextOID += lstrlenA(nextOID) + 1;
716                 }
717             }
718         }
719     }
720     CryptMemFree(validUsages.rgpszUsageIdentifier);
721     return ret;
722 }
723
724 /* Sets the CERT_KEY_PROV_INFO_PROP_ID property of context from pInfo, or, if
725  * pInfo is NULL, from the attributes of hProv.
726  */
727 static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context,
728  PCRYPT_KEY_PROV_INFO pInfo, HCRYPTPROV hProv)
729 {
730     CRYPT_KEY_PROV_INFO info = { 0 };
731     BOOL ret;
732
733     if (!pInfo)
734     {
735         DWORD size;
736         int len;
737
738         ret = CryptGetProvParam(hProv, PP_CONTAINER, NULL, &size, 0);
739         if (ret)
740         {
741             LPSTR szContainer = CryptMemAlloc(size);
742
743             if (szContainer)
744             {
745                 ret = CryptGetProvParam(hProv, PP_CONTAINER,
746                  (BYTE *)szContainer, &size, 0);
747                 if (ret)
748                 {
749                     len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
750                      NULL, 0);
751                     if (len)
752                     {
753                         info.pwszContainerName = CryptMemAlloc(len *
754                          sizeof(WCHAR));
755                         len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
756                          info.pwszContainerName, len);
757                     }
758                 }
759                 CryptMemFree(szContainer);
760             }
761         }
762         ret = CryptGetProvParam(hProv, PP_NAME, NULL, &size, 0);
763         if (ret)
764         {
765             LPSTR szProvider = CryptMemAlloc(size);
766
767             if (szProvider)
768             {
769                 ret = CryptGetProvParam(hProv, PP_NAME, (BYTE *)szProvider,
770                  &size, 0);
771                 if (ret)
772                 {
773                     len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
774                      NULL, 0);
775                     if (len)
776                     {
777                         info.pwszProvName = CryptMemAlloc(len *
778                          sizeof(WCHAR));
779                         len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
780                          info.pwszProvName, len);
781                     }
782                 }
783                 CryptMemFree(szProvider);
784             }
785         }
786         size = sizeof(info.dwKeySpec);
787         ret = CryptGetProvParam(hProv, PP_KEYSPEC, (LPBYTE)&info.dwKeySpec,
788          &size, 0);
789         if (!ret)
790             info.dwKeySpec = AT_SIGNATURE;
791         size = sizeof(info.dwProvType);
792         ret = CryptGetProvParam(hProv, PP_PROVTYPE, (LPBYTE)&info.dwProvType,
793          &size, 0);
794         if (!ret)
795             info.dwProvType = PROV_RSA_FULL;
796         pInfo = &info;
797     }
798
799     ret = CertSetCertificateContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID,
800      0, pInfo);
801
802     if (pInfo == &info)
803     {
804         CryptMemFree(info.pwszContainerName);
805         CryptMemFree(info.pwszProvName);
806     }
807 }
808
809 /* Creates a signed certificate context from the unsigned, encoded certificate
810  * in blob, using the crypto provider hProv and the signature algorithm sigAlgo.
811  */
812 static PCCERT_CONTEXT CRYPT_CreateSignedCert(PCRYPT_DER_BLOB blob,
813  HCRYPTPROV hProv, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo)
814 {
815     PCCERT_CONTEXT context = NULL;
816     BOOL ret;
817     DWORD sigSize = 0;
818
819     ret = CryptSignCertificate(hProv, AT_SIGNATURE, X509_ASN_ENCODING,
820      blob->pbData, blob->cbData, sigAlgo, NULL, NULL, &sigSize);
821     if (ret)
822     {
823         LPBYTE sig = CryptMemAlloc(sigSize);
824
825         ret = CryptSignCertificate(hProv, AT_SIGNATURE, X509_ASN_ENCODING,
826          blob->pbData, blob->cbData, sigAlgo, NULL, sig, &sigSize);
827         if (ret)
828         {
829             CERT_SIGNED_CONTENT_INFO signedInfo;
830             BYTE *encodedSignedCert = NULL;
831             DWORD encodedSignedCertSize = 0;
832
833             signedInfo.ToBeSigned.cbData = blob->cbData;
834             signedInfo.ToBeSigned.pbData = blob->pbData;
835             memcpy(&signedInfo.SignatureAlgorithm, sigAlgo,
836              sizeof(signedInfo.SignatureAlgorithm));
837             signedInfo.Signature.cbData = sigSize;
838             signedInfo.Signature.pbData = sig;
839             signedInfo.Signature.cUnusedBits = 0;
840             ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT,
841              &signedInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
842              (BYTE *)&encodedSignedCert, &encodedSignedCertSize);
843             if (ret)
844             {
845                 context = CertCreateCertificateContext(X509_ASN_ENCODING,
846                  encodedSignedCert, encodedSignedCertSize);
847                 LocalFree(encodedSignedCert);
848             }
849         }
850         CryptMemFree(sig);
851     }
852     return context;
853 }
854
855 /* Copies data from the parameters into info, where:
856  * pSubjectIssuerBlob: Specifies both the subject and issuer for info.
857  *                     Must not be NULL
858  * pSignatureAlgorithm: Optional.
859  * pStartTime: The starting time of the certificate.  If NULL, the current
860  *             system time is used.
861  * pEndTime: The ending time of the certificate.  If NULL, one year past the
862  *           starting time is used.
863  * pubKey: The public key of the certificate.  Must not be NULL.
864  * pExtensions: Extensions to be included with the certificate.  Optional.
865  */
866 static void CRYPT_MakeCertInfo(PCERT_INFO info,
867  PCERT_NAME_BLOB pSubjectIssuerBlob,
868  PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime,
869  PSYSTEMTIME pEndTime, PCERT_PUBLIC_KEY_INFO pubKey,
870  PCERT_EXTENSIONS pExtensions)
871 {
872     /* FIXME: what serial number to use? */
873     static const BYTE serialNum[] = { 1 };
874
875     assert(info);
876     assert(pSubjectIssuerBlob);
877     assert(pubKey);
878
879     info->dwVersion = CERT_V3;
880     info->SerialNumber.cbData = sizeof(serialNum);
881     info->SerialNumber.pbData = (LPBYTE)serialNum;
882     if (pSignatureAlgorithm)
883         memcpy(&info->SignatureAlgorithm, pSignatureAlgorithm,
884          sizeof(info->SignatureAlgorithm));
885     else
886     {
887         info->SignatureAlgorithm.pszObjId = szOID_RSA_SHA1RSA;
888         info->SignatureAlgorithm.Parameters.cbData = 0;
889         info->SignatureAlgorithm.Parameters.pbData = NULL;
890     }
891     info->Issuer.cbData = pSubjectIssuerBlob->cbData;
892     info->Issuer.pbData = pSubjectIssuerBlob->pbData;
893     if (pStartTime)
894         SystemTimeToFileTime(pStartTime, &info->NotBefore);
895     else
896         GetSystemTimeAsFileTime(&info->NotBefore);
897     if (pEndTime)
898         SystemTimeToFileTime(pStartTime, &info->NotAfter);
899     else
900     {
901         SYSTEMTIME endTime;
902
903         if (FileTimeToSystemTime(&info->NotBefore, &endTime))
904         {
905             endTime.wYear++;
906             SystemTimeToFileTime(&endTime, &info->NotAfter);
907         }
908     }
909     info->Subject.cbData = pSubjectIssuerBlob->cbData;
910     info->Subject.pbData = pSubjectIssuerBlob->pbData;
911     memcpy(&info->SubjectPublicKeyInfo, pubKey,
912      sizeof(info->SubjectPublicKeyInfo));
913     if (pExtensions)
914     {
915         info->cExtension = pExtensions->cExtension;
916         info->rgExtension = pExtensions->rgExtension;
917     }
918     else
919     {
920         info->cExtension = 0;
921         info->rgExtension = NULL;
922     }
923 }
924  
925 typedef RPC_STATUS (RPC_ENTRY *UuidCreateFunc)(UUID *);
926 typedef RPC_STATUS (RPC_ENTRY *UuidToStringFunc)(UUID *, unsigned char **);
927 typedef RPC_STATUS (RPC_ENTRY *RpcStringFreeFunc)(unsigned char **);
928
929 static HCRYPTPROV CRYPT_CreateKeyProv(void)
930 {
931     HCRYPTPROV hProv = 0;
932     HMODULE rpcrt = LoadLibraryA("rpcrt4");
933
934     if (rpcrt)
935     {
936         UuidCreateFunc uuidCreate = (UuidCreateFunc)GetProcAddress(rpcrt,
937          "UuidCreate");
938         UuidToStringFunc uuidToString = (UuidToStringFunc)GetProcAddress(rpcrt,
939          "UuidToString");
940         RpcStringFreeFunc rpcStringFree = (RpcStringFreeFunc)GetProcAddress(
941          rpcrt, "RpcStringFree");
942
943         if (uuidCreate && uuidToString && rpcStringFree)
944         {
945             UUID uuid;
946             RPC_STATUS status = uuidCreate(&uuid);
947
948             if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY)
949             {
950                 unsigned char *uuidStr;
951
952                 status = uuidToString(&uuid, &uuidStr);
953                 if (status == RPC_S_OK)
954                 {
955                     BOOL ret = CryptAcquireContextA(&hProv, (LPCSTR)uuidStr,
956                      MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_NEWKEYSET);
957
958                     if (ret)
959                     {
960                         HCRYPTKEY key;
961
962                         ret = CryptGenKey(hProv, AT_SIGNATURE, 0, &key);
963                         if (ret)
964                             CryptDestroyKey(key);
965                     }
966                     rpcStringFree(&uuidStr);
967                 }
968             }
969         }
970         FreeLibrary(rpcrt);
971     }
972     return hProv;
973 }
974
975 PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV hProv,
976  PCERT_NAME_BLOB pSubjectIssuerBlob, DWORD dwFlags,
977  PCRYPT_KEY_PROV_INFO pKeyProvInfo,
978  PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime,
979  PSYSTEMTIME pEndTime, PCERT_EXTENSIONS pExtensions)
980 {
981     PCCERT_CONTEXT context = NULL;
982     BOOL ret, releaseContext = FALSE;
983     PCERT_PUBLIC_KEY_INFO pubKey = NULL;
984     DWORD pubKeySize = 0;
985
986     TRACE("(0x%08lx, %p, %08lx, %p, %p, %p, %p, %p)\n", hProv,
987      pSubjectIssuerBlob, dwFlags, pKeyProvInfo, pSignatureAlgorithm, pStartTime,
988      pExtensions, pExtensions);
989
990     if (!hProv)
991     {
992         hProv = CRYPT_CreateKeyProv();
993         releaseContext = TRUE;
994     }
995
996     CryptExportPublicKeyInfo(hProv, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
997      &pubKeySize);
998     pubKey = CryptMemAlloc(pubKeySize);
999     if (pubKey)
1000     {
1001         ret = CryptExportPublicKeyInfo(hProv, AT_SIGNATURE, X509_ASN_ENCODING,
1002          pubKey, &pubKeySize);
1003         if (ret)
1004         {
1005             CERT_INFO info = { 0 };
1006             CRYPT_DER_BLOB blob = { 0, NULL };
1007             BOOL ret;
1008
1009             CRYPT_MakeCertInfo(&info, pSubjectIssuerBlob, pSignatureAlgorithm,
1010              pStartTime, pEndTime, pubKey, pExtensions);
1011             ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
1012              &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&blob.pbData,
1013              &blob.cbData);
1014             if (ret)
1015             {
1016                 if (!(dwFlags & CERT_CREATE_SELFSIGN_NO_SIGN))
1017                     context = CRYPT_CreateSignedCert(&blob, hProv,
1018                      &info.SignatureAlgorithm);
1019                 else
1020                     context = CertCreateCertificateContext(X509_ASN_ENCODING,
1021                      blob.pbData, blob.cbData);
1022                 if (context && !(dwFlags & CERT_CREATE_SELFSIGN_NO_KEY_INFO))
1023                     CertContext_SetKeyProvInfo(context, pKeyProvInfo, hProv);
1024                 LocalFree(blob.pbData);
1025             }
1026         }
1027         CryptMemFree(pubKey);
1028     }
1029     if (releaseContext)
1030         CryptReleaseContext(hProv, 0);
1031     return context;
1032 }