|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1995 - 1999
//
// File: certhlpr.cpp
//
// Contents: import and export of private keys
//
// Functions: ImportExoprtDllMain
// CryptImportPKCS8
// CryptExportPKCS8
//
// History:
//--------------------------------------------------------------------------
#include "global.hxx"
//#include "prvtkey.h"
#include "impexppk.h"
#include "pfxcrypt.h"
// All the *pvInfo extra stuff needs to be aligned
#define INFO_LEN_ALIGN(Len) ((Len + 7) & ~7)
static BOOL WINAPI ExportRSAPrivateKeyInfo( HCRYPTPROV hCryptProv, // in
DWORD dwKeySpec, // in
LPSTR pszPrivateKeyObjId, // in
DWORD dwFlags, // in
void *pvAuxInfo, // in
CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfo, // out
DWORD *pcbPrivateKeyInfo // in, out
);
static BOOL WINAPI ImportRSAPrivateKeyInfo( HCRYPTPROV hCryptProv, // in
CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfo, // in
DWORD dwFlags, // in, optional
void *pvAuxInfo // in, optional
);
static BOOL WINAPI ExportDSSPrivateKeyInfo( HCRYPTPROV hCryptProv, // in
DWORD dwKeySpec, // in
LPSTR pszPrivateKeyObjId, // in
DWORD dwFlags, // in
void *pvAuxInfo, // in
CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfo, // out
DWORD *pcbPrivateKeyInfo // in, out
);
static BOOL WINAPI ImportDSSPrivateKeyInfo( HCRYPTPROV hCryptProv, // in
CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfo, // in
DWORD dwFlags, // in, optional
void *pvAuxInfo // in, optional
);
static HCRYPTOIDFUNCSET hExportPrivKeyFuncSet; static HCRYPTOIDFUNCSET hImportPrivKeyFuncSet;
// Internal default OIDs
#define DEFAULT_CSP_PRIVKEY1 ((LPCSTR) 1)
#define DEFAULT_CSP_PRIVKEY2 ((LPCSTR) 2)
static const CRYPT_OID_FUNC_ENTRY ExportPrivKeyFuncTable[] = { DEFAULT_CSP_PRIVKEY1, ExportRSAPrivateKeyInfo, szOID_RSA_RSA, ExportRSAPrivateKeyInfo, szOID_OIWSEC_dsa, ExportDSSPrivateKeyInfo, szOID_X957_DSA, ExportDSSPrivateKeyInfo }; #define EXPORT_PRIV_KEY_FUNC_COUNT (sizeof(ExportPrivKeyFuncTable) / \
sizeof(ExportPrivKeyFuncTable[0]))
static const CRYPT_OID_FUNC_ENTRY ImportPrivKeyFuncTable[] = { szOID_RSA_RSA, ImportRSAPrivateKeyInfo, szOID_OIWSEC_dsa, ImportDSSPrivateKeyInfo, szOID_X957_DSA, ImportDSSPrivateKeyInfo }; #define IMPORT_PRIV_KEY_FUNC_COUNT (sizeof(ImportPrivKeyFuncTable) / \
sizeof(ImportPrivKeyFuncTable[0]))
BOOL WINAPI ImportExportDllMain( HMODULE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) { switch( ul_reason_for_call ) { case DLL_PROCESS_ATTACH: // Private key function setup
if (NULL == (hExportPrivKeyFuncSet = CryptInitOIDFunctionSet( CRYPT_OID_EXPORT_PRIVATE_KEY_INFO_FUNC, 0))) goto ErrorReturn; if (NULL == (hImportPrivKeyFuncSet = CryptInitOIDFunctionSet( CRYPT_OID_IMPORT_PRIVATE_KEY_INFO_FUNC, 0))) goto ErrorReturn;
if (!CryptInstallOIDFunctionAddress( NULL, // hModule
X509_ASN_ENCODING, CRYPT_OID_EXPORT_PRIVATE_KEY_INFO_FUNC, EXPORT_PRIV_KEY_FUNC_COUNT, ExportPrivKeyFuncTable, 0)) // dwFlags
goto ErrorReturn; if (!CryptInstallOIDFunctionAddress( NULL, // hModule
X509_ASN_ENCODING, CRYPT_OID_IMPORT_PRIVATE_KEY_INFO_FUNC, IMPORT_PRIV_KEY_FUNC_COUNT, ImportPrivKeyFuncTable, 0)) // dwFlags
goto ErrorReturn; break; case DLL_PROCESS_DETACH: break;
default: break; }
return TRUE;
ErrorReturn: return FALSE; }
//+-------------------------------------------------------------------------
// phCryptProv - a pointer to a HCRYPTPROV to put the handle of the provider
// that received the imported keyset. if this is NON_NULL then
// the caller is responsible for calling CryptReleaseContext().
// pdwKeySpec - a pointer to a DWORD to receive the KeySpec of imported keyset
// privateKeyAndParams - private key blob and corresponding parameters
// dwFlags - The available flags are:
// CRYPT_EXPORTABLE
// this flag is used when importing private keys, for a full
// explanation please see the documentation for CryptImportKey.
// phCryptProv - filled in with the handle of the provider the key was
// imported to, the caller is responsible for freeing it
// pvAuxInfo - This parameter is reserved for future use and should be set
// to NULL in the interim.
//+-------------------------------------------------------------------------
BOOL WINAPI CryptImportPKCS8( CRYPT_PKCS8_IMPORT_PARAMS sPrivateKeyAndParams, // in
DWORD dwFlags, // in, optional
HCRYPTPROV *phCryptProv, // out
void *pvAuxInfo // in, optional
) { BOOL fResult = TRUE; void *pvFuncAddr; HCRYPTOIDFUNCADDR hFuncAddr;
CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfoStruct = NULL; DWORD cbPrivateKeyInfoStruct = 0; CRYPT_ENCRYPTED_PRIVATE_KEY_INFO *pEncryptedPrivateKeyInfoStruct = NULL; DWORD cbEncryptedPrivateKeyInfoStruct = 0; BYTE *pbEncodedPrivateKey = sPrivateKeyAndParams.PrivateKey.pbData; DWORD cbEncodedPrivateKey = sPrivateKeyAndParams.PrivateKey.cbData; BOOL bEncodedPrivateKeyAlloced = FALSE; HCRYPTPROV hCryptProv = NULL;
// try to decode private key blob as a CRYPT_PRIVATE_KEY_INFO structure
if (!CryptDecodeObject(X509_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO, sPrivateKeyAndParams.PrivateKey.pbData, sPrivateKeyAndParams.PrivateKey.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &cbPrivateKeyInfoStruct)) { // that decode failed, so try to decode as CRYPT_ENCRYPTED_PRIVATE_KEY_INFO structure
if (!CryptDecodeObject(X509_ASN_ENCODING, PKCS_ENCRYPTED_PRIVATE_KEY_INFO, sPrivateKeyAndParams.PrivateKey.pbData, sPrivateKeyAndParams.PrivateKey.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &cbEncryptedPrivateKeyInfoStruct)) goto ErrorReturn;
if (NULL == (pEncryptedPrivateKeyInfoStruct = (CRYPT_ENCRYPTED_PRIVATE_KEY_INFO *) SSAlloc(cbEncryptedPrivateKeyInfoStruct))) goto ErrorReturn;
if (!CryptDecodeObject(X509_ASN_ENCODING, PKCS_ENCRYPTED_PRIVATE_KEY_INFO, sPrivateKeyAndParams.PrivateKey.pbData, sPrivateKeyAndParams.PrivateKey.cbData, CRYPT_DECODE_NOCOPY_FLAG, pEncryptedPrivateKeyInfoStruct, &cbEncryptedPrivateKeyInfoStruct)) goto ErrorReturn; // call back the callee to decrypt the private key info
pbEncodedPrivateKey = NULL; cbEncodedPrivateKey = 0; if (!sPrivateKeyAndParams.pDecryptPrivateKeyFunc( pEncryptedPrivateKeyInfoStruct->EncryptionAlgorithm, pEncryptedPrivateKeyInfoStruct->EncryptedPrivateKey, NULL, &cbEncodedPrivateKey, sPrivateKeyAndParams.pVoidDecryptFunc)) goto ErrorReturn;
if (NULL == (pbEncodedPrivateKey = (BYTE *) SSAlloc(cbEncodedPrivateKey))) goto ErrorReturn;
bEncodedPrivateKeyAlloced = TRUE; if (!sPrivateKeyAndParams.pDecryptPrivateKeyFunc( pEncryptedPrivateKeyInfoStruct->EncryptionAlgorithm, pEncryptedPrivateKeyInfoStruct->EncryptedPrivateKey, pbEncodedPrivateKey, &cbEncodedPrivateKey, sPrivateKeyAndParams.pVoidDecryptFunc)) goto ErrorReturn; // we are now back to square one with an encoded CRYPT_PRIVATE_KEY_INFO struct,
// so get the size of that when it's decoded
if (!CryptDecodeObject(X509_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO, pbEncodedPrivateKey, cbEncodedPrivateKey, CRYPT_DECODE_NOCOPY_FLAG, NULL, &cbPrivateKeyInfoStruct)) goto ErrorReturn; }
if (NULL == (pPrivateKeyInfoStruct = (CRYPT_PRIVATE_KEY_INFO *) SSAlloc(cbPrivateKeyInfoStruct))) goto ErrorReturn;
if (!CryptDecodeObject(X509_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO, pbEncodedPrivateKey, cbEncodedPrivateKey, CRYPT_DECODE_NOCOPY_FLAG, pPrivateKeyInfoStruct, &cbPrivateKeyInfoStruct)) goto ErrorReturn;
// call the caller back to get the provider to import to, if the
// call back is null then just use the default provider.
if (sPrivateKeyAndParams.pResolvehCryptProvFunc != NULL) { if (!sPrivateKeyAndParams.pResolvehCryptProvFunc( pPrivateKeyInfoStruct, &hCryptProv, sPrivateKeyAndParams.pVoidResolveFunc)) { goto ErrorReturn; } } else { if (!CryptAcquireContext( &hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) { goto ErrorReturn; } } // resolve what supporting import function to call based on the algorithm
// OID of the private key
if (CryptGetOIDFunctionAddress( hImportPrivKeyFuncSet, X509_ASN_ENCODING, pPrivateKeyInfoStruct->Algorithm.pszObjId, 0, // dwFlags
&pvFuncAddr, &hFuncAddr)) { fResult = ((PFN_IMPORT_PRIV_KEY_FUNC) pvFuncAddr)( hCryptProv, pPrivateKeyInfoStruct, dwFlags, pvAuxInfo ); CryptFreeOIDFunctionAddress(hFuncAddr, 0); } else { SetLastError(ERROR_UNSUPPORTED_TYPE); goto ErrorReturn; }
// check to see if the caller wants the hCryptProv
if (phCryptProv) { *phCryptProv = hCryptProv; } else { HRESULT hr = GetLastError(); CryptReleaseContext(hCryptProv, 0); SetLastError(hr); }
goto CommonReturn;
ErrorReturn: fResult = FALSE; if (hCryptProv) { HRESULT hr = GetLastError(); CryptReleaseContext(hCryptProv, 0); SetLastError(hr); }
CommonReturn: if (pPrivateKeyInfoStruct) SSFree(pPrivateKeyInfoStruct); if (pEncryptedPrivateKeyInfoStruct) SSFree(pEncryptedPrivateKeyInfoStruct); if (bEncodedPrivateKeyAlloced) SSFree(pbEncodedPrivateKey); return fResult; }
////////
// old crusty API kept around for compat reasons
BOOL WINAPI CryptExportPKCS8( HCRYPTPROV hCryptProv, // in
DWORD dwKeySpec, // in
LPSTR pszPrivateKeyObjId, // in
DWORD dwFlags, // in
void *pvAuxInfo, // in
BYTE *pbPrivateKeyBlob, // out
DWORD *pcbPrivateKeyBlob // in, out
) { CRYPT_PKCS8_EXPORT_PARAMS sExportParams; ZeroMemory(&sExportParams, sizeof(sExportParams));
// copy args to pkcs8_export struct
sExportParams.hCryptProv = hCryptProv; sExportParams.dwKeySpec = dwKeySpec; sExportParams.pszPrivateKeyObjId = pszPrivateKeyObjId;
// these are not available to non-Ex function
sExportParams.pEncryptPrivateKeyFunc = NULL; sExportParams.pVoidEncryptFunc = NULL;
return CryptExportPKCS8Ex( &sExportParams, dwFlags, pvAuxInfo, pbPrivateKeyBlob, pcbPrivateKeyBlob); }
//+-------------------------------------------------------------------------
// hCryptProv - specifies the provider to export from
// dwKeySpec - Identifies the public key to use from the provider's container.
// For example, AT_KEYEXCHANGE or AT_SIGNATURE.
// pszPrivateKeyObjId - Specifies the private key algorithm. If an installable
// function was not found for the pszPrivateKeyObjId, an
// attempt is made to export the key as a RSA Public Key
// (szOID_RSA_RSA).
// dwFlags - The flag values. Current supported values are:
// DELETE_KEYSET - (NOT CURRENTLY SUPPORTED!!!!)
// will delete key after export
// pvAuxInfo - This parameter is reserved for future use and should be set to
// NULL in the interim.
// pbPrivateKeyBlob - A pointer to the private key blob. It will be encoded
// as a PKCS8 PrivateKeyInfo.
// pcbPrivateKeyBlob - A pointer to a DWORD that contains the size, in bytes,
// of the private key blob being exported.
//+-------------------------------------------------------------------------
BOOL WINAPI CryptExportPKCS8Ex( CRYPT_PKCS8_EXPORT_PARAMS* psExportParams, // in
DWORD dwFlags, // in
void *pvAuxInfo, // in
BYTE *pbPrivateKeyBlob, // out
DWORD *pcbPrivateKeyBlob // in, out
) { BOOL fResult = TRUE; void *pvFuncAddr; HCRYPTOIDFUNCADDR hFuncAddr; CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfo = NULL; DWORD cbPrivateKeyInfo = 0; DWORD cbEncoded = 0;
// optional; used during encrypted export
PBYTE pbTmpKeyBlob = NULL; CRYPT_ENCRYPTED_PRIVATE_KEY_INFO sEncryptedKeyInfo; ZeroMemory(&sEncryptedKeyInfo, sizeof(sEncryptedKeyInfo)); if (CryptGetOIDFunctionAddress( hExportPrivKeyFuncSet, X509_ASN_ENCODING, psExportParams->pszPrivateKeyObjId, 0, // dwFlags
&pvFuncAddr, &hFuncAddr)) { if (!((PFN_EXPORT_PRIV_KEY_FUNC) pvFuncAddr)( psExportParams->hCryptProv, psExportParams->dwKeySpec, psExportParams->pszPrivateKeyObjId,
dwFlags & ~GIVE_ME_DATA, // sizeit
pvAuxInfo, NULL, &cbPrivateKeyInfo )) goto ErrorReturn;
if (NULL == (pPrivateKeyInfo = (CRYPT_PRIVATE_KEY_INFO *) SSAlloc(cbPrivateKeyInfo))) goto ErrorReturn;
if (!((PFN_EXPORT_PRIV_KEY_FUNC) pvFuncAddr)(
psExportParams->hCryptProv, psExportParams->dwKeySpec, psExportParams->pszPrivateKeyObjId,
dwFlags, // maybe real data...
pvAuxInfo, pPrivateKeyInfo, &cbPrivateKeyInfo )) goto ErrorReturn;
CryptFreeOIDFunctionAddress(hFuncAddr, 0); } else { // if (CryptGetOIDFunctionAddress())
SetLastError(ERROR_UNSUPPORTED_TYPE); return FALSE; } // encode the private key info struct
if (!CryptEncodeObject( X509_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO, pPrivateKeyInfo, NULL, &cbEncoded)) goto ErrorReturn;
if (NULL == psExportParams->pEncryptPrivateKeyFunc) { // no encryption; this is output buffer
// check to see if the caller specified a buffer and has enough space
if ((pbPrivateKeyBlob != NULL) && (*pcbPrivateKeyBlob >= cbEncoded)) { if (!CryptEncodeObject( X509_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO, pPrivateKeyInfo, pbPrivateKeyBlob, pcbPrivateKeyBlob)) goto ErrorReturn; } else { *pcbPrivateKeyBlob = cbEncoded; if (pbPrivateKeyBlob != NULL) { SetLastError((DWORD) ERROR_MORE_DATA); goto ErrorReturn; } } } else { // we do want to encrypt!!
// always encode: use tmp alloc
pbTmpKeyBlob = (PBYTE)SSAlloc(cbEncoded); if (pbTmpKeyBlob == NULL) goto ErrorReturn; DWORD cbTmpKeyBlob = cbEncoded;
// NOW add optional encryption and encode as ENCR_PRIV_KEY_INFO
CRYPT_DATA_BLOB sClearTextKey = { cbTmpKeyBlob, pbTmpKeyBlob};
// do inner encode
if (!CryptEncodeObject( X509_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO, pPrivateKeyInfo, pbTmpKeyBlob, &cbTmpKeyBlob)) goto ErrorReturn;
// exported the key; encoded as PRIVATE_KEY_INFO.
if (!psExportParams->pEncryptPrivateKeyFunc( &sEncryptedKeyInfo.EncryptionAlgorithm, // out
&sClearTextKey, // in
NULL, // opt
&sEncryptedKeyInfo.EncryptedPrivateKey.cbData, // out
psExportParams->pVoidEncryptFunc)) goto ErrorReturn;
if (NULL == (sEncryptedKeyInfo.EncryptedPrivateKey.pbData = (BYTE*) SSAlloc(sEncryptedKeyInfo.EncryptedPrivateKey.cbData))) goto ErrorReturn;
if (dwFlags & GIVE_ME_DATA) { if (!psExportParams->pEncryptPrivateKeyFunc( &sEncryptedKeyInfo.EncryptionAlgorithm, // out
&sClearTextKey, // in
sEncryptedKeyInfo.EncryptedPrivateKey.pbData, // opt
&sEncryptedKeyInfo.EncryptedPrivateKey.cbData, // out
psExportParams->pVoidEncryptFunc)) goto ErrorReturn; } else { // fill in phony encr key
FillMemory(sEncryptedKeyInfo.EncryptedPrivateKey.pbData, sEncryptedKeyInfo.EncryptedPrivateKey.cbData, 0x69); }
// item is now encrypted; now encode
// encode the private key info struct
if (!CryptEncodeObject( X509_ASN_ENCODING, PKCS_ENCRYPTED_PRIVATE_KEY_INFO, &sEncryptedKeyInfo, NULL, &cbEncoded)) goto ErrorReturn;
// check to see if the caller specified a buffer and has enough space
if ((pbPrivateKeyBlob != NULL) && (*pcbPrivateKeyBlob >= cbEncoded)) { if (!CryptEncodeObject( X509_ASN_ENCODING, PKCS_ENCRYPTED_PRIVATE_KEY_INFO, &sEncryptedKeyInfo, pbPrivateKeyBlob, pcbPrivateKeyBlob)) goto ErrorReturn; } else { *pcbPrivateKeyBlob = cbEncoded; if (pbPrivateKeyBlob != NULL) { SetLastError((DWORD) ERROR_MORE_DATA); goto ErrorReturn; } } }
goto CommonReturn;
ErrorReturn: fResult = FALSE;
CommonReturn: if (pPrivateKeyInfo) SSFree(pPrivateKeyInfo);
if (pbTmpKeyBlob) SSFree(pbTmpKeyBlob);
if (sEncryptedKeyInfo.EncryptedPrivateKey.pbData) SSFree(sEncryptedKeyInfo.EncryptedPrivateKey.pbData);
if (sEncryptedKeyInfo.EncryptionAlgorithm.Parameters.pbData) SSFree(sEncryptedKeyInfo.EncryptionAlgorithm.Parameters.pbData);
return fResult; }
static LONG counter = 0;
// hack function to create a mock RSA private key blob based only on size
BYTE * AllocFakeRSAPrivateKey(DWORD cb) { BLOBHEADER *pBlobHeader; RSAPUBKEY *pKey; BYTE *pByte; DWORD dwJumpSize;
pBlobHeader = (BLOBHEADER *) SSAlloc(cb); if (pBlobHeader == NULL) return NULL;
memset(pBlobHeader, 0, cb);
pBlobHeader->bType = PRIVATEKEYBLOB; pBlobHeader->bVersion = CUR_BLOB_VERSION; pBlobHeader->reserved = 0; pBlobHeader->aiKeyAlg = CALG_RSA_SIGN;
pKey = (RSAPUBKEY *) (((BYTE*) pBlobHeader) + sizeof(BLOBHEADER)); pKey->magic = 0x32415352; pKey->bitlen = ((cb - sizeof(BLOBHEADER) - sizeof(RSAPUBKEY)) / 9) * 2 * 8; pKey->pubexp = 65537;
dwJumpSize = (cb - sizeof(BLOBHEADER) - sizeof(RSAPUBKEY)) / 9; pByte = ((BYTE *) pBlobHeader) + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY); // put some bogus data at the start of the key so
// that we know will be unique for each key so that
// they look different durring a comparison
InterlockedIncrement(&counter); *((LONG *) pByte) = counter;
// most significant byte of modulus
pByte += (dwJumpSize * 2) - 1; *pByte = 0x80;
// most significant byte of prime1
pByte += dwJumpSize; *pByte = 0x80;
// most significant byte of prime2
pByte += dwJumpSize; *pByte = 0x80;
// most significant byte of exponent1
pByte += dwJumpSize; *pByte = 0x80;
// most significant byte of exponent2
pByte += dwJumpSize; *pByte = 0x80;
// most significant byte of coefficient
pByte += dwJumpSize; *pByte = 0x80;
// most significant byte of privateExponent
pByte += dwJumpSize * 2; *pByte = 0x80;
return ((BYTE *)pBlobHeader); }
static BOOL WINAPI ExportRSAPrivateKeyInfo( HCRYPTPROV hCryptProv, // in
DWORD dwKeySpec, // in
LPSTR pszPrivateKeyObjId, // in
DWORD dwFlags, // in
void *pvAuxInfo, // in
CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfo, // out
DWORD *pcbPrivateKeyInfo // in, out
) { BOOL fResult = TRUE; HCRYPTKEY hCryptKey = NULL; BYTE *pKeyBlob = NULL; DWORD cbKeyBlob = 0; BYTE *pEncodedKeyBlob = NULL; DWORD cbEncodedKeyBlob = 0; BYTE *pKeyUsage = NULL; DWORD cbKeyUsage = 0; DWORD dwSize = 0; CRYPT_BIT_BLOB CryptBitBlob; BYTE KeyUsageByte = 0; BYTE *pbCurrentLocation = NULL;
// get a handle to the keyset to export
if (!CryptGetUserKey( hCryptProv, dwKeySpec, &hCryptKey)) goto ErrorReturn;
// export the key set to a CAPI blob
if (!CryptExportKey( hCryptKey, 0, PRIVATEKEYBLOB, 0, NULL, &cbKeyBlob)) goto ErrorReturn;
// make sure the caller REALLY wants the key at this point
if ((dwFlags & PFX_MODE) && !(dwFlags & GIVE_ME_DATA)) { if (NULL == (pKeyBlob = AllocFakeRSAPrivateKey(cbKeyBlob))) goto ErrorReturn; } // if not in PFX export mode or we really want the key then just do normal processing
else { if (NULL == (pKeyBlob = (BYTE *) SSAlloc(cbKeyBlob))) goto ErrorReturn; if (!CryptExportKey( hCryptKey, 0, PRIVATEKEYBLOB, 0, pKeyBlob, &cbKeyBlob)) goto ErrorReturn; }
// encode the key blob to a RSA private key
if (!CryptEncodeObject( X509_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, pKeyBlob, NULL, &cbEncodedKeyBlob)) goto ErrorReturn;
if (NULL == (pEncodedKeyBlob = (BYTE *) SSAlloc(cbEncodedKeyBlob))) goto ErrorReturn; if (!CryptEncodeObject( X509_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, pKeyBlob, pEncodedKeyBlob, &cbEncodedKeyBlob)) goto ErrorReturn; // encode the KEY_USAGE attribute
CryptBitBlob.cbData = 1; CryptBitBlob.pbData = &KeyUsageByte; CryptBitBlob.cUnusedBits = 0; if (((BLOBHEADER *) pKeyBlob)->aiKeyAlg == CALG_RSA_SIGN) KeyUsageByte = CERT_DIGITAL_SIGNATURE_KEY_USAGE; else if (((BLOBHEADER *) pKeyBlob)->aiKeyAlg == CALG_RSA_KEYX) KeyUsageByte = CERT_DATA_ENCIPHERMENT_KEY_USAGE; else { goto ErrorReturn; }
if (!CryptEncodeObject( X509_ASN_ENCODING, X509_BITS, (void *) &CryptBitBlob, NULL, &cbKeyUsage)) goto ErrorReturn;
if (NULL == (pKeyUsage = (BYTE *) SSAlloc(cbKeyUsage))) goto ErrorReturn;
if (!CryptEncodeObject( X509_ASN_ENCODING, X509_BITS, (void *) &CryptBitBlob, pKeyUsage, &cbKeyUsage)) goto ErrorReturn;
// we can now calculate the size needed
dwSize = sizeof(CRYPT_PRIVATE_KEY_INFO) + // main private key info struct
INFO_LEN_ALIGN(sizeof(szOID_RSA_RSA)) + // size of the RSA algorithm identifier string
INFO_LEN_ALIGN(cbEncodedKeyBlob) + // buffer that holds encoded RSA private key
sizeof(CRYPT_ATTRIBUTES) + // struct for private key attributes
sizeof(CRYPT_ATTRIBUTE) + // struct for the one attribute being set, KEY_USAGE
INFO_LEN_ALIGN(sizeof(szOID_KEY_USAGE)) + // size of attribute OID for key usage
sizeof(CRYPT_ATTR_BLOB) + // struct for values in attribute
cbKeyUsage; // size of buffer for encoded attribute
// check to see if the caller passed in a buffer, and enough space
if (pPrivateKeyInfo == NULL) goto CommonReturn; else if (*pcbPrivateKeyInfo < dwSize) { SetLastError((DWORD) ERROR_MORE_DATA); goto ErrorReturn; }
// everything is OK so copy all the information to the caller's buffer
pbCurrentLocation = ((BYTE *) pPrivateKeyInfo) + sizeof(CRYPT_PRIVATE_KEY_INFO); pPrivateKeyInfo->Version = 0; pPrivateKeyInfo->Algorithm.pszObjId = (LPSTR) pbCurrentLocation; memcpy(pbCurrentLocation, szOID_RSA_RSA, sizeof(szOID_RSA_RSA)); pbCurrentLocation += INFO_LEN_ALIGN(sizeof(szOID_RSA_RSA)); pPrivateKeyInfo->Algorithm.Parameters.cbData = 0; // no parameters for RSA
pPrivateKeyInfo->Algorithm.Parameters.pbData = NULL;// no parameters for RSA
pPrivateKeyInfo->PrivateKey.cbData = cbEncodedKeyBlob; pPrivateKeyInfo->PrivateKey.pbData = pbCurrentLocation; memcpy(pbCurrentLocation, pEncodedKeyBlob, cbEncodedKeyBlob); pbCurrentLocation += INFO_LEN_ALIGN(cbEncodedKeyBlob);
pPrivateKeyInfo->pAttributes = (PCRYPT_ATTRIBUTES) pbCurrentLocation; pbCurrentLocation += sizeof(CRYPT_ATTRIBUTES); pPrivateKeyInfo->pAttributes->cAttr = 1; // the only attribute right now is KEY_USAGE
pPrivateKeyInfo->pAttributes->rgAttr = (PCRYPT_ATTRIBUTE) pbCurrentLocation; pbCurrentLocation += sizeof(CRYPT_ATTRIBUTE); pPrivateKeyInfo->pAttributes->rgAttr[0].pszObjId = (LPSTR) pbCurrentLocation; memcpy(pbCurrentLocation, szOID_KEY_USAGE, sizeof(szOID_KEY_USAGE)); pbCurrentLocation += INFO_LEN_ALIGN(sizeof(szOID_KEY_USAGE)); pPrivateKeyInfo->pAttributes->rgAttr[0].cValue = 1; pPrivateKeyInfo->pAttributes->rgAttr[0].rgValue = (PCRYPT_ATTR_BLOB) pbCurrentLocation; pbCurrentLocation += sizeof(CRYPT_ATTR_BLOB); pPrivateKeyInfo->pAttributes->rgAttr[0].rgValue[0].cbData = cbKeyUsage; pPrivateKeyInfo->pAttributes->rgAttr[0].rgValue[0].pbData = pbCurrentLocation; memcpy(pbCurrentLocation, pKeyUsage, cbKeyUsage); goto CommonReturn;
ErrorReturn: fResult = FALSE;
CommonReturn: *pcbPrivateKeyInfo = dwSize;
if (hCryptKey) { DWORD dwErr = GetLastError(); CryptDestroyKey(hCryptKey); SetLastError(dwErr); } if (pKeyBlob) SSFree(pKeyBlob); if (pEncodedKeyBlob) SSFree(pEncodedKeyBlob); if (pKeyUsage) SSFree(pKeyUsage); return fResult; }
static DWORD ResolveKeySpec( PCRYPT_ATTRIBUTES pCryptAttributes) { DWORD i = 0; DWORD dwKeySpec = 0; DWORD cbAttribute = 0; CRYPT_BIT_BLOB *pAttribute = NULL;
if (pCryptAttributes != NULL) while (i < pCryptAttributes->cAttr) { if (lstrcmp(pCryptAttributes->rgAttr[i].pszObjId, szOID_KEY_USAGE) == 0) { if (!CryptDecodeObject( X509_ASN_ENCODING, X509_BITS, pCryptAttributes->rgAttr[i].rgValue->pbData, pCryptAttributes->rgAttr[i].rgValue->cbData, 0, NULL, &cbAttribute )) { i++; continue; } if (NULL == (pAttribute = (CRYPT_BIT_BLOB *) SSAlloc(cbAttribute))) { i++; continue; } if (!CryptDecodeObject( X509_ASN_ENCODING, X509_BITS, pCryptAttributes->rgAttr[i].rgValue->pbData, pCryptAttributes->rgAttr[i].rgValue->cbData, 0, pAttribute, &cbAttribute )) { i++; SSFree(pAttribute); continue; } if ((pAttribute->pbData[0] & CERT_KEY_ENCIPHERMENT_KEY_USAGE) || (pAttribute->pbData[0] & CERT_DATA_ENCIPHERMENT_KEY_USAGE)) { dwKeySpec = AT_KEYEXCHANGE; goto CommonReturn; } else if ((pAttribute->pbData[0] & CERT_DIGITAL_SIGNATURE_KEY_USAGE) || (pAttribute->pbData[0] & CERT_KEY_CERT_SIGN_KEY_USAGE) || (pAttribute->pbData[0] & CERT_CRL_SIGN_KEY_USAGE)) { dwKeySpec = AT_SIGNATURE; goto CommonReturn; } } // if (lstrcmp(pCryptAttributes->rgAttr[i].pszObjId, szOID_KEY_USAGE) == 0)
i++; } // while (i < pCryptAttributes->cAttr)
//ErrorReturn:
CommonReturn: if (pAttribute) SSFree(pAttribute); return dwKeySpec; }
static BOOL WINAPI ImportRSAPrivateKeyInfo( HCRYPTPROV hCryptProv, // in
CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfo, // in
DWORD dwFlags, // in, optional
void *pvAuxInfo // in, optional
) { BOOL fResult = TRUE; DWORD cbRSAPrivateKey = 0; BYTE *pbRSAPrivateKey = NULL; HCRYPTKEY hCryptKey = NULL; DWORD dwKeySpec = 0;
// decode the rsa der-encoded keyblob into a CAPI type keyblob
if (!CryptDecodeObject(X509_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, pPrivateKeyInfo->PrivateKey.pbData, pPrivateKeyInfo->PrivateKey.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &cbRSAPrivateKey)) goto ErrorReturn;
if (NULL == (pbRSAPrivateKey = (BYTE *) SSAlloc(cbRSAPrivateKey))) goto ErrorReturn;
if (!CryptDecodeObject(X509_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, pPrivateKeyInfo->PrivateKey.pbData, pPrivateKeyInfo->PrivateKey.cbData, CRYPT_DECODE_NOCOPY_FLAG, pbRSAPrivateKey, &cbRSAPrivateKey)) goto ErrorReturn; // figure out what keyspec to use and manually set the algid in the keyblob accordingly
dwKeySpec = ResolveKeySpec(pPrivateKeyInfo->pAttributes); if ((dwKeySpec == AT_KEYEXCHANGE) || (dwKeySpec == 0)) ((BLOBHEADER *) pbRSAPrivateKey)->aiKeyAlg = CALG_RSA_KEYX; else ((BLOBHEADER *) pbRSAPrivateKey)->aiKeyAlg = CALG_RSA_SIGN;
// import this thing
if (!CryptImportKey(hCryptProv, pbRSAPrivateKey, cbRSAPrivateKey, 0, dwFlags & (CRYPT_EXPORTABLE | CRYPT_USER_PROTECTED), // mask the flags that are used
&hCryptKey)) // during the CryptImportKey
goto ErrorReturn;
goto CommonReturn;
ErrorReturn: fResult = FALSE;
CommonReturn: if (pbRSAPrivateKey) SSFree(pbRSAPrivateKey); if (hCryptKey) CryptDestroyKey(hCryptKey);
return fResult;
}
#ifndef DSS2
#define DSS2 ((DWORD)'D'+((DWORD)'S'<<8)+((DWORD)'S'<<16)+((DWORD)'2'<<24))
#endif
#ifndef DSS_Q_LEN
#define DSS_Q_LEN 20
#endif
// hack function to create a mock RSA private key blob based only on size
BYTE * AllocFakeDSSPrivateKey(DWORD cb) { BLOBHEADER *pBlobHeader; DSSPUBKEY *pCspPubKey = NULL; BYTE *pbKeyBlob; BYTE *pbKey; DWORD cbKey; DSSSEED *pCspSeed = NULL;
pBlobHeader = (BLOBHEADER *) SSAlloc(cb); if (pBlobHeader == NULL) return NULL;
memset(pBlobHeader, 0, cb);
pbKeyBlob = (BYTE *) pBlobHeader; pCspPubKey = (DSSPUBKEY *) (pbKeyBlob + sizeof(BLOBHEADER)); pbKey = pbKeyBlob + sizeof(BLOBHEADER) + sizeof(DSSPUBKEY);
// BLOBHEADER
pBlobHeader->bType = PRIVATEKEYBLOB; pBlobHeader->bVersion = CUR_BLOB_VERSION; pBlobHeader->reserved = 0; pBlobHeader->aiKeyAlg = CALG_DSS_SIGN;
// DSSPUBKEY
pCspPubKey->magic = DSS2; cbKey = (cb - sizeof(BLOBHEADER) - sizeof(DSSPUBKEY) - (2 * DSS_Q_LEN) - sizeof(DSSSEED)) / 2; pCspPubKey->bitlen = cbKey * 8;
// put some bogus data at the start of the key so
// that we know will be unique for each key so that
// they look different durring a comparison
InterlockedIncrement(&counter); // rgbP[cbKey]
memset(pbKey, counter, cbKey); pbKey += cbKey; *(pbKey-1) = 0x80;
// rgbQ[20]
memset(pbKey, counter, DSS_Q_LEN); pbKey += DSS_Q_LEN; *(pbKey-1) = 0x80; // rgbG[cbKey]
memset(pbKey, counter, cbKey); pbKey += cbKey; *(pbKey-1) = 0x80;
// rgbX[20]
memset(pbKey, counter, DSS_Q_LEN); pbKey += DSS_Q_LEN; *(pbKey-1) = 0x80; // DSSSEED: set counter to 0xFFFFFFFF to indicate not available
pCspSeed = (DSSSEED *) pbKey; memset(&pCspSeed->counter, 0xFF, sizeof(pCspSeed->counter));
return ((BYTE *)pBlobHeader); }
static BOOL WINAPI ExportDSSPrivateKeyInfo( HCRYPTPROV hCryptProv, // in
DWORD dwKeySpec, // in
LPSTR pszPrivateKeyObjId, // in
DWORD dwFlags, // in
void *pvAuxInfo, // in
CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfo, // out
DWORD *pcbPrivateKeyInfo // in, out
) { BOOL fResult = TRUE; HCRYPTKEY hCryptKey = NULL; BYTE *pbKeyBlob = NULL; DWORD cbKeyBlob = 0; BYTE *pbEncodedPrivateKeyBlob = NULL; DWORD cbEncodedPrivateKeyBlob = 0; BYTE *pbEncodedParameters = NULL; DWORD cbEncodedParameters = 0; CRYPT_INTEGER_BLOB PrivateKeyBlob; CERT_DSS_PARAMETERS DssParameters; DWORD cbKey; DSSPUBKEY *pCspPubKey = NULL; BYTE *pbBytes; DWORD dwSize = 0; BYTE *pbCurrentLocation; // get a handle to the keyset to export
if (!CryptGetUserKey( hCryptProv, dwKeySpec, &hCryptKey)) goto ErrorReturn;
// export the key set to a CAPI blob
if (!CryptExportKey( hCryptKey, 0, PRIVATEKEYBLOB, 0, NULL, &cbKeyBlob)) goto ErrorReturn;
// make sure the caller REALLY wants the key at this point
if ((dwFlags & PFX_MODE) && !(dwFlags & GIVE_ME_DATA)) { if (NULL == (pbKeyBlob = AllocFakeDSSPrivateKey(cbKeyBlob))) goto ErrorReturn; } // if not in PFX export mode or we really want the key then just do normal processing
else { if (NULL == (pbKeyBlob = (BYTE *) SSAlloc(cbKeyBlob))) goto ErrorReturn; if (!CryptExportKey( hCryptKey, 0, PRIVATEKEYBLOB, 0, pbKeyBlob, &cbKeyBlob)) goto ErrorReturn; }
pCspPubKey = (DSSPUBKEY *) (pbKeyBlob + sizeof(BLOBHEADER)); pbBytes = pbKeyBlob + sizeof(PUBLICKEYSTRUC) + sizeof(DSSPUBKEY); cbKey = pCspPubKey->bitlen / 8;
// encode the DSS paramaters
memset(&DssParameters, 0, sizeof(CERT_DSS_PARAMETERS)); DssParameters.p.cbData = cbKey; DssParameters.p.pbData = pbBytes; pbBytes += cbKey; DssParameters.q.cbData = DSS_Q_LEN; DssParameters.q.pbData = pbBytes; pbBytes += DSS_Q_LEN; DssParameters.g.cbData = cbKey; DssParameters.g.pbData = pbBytes; pbBytes += cbKey;
if (!CryptEncodeObject( X509_ASN_ENCODING, X509_DSS_PARAMETERS, &DssParameters, NULL, &cbEncodedParameters)) goto ErrorReturn;
if (NULL == (pbEncodedParameters = (BYTE *) SSAlloc(cbEncodedParameters))) goto ErrorReturn;
if (!CryptEncodeObject( X509_ASN_ENCODING, X509_DSS_PARAMETERS, &DssParameters, pbEncodedParameters, &cbEncodedParameters)) goto ErrorReturn;
// encode the key DSS private key
PrivateKeyBlob.cbData = DSS_Q_LEN; PrivateKeyBlob.pbData = pbBytes;
if (!CryptEncodeObject( X509_ASN_ENCODING, X509_MULTI_BYTE_INTEGER, &PrivateKeyBlob, NULL, &cbEncodedPrivateKeyBlob)) goto ErrorReturn;
if (NULL == (pbEncodedPrivateKeyBlob = (BYTE *) SSAlloc(cbEncodedPrivateKeyBlob))) goto ErrorReturn; if (!CryptEncodeObject( X509_ASN_ENCODING, X509_MULTI_BYTE_INTEGER, &PrivateKeyBlob, pbEncodedPrivateKeyBlob, &cbEncodedPrivateKeyBlob)) goto ErrorReturn; // we can now calculate the size needed
dwSize = sizeof(CRYPT_PRIVATE_KEY_INFO) + // main private key info struct
sizeof(szOID_X957_DSA) + // size of the DSA algorithm identifier string
cbEncodedParameters + // size of the DSA parameters
cbEncodedPrivateKeyBlob; // buffer that holds encoded DSS private key
// check to see if the caller passed in a buffer, and enough space
if (pPrivateKeyInfo == NULL) goto CommonReturn; else if (*pcbPrivateKeyInfo < dwSize) { SetLastError((DWORD) ERROR_MORE_DATA); goto ErrorReturn; }
// everything is OK so copy all the information to the caller's buffer
pbCurrentLocation = ((BYTE *) pPrivateKeyInfo) + sizeof(CRYPT_PRIVATE_KEY_INFO); pPrivateKeyInfo->Version = 0; pPrivateKeyInfo->Algorithm.pszObjId = (LPSTR) pbCurrentLocation; memcpy(pbCurrentLocation, szOID_X957_DSA, sizeof(szOID_X957_DSA)); pbCurrentLocation += sizeof(szOID_X957_DSA); pPrivateKeyInfo->Algorithm.Parameters.cbData = cbEncodedParameters; pPrivateKeyInfo->Algorithm.Parameters.pbData = pbCurrentLocation; memcpy(pbCurrentLocation, pbEncodedParameters, cbEncodedParameters); pbCurrentLocation += cbEncodedParameters;
pPrivateKeyInfo->PrivateKey.cbData = cbEncodedPrivateKeyBlob; pPrivateKeyInfo->PrivateKey.pbData = pbCurrentLocation; memcpy(pbCurrentLocation, pbEncodedPrivateKeyBlob, cbEncodedPrivateKeyBlob); pbCurrentLocation += cbEncodedPrivateKeyBlob;
pPrivateKeyInfo->pAttributes = NULL; goto CommonReturn;
ErrorReturn: fResult = FALSE;
CommonReturn: *pcbPrivateKeyInfo = dwSize;
if (hCryptKey) { DWORD dwErr = GetLastError(); CryptDestroyKey(hCryptKey); SetLastError(dwErr); } if (pbKeyBlob) SSFree(pbKeyBlob); if (pbEncodedParameters) SSFree(pbEncodedParameters); if (pbEncodedPrivateKeyBlob) SSFree(pbEncodedPrivateKeyBlob);
return fResult; }
static BOOL WINAPI ImportDSSPrivateKeyInfo( HCRYPTPROV hCryptProv, // in
CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfo, // in
DWORD dwFlags, // in, optional
void *pvAuxInfo // in, optional
) { BOOL fResult = TRUE; DWORD cbDSSPrivateKey = 0; CRYPT_DATA_BLOB *pbDSSPrivateKey = NULL; HCRYPTKEY hCryptKey = NULL; DWORD dwKeySpec = 0; DWORD cbParameters = 0; PCERT_DSS_PARAMETERS pDssParameters = NULL; BLOBHEADER *pPrivateKeyBlob = NULL; DWORD cbPrivateKeyStruc = 0; DSSPUBKEY *pCspPubKey = NULL; DSSSEED *pCspSeed = NULL; BYTE *pbKey = NULL; BYTE *pbKeyBlob = NULL; DWORD cb; DWORD cbKey;
// decode the DSS private key
if (!CryptDecodeObject(X509_ASN_ENCODING, X509_MULTI_BYTE_UINT, pPrivateKeyInfo->PrivateKey.pbData, pPrivateKeyInfo->PrivateKey.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &cbDSSPrivateKey)) goto ErrorReturn;
if (NULL == (pbDSSPrivateKey = (CRYPT_DATA_BLOB *) SSAlloc(cbDSSPrivateKey))) { SetLastError(E_OUTOFMEMORY); goto ErrorReturn; }
if (!CryptDecodeObject(X509_ASN_ENCODING, X509_MULTI_BYTE_UINT, pPrivateKeyInfo->PrivateKey.pbData, pPrivateKeyInfo->PrivateKey.cbData, CRYPT_DECODE_NOCOPY_FLAG, pbDSSPrivateKey, &cbDSSPrivateKey)) goto ErrorReturn;
// decode the DSS parameters
if (!CryptDecodeObject( X509_ASN_ENCODING, X509_DSS_PARAMETERS, pPrivateKeyInfo->Algorithm.Parameters.pbData, pPrivateKeyInfo->Algorithm.Parameters.cbData, 0, NULL, &cbParameters )) goto ErrorReturn; if (NULL == (pDssParameters = (PCERT_DSS_PARAMETERS) SSAlloc(cbParameters))) { SetLastError(E_OUTOFMEMORY); goto ErrorReturn; }
if (!CryptDecodeObject( X509_ASN_ENCODING, X509_DSS_PARAMETERS, pPrivateKeyInfo->Algorithm.Parameters.pbData, pPrivateKeyInfo->Algorithm.Parameters.cbData, 0, pDssParameters, &cbParameters )) goto ErrorReturn;
// The CAPI private key representation consists of the following sequence:
// - BLOBHEADER
// - DSSPUBKEY
// - rgbP[cbKey]
// - rgbQ[20]
// - rgbG[cbKey]
// - rgbX[20]
// - DSSSEED
cbKey = pDssParameters->p.cbData; if (0 == cbKey) goto ErrorInvalidKey;
cbPrivateKeyStruc = sizeof(BLOBHEADER) + sizeof(DSSPUBKEY) + cbKey + DSS_Q_LEN + cbKey + DSS_Q_LEN + sizeof(DSSSEED);
if (NULL == (pPrivateKeyBlob = (BLOBHEADER *) SSAlloc(cbPrivateKeyStruc))) { SetLastError(E_OUTOFMEMORY); goto ErrorReturn; } pbKeyBlob = (BYTE *) pPrivateKeyBlob; pCspPubKey = (DSSPUBKEY *) (pbKeyBlob + sizeof(BLOBHEADER)); pbKey = pbKeyBlob + sizeof(BLOBHEADER) + sizeof(DSSPUBKEY);
// NOTE, the length of G can be less than the length of P.
// The CSP requires G to be padded out with 0x00 bytes if it
// is less and in little endian form
// BLOBHEADER
pPrivateKeyBlob->bType = PRIVATEKEYBLOB; pPrivateKeyBlob->bVersion = CUR_BLOB_VERSION; pPrivateKeyBlob->reserved = 0; pPrivateKeyBlob->aiKeyAlg = CALG_DSS_SIGN;
// DSSPUBKEY
pCspPubKey->magic = DSS2; pCspPubKey->bitlen = cbKey * 8;
// rgbP[cbKey]
memcpy(pbKey, pDssParameters->p.pbData, cbKey); pbKey += cbKey;
// rgbQ[20]
cb = pDssParameters->q.cbData; if (0 == cb || cb > DSS_Q_LEN) goto ErrorInvalidKey; memcpy(pbKey, pDssParameters->q.pbData, cb); if (DSS_Q_LEN > cb) memset(pbKey + cb, 0, DSS_Q_LEN - cb); pbKey += DSS_Q_LEN;
// rgbG[cbKey]
cb = pDssParameters->g.cbData; if (0 == cb || cb > cbKey) goto ErrorInvalidKey; memcpy(pbKey, pDssParameters->g.pbData, cb); if (cbKey > cb) memset(pbKey + cb, 0, cbKey - cb); pbKey += cbKey;
// rgbX[20]
cb = pbDSSPrivateKey->cbData; if (0 == cb || cb > DSS_Q_LEN) goto ErrorInvalidKey; memcpy(pbKey, pbDSSPrivateKey->pbData, cb); if (DSS_Q_LEN > cb) memset(pbKey + cb, 0, DSS_Q_LEN - cb); pbKey += DSS_Q_LEN;
// DSSSEED: set counter to 0xFFFFFFFF to indicate not available
pCspSeed = (DSSSEED *) pbKey; memset(&pCspSeed->counter, 0xFF, sizeof(pCspSeed->counter));
// import this thing
if (!CryptImportKey(hCryptProv, (BYTE *)pPrivateKeyBlob, cbPrivateKeyStruc, 0, dwFlags & (CRYPT_EXPORTABLE | CRYPT_USER_PROTECTED), // mask the flags that are used
&hCryptKey)) // during the CryptImportKey
{ DWORD dw = GetLastError(); goto ErrorReturn; }
goto CommonReturn;
ErrorInvalidKey: SetLastError(E_INVALIDARG);
ErrorReturn: fResult = FALSE;
CommonReturn: if (pbDSSPrivateKey) SSFree(pbDSSPrivateKey); if (pDssParameters) SSFree(pDssParameters); if (pPrivateKeyBlob) SSFree(pPrivateKeyBlob); if (hCryptKey) CryptDestroyKey(hCryptKey);
return fResult;
}
|