How to create a self-signed certificate with CryptoAPI (C++)
Hi all,
The following C++ sample shows how to use CertCreateSelfSignCertificate API to create a self-signed certificate. The private/public key pair will be created in the machine profile and the certificate will be stored in the Trusted Root CA store of that same profile:
#include "stdio.h"
#include "conio.h"
#include "windows.h"
#include "wincrypt.h"
#include "tchar.h"
int SelfSignedCertificateTest()
{
// CREATE KEY PAIR FOR SELF-SIGNED CERTIFICATE IN MACHINE PROFILE
HCRYPTPROV hCryptProv = NULL;
HCRYPTKEY hKey = NULL;
__try
{
// Acquire key container
_tprintf(_T("CryptAcquireContext... "));
if (!CryptAcquireContext(&hCryptProv, _T("alejacma"), NULL, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
{
// Error
_tprintf(_T("Error 0x%x\n"), GetLastError());
// Try to create a new key container
_tprintf(_T("CryptAcquireContext... "));
if (!CryptAcquireContext(&hCryptProv, _T("alejacma"), NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
{
// Error
_tprintf(_T("Error 0x%x\n"), GetLastError());
return 0;
}
else
{
_tprintf(_T("Success\n"));
}
}
else
{
_tprintf(_T("Success\n"));
}
// Generate new key pair
_tprintf(_T("CryptGenKey... "));
if (!CryptGenKey(hCryptProv, AT_SIGNATURE, 0x08000000 /*RSA-2048-BIT_KEY*/, &hKey))
{
// Error
_tprintf(_T("Error 0x%x\n"), GetLastError());
return 0;
}
else
{
_tprintf(_T("Success\n"));
}
}
__finally
{
// Clean up
if (hKey)
{
_tprintf(_T("CryptDestroyKey... "));
CryptDestroyKey(hKey);
_tprintf(_T("Success\n"));
}
if (hCryptProv)
{
_tprintf(_T("CryptReleaseContext... "));
CryptReleaseContext(hCryptProv, 0);
_tprintf(_T("Success\n"));
}
}
// CREATE SELF-SIGNED CERTIFICATE AND ADD IT TO ROOT STORE IN MACHINE PROFILE
PCCERT_CONTEXT pCertContext = NULL;
BYTE *pbEncoded = NULL;
HCERTSTORE hStore = NULL;
HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProvOrNCryptKey = NULL;
BOOL fCallerFreeProvOrNCryptKey = FALSE;
__try
{
// Encode certificate Subject
LPCTSTR pszX500 = _T("CN=Alejacma, T=Test");
DWORD cbEncoded = 0;
_tprintf(_T("CertStrToName... "));
if (!CertStrToName(X509_ASN_ENCODING, pszX500, CERT_X500_NAME_STR, NULL, pbEncoded, &cbEncoded, NULL))
{
// Error
_tprintf(_T("Error 0x%x\n"), GetLastError());
return 0;
}
else
{
_tprintf(_T("Success\n"));
}
_tprintf(_T("malloc... "));
if (!(pbEncoded = (BYTE *)malloc(cbEncoded)))
{
// Error
_tprintf(_T("Error 0x%x\n"), GetLastError());
return 0;
}
else
{
_tprintf(_T("Success\n"));
}
_tprintf(_T("CertStrToName... "));
if (!CertStrToName(X509_ASN_ENCODING, pszX500, CERT_X500_NAME_STR, NULL, pbEncoded, &cbEncoded, NULL))
{
// Error
_tprintf(_T("Error 0x%x\n"), GetLastError());
return 0;
}
else
{
_tprintf(_T("Success\n"));
}
// Prepare certificate Subject for self-signed certificate
CERT_NAME_BLOB SubjectIssuerBlob;
memset(&SubjectIssuerBlob, 0, sizeof(SubjectIssuerBlob));
SubjectIssuerBlob.cbData = cbEncoded;
SubjectIssuerBlob.pbData = pbEncoded;
// Prepare key provider structure for self-signed certificate
CRYPT_KEY_PROV_INFO KeyProvInfo;
memset(&KeyProvInfo, 0, sizeof(KeyProvInfo));
KeyProvInfo.pwszContainerName = _T("alejacma");
KeyProvInfo.pwszProvName = NULL;
KeyProvInfo.dwProvType = PROV_RSA_FULL;
KeyProvInfo.dwFlags = CRYPT_MACHINE_KEYSET;
KeyProvInfo.cProvParam = 0;
KeyProvInfo.rgProvParam = NULL;
KeyProvInfo.dwKeySpec = AT_SIGNATURE;
// Prepare algorithm structure for self-signed certificate
CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
memset(&SignatureAlgorithm, 0, sizeof(SignatureAlgorithm));
SignatureAlgorithm.pszObjId = szOID_RSA_SHA1RSA;
// Prepare Expiration date for self-signed certificate
SYSTEMTIME EndTime;
GetSystemTime(&EndTime);
EndTime.wYear += 5;
// Create self-signed certificate
_tprintf(_T("CertCreateSelfSignCertificate... "));
pCertContext = CertCreateSelfSignCertificate(NULL, &SubjectIssuerBlob, 0, &KeyProvInfo, &SignatureAlgorithm, 0, &EndTime, 0);
if (!pCertContext)
{
// Error
_tprintf(_T("Error 0x%x\n"), GetLastError());
return 0;
}
else
{
_tprintf(_T("Success\n"));
}
// Open Root cert store in machine profile
_tprintf(_T("CertOpenStore... "));
hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"Root");
if (!hStore)
{
// Error
_tprintf(_T("Error 0x%x\n"), GetLastError());
return 0;
}
else
{
_tprintf(_T("Success\n"));
}
// Add self-signed cert to the store
_tprintf(_T("CertAddCertificateContextToStore... "));
if (!CertAddCertificateContextToStore(hStore, pCertContext, CERT_STORE_ADD_REPLACE_EXISTING, 0))
{
// Error
_tprintf(_T("Error 0x%x\n"), GetLastError());
return 0;
}
else
{
_tprintf(_T("Success\n"));
}
// Just for testing, verify that we can access self-signed cert's private key
DWORD dwKeySpec;
_tprintf(_T("CryptAcquireCertificatePrivateKey... "));
if (!CryptAcquireCertificatePrivateKey(pCertContext, 0, NULL, &hCryptProvOrNCryptKey, &dwKeySpec, &fCallerFreeProvOrNCryptKey))
{
// Error
_tprintf(_T("Error 0x%x\n"), GetLastError());
return 0;
}
else
{
_tprintf(_T("Success\n"));
}
}
__finally
{
// Clean up
if (!pbEncoded) {
_tprintf(_T("free... "));
free(pbEncoded);
_tprintf(_T("Success\n"));
}
if (hCryptProvOrNCryptKey)
{
_tprintf(_T("CryptReleaseContext... "));
CryptReleaseContext(hCryptProvOrNCryptKey, 0);
_tprintf(_T("Success\n"));
}
if (pCertContext)
{
_tprintf(_T("CertFreeCertificateContext... "));
CertFreeCertificateContext(pCertContext);
_tprintf(_T("Success\n"));
}
if (hStore)
{
_tprintf(_T("CertCloseStore... "));
CertCloseStore(hStore, 0);
_tprintf(_T("Success\n"));
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
SelfSignedCertificateTest();
_tprintf(_T("<< Press any key>>\n"));
_getch();
return 0;
}
I hope this helps.
Regards,
Alex (Alejandro Campos Magencio)