advpack: Set the ldids of the install section in install_init.
[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     if (!pCertContext || !pcbUsage)
327     {
328         SetLastError(ERROR_INVALID_PARAMETER);
329         return FALSE;
330     }
331
332     TRACE("(%p, %08lx, %p, %ld)\n", pCertContext, dwFlags, pUsage, *pcbUsage);
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,
741                  (BYTE *)szContainer, &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,
765                  &size, 0);
766                 if (ret)
767                 {
768                     len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
769                      NULL, 0);
770                     if (len)
771                     {
772                         info.pwszProvName = CryptMemAlloc(len *
773                          sizeof(WCHAR));
774                         len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
775                          info.pwszProvName, len);
776                     }
777                 }
778                 CryptMemFree(szProvider);
779             }
780         }
781         size = sizeof(info.dwKeySpec);
782         ret = CryptGetProvParam(hProv, PP_KEYSPEC, (LPBYTE)&info.dwKeySpec,
783          &size, 0);
784         if (!ret)
785             info.dwKeySpec = AT_SIGNATURE;
786         size = sizeof(info.dwProvType);
787         ret = CryptGetProvParam(hProv, PP_PROVTYPE, (LPBYTE)&info.dwProvType,
788          &size, 0);
789         if (!ret)
790             info.dwProvType = PROV_RSA_FULL;
791         pInfo = &info;
792     }
793
794     ret = CertSetCertificateContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID,
795      0, pInfo);
796
797     if (pInfo == &info)
798     {
799         CryptMemFree(info.pwszContainerName);
800         CryptMemFree(info.pwszProvName);
801     }
802 }
803
804 /* Creates a signed certificate context from the unsigned, encoded certificate
805  * in blob, using the crypto provider hProv and the signature algorithm sigAlgo.
806  */
807 static PCCERT_CONTEXT CRYPT_CreateSignedCert(PCRYPT_DER_BLOB blob,
808  HCRYPTPROV hProv, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo)
809 {
810     PCCERT_CONTEXT context = NULL;
811     BOOL ret;
812     DWORD sigSize = 0;
813
814     ret = CryptSignCertificate(hProv, AT_SIGNATURE, X509_ASN_ENCODING,
815      blob->pbData, blob->cbData, sigAlgo, NULL, NULL, &sigSize);
816     if (ret)
817     {
818         LPBYTE sig = CryptMemAlloc(sigSize);
819
820         ret = CryptSignCertificate(hProv, AT_SIGNATURE, X509_ASN_ENCODING,
821          blob->pbData, blob->cbData, sigAlgo, NULL, sig, &sigSize);
822         if (ret)
823         {
824             CERT_SIGNED_CONTENT_INFO signedInfo;
825             BYTE *encodedSignedCert = NULL;
826             DWORD encodedSignedCertSize = 0;
827
828             signedInfo.ToBeSigned.cbData = blob->cbData;
829             signedInfo.ToBeSigned.pbData = blob->pbData;
830             memcpy(&signedInfo.SignatureAlgorithm, sigAlgo,
831              sizeof(signedInfo.SignatureAlgorithm));
832             signedInfo.Signature.cbData = sigSize;
833             signedInfo.Signature.pbData = sig;
834             signedInfo.Signature.cUnusedBits = 0;
835             ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT,
836              &signedInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
837              (BYTE *)&encodedSignedCert, &encodedSignedCertSize);
838             if (ret)
839             {
840                 context = CertCreateCertificateContext(X509_ASN_ENCODING,
841                  encodedSignedCert, encodedSignedCertSize);
842                 LocalFree(encodedSignedCert);
843             }
844         }
845         CryptMemFree(sig);
846     }
847     return context;
848 }
849
850 /* Copies data from the parameters into info, where:
851  * pSubjectIssuerBlob: Specifies both the subject and issuer for info.
852  *                     Must not be NULL
853  * pSignatureAlgorithm: Optional.
854  * pStartTime: The starting time of the certificate.  If NULL, the current
855  *             system time is used.
856  * pEndTime: The ending time of the certificate.  If NULL, one year past the
857  *           starting time is used.
858  * pubKey: The public key of the certificate.  Must not be NULL.
859  * pExtensions: Extensions to be included with the certificate.  Optional.
860  */
861 static void CRYPT_MakeCertInfo(PCERT_INFO info,
862  PCERT_NAME_BLOB pSubjectIssuerBlob,
863  PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime,
864  PSYSTEMTIME pEndTime, PCERT_PUBLIC_KEY_INFO pubKey,
865  PCERT_EXTENSIONS pExtensions)
866 {
867     /* FIXME: what serial number to use? */
868     static const BYTE serialNum[] = { 1 };
869
870     assert(info);
871     assert(pSubjectIssuerBlob);
872     assert(pubKey);
873
874     info->dwVersion = CERT_V3;
875     info->SerialNumber.cbData = sizeof(serialNum);
876     info->SerialNumber.pbData = (LPBYTE)serialNum;
877     if (pSignatureAlgorithm)
878         memcpy(&info->SignatureAlgorithm, pSignatureAlgorithm,
879          sizeof(info->SignatureAlgorithm));
880     else
881     {
882         info->SignatureAlgorithm.pszObjId = szOID_RSA_SHA1RSA;
883         info->SignatureAlgorithm.Parameters.cbData = 0;
884         info->SignatureAlgorithm.Parameters.pbData = NULL;
885     }
886     info->Issuer.cbData = pSubjectIssuerBlob->cbData;
887     info->Issuer.pbData = pSubjectIssuerBlob->pbData;
888     if (pStartTime)
889         SystemTimeToFileTime(pStartTime, &info->NotBefore);
890     else
891         GetSystemTimeAsFileTime(&info->NotBefore);
892     if (pEndTime)
893         SystemTimeToFileTime(pStartTime, &info->NotAfter);
894     else
895     {
896         SYSTEMTIME endTime;
897
898         if (FileTimeToSystemTime(&info->NotBefore, &endTime))
899         {
900             endTime.wYear++;
901             SystemTimeToFileTime(&endTime, &info->NotAfter);
902         }
903     }
904     info->Subject.cbData = pSubjectIssuerBlob->cbData;
905     info->Subject.pbData = pSubjectIssuerBlob->pbData;
906     memcpy(&info->SubjectPublicKeyInfo, pubKey,
907      sizeof(info->SubjectPublicKeyInfo));
908     if (pExtensions)
909     {
910         info->cExtension = pExtensions->cExtension;
911         info->rgExtension = pExtensions->rgExtension;
912     }
913     else
914     {
915         info->cExtension = 0;
916         info->rgExtension = NULL;
917     }
918 }
919  
920 typedef RPC_STATUS (RPC_ENTRY *UuidCreateFunc)(UUID *);
921 typedef RPC_STATUS (RPC_ENTRY *UuidToStringFunc)(UUID *, unsigned char **);
922 typedef RPC_STATUS (RPC_ENTRY *RpcStringFreeFunc)(unsigned char **);
923
924 static HCRYPTPROV CRYPT_CreateKeyProv(void)
925 {
926     HCRYPTPROV hProv = 0;
927     HMODULE rpcrt = LoadLibraryA("rpcrt4");
928
929     if (rpcrt)
930     {
931         UuidCreateFunc uuidCreate = (UuidCreateFunc)GetProcAddress(rpcrt,
932          "UuidCreate");
933         UuidToStringFunc uuidToString = (UuidToStringFunc)GetProcAddress(rpcrt,
934          "UuidToString");
935         RpcStringFreeFunc rpcStringFree = (RpcStringFreeFunc)GetProcAddress(
936          rpcrt, "RpcStringFree");
937
938         if (uuidCreate && uuidToString && rpcStringFree)
939         {
940             UUID uuid;
941             RPC_STATUS status = uuidCreate(&uuid);
942
943             if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY)
944             {
945                 unsigned char *uuidStr;
946
947                 status = uuidToString(&uuid, &uuidStr);
948                 if (status == RPC_S_OK)
949                 {
950                     BOOL ret = CryptAcquireContextA(&hProv, (LPCSTR)uuidStr,
951                      MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_NEWKEYSET);
952
953                     if (ret)
954                     {
955                         HCRYPTKEY key;
956
957                         ret = CryptGenKey(hProv, AT_SIGNATURE, 0, &key);
958                         if (ret)
959                             CryptDestroyKey(key);
960                     }
961                     rpcStringFree(&uuidStr);
962                 }
963             }
964         }
965         FreeLibrary(rpcrt);
966     }
967     return hProv;
968 }
969
970 PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV hProv,
971  PCERT_NAME_BLOB pSubjectIssuerBlob, DWORD dwFlags,
972  PCRYPT_KEY_PROV_INFO pKeyProvInfo,
973  PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime,
974  PSYSTEMTIME pEndTime, PCERT_EXTENSIONS pExtensions)
975 {
976     PCCERT_CONTEXT context = NULL;
977     BOOL ret, releaseContext = FALSE;
978     PCERT_PUBLIC_KEY_INFO pubKey = NULL;
979     DWORD pubKeySize = 0;
980
981     TRACE("(0x%08lx, %p, %08lx, %p, %p, %p, %p, %p)\n", hProv,
982      pSubjectIssuerBlob, dwFlags, pKeyProvInfo, pSignatureAlgorithm, pStartTime,
983      pExtensions, pExtensions);
984
985     if (!hProv)
986     {
987         hProv = CRYPT_CreateKeyProv();
988         releaseContext = TRUE;
989     }
990
991     CryptExportPublicKeyInfo(hProv, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
992      &pubKeySize);
993     pubKey = CryptMemAlloc(pubKeySize);
994     if (pubKey)
995     {
996         ret = CryptExportPublicKeyInfo(hProv, AT_SIGNATURE, X509_ASN_ENCODING,
997          pubKey, &pubKeySize);
998         if (ret)
999         {
1000             CERT_INFO info = { 0 };
1001             CRYPT_DER_BLOB blob = { 0, NULL };
1002             BOOL ret;
1003
1004             CRYPT_MakeCertInfo(&info, pSubjectIssuerBlob, pSignatureAlgorithm,
1005              pStartTime, pEndTime, pubKey, pExtensions);
1006             ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
1007              &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&blob.pbData,
1008              &blob.cbData);
1009             if (ret)
1010             {
1011                 if (!(dwFlags & CERT_CREATE_SELFSIGN_NO_SIGN))
1012                     context = CRYPT_CreateSignedCert(&blob, hProv,
1013                      &info.SignatureAlgorithm);
1014                 else
1015                     context = CertCreateCertificateContext(X509_ASN_ENCODING,
1016                      blob.pbData, blob.cbData);
1017                 if (context && !(dwFlags & CERT_CREATE_SELFSIGN_NO_KEY_INFO))
1018                     CertContext_SetKeyProvInfo(context, pKeyProvInfo, hProv);
1019                 LocalFree(blob.pbData);
1020             }
1021         }
1022         CryptMemFree(pubKey);
1023     }
1024     if (releaseContext)
1025         CryptReleaseContext(hProv, 0);
1026     return context;
1027 }