Reputation: 3
Trying to acquire a cryptographic context from a CSP of type PROV_RSA_FULL the API function CryptAcquireContext(...) always returns an error code and last error is "Keyset does not exist". The code enumerates the CSPs and 4 of them have type PROV_RSA_FULL: Microsoft Base Cryptographic Provider v1.0 Microsoft Base Smart Card Crypto Provider Microsoft Enhanced Cryptographic Provider v1.0 Microsoft Strong Cryptographic Provider
Debug Output shows: CSP: Microsoft Base Cryptographic Provider v1.0 is a PROV_RSA_FULL type provider Keyset does not exist ... CSP: Microsoft Base Smart Card Crypto Provider is a PROV_RSA_FULL type provider Keyset does not exist ... CSP: Microsoft Enhanced Cryptographic Provider v1.0 is a PROV_RSA_FULL type provider Keyset does not exist ... CSP: Microsoft Strong Cryptographic Provider is a PROV_RSA_FULL type provider Keyset does not exist
void main()
{
//-------------------------------------------------------------------
// Declare and initialize variables. This includes getting a pointer
// to the message to be encrypted. This code creates a message
// and gets a pointer to it. In reality, the message content
// usually exists somewhere and a pointer to the message is
// passed to the application.
BYTE* pbContent = (BYTE*)"Security is our business.";
// The message
DWORD cbContent = strlen((char*)pbContent) + 1;
// Size of message
HCRYPTPROV hCryptProv; // CSP handle
HCERTSTORE hStoreHandle;
PCCERT_CONTEXT pRecipientCert;
PCCERT_CONTEXT RecipientCertArray[1];
DWORD EncryptAlgSize;
CRYPT_ALGORITHM_IDENTIFIER EncryptAlgorithm;
CRYPT_ENCRYPT_MESSAGE_PARA EncryptParams;
DWORD EncryptParamsSize;
BYTE* pbEncryptedBlob;
DWORD cbEncryptedBlob;
//-------------------------------------------------------------------
// Begin processing.
printf("About to begin with the message %s.\n", pbContent);
printf("The message length is %d bytes. \n", cbContent);
DWORD cbName=0;
DWORD dwType=0;
DWORD dwIndex = 0;
LPWSTR pszName;
DWORD pdwProvType;
DWORD pcbProvName;
// Loop through enumerating providers.
while(CryptEnumProvidersW(
dwIndex,
NULL,
0,
&pdwProvType,
NULL,
&pcbProvName
))
{
//-----------------------------------------------------------
// cbName is the length of the name of the next provider
// type.
// Allocate memory in a buffer to retrieve that name.
if (!(pszName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, pcbProvName)))
{
MyHandleError((char*)std::string::basic_string("ERROR LocalAlloc failed!\n").c_str());
}
//-----------------------------------------------------------
// Get the provider type name.
if (CryptEnumProvidersW(
dwIndex++,
NULL,
0,
&pdwProvType,
pszName,
&pcbProvName
))
{
std::wostringstream os;
os << "CSP: " << pszName << "\n";
OutputDebugString(os.str().c_str());
printf(" %4.0d %ls\n",dwType, pszName);
if (pdwProvType==PROV_RSA_FULL)
{
std::wstring s(L"is a PROV_RSA_FULL type provider");
OutputDebugString(s.c_str());
//MS_DEF_PROV
}
}
else
{
MyHandleError((char*) std::string::basic_string("ERROR CryptEnumProviders.\n").c_str());
}
//-------------------------------------------------------------------
// Get a handle to a cryptographic provider.
if (CryptAcquireContext(
&hCryptProv, // Address for handle to be returned.
NULL, // Use the current user's logon name.
pszName, // Use the default provider.
PROV_RSA_FULL, // Need to both encrypt and sign.
NULL)) // No flags needed.
{
printf("A CSP has been acquired \n");
break;
}
else
{
/*
DWORD e= GetLastError();
std::wstring ermsg=getErrorMsg();
OutputDebugString(ermsg.c_str());// ALWAYS OUTPUTS "Keyset does not exist"
// WHY??????????????????????????????????????????????????????????????????????????????????
printf("Cryptographic context could not be acquired.\n");
}
*/
DWORD e = GetLastError();
std::wstring ermsg = getErrorMsg();
OutputDebugString(ermsg.c_str());
std::wostringstream os;
os << "Cryptographic context could not be acquired, the
default container not found.\n";
OutputDebugString(os.str().c_str());
// No default container was found. Attempt to create it.
if (CryptAcquireContext(
&hCryptProv,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_NEWKEYSET))
{
std::wostringstream os;
os << "A PROV_RSA_FULL CSP has been acquired \n";
OutputDebugString(os.str().c_str());
AcquiredCryptographicContext = TRUE;
//break;
}
else
{
DWORD e = GetLastError();
std::wstring ermsg = getErrorMsg();
OutputDebugString(ermsg.c_str());
MyHandleError((char*)std::string::basic_string("Could
not create the default key container.\n").c_str());
}
if (hCryptProv != NULL)
{
if (!CryptReleaseContext(
hCryptProv,
0))
{
MyHandleError((char*)std::string::basic_string("FAILED To
RELEASE CryptoContext.\n").c_str());
}
}
if(pszName!=NULL)
{
LocalFree(pszName);
}
}
}
I have a self signed certificate in my personal store. Other code can retrieve all it's properties, extended properties, and the public certificate. I was expecting to get CryptAcquireContext to succeed and return a handle. I would then use this with the self-signed cert to encrypt a message. ** I KNOW ** this is a deprecated api but I am having similar issues using NGC to get a certificate context. NCryptGetProperty for NCRYPT_CERTIFICATE_PROPERTY fails with error NTE_NOT_FOUND. I can post this code if needed but it is a different issue, or do I have a configuration problem causing both?
Upvotes: 0
Views: 72
Reputation: 3
I have updated the code with the final answer.
After the first call to CryptAcquireContext fails with error "Keyset does not exist" I make a second call to CryptAcquireContext with dwFlags parameter set to CRYPT_NEWKEYSET. This succeeded, and when it is run again, the first call now succeeds. The first CSP with PROV_RSA_FULL type: Microsoft Base Cryptographic Provider v1.0 now has a default Keyset. This implies none of my CSPs with PROV_RSA_FULL type had a default Keyset.
Thanks to bartonjs for catching the pszName parameter issue. "pszName is the name of the CSP, but you're passing it to CryptAcquireContext as the name of a key container" With this fixed, the first call to CryptAcquireContext still returned the same error "Keyset does not exist".
https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src/SecCrypto/example-c-program-using-cryptacquirecontext.md is an example of creating a Keyset
Upvotes: 0