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)
Comments
Anonymous
April 22, 2009
Hi Alex,Can you please let me know where the selfsigned certificates are stored that are bind to service. for e.g in Exchange 2007 the server generates selfsigned certificates & binds it to IMAP, SMTP, UM, POP3 services.Is it stored in AD? or on the Exchange server host machine? Documents and SettingsAll UsersApplicationDataMicrosoftCryptoRSAMachineKeysThanks, EknathAnonymous
March 10, 2010
You write a good example. Thanks a LOT!Anonymous
July 27, 2015
Can you specify how to add keyusages along with certificate creation..Anonymous
July 28, 2015
Can any one specify how to add keyusages when creating certificate using Wincrypto API..