Decrypt my World

Cryptography, Security, Debugging and more!

How to create a self-signed certificate with CryptoAPI (C++)

How to create a self-signed certificate with CryptoAPI (C++)

  • Comments 2

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)

  • 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 Settings\All Users\Application

    Data\Microsoft\Crypto\RSA\MachineKeys

    Thanks, Eknath

  • You write a good example. Thanks a LOT!

Page 1 of 1 (2 items)
Leave a Comment
  • Please add 8 and 6 and type the answer here:
  • Post
Translate This Page