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