|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: pfxmain.cpp
//
//--------------------------------------------------------------------------
#include "global.hxx"
#include <wincrypt.h>
#include "pfxhelp.h"
#include "pfxcmn.h"
#include "pfxcrypt.h"
#include "pfx.h"
#include "impexppk.h"
#include "encdecpk.h"
#include <rpcdce.h>
HINSTANCE g_hInst;
BOOL WINAPI CryptPFXDllMain( HMODULE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) {
if (!ImportExportDllMain(hInst, ul_reason_for_call, lpReserved)) { goto ImportExportError; }
if (!EncodeDecodeDllMain(hInst, ul_reason_for_call, lpReserved)) { goto EncodeDecodeError; }
switch( ul_reason_for_call ) { case DLL_PROCESS_ATTACH: g_hInst = hInst;
if (!InitPFX()) goto InitPFXError; if (!InitNSCP()) goto InitNSCPError;
break;
case DLL_PROCESS_DETACH: TerminatePFX(); TerminateNSCP(); break;
default: break; }
return TRUE;
InitNSCPError: TerminatePFX(); InitPFXError: EncodeDecodeDllMain(hInst, DLL_PROCESS_DETACH, NULL); EncodeDecodeError: ImportExportDllMain(hInst, DLL_PROCESS_DETACH, NULL); ImportExportError: return FALSE; }
BOOL FreeCryptSafeContents( SAFE_CONTENTS *pSafeContents ) { DWORD i,j,k;
// loop for each SAFE_BAG
for (i=0; i<pSafeContents->cSafeBags; i++) {
if (pSafeContents->pSafeBags[i].pszBagTypeOID) SSFree(pSafeContents->pSafeBags[i].pszBagTypeOID);
if (pSafeContents->pSafeBags[i].BagContents.pbData) SSFree(pSafeContents->pSafeBags[i].BagContents.pbData);
// loop for each attribute
for (j=0; j<pSafeContents->pSafeBags[i].Attributes.cAttr; j++) { if (pSafeContents->pSafeBags[i].Attributes.rgAttr[j].pszObjId) SSFree(pSafeContents->pSafeBags[i].Attributes.rgAttr[j].pszObjId);
// l0op for each value
for (k=0; k<pSafeContents->pSafeBags[i].Attributes.rgAttr[j].cValue; k++) { if (pSafeContents->pSafeBags[i].Attributes.rgAttr[j].rgValue[k].pbData) SSFree(pSafeContents->pSafeBags[i].Attributes.rgAttr[j].rgValue[k].pbData); }
// free the value struct array
if (pSafeContents->pSafeBags[i].Attributes.rgAttr[j].rgValue) SSFree(pSafeContents->pSafeBags[i].Attributes.rgAttr[j].rgValue); }
// free the attribute struct array
if (pSafeContents->pSafeBags[i].Attributes.rgAttr) SSFree(pSafeContents->pSafeBags[i].Attributes.rgAttr); }
if (pSafeContents->pSafeBags) SSFree(pSafeContents->pSafeBags);
return TRUE; }
BOOL CALLBACK Decrypt_Private_Key( CRYPT_ALGORITHM_IDENTIFIER Alg, CRYPT_DATA_BLOB EncrBlob, BYTE* pbClearText, DWORD* pcbClearText, LPVOID pVoidDecrypt) { BOOL fRet = TRUE; DWORD cbSalt = 0; BYTE *pbSalt = NULL; int iIterationCount; int iEncrType; BYTE *pbTempBuffer = NULL; DWORD cbTempBuffer = 0; if (0 == strcmp(Alg.pszObjId, szOID_PKCS_12_pbeWithSHA1And40BitRC2)) { iEncrType = RC2_40; } else if (0 == strcmp(Alg.pszObjId, szOID_PKCS_12_pbeWithSHA1And3KeyTripleDES)) { iEncrType = TripleDES; } else goto ErrorReturn;
if (!GetSaltAndIterationCount( Alg.Parameters.pbData, Alg.Parameters.cbData, &pbSalt, &cbSalt, &iIterationCount)) { goto ErrorReturn; } // since the decode is done in-place, copy the buffer to decode into a temp buffer,
// we need to use our temp buffer because the decrypt function may do a realloc
// on the decode buffer
if (NULL == (pbTempBuffer = (BYTE *) SSAlloc(EncrBlob.cbData))) goto ErrorReturn;
memcpy(pbTempBuffer, EncrBlob.pbData, EncrBlob.cbData); cbTempBuffer = EncrBlob.cbData;
if (!PFXPasswordDecryptData( iEncrType, (LPWSTR) pVoidDecrypt,
iIterationCount, pbSalt, cbSalt,
&pbTempBuffer, &cbTempBuffer)) goto SetPFXDecryptError;
// if pcbClearText is not 0 and there is not enough space then error out
if ((0 != *pcbClearText) && (*pcbClearText < cbTempBuffer)){ *pcbClearText = cbTempBuffer; goto Ret; } else if (0 != *pcbClearText) { memcpy(pbClearText, pbTempBuffer, cbTempBuffer); }
*pcbClearText = cbTempBuffer;
goto Ret;
SetPFXDecryptError: SetLastError(NTE_FAIL); fRet = FALSE; goto Ret;
ErrorReturn: fRet = FALSE; Ret: if (pbSalt) SSFree(pbSalt);
if (pbTempBuffer) SSFree(pbTempBuffer);
return fRet; }
typedef struct _ENCRYPT_PRIVATE_PARAM_DATASTRUCT { HCRYPTPROV hVerifyProv; LPCWSTR szPwd; } ENCRYPT_PRIVATE_PARAM_DATASTRUCT, *PENCRYPT_PRIVATE_PARAM_DATASTRUCT;
BOOL CALLBACK Encrypt_Private_Key( CRYPT_ALGORITHM_IDENTIFIER* pAlg, CRYPT_DATA_BLOB* pClearTextPrivateKey, BYTE* pbEncryptedKey, DWORD* pcbEncryptedKey, LPVOID pVoidEncrypt) { BOOL fRet = TRUE; DWORD cbSalt = 0; BYTE *pbSalt = NULL; int iIterationCount; int iEncrType; BYTE *pbTempBuffer = NULL; DWORD cbTempBuffer = 0;
// crack param
ENCRYPT_PRIVATE_PARAM_DATASTRUCT* pParam = (ENCRYPT_PRIVATE_PARAM_DATASTRUCT*)pVoidEncrypt; HCRYPTPROV hVerifyProv = pParam->hVerifyProv; LPCWSTR szPwd = pParam->szPwd; // use hardcoded params
iEncrType = TripleDES; iIterationCount = PKCS12_ENCR_PWD_ITERATIONS; pbSalt = (BYTE *) SSAlloc(PBE_SALT_LENGTH); if (pbSalt == NULL) goto SetPFXAllocError;
cbSalt = PBE_SALT_LENGTH;
if (!CryptGenRandom(hVerifyProv, cbSalt, pbSalt)) goto ErrorReturn;
// out param
pAlg->pszObjId = szOID_PKCS_12_pbeWithSHA1And3KeyTripleDES;
if (!SetSaltAndIterationCount( &pAlg->Parameters.pbData, &pAlg->Parameters.cbData, pbSalt, cbSalt, iIterationCount)) { goto ErrorReturn; } // since the decode is done in-place, copy the buffer to decode into a temp buffer,
// we need to use our temp buffer because the decrypt function may do a realloc
// on the decode buffer
if (NULL == (pbTempBuffer = (BYTE *) SSAlloc(pClearTextPrivateKey->cbData))) goto SetPFXAllocError;
CopyMemory(pbTempBuffer, pClearTextPrivateKey->pbData, pClearTextPrivateKey->cbData); cbTempBuffer = pClearTextPrivateKey->cbData;
if (!PFXPasswordEncryptData( iEncrType, szPwd,
(pbEncryptedKey == NULL) ? 1 : iIterationCount, // don't bother iterating if we're just sizing
pbSalt, cbSalt,
&pbTempBuffer, &cbTempBuffer)) goto SetPFXDecryptError;
// if pcbEncryptedKey is not 0 and there is not enough space then error out
if (pbEncryptedKey == NULL) { // just sizing; return cb
*pcbEncryptedKey = cbTempBuffer; goto Ret; } else if (*pcbEncryptedKey < cbTempBuffer) { // buffer passed in too small
*pcbEncryptedKey = cbTempBuffer; goto ErrorReturn; } else { // buffer sufficient
memcpy(pbEncryptedKey, pbTempBuffer, cbTempBuffer); *pcbEncryptedKey = cbTempBuffer; }
goto Ret;
SetPFXDecryptError: SetLastError(NTE_FAIL); fRet = FALSE; goto Ret;
SetPFXAllocError: SetLastError(ERROR_NOT_ENOUGH_MEMORY); fRet = FALSE; goto Ret;
ErrorReturn: fRet = FALSE; Ret: if (pbSalt) SSFree(pbSalt);
if (pbTempBuffer) SSFree(pbTempBuffer);
return fRet; }
BOOL GetNamedProviderType( LPCWSTR pwszProvName, DWORD *pdwProvType) { BOOL fResult = FALSE; LPWSTR pwszTempProvName; DWORD cbTempProvName; DWORD dwProvType; DWORD dwProvIndex;
for (dwProvIndex = 0; TRUE; dwProvIndex++) { cbTempProvName = 0; dwProvType = 0; pwszTempProvName = NULL;
if (!CryptEnumProvidersU( dwProvIndex, NULL, // pdwReserved
0, // dwFlags
&dwProvType, NULL, // pwszProvName,
&cbTempProvName ) || 0 == cbTempProvName) { if (ERROR_NO_MORE_ITEMS != GetLastError()) { break; } } if (NULL == (pwszTempProvName = (LPWSTR) SSAlloc( (cbTempProvName + 1) * sizeof(WCHAR)))) { break; }
if (!CryptEnumProvidersU( dwProvIndex, NULL, // pdwReserved
0, // dwFlags
&dwProvType, pwszTempProvName, &cbTempProvName )) { SSFree(pwszTempProvName); break; }
if (0 == wcscmp(pwszTempProvName, pwszProvName)) { *pdwProvType = dwProvType; fResult = TRUE; SSFree(pwszTempProvName); break; }
SSFree(pwszTempProvName); }
return fResult; }
BOOL CALLBACK HCryptProv_Query_Func( CRYPT_PRIVATE_KEY_INFO *pPrivateKeyInfo, DWORD dwSafeBagIndex, HCRYPTPROV *phCryptProv, LPVOID pVoidhCryptProvQuery, DWORD dwPFXImportFlags ) { DWORD dwErr = ERROR_SUCCESS;
SAFE_CONTENTS *pSafeContents = (SAFE_CONTENTS *) pVoidhCryptProvQuery; DWORD i = 0; WCHAR szName[256]; DWORD dwLocalMachineFlag = 0; GUID guidContainerName; DWORD cbProviderName = 0; CERT_NAME_VALUE *providerName = NULL; LPWSTR szSizeDeterminedProvider = NULL; DWORD dwKeyBitLen; DWORD dwProvType; RPC_STATUS rpcStatus;
// UNDONE: support other than RSA or DSA keys
if ((pPrivateKeyInfo->Algorithm.pszObjId) && !( (0 == strcmp(pPrivateKeyInfo->Algorithm.pszObjId, szOID_RSA_RSA)) || (0 == strcmp(pPrivateKeyInfo->Algorithm.pszObjId, szOID_ANSI_X942_DH)) || (0 == strcmp(pPrivateKeyInfo->Algorithm.pszObjId, szOID_OIWSEC_dsa)) || (0 == strcmp(pPrivateKeyInfo->Algorithm.pszObjId, szOID_X957_DSA)))) { SetLastError(NTE_BAD_ALGID); goto ErrorReturn; }
// generate a GUID as the containter name for the keyset being imported
rpcStatus = UuidCreate(&guidContainerName); if ((rpcStatus != RPC_S_OK) && (rpcStatus != RPC_S_UUID_LOCAL_ONLY)) { SetLastError(rpcStatus); goto ErrorReturn; } guid2wstr(&guidContainerName, &(szName[0]));
// get the provider name
while ((i<pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.cAttr) && (strcmp(pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr[i].pszObjId, szOID_PKCS_12_KEY_PROVIDER_NAME_ATTR) != 0)) { i++; }
// check to see if a provider name was found
if (i<pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.cAttr) { // decode the provider name
if (!CryptDecodeObject( X509_ASN_ENCODING, X509_UNICODE_ANY_STRING, pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr[i].rgValue[0].pbData, pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr[i].rgValue[0].cbData, 0, NULL, &cbProviderName)) { goto ErrorReturn; }
if (NULL == (providerName = (CERT_NAME_VALUE *) SSAlloc(cbProviderName))) goto SetPFXAllocError; // decode the provider name
if (!CryptDecodeObject( X509_ASN_ENCODING, X509_UNICODE_ANY_STRING, pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr[i].rgValue[0].pbData, pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr[i].rgValue[0].cbData, 0, (BYTE *) providerName, &cbProviderName)) { goto ErrorReturn; } } // check to see if the szOID_LOCAL_MACHINE_KEYSET OID is present
i = 0; while ((i<pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.cAttr) && (strcmp(pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr[i].pszObjId, szOID_LOCAL_MACHINE_KEYSET) != 0)) { i++; } if (i<pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.cAttr) { dwLocalMachineFlag = CRYPT_MACHINE_KEYSET; }
// regardless of whether the CRYPT_MACHINE_KEYSET property was in the pfx blob,
// if the caller specifies a preference of user or local machine honor that
// preference ultimately
if (dwPFXImportFlags & CRYPT_MACHINE_KEYSET) { dwLocalMachineFlag = CRYPT_MACHINE_KEYSET; } else if (dwPFXImportFlags & CRYPT_USER_KEYSET) { dwLocalMachineFlag = 0; }
// still don't know where to put this: need keysize to determine
if ((NULL == providerName) && (0 == strcmp(pPrivateKeyInfo->Algorithm.pszObjId, szOID_RSA_RSA))) { PBYTE pbRSAPrivateKey = NULL; DWORD cbRSAPrivateKey;
// 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 SetPFXAllocError;
if (!CryptDecodeObject(X509_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, pPrivateKeyInfo->PrivateKey.pbData, pPrivateKeyInfo->PrivateKey.cbData, CRYPT_DECODE_NOCOPY_FLAG, pbRSAPrivateKey, &cbRSAPrivateKey)) { if (pbRSAPrivateKey) SSFree(pbRSAPrivateKey);
goto ErrorReturn; }
dwKeyBitLen = ((RSAPUBKEY*) (pbRSAPrivateKey + sizeof(BLOBHEADER)) )->bitlen;
szSizeDeterminedProvider = (dwKeyBitLen <= 1024) ? MS_DEF_PROV_W : MS_ENHANCED_PROV_W;
ZeroMemory(pbRSAPrivateKey, cbRSAPrivateKey); SSFree(pbRSAPrivateKey); } if (0 == strcmp(pPrivateKeyInfo->Algorithm.pszObjId, szOID_RSA_RSA)) { if ((providerName == NULL) || (!GetNamedProviderType((LPWSTR)providerName->Value.pbData, &dwProvType))) { dwProvType = PROV_RSA_FULL; }
// if we have a prov name AND acq works, we're done
// try prov name if given to us
if (CryptAcquireContextU( phCryptProv, szName, (providerName != NULL) ? (LPWSTR)providerName->Value.pbData : szSizeDeterminedProvider, dwProvType, dwLocalMachineFlag | CRYPT_NEWKEYSET )) goto CommonReturn;
// otherwise attempt default
if (CryptAcquireContextU( phCryptProv, szName, NULL, PROV_RSA_FULL, dwLocalMachineFlag | CRYPT_NEWKEYSET )) goto CommonReturn;
// Neither succeeded; fail
} else { if ((providerName == NULL) || (!GetNamedProviderType((LPWSTR)providerName->Value.pbData, &dwProvType))) { dwProvType = PROV_DSS_DH; } if (CryptAcquireContextU( phCryptProv, szName, (providerName != NULL) ? (LPWSTR)providerName->Value.pbData : MS_DEF_DSS_DH_PROV_W, dwProvType, dwLocalMachineFlag | CRYPT_NEWKEYSET )) { goto CommonReturn; } else if (CryptAcquireContextU( phCryptProv, szName, NULL, PROV_DSS_DH, dwLocalMachineFlag | CRYPT_NEWKEYSET )) { goto CommonReturn; }
// did not succeed, so fail
}
ErrorReturn: dwErr = GetLastError(); goto CommonReturn;
SetPFXAllocError: dwErr = ERROR_NOT_ENOUGH_MEMORY; goto CommonReturn;
CommonReturn: if (providerName) SSFree(providerName);
return (ERROR_SUCCESS == dwErr); }
IMPORT_SAFE_CALLBACK_STRUCT g_sImportCallbacks = {HCryptProv_Query_Func, NULL, Decrypt_Private_Key, NULL};
//+-------------------------------------------------------------------------
// PFXImportCertStore
//
// Import the PFX blob and return a store containing certificates
//
// if the password parameter is incorrect or any other problems decoding
// the PFX blob are encountered, the function will return NULL and the
// error code can be found from GetLastError().
//
// The dwFlags parameter may be set to:
// CRYPT_EXPORTABLE - which would then specify that any imported keys should
// be marked as exportable (see documentation on CryptImportKey)
// CRYPT_USER_PROTECTED - (see documentation on CryptImportKey)
// PKCS12_NO_DATA_COMMIT - will unpack the pfx blob but does not persist its contents.
// In this case, returns BOOL indicating successful unpack.
// CRYPT_MACHINE_KEYSET - used to force the private key to be stored in the
// the local machine and not the current user.
// CRYPT_USER_KEYSET - used to force the private key to be stored in the
// the current user and not the local machine, even if
// the pfx blob specifies that it should go into local machine.
//--------------------------------------------------------------------------
#define PKCS12_NO_DATA_COMMIT 0x10000000 // unpack but don't persist results
HCERTSTORE WINAPI PFXImportCertStore( CRYPT_DATA_BLOB* pPFX, LPCWSTR szPassword, DWORD dwFlags) { BOOL fRet = FALSE; BOOL fDataCommit = TRUE; HPFX hPfx = NULL; HCERTSTORE hStore = NULL; SAFE_CONTENTS sContents; MAKEZERO(sContents); SAFE_CONTENTS *pSafeContents = NULL; LPCWSTR szOldNetscapeNull = L""; LPCWSTR szNetscapePassword = NULL;
if (dwFlags & ~( CRYPT_EXPORTABLE | CRYPT_USER_PROTECTED | PKCS12_NO_DATA_COMMIT | CRYPT_MACHINE_KEYSET | CRYPT_USER_KEYSET)) { SetLastError(ERROR_INVALID_PARAMETER); goto Ret; }
if ((pPFX == NULL)) { SetLastError(ERROR_INVALID_PARAMETER); goto Ret; }
// shall we commit the data we unpack?
if (PKCS12_NO_DATA_COMMIT == (dwFlags & PKCS12_NO_DATA_COMMIT)) { // no
fDataCommit = FALSE; } else { // yes, open a store to populate
hStore = CertOpenStore( CERT_STORE_PROV_MEMORY, 0, NULL, 0, NULL); } // try to import as real PKCS12
if (NULL != (hPfx = PfxImportBlob ( szPassword, pPFX->pbData, pPFX->cbData, dwFlags)) ) { // break out if not saving data
if (!fDataCommit) { fRet = TRUE; goto Ret; }
// import all private keys and certs
if (PfxGetKeysAndCerts(hPfx, &sContents)) { g_sImportCallbacks.pVoidhCryptProvQuery = &sContents; g_sImportCallbacks.pVoidDecryptFunc = (void *) szPassword;
if (!CertImportSafeContents( hStore, &sContents, CERT_STORE_ADD_ALWAYS, &g_sImportCallbacks, dwFlags, NULL)) goto Ret; } } else { if (GetLastError() == CRYPT_E_BAD_ENCODE) { // that decode failed; try an old netscape version
// if the password is NULL then use L"" because that is what
// Netscape did in their old version, otherwise just use the password passed in
if (szPassword == NULL) szNetscapePassword = szOldNetscapeNull; else szNetscapePassword = szPassword;
if (NSCPImportBlob( szNetscapePassword, pPFX->pbData, pPFX->cbData, &pSafeContents)) {
// break out if not saving data
if (!fDataCommit) { fRet = TRUE; goto Ret; } g_sImportCallbacks.pVoidhCryptProvQuery = pSafeContents; if (!CertImportSafeContents( hStore, pSafeContents, CERT_STORE_ADD_ALWAYS, &g_sImportCallbacks, dwFlags, NULL)) goto Ret; SSFree(pSafeContents); } else // nscp import fail
goto Ret; } else { // pfx import fail, not a decoding error
goto Ret; } }
fRet = TRUE; Ret:
if (hPfx) PfxCloseHandle(hPfx);
FreeCryptSafeContents(&sContents);
if (!fRet) { if (hStore) { CertCloseStore(hStore, 0); hStore = NULL; } }
if (fDataCommit) return hStore; else return (HCERTSTORE)(ULONG_PTR) fRet; }
EXPORT_SAFE_CALLBACK_STRUCT g_sExportCallbacks = { Encrypt_Private_Key, NULL };
//+-------------------------------------------------------------------------
// PFXExportCertStoreEx
//
// Export the certificates and private keys referenced in the passed-in store
//
// This API encodes the blob under a stronger algorithm. The resulting
// PKCS12 blobs are incompatible with the earlier APIs.
//
// The value passed in the password parameter will be used to encrypt and
// verify the integrity of the PFX packet. If any problems encoding the store
// are encountered, the function will return FALSE and the error code can
// be found from GetLastError().
//
// The dwFlags parameter may be set to any combination of
// EXPORT_PRIVATE_KEYS
// REPORT_NO_PRIVATE_KEY
// REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY
// These flags are as documented in the CertExportSafeContents Crypt32 API
//--------------------------------------------------------------------------
BOOL WINAPI PFXExportCertStoreEx( HCERTSTORE hStore, CRYPT_DATA_BLOB* pPFX, LPCWSTR szPassword, void* pvReserved, DWORD dwFlags) { return PFXExportCertStore( hStore, pPFX, szPassword, (dwFlags | PKCS12_ENHANCED_STRENGTH_ENCODING) ); }
//+-------------------------------------------------------------------------
// PFXExportCertStore
//
// Export the certificates and private keys referenced in the passed-in store
//
// This is an old API kept for compatibility with IE4 clients. New applications
// should call PfxExportCertStoreEx for enhanced security.
//
// The value passed in the password parameter will be used to encrypt and
// verify the integrity of the PFX packet. If any problems encoding the store
// are encountered, the function will return FALSE and the error code can
// be found from GetLastError().
//
// The dwFlags parameter may be set to any combination of
// EXPORT_PRIVATE_KEYS
// REPORT_NO_PRIVATE_KEY
// REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY
// PKCS12_ENHANCED_STRENGTH_ENCODING (used only by ExportCertStoreEx)
// These flags are as documented in the CertExportSafeContents Crypt32 API
//--------------------------------------------------------------------------
BOOL WINAPI PFXExportCertStore( HCERTSTORE hStore, CRYPT_DATA_BLOB* pPFX, LPCWSTR szPassword, DWORD dwFlags) { BOOL fRet = FALSE; SAFE_CONTENTS* pContents = NULL; DWORD cbContents = 0; HPFX hPfx = NULL; HCRYPTPROV hCrypt = NULL; ENCRYPT_PRIVATE_PARAM_DATASTRUCT sParam;
PCCERT_CONTEXT pBadCert = NULL;
if (dwFlags & ~( EXPORT_PRIVATE_KEYS | REPORT_NO_PRIVATE_KEY | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY | PKCS12_ENHANCED_STRENGTH_ENCODING )) { SetLastError(ERROR_INVALID_PARAMETER); goto Ret; }
if ((hStore == NULL) || (pPFX == NULL)) { SetLastError(ERROR_INVALID_PARAMETER); goto Ret; }
// get HCRYPTPROV for rng
if (!CryptAcquireContextA(&hCrypt, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) goto Ret;
sParam.hVerifyProv = hCrypt; sParam.szPwd = szPassword; g_sExportCallbacks.pVoidEncryptFunc = &sParam;
if (!CertExportSafeContents( hStore, pContents, &cbContents, &g_sExportCallbacks, dwFlags | PFX_MODE, &pBadCert, NULL)) goto Ret; pContents = (SAFE_CONTENTS*)SSAlloc(cbContents); if (pContents == NULL) goto Ret;
if (!CertExportSafeContents( hStore, pContents, &cbContents, &g_sExportCallbacks, (pPFX->cbData != 0) ? dwFlags | PFX_MODE | GIVE_ME_DATA : dwFlags | PFX_MODE, &pBadCert, NULL)) goto Ret;
if (NULL == (hPfx = PfxExportCreate(szPassword)) ) goto Ret;
if (!PfxAddSafeBags(hPfx, pContents->pSafeBags, pContents->cSafeBags)) goto Ret;
// export
if (!PfxExportBlob( hPfx, pPFX->pbData, &pPFX->cbData, dwFlags)) goto Ret;
fRet = TRUE; Ret: if (pBadCert != NULL) CertFreeCertificateContext(pBadCert);
if (pContents) SSFree(pContents);
if (hPfx) PfxCloseHandle(hPfx);
if (hCrypt) { HRESULT hr = GetLastError(); CryptReleaseContext(hCrypt, 0); SetLastError(hr); }
return fRet; }
//+-------------------------------------------------------------------------
// IsPFXBlob
//
// This function will try to decode the outer layer of the blob as a pfx
// blob, and if that works it will return TRUE, it will return FALSE otherwise
//
//--------------------------------------------------------------------------
BOOL WINAPI PFXIsPFXBlob( CRYPT_DATA_BLOB* pPFX) { if (IsRealPFXBlob(pPFX)) { return TRUE; }
if (IsNetscapePFXBlob(pPFX)) { return TRUE; }
return FALSE; }
//+-------------------------------------------------------------------------
// VerifyPassword
//
// This function will attempt to decode the outer layer of the blob as a pfx
// blob and decrypt with the given password. No data from the blob will be imported.
// Return value is TRUE if password appears correct, FALSE otherwise.
//
//--------------------------------------------------------------------------
BOOL WINAPI PFXVerifyPassword( CRYPT_DATA_BLOB* pPFX, LPCWSTR szPassword, DWORD dwFlags) { // uses overloaded ImportCertStore API
HCERTSTORE h; h = PFXImportCertStore( pPFX, szPassword, PKCS12_NO_DATA_COMMIT);
return (h==NULL) ? FALSE:TRUE; }
|