0x80090016 Keyset does not exist
Hi all,
This is the code i am using in trying to renew an email certificate.
It fails on creating the request blob:
hr=CertEnroll->createRequestWStr( dwCreateFlags, wszEntityDN, L"", &MyBlob );
giving the error "0x80090016 Keyset does not exist". Can someone please help in pinpointing what it is that i am doing wrong! I find the correct certificate and everything is ok until that point. I need to use the existing keyset.
here comes the code:
#include "stdafx.h"
#include <windows.h>
#include <Xenroll.h>
static DWORD dwProviderType = PROV_RSA_FULL;
static DWORD dwKeyLength = 1024;
static DWORD dwGenKeyFlags = ( dwKeyLength << 16 ) | CRYPT_EXPORTABLE;
static LPCWSTR wszEntityDN = NULL;
static LPCWSTR wszTemplateName = L"MyEFS";
// EKU OIDs : EFS
//static LPSTR szstrCertUsage = "1.3.6.1.4.1.311.10.3.4";
static LPSTR szstrCertUsage = "1.3.6.1.5.5.7.3.4";
static LPCWSTR szReqB64FileName = L"CertRequest.B64";
static LPCTSTR szReqBinaryFileName = _T( "CertRequest.BIN" );
static DWORD dwCreateFlags = XECR_CMC;
static BOOL WriteRequestFile( LPCTSTR Filename, CRYPT_DATA_BLOB* data );
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr;
IEnroll4* CertEnroll = NULL;
CRYPT_DATA_BLOB MyBlob = { 0, NULL };
LPWSTR OutputString = NULL;
HCERTSTORE hCertStore = NULL;
PCCERT_CONTEXT pEnrollmentCert = NULL; // Set to NULL for the first call to CertFindCertificateInStore
CERT_ENHKEY_USAGE stCertUsage = {1, &szstrCertUsage };
CRYPT_KEY_PROV_INFO* ProvInfo = NULL;
DWORD ProvInfoSiz = 0;
CRYPT_DATA_BLOB MyB64Blob = { 0, NULL };
LPWSTR TemplateName = NULL;
LPWSTR AllocatedTemplateName = NULL;
CERT_TEMPLATE_EXT* TemplateExt = NULL;
DWORD TemplateExtSiz = 0;
CERT_NAME_VALUE* TemplateExtName = NULL;
DWORD TemplateExtNameSiz = 0;
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (FAILED(hr))
{
wprintf( L"CoInitializeEx failed: 0x%x\n", hr);
goto error;
}
hr = CoCreateInstance(CLSID_CEnroll,
NULL,
CLSCTX_INPROC_SERVER,
IID_IEnroll4,
(void **)&CertEnroll);
if (FAILED(hr))
{
wprintf( L"CoCreateInstance failed: 0x%x\n", hr);
goto error;
}
// We now need to get the enrollment agent certificate
hCertStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM, // The store provider type.
0, // The encoding type is not needed.
NULL, // Use the default HCRYPTPROV.
CERT_SYSTEM_STORE_CURRENT_USER,
// Set the store location in a
// registry location.
L"MY" // The store name as a Unicode string.
);
if(!hCertStore)
{
hr=HRESULT_FROM_WIN32(GetLastError());
wprintf( L"CertOpenStore failed: 0x%x\n", hr );
goto error;
}
// Look for a cert to renew with the required OID
// For a typical certificate renewal a certificate would be selected that is near expiry.
if((pEnrollmentCert=CertFindCertificateInStore(
hCertStore,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
0, // No dwFlags needed.
CERT_FIND_ENHKEY_USAGE,
&stCertUsage,
NULL)) == NULL)
{
hr=HRESULT_FROM_WIN32(GetLastError());
wprintf( L"Find Renewal Certifcate : CertFindCertificateInStore( ... ) failed: 0x%x\n", hr );
goto error;
}
// We get a ptr to the V2 Certificate Template Extension
PCERT_EXTENSION ext = CertFindExtension(
szOID_CERTIFICATE_TEMPLATE,
pEnrollmentCert->pCertInfo->cExtension,
pEnrollmentCert->pCertInfo->rgExtension );
if ( !ext )
{
// If there is no V2 Template Extension, look for the V1 template extension.
ext = CertFindExtension(
szOID_ENROLL_CERTTYPE_EXTENSION,
pEnrollmentCert->pCertInfo->cExtension,
pEnrollmentCert->pCertInfo->rgExtension );
if ( !ext )
{
hr=HRESULT_FROM_WIN32(GetLastError());
wprintf( L"CertFindExtension( ... ) failed: 0x%x\n", hr );
goto error;
}
// The V1 Template Extension is a string.
if ( !CryptDecodeObjectEx(
(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING),
X509_UNICODE_NAME_VALUE,
ext->Value.pbData,
ext->Value.cbData,
CRYPT_DECODE_ALLOC_FLAG,
NULL,
&TemplateExtName,
&TemplateExtNameSiz ))
{
hr=HRESULT_FROM_WIN32(GetLastError());
wprintf( L"Template Extension : CryptDecodeObjectEx( ... ) failed: 0x%x\n", hr );
goto error;
}
TemplateName = (LPWSTR) TemplateExtName->Value.pbData;
}
else
{
// The V2 Template extension has major/minor version numbers and an OID.
if ( !CryptDecodeObjectEx(
(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING),
X509_CERTIFICATE_TEMPLATE,
ext->Value.pbData,
ext->Value.cbData,
CRYPT_DECODE_ALLOC_FLAG,
NULL,
&TemplateExt,
&TemplateExtSiz ))
{
hr=HRESULT_FROM_WIN32(GetLastError());
wprintf( L"Template Extension : CryptDecodeObjectEx( ... ) failed: 0x%x\n", hr );
goto error;
}
// Convert the ASCII OID to Unicode
int tmplen = MultiByteToWideChar( CP_THREAD_ACP, 0, TemplateExt->pszObjId, -1, NULL, 0 );
if ( !tmplen )
{
hr=HRESULT_FROM_WIN32(GetLastError());
wprintf( L"MultiByteToWideChar( ... ) failed: 0x%x\n", hr );
goto error;
}
AllocatedTemplateName = (LPWSTR) LocalAlloc( LPTR, sizeof(WCHAR) * tmplen );
if ( !AllocatedTemplateName )
{
hr=HRESULT_FROM_WIN32(GetLastError());
wprintf( L"LocalAlloc( ... ) failed: 0x%x\n", hr );
goto error;
}
tmplen = MultiByteToWideChar( CP_THREAD_ACP, 0, TemplateExt->pszObjId, -1, AllocatedTemplateName, tmplen );
if ( !tmplen )
{
hr=HRESULT_FROM_WIN32(GetLastError());
wprintf( L"MultiByteToWideChar( ... ) failed: 0x%x\n", hr );
goto error;
}
TemplateName = AllocatedTemplateName;
}
// Add the certificate template name - this has to match to renew.
hr = CertEnroll->AddCertTypeToRequestWStr(TemplateName);
if (FAILED(hr))
{
wprintf(L"CertEnroll->AddCertTypeToRequestWStr(..) failed: 0x%x\n", hr);
goto error;
}
// Get the Key information for the certificate
if ( !CertGetCertificateContextProperty(
pEnrollmentCert,
CERT_KEY_PROV_INFO_PROP_ID,
NULL,
&ProvInfoSiz))
{
hr=HRESULT_FROM_WIN32(GetLastError());
wprintf( L"CertGetCertificateContextProperty() failed: 0x%x\n", hr );
goto error;
}
ProvInfo = (CRYPT_KEY_PROV_INFO*) LocalAlloc( LPTR, ProvInfoSiz );
if ( !ProvInfo )
{
hr=HRESULT_FROM_WIN32(GetLastError());
wprintf( L"LocalAlloc() failed: 0x%x\n", hr );
goto error;
}
if ( !CertGetCertificateContextProperty(
pEnrollmentCert,
CERT_KEY_PROV_INFO_PROP_ID,
ProvInfo,
&ProvInfoSiz))
{
hr=HRESULT_FROM_WIN32(GetLastError());
wprintf( L"CertGetCertificateContextProperty() failed: 0x%x\n", hr );
goto error;
}
// Now add the renewal certificate to the request.
hr=CertEnroll->put_RenewalCertificate( pEnrollmentCert );
if(FAILED(hr))
{
wprintf( L"CertEnroll->put_RenewalCertificate( ... ) failed: 0x%x\n", hr );
goto error;
}
// Renew with existing key
hr=CertEnroll->put_UseExistingKeySet( TRUE );
if (FAILED(hr))
{
hr=HRESULT_FROM_WIN32(GetLastError());
wprintf( L"put_UseExistingKeySet() failed: 0x%x\n", hr );
goto error;
}
// Set the CSP name from the existing key
hr = CertEnroll->put_ProviderNameWStr(ProvInfo->pwszProvName);
if (FAILED(hr))
{
wprintf( L"CertEnroll->put_ProviderNameWStr() failed: 0x%x\n", hr);
goto error;
}
// Set the container name for the existing key.
hr=CertEnroll->put_ContainerNameWStr(ProvInfo->pwszContainerName);
if (FAILED(hr))
{
hr=HRESULT_FROM_WIN32(GetLastError());
wprintf( L"put_ContainerNameWStr() failed: 0x%x\n", hr );
goto error;
}
// Ste the key spec for the renewal.
hr=CertEnroll->put_KeySpec( ProvInfo->dwKeySpec );
if(FAILED(hr))
{
wprintf(L"CertEnroll->put_KeySpec() failed: 0x%x\n", hr);
goto error;
}
// Set ProviderType if default is not OK
hr=CertEnroll->put_ProviderType( dwProviderType );
if(FAILED(hr))
{
wprintf(L"CertEnroll->put_ProviderType( %d ) failed: 0x%x\n", dwProviderType, hr);
goto error;
}
hr = CertEnroll->put_EnableSMIMECapabilities( TRUE );
if(FAILED(hr))
{
wprintf( L"CertEnroll->put_EnableSMIMECapabilities( FALSE ) failed: 0x%x\n", hr );
goto error;
}
// Create the request blob
hr=CertEnroll->createRequestWStr( dwCreateFlags, wszEntityDN, L"", &MyBlob );
if(FAILED(hr))
{
wprintf( L"CertEnroll->createRequestWStr( ... ) failed: 0x%x\n", hr );
goto error;
}
// Write the blob to a file
if ( !WriteRequestFile( szReqBinaryFileName, &MyBlob ))
{
hr=HRESULT_FROM_WIN32(GetLastError());
wprintf( L"WriteRequestFile() failed: 0x%x\n", hr );
goto error;
}
hr=CertEnroll->binaryBlobToString( CRYPT_STRING_BASE64REQUESTHEADER, &MyBlob, &OutputString );
if(FAILED(hr))
{
wprintf( L"CertEnroll->binaryBlobToString( ... ) failed: 0x%x\n", hr );
goto error;
}
MyB64Blob.cbData = WideCharToMultiByte( CP_THREAD_ACP, 0, OutputString, -1, NULL, 0, NULL, NULL );
MyB64Blob.pbData = (BYTE*) LocalAlloc( LPTR, MyB64Blob.cbData );
WideCharToMultiByte( CP_THREAD_ACP, 0, OutputString, -1, (LPSTR) MyB64Blob.pbData, MyB64Blob.cbData, NULL, NULL );
// Write the Base 64 to a file
if ( !WriteRequestFile( szReqB64FileName, &MyB64Blob ))
{
hr=HRESULT_FROM_WIN32(GetLastError());
wprintf( L"WriteRequestFile() failed: 0x%x\n", hr );
goto error;
}
hr = 0;
error:
if ( NULL != AllocatedTemplateName )
LocalFree( AllocatedTemplateName );
if ( NULL != TemplateExtName )
LocalFree( TemplateExtName );
if ( NULL != MyB64Blob.pbData )
LocalFree( MyB64Blob.pbData );
if ( NULL != pEnrollmentCert )
CertFreeCertificateContext( pEnrollmentCert );
if ( NULL != hCertStore )
CertCloseStore( hCertStore, 0 );
if ( NULL != CertEnroll )
CertEnroll->Release();
if ( NULL != MyBlob.pbData )
LocalFree( MyBlob.pbData );
if ( NULL != OutputString )
LocalFree( OutputString );
// Free COM resources.
CoUninitialize();
return hr;
}
BOOL WriteRequestFile( LPCTSTR Filename, CRYPT_DATA_BLOB* data )
{
DWORD numbytes = 0;
HANDLE fh = CreateFile(
Filename,
FILE_WRITE_DATA,
0,
NULL,
CREATE_ALWAYS,
0,
NULL );
if ( fh == INVALID_HANDLE_VALUE )
{
return FALSE;
}
WriteFile( fh, data->pbData, data->cbData, &numbytes, NULL );
CloseHandle( fh );
return TRUE;
}