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 (4)

  1. Anonymous says:

    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 UsersApplication

    DataMicrosoftCryptoRSAMachineKeys

    Thanks, Eknath

  2. Anonymous says:

    You write a good example. Thanks a LOT!

  3. Anonymous says:

    Can you specify how to add keyusages along with certificate creation..

  4. Srujan says:

    Can any one specify how to add keyusages when creating certificate using Wincrypto API..