2 * Copyright 2004-2006 Juan Lang
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.
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.
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
27 #include "wine/debug.h"
28 #include "crypt32_private.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
32 BOOL WINAPI CertCompareCertificate(DWORD dwCertEncodingType,
33 PCERT_INFO pCertId1, PCERT_INFO pCertId2)
35 TRACE("(%08lx, %p, %p)\n", dwCertEncodingType, pCertId1, pCertId2);
37 return CertCompareCertificateName(dwCertEncodingType, &pCertId1->Issuer,
38 &pCertId2->Issuer) && CertCompareIntegerBlob(&pCertId1->SerialNumber,
39 &pCertId2->SerialNumber);
42 BOOL WINAPI CertCompareCertificateName(DWORD dwCertEncodingType,
43 PCERT_NAME_BLOB pCertName1, PCERT_NAME_BLOB pCertName2)
47 TRACE("(%08lx, %p, %p)\n", dwCertEncodingType, pCertName1, pCertName2);
49 if (pCertName1->cbData == pCertName2->cbData)
51 if (pCertName1->cbData)
52 ret = !memcmp(pCertName1->pbData, pCertName2->pbData,
62 /* Returns the number of significant bytes in pInt, where a byte is
63 * insignificant if it's a leading 0 for positive numbers or a leading 0xff
64 * for negative numbers. pInt is assumed to be little-endian.
66 static DWORD CRYPT_significantBytes(PCRYPT_INTEGER_BLOB pInt)
68 DWORD ret = pInt->cbData;
72 if (pInt->pbData[ret - 2] <= 0x7f && pInt->pbData[ret - 1] == 0)
74 else if (pInt->pbData[ret - 2] >= 0x80 && pInt->pbData[ret - 1] == 0xff)
82 BOOL WINAPI CertCompareIntegerBlob(PCRYPT_INTEGER_BLOB pInt1,
83 PCRYPT_INTEGER_BLOB pInt2)
88 TRACE("(%p, %p)\n", pInt1, pInt2);
90 cb1 = CRYPT_significantBytes(pInt1);
91 cb2 = CRYPT_significantBytes(pInt2);
93 ret = !memcmp(pInt1->pbData, pInt1->pbData, cb1);
99 BOOL WINAPI CertComparePublicKeyInfo(DWORD dwCertEncodingType,
100 PCERT_PUBLIC_KEY_INFO pPublicKey1, PCERT_PUBLIC_KEY_INFO pPublicKey2)
104 TRACE("(%08lx, %p, %p)\n", dwCertEncodingType, pPublicKey1, pPublicKey2);
106 if (pPublicKey1->PublicKey.cbData == pPublicKey2->PublicKey.cbData &&
107 pPublicKey1->PublicKey.cUnusedBits == pPublicKey2->PublicKey.cUnusedBits)
109 if (pPublicKey2->PublicKey.cbData)
110 ret = !memcmp(pPublicKey1->PublicKey.pbData,
111 pPublicKey2->PublicKey.pbData, pPublicKey1->PublicKey.cbData);
120 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
121 CRYPT_ATTRIBUTE rgAttr[])
123 PCRYPT_ATTRIBUTE ret = NULL;
126 TRACE("%s %ld %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
132 SetLastError(ERROR_INVALID_PARAMETER);
136 for (i = 0; !ret && i < cAttr; i++)
137 if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
142 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
143 CERT_EXTENSION rgExtensions[])
145 PCERT_EXTENSION ret = NULL;
148 TRACE("%s %ld %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
154 SetLastError(ERROR_INVALID_PARAMETER);
158 for (i = 0; !ret && i < cExtensions; i++)
159 if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
160 rgExtensions[i].pszObjId))
161 ret = &rgExtensions[i];
165 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
167 PCERT_RDN_ATTR ret = NULL;
170 TRACE("%s %p\n", debugstr_a(pszObjId), pName);
174 SetLastError(ERROR_INVALID_PARAMETER);
178 for (i = 0; !ret && i < pName->cRDN; i++)
179 for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
180 if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
181 pName->rgRDN[i].rgRDNAttr[j].pszObjId))
182 ret = &pName->rgRDN[i].rgRDNAttr[j];
186 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
187 PCERT_INFO pCertInfo)
196 GetSystemTime(&sysTime);
197 SystemTimeToFileTime(&sysTime, &fileTime);
198 pTimeToVerify = &fileTime;
200 if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
202 ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
209 BOOL WINAPI CryptHashCertificate(HCRYPTPROV hCryptProv, ALG_ID Algid,
210 DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
211 DWORD *pcbComputedHash)
214 HCRYPTHASH hHash = 0;
216 TRACE("(%ld, %d, %08lx, %p, %ld, %p, %p)\n", hCryptProv, Algid, dwFlags,
217 pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
220 hCryptProv = CRYPT_GetDefaultProvider();
225 ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
228 ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
230 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
232 CryptDestroyHash(hHash);
238 BOOL WINAPI CryptSignCertificate(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
239 DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned,
240 DWORD cbEncodedToBeSigned, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
241 const void *pvHashAuxInfo, BYTE *pbSignature, DWORD *pcbSignature)
247 TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %p, %p, %p)\n", hCryptProv,
248 dwKeySpec, dwCertEncodingType, pbEncodedToBeSigned, cbEncodedToBeSigned,
249 pSignatureAlgorithm, pvHashAuxInfo, pbSignature, pcbSignature);
251 algID = CertOIDToAlgId(pSignatureAlgorithm->pszObjId);
254 SetLastError(NTE_BAD_ALGID);
259 SetLastError(ERROR_INVALID_PARAMETER);
263 ret = CryptCreateHash(hCryptProv, algID, 0, 0, &hHash);
266 ret = CryptHashData(hHash, pbEncodedToBeSigned, cbEncodedToBeSigned, 0);
268 ret = CryptSignHashW(hHash, dwKeySpec, NULL, 0, pbSignature,
270 CryptDestroyHash(hHash);
275 BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV hCryptProv,
276 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
277 PCERT_PUBLIC_KEY_INFO pPublicKey)
279 return CryptVerifyCertificateSignatureEx(hCryptProv, dwCertEncodingType,
280 CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, (void *)pbEncoded,
281 CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
284 static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV hCryptProv,
285 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pubKeyInfo,
286 PCERT_SIGNED_CONTENT_INFO signedCert)
289 ALG_ID algID = CertOIDToAlgId(pubKeyInfo->Algorithm.pszObjId);
292 /* Load the default provider if necessary */
294 hCryptProv = CRYPT_GetDefaultProvider();
295 ret = CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType,
296 pubKeyInfo, algID, 0, NULL, &key);
301 /* Some key algorithms aren't hash algorithms, so map them */
302 if (algID == CALG_RSA_SIGN || algID == CALG_RSA_KEYX)
304 ret = CryptCreateHash(hCryptProv, algID, 0, 0, &hash);
307 ret = CryptHashData(hash, signedCert->ToBeSigned.pbData,
308 signedCert->ToBeSigned.cbData, 0);
310 ret = CryptVerifySignatureW(hash, signedCert->Signature.pbData,
311 signedCert->Signature.cbData, key, NULL, 0);
312 CryptDestroyHash(hash);
314 CryptDestroyKey(key);
319 BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV hCryptProv,
320 DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
321 DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
324 CRYPT_DATA_BLOB subjectBlob;
326 TRACE("(%08lx, %ld, %ld, %p, %ld, %p, %08lx, %p)\n", hCryptProv,
327 dwCertEncodingType, dwSubjectType, pvSubject, dwIssuerType, pvIssuer,
328 dwFlags, pvReserved);
330 switch (dwSubjectType)
332 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB:
334 PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvSubject;
336 subjectBlob.pbData = blob->pbData;
337 subjectBlob.cbData = blob->cbData;
340 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT:
342 PCERT_CONTEXT context = (PCERT_CONTEXT)pvSubject;
344 subjectBlob.pbData = context->pbCertEncoded;
345 subjectBlob.cbData = context->cbCertEncoded;
348 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL:
350 PCRL_CONTEXT context = (PCRL_CONTEXT)pvSubject;
352 subjectBlob.pbData = context->pbCrlEncoded;
353 subjectBlob.cbData = context->cbCrlEncoded;
357 SetLastError(E_INVALIDARG);
363 PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
366 ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
367 subjectBlob.pbData, subjectBlob.cbData,
368 CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
369 (BYTE *)&signedCert, &size);
372 switch (dwIssuerType)
374 case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY:
375 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
376 dwCertEncodingType, (PCERT_PUBLIC_KEY_INFO)pvIssuer,
379 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT:
380 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
382 &((PCCERT_CONTEXT)pvIssuer)->pCertInfo->SubjectPublicKeyInfo,
385 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN:
386 FIXME("CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: stub\n");
389 case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL:
392 SetLastError(E_INVALIDARG);
397 FIXME("unimplemented for NULL signer\n");
398 SetLastError(E_INVALIDARG);
403 SetLastError(E_INVALIDARG);
406 LocalFree(signedCert);
412 BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags,
413 PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage)
415 PCERT_ENHKEY_USAGE usage = NULL;
419 if (!pCertContext || !pcbUsage)
421 SetLastError(ERROR_INVALID_PARAMETER);
425 TRACE("(%p, %08lx, %p, %ld)\n", pCertContext, dwFlags, pUsage, *pcbUsage);
427 if (!(dwFlags & CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG))
431 if (CertGetCertificateContextProperty(pCertContext,
432 CERT_ENHKEY_USAGE_PROP_ID, NULL, &propSize))
434 LPBYTE buf = CryptMemAlloc(propSize);
438 if (CertGetCertificateContextProperty(pCertContext,
439 CERT_ENHKEY_USAGE_PROP_ID, buf, &propSize))
441 ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
442 X509_ENHANCED_KEY_USAGE, buf, propSize,
443 CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
449 if (!usage && !(dwFlags & CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG))
451 PCERT_EXTENSION ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
452 pCertContext->pCertInfo->cExtension,
453 pCertContext->pCertInfo->rgExtension);
457 ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
458 X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
459 CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
464 /* If a particular location is specified, this should fail. Otherwise
465 * it should succeed with an empty usage. (This is true on Win2k and
466 * later, which we emulate.)
470 SetLastError(CRYPT_E_NOT_FOUND);
474 bytesNeeded = sizeof(CERT_ENHKEY_USAGE);
480 *pcbUsage = bytesNeeded;
481 else if (*pcbUsage < bytesNeeded)
483 SetLastError(ERROR_MORE_DATA);
484 *pcbUsage = bytesNeeded;
489 *pcbUsage = bytesNeeded;
493 LPSTR nextOID = (LPSTR)((LPBYTE)pUsage +
494 sizeof(CERT_ENHKEY_USAGE) +
495 usage->cUsageIdentifier * sizeof(LPSTR));
497 pUsage->cUsageIdentifier = usage->cUsageIdentifier;
498 pUsage->rgpszUsageIdentifier = (LPSTR *)((LPBYTE)pUsage +
499 sizeof(CERT_ENHKEY_USAGE));
500 for (i = 0; i < usage->cUsageIdentifier; i++)
502 pUsage->rgpszUsageIdentifier[i] = nextOID;
503 strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
504 nextOID += strlen(nextOID) + 1;
508 pUsage->cUsageIdentifier = 0;
513 TRACE("returning %d\n", ret);
517 BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext,
518 PCERT_ENHKEY_USAGE pUsage)
522 TRACE("(%p, %p)\n", pCertContext, pUsage);
526 CRYPT_DATA_BLOB blob = { 0, NULL };
528 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
529 pUsage, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData, &blob.cbData);
532 ret = CertSetCertificateContextProperty(pCertContext,
533 CERT_ENHKEY_USAGE_PROP_ID, 0, &blob);
534 LocalFree(blob.pbData);
538 ret = CertSetCertificateContextProperty(pCertContext,
539 CERT_ENHKEY_USAGE_PROP_ID, 0, NULL);
543 BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
544 LPCSTR pszUsageIdentifier)
549 TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
551 if (CertGetEnhancedKeyUsage(pCertContext,
552 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size))
554 PCERT_ENHKEY_USAGE usage = CryptMemAlloc(size);
558 ret = CertGetEnhancedKeyUsage(pCertContext,
559 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size);
562 PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size +
563 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
570 newUsage->rgpszUsageIdentifier =
571 (LPSTR *)((LPBYTE)newUsage + sizeof(CERT_ENHKEY_USAGE));
572 nextOID = (LPSTR)((LPBYTE)newUsage->rgpszUsageIdentifier +
573 (usage->cUsageIdentifier + 1) * sizeof(LPSTR));
574 for (i = 0; i < usage->cUsageIdentifier; i++)
576 newUsage->rgpszUsageIdentifier[i] = nextOID;
577 strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
578 nextOID += strlen(nextOID) + 1;
580 newUsage->rgpszUsageIdentifier[i] = nextOID;
581 strcpy(nextOID, pszUsageIdentifier);
582 newUsage->cUsageIdentifier = i + 1;
583 ret = CertSetEnhancedKeyUsage(pCertContext, newUsage);
584 CryptMemFree(newUsage);
594 PCERT_ENHKEY_USAGE usage = CryptMemAlloc(sizeof(CERT_ENHKEY_USAGE) +
595 sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
599 usage->rgpszUsageIdentifier =
600 (LPSTR *)((LPBYTE)usage + sizeof(CERT_ENHKEY_USAGE));
601 usage->rgpszUsageIdentifier[0] = (LPSTR)((LPBYTE)usage +
602 sizeof(CERT_ENHKEY_USAGE) + sizeof(LPSTR));
603 strcpy(usage->rgpszUsageIdentifier[0], pszUsageIdentifier);
604 usage->cUsageIdentifier = 1;
605 ret = CertSetEnhancedKeyUsage(pCertContext, usage);
614 BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
615 LPCSTR pszUsageIdentifier)
619 CERT_ENHKEY_USAGE usage;
621 TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
623 size = sizeof(usage);
624 ret = CertGetEnhancedKeyUsage(pCertContext,
625 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, &usage, &size);
626 if (!ret && GetLastError() == ERROR_MORE_DATA)
628 PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
632 ret = CertGetEnhancedKeyUsage(pCertContext,
633 CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
636 if (pUsage->cUsageIdentifier)
641 for (i = 0; i < pUsage->cUsageIdentifier; i++)
643 if (!strcmp(pUsage->rgpszUsageIdentifier[i],
646 if (found && i < pUsage->cUsageIdentifier - 1)
647 pUsage->rgpszUsageIdentifier[i] =
648 pUsage->rgpszUsageIdentifier[i + 1];
650 pUsage->cUsageIdentifier--;
651 /* Remove the usage if it's empty */
652 if (pUsage->cUsageIdentifier)
653 ret = CertSetEnhancedKeyUsage(pCertContext, pUsage);
655 ret = CertSetEnhancedKeyUsage(pCertContext, NULL);
658 CryptMemFree(pUsage);
665 /* it fit in an empty usage, therefore there's nothing to remove */
671 BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts,
672 int *cNumOIDSs, LPSTR *rghOIDs, DWORD *pcbOIDs)
676 BOOL allUsagesValid = TRUE;
677 CERT_ENHKEY_USAGE validUsages = { 0, NULL };
679 TRACE("(%ld, %p, %p, %p, %ld)\n", cCerts, *rghCerts, cNumOIDSs,
682 for (i = 0; ret && i < cCerts; i++)
684 CERT_ENHKEY_USAGE usage;
685 DWORD size = sizeof(usage);
687 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, &usage, &size);
688 /* Success is deliberately ignored: it implies all usages are valid */
689 if (!ret && GetLastError() == ERROR_MORE_DATA)
691 PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
693 allUsagesValid = FALSE;
696 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, pUsage, &size);
699 if (!validUsages.cUsageIdentifier)
703 cbOIDs = pUsage->cUsageIdentifier * sizeof(LPSTR);
704 validUsages.cUsageIdentifier = pUsage->cUsageIdentifier;
705 for (j = 0; j < validUsages.cUsageIdentifier; j++)
706 cbOIDs += lstrlenA(pUsage->rgpszUsageIdentifier[j])
708 validUsages.rgpszUsageIdentifier =
709 CryptMemAlloc(cbOIDs);
710 if (validUsages.rgpszUsageIdentifier)
712 LPSTR nextOID = (LPSTR)
713 ((LPBYTE)validUsages.rgpszUsageIdentifier +
714 validUsages.cUsageIdentifier * sizeof(LPSTR));
716 for (j = 0; j < validUsages.cUsageIdentifier; j++)
718 validUsages.rgpszUsageIdentifier[j] = nextOID;
719 lstrcpyA(validUsages.rgpszUsageIdentifier[j],
720 pUsage->rgpszUsageIdentifier[j]);
721 nextOID += lstrlenA(nextOID) + 1;
729 DWORD j, k, validIndexes = 0, numRemoved = 0;
731 /* Merge: build a bitmap of all the indexes of
732 * validUsages.rgpszUsageIdentifier that are in pUsage.
734 for (j = 0; j < pUsage->cUsageIdentifier; j++)
736 for (k = 0; k < validUsages.cUsageIdentifier; k++)
738 if (!strcmp(pUsage->rgpszUsageIdentifier[j],
739 validUsages.rgpszUsageIdentifier[k]))
741 validIndexes |= (1 << k);
746 /* Merge by removing from validUsages those that are
749 for (j = 0; j < validUsages.cUsageIdentifier; j++)
751 if (!(validIndexes & (1 << j)))
753 if (j < validUsages.cUsageIdentifier - 1)
755 memcpy(&validUsages.rgpszUsageIdentifier[j],
756 &validUsages.rgpszUsageIdentifier[j +
758 (validUsages.cUsageIdentifier - numRemoved
759 - j - 1) * sizeof(LPSTR));
761 validUsages.rgpszUsageIdentifier[j]) + 1 +
766 validUsages.cUsageIdentifier--;
771 CryptMemFree(pUsage);
786 if (!rghOIDs || *pcbOIDs < cbOIDs)
789 SetLastError(ERROR_MORE_DATA);
794 LPSTR nextOID = (LPSTR)((LPBYTE)rghOIDs +
795 validUsages.cUsageIdentifier * sizeof(LPSTR));
798 *cNumOIDSs = validUsages.cUsageIdentifier;
799 for (i = 0; i < validUsages.cUsageIdentifier; i++)
801 rghOIDs[i] = nextOID;
802 lstrcpyA(nextOID, validUsages.rgpszUsageIdentifier[i]);
803 nextOID += lstrlenA(nextOID) + 1;
808 CryptMemFree(validUsages.rgpszUsageIdentifier);
812 /* Sets the CERT_KEY_PROV_INFO_PROP_ID property of context from pInfo, or, if
813 * pInfo is NULL, from the attributes of hProv.
815 static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context,
816 PCRYPT_KEY_PROV_INFO pInfo, HCRYPTPROV hProv)
818 CRYPT_KEY_PROV_INFO info = { 0 };
826 ret = CryptGetProvParam(hProv, PP_CONTAINER, NULL, &size, 0);
829 LPSTR szContainer = CryptMemAlloc(size);
833 ret = CryptGetProvParam(hProv, PP_CONTAINER,
834 (BYTE *)szContainer, &size, 0);
837 len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
841 info.pwszContainerName = CryptMemAlloc(len *
843 len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
844 info.pwszContainerName, len);
847 CryptMemFree(szContainer);
850 ret = CryptGetProvParam(hProv, PP_NAME, NULL, &size, 0);
853 LPSTR szProvider = CryptMemAlloc(size);
857 ret = CryptGetProvParam(hProv, PP_NAME, (BYTE *)szProvider,
861 len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
865 info.pwszProvName = CryptMemAlloc(len *
867 len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
868 info.pwszProvName, len);
871 CryptMemFree(szProvider);
874 size = sizeof(info.dwKeySpec);
875 ret = CryptGetProvParam(hProv, PP_KEYSPEC, (LPBYTE)&info.dwKeySpec,
878 info.dwKeySpec = AT_SIGNATURE;
879 size = sizeof(info.dwProvType);
880 ret = CryptGetProvParam(hProv, PP_PROVTYPE, (LPBYTE)&info.dwProvType,
883 info.dwProvType = PROV_RSA_FULL;
887 ret = CertSetCertificateContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID,
892 CryptMemFree(info.pwszContainerName);
893 CryptMemFree(info.pwszProvName);
897 /* Creates a signed certificate context from the unsigned, encoded certificate
898 * in blob, using the crypto provider hProv and the signature algorithm sigAlgo.
900 static PCCERT_CONTEXT CRYPT_CreateSignedCert(PCRYPT_DER_BLOB blob,
901 HCRYPTPROV hProv, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo)
903 PCCERT_CONTEXT context = NULL;
907 ret = CryptSignCertificate(hProv, AT_SIGNATURE, X509_ASN_ENCODING,
908 blob->pbData, blob->cbData, sigAlgo, NULL, NULL, &sigSize);
911 LPBYTE sig = CryptMemAlloc(sigSize);
913 ret = CryptSignCertificate(hProv, AT_SIGNATURE, X509_ASN_ENCODING,
914 blob->pbData, blob->cbData, sigAlgo, NULL, sig, &sigSize);
917 CERT_SIGNED_CONTENT_INFO signedInfo;
918 BYTE *encodedSignedCert = NULL;
919 DWORD encodedSignedCertSize = 0;
921 signedInfo.ToBeSigned.cbData = blob->cbData;
922 signedInfo.ToBeSigned.pbData = blob->pbData;
923 memcpy(&signedInfo.SignatureAlgorithm, sigAlgo,
924 sizeof(signedInfo.SignatureAlgorithm));
925 signedInfo.Signature.cbData = sigSize;
926 signedInfo.Signature.pbData = sig;
927 signedInfo.Signature.cUnusedBits = 0;
928 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT,
929 &signedInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
930 (BYTE *)&encodedSignedCert, &encodedSignedCertSize);
933 context = CertCreateCertificateContext(X509_ASN_ENCODING,
934 encodedSignedCert, encodedSignedCertSize);
935 LocalFree(encodedSignedCert);
943 /* Copies data from the parameters into info, where:
944 * pSubjectIssuerBlob: Specifies both the subject and issuer for info.
946 * pSignatureAlgorithm: Optional.
947 * pStartTime: The starting time of the certificate. If NULL, the current
948 * system time is used.
949 * pEndTime: The ending time of the certificate. If NULL, one year past the
950 * starting time is used.
951 * pubKey: The public key of the certificate. Must not be NULL.
952 * pExtensions: Extensions to be included with the certificate. Optional.
954 static void CRYPT_MakeCertInfo(PCERT_INFO info,
955 PCERT_NAME_BLOB pSubjectIssuerBlob,
956 PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime,
957 PSYSTEMTIME pEndTime, PCERT_PUBLIC_KEY_INFO pubKey,
958 PCERT_EXTENSIONS pExtensions)
960 /* FIXME: what serial number to use? */
961 static const BYTE serialNum[] = { 1 };
964 assert(pSubjectIssuerBlob);
967 info->dwVersion = CERT_V3;
968 info->SerialNumber.cbData = sizeof(serialNum);
969 info->SerialNumber.pbData = (LPBYTE)serialNum;
970 if (pSignatureAlgorithm)
971 memcpy(&info->SignatureAlgorithm, pSignatureAlgorithm,
972 sizeof(info->SignatureAlgorithm));
975 info->SignatureAlgorithm.pszObjId = szOID_RSA_SHA1RSA;
976 info->SignatureAlgorithm.Parameters.cbData = 0;
977 info->SignatureAlgorithm.Parameters.pbData = NULL;
979 info->Issuer.cbData = pSubjectIssuerBlob->cbData;
980 info->Issuer.pbData = pSubjectIssuerBlob->pbData;
982 SystemTimeToFileTime(pStartTime, &info->NotBefore);
984 GetSystemTimeAsFileTime(&info->NotBefore);
986 SystemTimeToFileTime(pStartTime, &info->NotAfter);
991 if (FileTimeToSystemTime(&info->NotBefore, &endTime))
994 SystemTimeToFileTime(&endTime, &info->NotAfter);
997 info->Subject.cbData = pSubjectIssuerBlob->cbData;
998 info->Subject.pbData = pSubjectIssuerBlob->pbData;
999 memcpy(&info->SubjectPublicKeyInfo, pubKey,
1000 sizeof(info->SubjectPublicKeyInfo));
1003 info->cExtension = pExtensions->cExtension;
1004 info->rgExtension = pExtensions->rgExtension;
1008 info->cExtension = 0;
1009 info->rgExtension = NULL;
1013 typedef RPC_STATUS (RPC_ENTRY *UuidCreateFunc)(UUID *);
1014 typedef RPC_STATUS (RPC_ENTRY *UuidToStringFunc)(UUID *, unsigned char **);
1015 typedef RPC_STATUS (RPC_ENTRY *RpcStringFreeFunc)(unsigned char **);
1017 static HCRYPTPROV CRYPT_CreateKeyProv(void)
1019 HCRYPTPROV hProv = 0;
1020 HMODULE rpcrt = LoadLibraryA("rpcrt4");
1024 UuidCreateFunc uuidCreate = (UuidCreateFunc)GetProcAddress(rpcrt,
1026 UuidToStringFunc uuidToString = (UuidToStringFunc)GetProcAddress(rpcrt,
1028 RpcStringFreeFunc rpcStringFree = (RpcStringFreeFunc)GetProcAddress(
1029 rpcrt, "RpcStringFree");
1031 if (uuidCreate && uuidToString && rpcStringFree)
1034 RPC_STATUS status = uuidCreate(&uuid);
1036 if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY)
1038 unsigned char *uuidStr;
1040 status = uuidToString(&uuid, &uuidStr);
1041 if (status == RPC_S_OK)
1043 BOOL ret = CryptAcquireContextA(&hProv, (LPCSTR)uuidStr,
1044 MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_NEWKEYSET);
1050 ret = CryptGenKey(hProv, AT_SIGNATURE, 0, &key);
1052 CryptDestroyKey(key);
1054 rpcStringFree(&uuidStr);
1063 PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV hProv,
1064 PCERT_NAME_BLOB pSubjectIssuerBlob, DWORD dwFlags,
1065 PCRYPT_KEY_PROV_INFO pKeyProvInfo,
1066 PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime,
1067 PSYSTEMTIME pEndTime, PCERT_EXTENSIONS pExtensions)
1069 PCCERT_CONTEXT context = NULL;
1070 BOOL ret, releaseContext = FALSE;
1071 PCERT_PUBLIC_KEY_INFO pubKey = NULL;
1072 DWORD pubKeySize = 0;
1074 TRACE("(0x%08lx, %p, %08lx, %p, %p, %p, %p, %p)\n", hProv,
1075 pSubjectIssuerBlob, dwFlags, pKeyProvInfo, pSignatureAlgorithm, pStartTime,
1076 pExtensions, pExtensions);
1080 hProv = CRYPT_CreateKeyProv();
1081 releaseContext = TRUE;
1084 CryptExportPublicKeyInfo(hProv, AT_SIGNATURE, X509_ASN_ENCODING, NULL,
1086 pubKey = CryptMemAlloc(pubKeySize);
1089 ret = CryptExportPublicKeyInfo(hProv, AT_SIGNATURE, X509_ASN_ENCODING,
1090 pubKey, &pubKeySize);
1093 CERT_INFO info = { 0 };
1094 CRYPT_DER_BLOB blob = { 0, NULL };
1097 CRYPT_MakeCertInfo(&info, pSubjectIssuerBlob, pSignatureAlgorithm,
1098 pStartTime, pEndTime, pubKey, pExtensions);
1099 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
1100 &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&blob.pbData,
1104 if (!(dwFlags & CERT_CREATE_SELFSIGN_NO_SIGN))
1105 context = CRYPT_CreateSignedCert(&blob, hProv,
1106 &info.SignatureAlgorithm);
1108 context = CertCreateCertificateContext(X509_ASN_ENCODING,
1109 blob.pbData, blob.cbData);
1110 if (context && !(dwFlags & CERT_CREATE_SELFSIGN_NO_KEY_INFO))
1111 CertContext_SetKeyProvInfo(context, pKeyProvInfo, hProv);
1112 LocalFree(blob.pbData);
1115 CryptMemFree(pubKey);
1118 CryptReleaseContext(hProv, 0);