Welcome to MSDN Blogs Sign in | Join | Help

Decrypt my World

Cryptography, Security, Debugging and more!
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)

Posted: Monday, March 16, 2009 1:36 PM by alejacma
Filed under:

Comments

Eknath Rao said:

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

# April 23, 2009 7:15 AM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

  
Enter Code Here: Required

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Page view tracker