Reputation: 123662
I'm using the Microsoft CNG Cryptography API and I'm trying to create a self signed certificate.
We have existing code which uses the CertCreateSelfSignCertificate
method, combined with NCryptOpenStorageProvider
and NCryptCreatePersistedKey
to create the key pair.
The problem I'm facing now, is that the above combination creates a key which ends up in the windows crypto store. I explicitly don't want to store keys there, I want the certificate and private key to both be in-memory as I plan to then write them to encrypted/protected storage of our own choosing.
From what I've been able to tell, the BCrypt family of functions is designed for in-memory use, and indeed I can use BCryptGenerateKeyPair
to do this, but then the CertCreateSelfSignCertificate
doesn't work as it expects a key storage provider.
Is there any way to solve this? I was thinking either to try make a tempory in-memory key storage provider somehow, or else to do it the hard way and build the entire X509 certificate blob myself using a complex chain of calls to CryptEncodeObjectEx
. Documentation/reference and example code on this kind of stuff is terrible and I've struggled to find anything despite extensive googling :-(
Any help for different ideas or example code that might work would be much appreciated
Upvotes: 3
Views: 2042
Reputation: 1430
The following code is the exact code from one of my applications that I make (except a few changes to the app name in the code.)
It creates a self signed certificate in memory and adds it to the local system store. A few tweaks and you can get the certificate context itself. It uses the CNG Next Generation API to stay modern.
bool GenerateSelfSignedCertificate()
{
auto result{ false };
CERT_NAME_BLOB nameBlob{ 0 };
CERT_EXTENSIONS certExtensions{ 0 };
NCRYPT_PROV_HANDLE providerHandle{ 0 };
NCRYPT_KEY_HANDLE keyHandle{ 0 };
PCCERT_CONTEXT certContext{ nullptr };
HCERTSTORE certStore{ nullptr };
CRYPT_KEY_PROV_INFO keyProvInfo{
const_cast<LPWSTR>(L"MyService_Key"), const_cast<LPWSTR>(MS_KEY_STORAGE_PROVIDER),
0, NCRYPT_SILENT_FLAG, 0, nullptr, AT_KEYEXCHANGE
};
if (!CertStrToNameW(X509_ASN_ENCODING, L"CN=MyService", 0, nullptr, nameBlob.pbData,
&nameBlob.cbData, nullptr))
goto fail;
nameBlob.pbData = new UCHAR[nameBlob.cbData];
if (!CertStrToNameW(X509_ASN_ENCODING, L"CN=MyService", 0, nullptr, nameBlob.pbData,
&nameBlob.cbData, nullptr))
goto fail;
if (NCryptOpenStorageProvider(&providerHandle, MS_KEY_STORAGE_PROVIDER, 0) != ERROR_SUCCESS)
goto fail;
if (NCryptCreatePersistedKey(providerHandle, &keyHandle, BCRYPT_RSA_ALGORITHM, L"MyService_Key",
AT_KEYEXCHANGE, 0) != ERROR_SUCCESS)
goto fail;
if (NCryptFinalizeKey(keyHandle, NCRYPT_SILENT_FLAG) != ERROR_SUCCESS)
goto fail;
certContext = CertCreateSelfSignCertificate(keyHandle, &nameBlob, 0, &keyProvInfo, nullptr,
nullptr, nullptr, &certExtensions);
if (!certContext)
goto fail;
certStore = CertOpenSystemStoreW(NULL, L"MY");
if (!certStore)
goto fail;
if (!CertAddCertificateContextToStore(certStore, certContext, CERT_STORE_ADD_REPLACE_EXISTING, nullptr))
goto fail;
result = true;
fail:
delete[] nameBlob.pbData;
if (keyHandle)
OutputDebugStringW(L"NCryptFinalizeKey successfully finalized the key for use in the certificate.\r\n");
if (providerHandle)
NCryptFreeObject(providerHandle);
if (certStore)
CertCloseStore(certStore, 0);
if (certContext)
CertFreeCertificateContext(certContext);
return result;
}
Please let me know if this helps you. Thanks.
Upvotes: 4