Freigeben über


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, Eknath

  • Anonymous
    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..