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!