windows-nt/Source/XPSP1/NT/ds/security/cryptoapi/pki/pfxlib/nscpfmt.cpp
2020-09-26 16:20:57 +08:00

1485 lines
49 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: nscp.cpp
//
// Contents: PFX: Personal Information Exchange.
//
// Functions:
//
// History: 02-Jun-97 mattt created
//
//--------------------------------------------------------------------------
#include "global.hxx"
#include <wincrypt.h>
#include "shacomm.h"
#include "des.h"
#include "tripldes.h"
#include "modes.h"
#define _PFX_SOURCE_
#include "dbgdef.h"
extern "C" {
#include "pfxnscp.h" // ASN1 generated
}
#include "pfxhelp.h"
#include "pfxcrypt.h"
#include "pfxcmn.h"
#define DES_BLOCKLEN 8
///////////////////////////////////////////////////////////////////////////////////
// OLD PKCS #12 Object Identifiers - these are for supporting the old netscape file format
#define OLD_szOID_PKCS_12_OIDs szOID_PKCS_12 ".5" // 1.2.840.113549.1.12.5
#define OLD_szOID_PKCS_12_PbeIds OLD_szOID_PKCS_12_OIDs ".1"
#define OLD_szOID_PKCS_12_pbeWithSHA1And128BitRC4 OLD_szOID_PKCS_12_PbeIds ".1"
#define OLD_szOID_PKCS_12_pbeWithSHA1And40BitRC4 OLD_szOID_PKCS_12_PbeIds ".2"
#define OLD_szOID_PKCS_12_pbeWithSHA1AndTripleDES OLD_szOID_PKCS_12_PbeIds ".3"
#define OLD_szOID_PKCS_12_pbeWithSHA1And128BitRC2 OLD_szOID_PKCS_12_PbeIds ".4"
#define OLD_szOID_PKCS_12_pbeWithSHA1And40BitRC2 OLD_szOID_PKCS_12_PbeIds ".5"
#define OLD_szOID_PKCS_12_EnvelopingIds OLD_szOID_PKCS_12_OIDs ".2"
#define OLD_szOID_PKCS_12_rsaEncryptionWith128BitRC4 OLD_szOID_PKCS_12_EnvelopingIds ".1"
#define OLD_szOID_PKCS_12_rsaEncryptionWith40BitRC4 OLD_szOID_PKCS_12_EnvelopingIds ".2"
#define OLD_szOID_PKCS_12_rsaEncryptionWithTripleDES OLD_szOID_PKCS_12_EnvelopingIds ".3"
#define OLD_szOID_PKCS_12_SignatureIds OLD_szOID_PKCS_12_OIDs ".3"
#define OLD_szOID_PKCS_12_rsaSignatureWithSHA1Digest OLD_szOID_PKCS_12_SignatureIds ".1"
#define OLD_szOID_PKCS_12_ModeIDs OLD_szOID_PKCS_12 ".1" // 1.2.840.113549.1.12.1
#define OLD_szOID_PKCS_12_PubKeyMode OLD_szOID_PKCS_12_ModeIDs ".1" // 1.2.840.113549.1.12.1.1
#define OLD_szOID_PKCS_12_PasswdMode OLD_szOID_PKCS_12_ModeIDs ".2" // 1.2.840.113549.1.12.1.2
#define OLD_szOID_PKCS_12_offlineTransportMode OLD_szOID_PKCS_12_ModeIds ".1" // obsolete
#define OLD_szOID_PKCS_12_onlineTransportMode OLD_szOID_PKCS_12_ModeIds ".2" // obsolete
#define OLD_szOID_PKCS_12_EspvkIDs OLD_szOID_PKCS_12 ".2" // 1.2.840.113549.1.12.2
#define OLD_szOID_PKCS_12_KeyShrouding OLD_szOID_PKCS_12_EspvkIDs ".1" // 1.2.840.113549.1.12.2.1
#define OLD_szOID_PKCS_12_BagIDs OLD_szOID_PKCS_12 ".3" // obsolete
#define OLD_szOID_PKCS_12_KeyBagIDs OLD_szOID_PKCS_12_BagIDs ".1" // obsolete
#define OLD_szOID_PKCS_12_CertCrlBagIDs OLD_szOID_PKCS_12_BagIDs ".2" // obsolete
#define OLD_szOID_PKCS_12_SecretBagIDs OLD_szOID_PKCS_12_BagIDs ".3" // obsolete
#define OLD_szOID_PKCS_12_SafeCntIDs OLD_szOID_PKCS_12_BagIDs ".4" // obsolete
#define OLD_szOID_PKCS_12_ShrKeyBagIDs OLD_szOID_PKCS_12_BagIDs ".5" // obsolete
#define OLD_szOID_PKCS_12_CertBagIDs OLD_szOID_PKCS_12 ".4" // obsolete
#define OLD_szOID_PKCS_12_x509CertCrlBagIDs OLD_szOID_PKCS_12_CertBagIDs ".1" // obsolete
#define OLD_szOID_PKCS_12_sdsiCertBagIDs OLD_szOID_PKCS_12_CertBagIDs ".2" // obsolete
static HCRYPTASN1MODULE hNSCPAsn1Module;
// fwd
//BOOL FNSCPDumpSafeCntsToHPFX(SafeContents* pSafeCnts, HPFX hpfx);
BOOL InitNSCP()
{
#ifdef OSS_CRYPT_ASN1
if (0 == (hNSCPAsn1Module = I_CryptInstallAsn1Module(pfxnscp, 0, NULL)) )
return FALSE;
#else
PFXNSCP_Module_Startup();
if (0 == (hNSCPAsn1Module = I_CryptInstallAsn1Module(
PFXNSCP_Module, 0, NULL))) {
PFXNSCP_Module_Cleanup();
return FALSE;
}
#endif // OSS_CRYPT_ASN1
return TRUE;
}
BOOL TerminateNSCP()
{
I_CryptUninstallAsn1Module(hNSCPAsn1Module);
#ifndef OSS_CRYPT_ASN1
PFXNSCP_Module_Cleanup();
#endif // OSS_CRYPT_ASN1
return TRUE;
}
static inline ASN1decoding_t GetDecoder(void)
{
return I_CryptGetAsn1Decoder(hNSCPAsn1Module);
}
//+-------------------------------------------------------------------------
// Function: INSCP_Asn1ToObjectID
//
// Synopsis: Convert a dotted string oid to an ASN1 ObjectID
//
// Returns: FALSE iff failed
//--------------------------------------------------------------------------
BOOL
INSCP_Asn1ToObjectID(
IN OID oid,
OUT ObjectID *pooid
)
{
BOOL fRet;
pooid->count = 16;
if (!PkiAsn1ToObjectIdentifier(
oid,
&pooid->count,
pooid->value))
goto PkiAsn1ToObjectIdentifierError;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
SetLastError(CRYPT_E_OID_FORMAT);
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(PkiAsn1ToObjectIdentifierError)
}
//+-------------------------------------------------------------------------
// Function: INSCP_Asn1FromObjectID
//
// Synopsis: Convert an ASN1 ObjectID to a dotted string oid
//
// Returns: FALSE iff failed
//--------------------------------------------------------------------------
BOOL
INSCP_Asn1FromObjectID(
IN ObjectID *pooid,
OUT OID *poid
)
{
BOOL fRet;
OID oid = NULL;
DWORD cb;
if (!PkiAsn1FromObjectIdentifier(
pooid->count,
pooid->value,
NULL,
&cb))
goto PkiAsn1FromObjectIdentifierSizeError;
if (NULL == (oid = (OID)SSAlloc( cb)))
goto OidAllocError;
if (!PkiAsn1FromObjectIdentifier(
pooid->count,
pooid->value,
oid,
&cb))
goto PkiAsn1FromObjectIdentifierError;
fRet = TRUE;
CommonReturn:
*poid = oid;
return fRet;
ErrorReturn:
SSFree(oid);
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(OidAllocError)
SET_ERROR(PkiAsn1FromObjectIdentifierSizeError , CRYPT_E_OID_FORMAT)
SET_ERROR(PkiAsn1FromObjectIdentifierError , CRYPT_E_OID_FORMAT)
}
//+-------------------------------------------------------------------------
// Function: INSCP_EqualObjectIDs
//
// Compare 2 OSS object id's.
//
// Returns: FALSE iff !equal
//--------------------------------------------------------------------------
BOOL
WINAPI
INSCP_EqualObjectIDs(
IN ObjectID *poid1,
IN ObjectID *poid2)
{
BOOL fRet;
DWORD i;
PDWORD pdw1;
PDWORD pdw2;
if (poid1->count != poid2->count)
goto Unequal;
for (i=poid1->count, pdw1=poid1->value, pdw2=poid2->value;
(i>0) && (*pdw1==*pdw2);
i--, pdw1++, pdw2++)
;
if (i>0)
goto Unequal;
fRet = TRUE; // equal
CommonReturn:
return fRet;
Unequal:
fRet = FALSE; // !equal
goto CommonReturn;
}
//+ --------------------------------------------------------------
// in NSCP's initial implementation of PFX020, this
// is the algorithm they used to derive a key from a password.
// ACTUALLY, they have two slightly different methods of generating
// a key, this is the one needed to decrypt the baggage.
// We include it so we can interoperate.
BOOL NCSPDeriveBaggageDecryptionKey(
LPCWSTR szPassword,
int iPKCS5Iterations,
PBYTE pbPKCS5Salt,
DWORD cbPKCS5Salt,
PBYTE pbDerivedMaterial,
DWORD cbDerivedMaterial)
{
BOOL fRet = TRUE;
LPSTR szASCIIPassword = NULL;
DWORD cbASCIIPassword = 0;
DWORD i;
BYTE paddedPKCS5Salt[20];
BYTE *pbTempPKCS5Salt = NULL;
DWORD cbTempPKCS5Salt = 0;
BYTE rgbPKCS5Key[A_SHA_DIGEST_LEN];
// for some reason the password is used as ASCII in this key derivation
// so change it from unicode to ASCII
if (0 == (cbASCIIPassword = WideCharToMultiByte(
CP_ACP,
0,
szPassword,
-1,
NULL,
0,
NULL,
NULL))) {
goto ErrorReturn;
}
if (NULL == (szASCIIPassword = (LPSTR) SSAlloc(cbASCIIPassword)))
goto ErrorReturn;
if (0 == (cbASCIIPassword = WideCharToMultiByte(
CP_ACP,
0,
szPassword,
-1,
szASCIIPassword,
cbASCIIPassword,
NULL,
NULL))) {
goto ErrorReturn;
}
// get rid of the NULL character, Netscape doesn't include it
cbASCIIPassword--;
// because of a Netscape bug the minimum length of password + salt is 20,
// if the password + salt is less than 20 they pad with 0's.
// so, check to see if the password + salt is less than 20, if so then pad the
// salt since it will be appended to the password.
if (cbASCIIPassword+cbPKCS5Salt < 20) {
// reset the pbPKCS5Salt pointer to a local buffer
// which is padded with 0's, and adjust cbPKCS5Salt
memset(paddedPKCS5Salt, 0, 20);
memcpy(paddedPKCS5Salt, pbPKCS5Salt, cbPKCS5Salt);
pbTempPKCS5Salt = paddedPKCS5Salt;
cbTempPKCS5Salt = 20 - cbASCIIPassword;
}
else {
pbTempPKCS5Salt = pbPKCS5Salt;
cbTempPKCS5Salt = cbPKCS5Salt;
}
// use PKCS#5 to generate initial bit stream (seed)
if (!PKCS5_GenKey(
iPKCS5Iterations,
(BYTE *)szASCIIPassword,
cbASCIIPassword,
pbTempPKCS5Salt,
cbTempPKCS5Salt,
rgbPKCS5Key))
goto Ret;
// if there isn't engough key material, then use PHash to generate more
if (cbDerivedMaterial > sizeof(rgbPKCS5Key))
{
// P_hash (secret, seed) = HMAC_hash (secret, A(0) + seed),
// HMAC_hash (secret, A(1) + seed),
// HMAC_hash (secret, A(2) + seed),
// HMAC_hash (secret, A(3) + seed) ...
// where
// A(0) = seed
// A(i) = HMAC_hash(secret, A(i-1))
// seed = PKCS5 salt for PKCS5 PBE param
// secret = normal PKCS5 hashed key
if (!P_Hash (
rgbPKCS5Key,
sizeof(rgbPKCS5Key),
pbPKCS5Salt,
cbPKCS5Salt,
pbDerivedMaterial, // output
cbDerivedMaterial, // # of output bytes requested
TRUE) ) // NSCP compat mode?
goto Ret;
}
else
{
// we already have enough bits to satisfy the request
CopyMemory(pbDerivedMaterial, rgbPKCS5Key, cbDerivedMaterial);
}
goto Ret;
ErrorReturn:
fRet = FALSE;
Ret:
if (szASCIIPassword)
SSFree(szASCIIPassword);
return fRet;
}
// this function will create a SAFE_BAG structure contained in a single buffer
// for the given encoded private key, friendly name, and local key ID
static
BOOL
SetupKeyBag (
SAFE_BAG **ppKeyBag,
DWORD dwLocalKeyID,
BYTE *pbFriendlyName,
DWORD cbFriendlyName,
BYTE *pbEncodedPrivateKey,
DWORD cbEncodedPrivateKey
)
{
BOOL fRet = TRUE;
SAFE_BAG *pSafeBag;
DWORD cbBytesNeeded = sizeof(SAFE_BAG);
DWORD dwKeyID = 0;
CRYPT_ATTR_BLOB keyID;
CERT_NAME_VALUE wideFriendlyName;
BYTE *pbEncodedLocalKeyID = NULL;
DWORD cbEncodedLocalKeyID = 0;
BYTE *pbEncodedFriendlyName = NULL;
DWORD cbEncodedFriendlyName = 0;
BYTE *pbCurrentBufferLocation = NULL;
keyID.pbData = (BYTE *) &dwKeyID;
keyID.cbData = sizeof(DWORD);
dwKeyID = dwLocalKeyID;
// calculate the size needed for a buffer to fit all the SAFE_BAG information
cbBytesNeeded += strlen(szOID_PKCS_12_KEY_BAG) + 1;
cbBytesNeeded += cbEncodedPrivateKey;
cbBytesNeeded += sizeof(CRYPT_ATTRIBUTE) * 2;
cbBytesNeeded += strlen(szOID_PKCS_12_LOCAL_KEY_ID) + 1;
cbBytesNeeded += sizeof(CRYPT_ATTR_BLOB);
// encode the keyID attribute
if (!CryptEncodeObject(
X509_ASN_ENCODING,
X509_OCTET_STRING,
&keyID,
NULL,
&cbEncodedLocalKeyID)) {
goto ErrorReturn;
}
if (NULL == (pbEncodedLocalKeyID = (BYTE *) SSAlloc(cbEncodedLocalKeyID)))
goto ErrorReturn;
cbBytesNeeded += cbEncodedLocalKeyID;
if (!CryptEncodeObject(
X509_ASN_ENCODING,
X509_OCTET_STRING,
&keyID,
pbEncodedLocalKeyID,
&cbEncodedLocalKeyID)) {
goto ErrorReturn;
}
cbBytesNeeded += strlen(szOID_PKCS_12_FRIENDLY_NAME_ATTR) + 1;
cbBytesNeeded += sizeof(CRYPT_ATTR_BLOB);
// encode the friendly name attribute
wideFriendlyName.dwValueType = CERT_RDN_BMP_STRING;
wideFriendlyName.Value.pbData = pbFriendlyName;
wideFriendlyName.Value.cbData = 0;
if (!CryptEncodeObject(
X509_ASN_ENCODING,
X509_UNICODE_ANY_STRING,
(void *)&wideFriendlyName,
NULL,
&cbEncodedFriendlyName)) {
goto ErrorReturn;
}
if (NULL == (pbEncodedFriendlyName = (BYTE *) SSAlloc(cbEncodedFriendlyName)))
goto ErrorReturn;
cbBytesNeeded += cbEncodedFriendlyName;
if (!CryptEncodeObject(
X509_ASN_ENCODING,
X509_UNICODE_ANY_STRING,
(void *)&wideFriendlyName,
pbEncodedFriendlyName,
&cbEncodedFriendlyName)) {
goto ErrorReturn;
}
// now allocate space for the all the SAFE_BAG data and copy the data into the buffer
if (NULL == (pSafeBag = (SAFE_BAG *) SSAlloc(cbBytesNeeded)))
goto ErrorReturn;
memset(pSafeBag, 0, cbBytesNeeded);
// set current buffer location to be at the end of the SAFE_BAG
// structure which is at the head of the buffer
pbCurrentBufferLocation = ((BYTE *) pSafeBag) + sizeof(SAFE_BAG);
// copy key bag type OID
pSafeBag->pszBagTypeOID = (LPSTR) pbCurrentBufferLocation;
strcpy((LPSTR) pbCurrentBufferLocation, szOID_PKCS_12_KEY_BAG);
pbCurrentBufferLocation += strlen(szOID_PKCS_12_KEY_BAG) + 1;
// copy the private key
pSafeBag->BagContents.pbData = pbCurrentBufferLocation;
pSafeBag->BagContents.cbData = cbEncodedPrivateKey;
memcpy(pbCurrentBufferLocation, pbEncodedPrivateKey, cbEncodedPrivateKey);
pbCurrentBufferLocation += cbEncodedPrivateKey;
// create space for the attributes array
pSafeBag->Attributes.cAttr = 2;
pSafeBag->Attributes.rgAttr = (CRYPT_ATTRIBUTE *) pbCurrentBufferLocation;
pbCurrentBufferLocation += sizeof(CRYPT_ATTRIBUTE) * 2;
// copy the local key ID attribute and value
pSafeBag->Attributes.rgAttr[0].pszObjId = (LPSTR) pbCurrentBufferLocation;
strcpy((LPSTR) pbCurrentBufferLocation, szOID_PKCS_12_LOCAL_KEY_ID);
pbCurrentBufferLocation += strlen(szOID_PKCS_12_LOCAL_KEY_ID) + 1;
pSafeBag->Attributes.rgAttr[0].cValue = 1;
pSafeBag->Attributes.rgAttr[0].rgValue = (CRYPT_ATTR_BLOB *) pbCurrentBufferLocation;
pbCurrentBufferLocation += sizeof(CRYPT_ATTR_BLOB);
pSafeBag->Attributes.rgAttr[0].rgValue->cbData = cbEncodedLocalKeyID;
pSafeBag->Attributes.rgAttr[0].rgValue->pbData = pbCurrentBufferLocation;
memcpy(pbCurrentBufferLocation, pbEncodedLocalKeyID, cbEncodedLocalKeyID);
pbCurrentBufferLocation += cbEncodedLocalKeyID;
// copy the friendly name attribute and value
pSafeBag->Attributes.rgAttr[1].pszObjId = (LPSTR) pbCurrentBufferLocation;
strcpy((LPSTR) pbCurrentBufferLocation, szOID_PKCS_12_FRIENDLY_NAME_ATTR);
pbCurrentBufferLocation += strlen(szOID_PKCS_12_FRIENDLY_NAME_ATTR) + 1;
pSafeBag->Attributes.rgAttr[1].cValue = 1;
pSafeBag->Attributes.rgAttr[1].rgValue = (CRYPT_ATTR_BLOB *) pbCurrentBufferLocation;
pbCurrentBufferLocation += sizeof(CRYPT_ATTR_BLOB);
pSafeBag->Attributes.rgAttr[1].rgValue->cbData = cbEncodedFriendlyName;
pSafeBag->Attributes.rgAttr[1].rgValue->pbData = pbCurrentBufferLocation;
memcpy(pbCurrentBufferLocation, pbEncodedFriendlyName, cbEncodedFriendlyName);
*ppKeyBag = pSafeBag;
goto Ret;
ErrorReturn:
fRet = FALSE;
Ret:
if (pbEncodedLocalKeyID)
SSFree(pbEncodedLocalKeyID);
if (pbEncodedFriendlyName)
SSFree(pbEncodedFriendlyName);
return fRet;
}
// this function will extract a private key from the baggage structure handed in
// and put the private key in a SAFE_BAG structure, where all the data of the
// SAFE_BAG is contained in a single in a single buffer
static
BOOL
ExtractKeyFromBaggage(
Baggage baggage,
SAFE_BAG **ppKeyBag,
LPCWSTR szPassword,
DWORD dwLocalKeyID,
BYTE **ppbCertThumbprint
)
{
BOOL fRet = TRUE;
DWORD dwErr;
DWORD cbEncryptedPrivateKeyInfoStruct = 0;
CRYPT_ENCRYPTED_PRIVATE_KEY_INFO *pEncryptedPrivateKeyInfoStruct = NULL;
BYTE rgbDerivedKeyMatl[40]; // 320 bits is enough for 128 bit key, 64 bit IV
DWORD cbEncodedPrivateKeyInfoStruct = 0;
BYTE *pbEncodedPrivateKeyInfoStruct = NULL;
PBEParameter *pPBEParameter = NULL;
ASN1decoding_t pDec = GetDecoder();
// there should only be one baggage item
if (baggage.count != 1)
goto SetPFXDecodeError;
// there should only be one private key
if (baggage.value->espvks.count != 1)
goto SetPFXDecodeError;
// decode the PKCS8, which is actually stored in the espvkCipherText field
// of the ESPVK structure. it's a Netscape thing man!!!!
if (!CryptDecodeObject(X509_ASN_ENCODING,
PKCS_ENCRYPTED_PRIVATE_KEY_INFO,
(BYTE *) baggage.value->espvks.value->espvkCipherText.value,
baggage.value->espvks.value->espvkCipherText.length,
CRYPT_DECODE_NOCOPY_FLAG,
NULL,
&cbEncryptedPrivateKeyInfoStruct))
goto SetPFXDecodeError;
if (NULL == (pEncryptedPrivateKeyInfoStruct = (CRYPT_ENCRYPTED_PRIVATE_KEY_INFO *)
SSAlloc(cbEncryptedPrivateKeyInfoStruct)))
goto SetPFXDecodeError;
if (!CryptDecodeObject(X509_ASN_ENCODING,
PKCS_ENCRYPTED_PRIVATE_KEY_INFO,
(BYTE *) baggage.value->espvks.value->espvkCipherText.value,
baggage.value->espvks.value->espvkCipherText.length,
CRYPT_DECODE_NOCOPY_FLAG,
pEncryptedPrivateKeyInfoStruct,
&cbEncryptedPrivateKeyInfoStruct))
goto SetPFXDecodeError;
// verify that the algorithm is the one we expect
if (strcmp("1.2.840.113549.1.12.5.1.3", pEncryptedPrivateKeyInfoStruct->EncryptionAlgorithm.pszObjId) != 0)
goto SetPFXDecodeError;
if (0 != PkiAsn1Decode(
pDec,
(void **)&pPBEParameter,
PBEParameter_PDU,
pEncryptedPrivateKeyInfoStruct->EncryptionAlgorithm.Parameters.pbData,
pEncryptedPrivateKeyInfoStruct->EncryptionAlgorithm.Parameters.cbData))
goto SetPFXDecodeError;
// derive the key to be used for decrypting,
if (!NCSPDeriveBaggageDecryptionKey(
szPassword,
pPBEParameter->iterationCount,
pPBEParameter->salt.value, // pkcs5 salt
pPBEParameter->salt.length,
rgbDerivedKeyMatl,
40)) { // 192 bits for triple des - 3key, and 64 bit IV ---- for some reason netscape asks for
// 40 bytes of key material, then uses the first 192 bits for key and last 64 bits for IV,
// skipping 64 bits in between. who knows why they do these things!!
goto ErrorReturn;
}
// decrypt the private key
{
DWORD dwDataPos;
DWORD cbToBeDec = pEncryptedPrivateKeyInfoStruct->EncryptedPrivateKey.cbData;
DES3TABLE des3Table;
BYTE des3Fdbk [DES_BLOCKLEN];
// key setup
tripledes3key(&des3Table, rgbDerivedKeyMatl);
CopyMemory(des3Fdbk, &rgbDerivedKeyMatl[40 - sizeof(des3Fdbk)], sizeof(des3Fdbk)); // fdbk is last chunk
cbEncodedPrivateKeyInfoStruct =
((pEncryptedPrivateKeyInfoStruct->EncryptedPrivateKey.cbData + 7) / 8) * 8;
if (NULL == (pbEncodedPrivateKeyInfoStruct = (BYTE *) SSAlloc(cbEncodedPrivateKeyInfoStruct)))
goto ErrorReturn;
for (dwDataPos=0; cbToBeDec > 0; dwDataPos += DES_BLOCKLEN, cbToBeDec -= DES_BLOCKLEN)
{
BYTE rgbDec[DES_BLOCKLEN];
CBC(
tripledes,
DES_BLOCKLEN,
rgbDec,
&(pEncryptedPrivateKeyInfoStruct->EncryptedPrivateKey.pbData[dwDataPos]),
(void *) &des3Table,
DECRYPT,
des3Fdbk);
CopyMemory(&pbEncodedPrivateKeyInfoStruct[dwDataPos], rgbDec, DES_BLOCKLEN);
}
}
// set up the SAFE_BAG to be returned
if (!SetupKeyBag(
ppKeyBag,
dwLocalKeyID,
(BYTE *) baggage.value->espvks.value->espvkData.nickname.value,
baggage.value->espvks.value->espvkData.nickname.length,
pbEncodedPrivateKeyInfoStruct,
cbEncodedPrivateKeyInfoStruct)) {
goto ErrorReturn;
}
// copy the cert thumbprint
assert(baggage.value->espvks.value->espvkData.assocCerts.count == 1);
if (NULL == (*ppbCertThumbprint = (BYTE *)
SSAlloc(baggage.value->espvks.value->espvkData.assocCerts.value->digest.length)))
goto ErrorReturn;
memcpy(
*ppbCertThumbprint,
baggage.value->espvks.value->espvkData.assocCerts.value->digest.value,
baggage.value->espvks.value->espvkData.assocCerts.value->digest.length);
goto Ret;
SetPFXDecodeError:
SetLastError(CRYPT_E_BAD_ENCODE);
ErrorReturn:
fRet = FALSE;
Ret:
// save last error from TLS madness
dwErr = GetLastError();
if (pEncryptedPrivateKeyInfoStruct)
SSFree(pEncryptedPrivateKeyInfoStruct);
if (pbEncodedPrivateKeyInfoStruct)
SSFree(pbEncodedPrivateKeyInfoStruct);
PkiAsn1FreeDecoded(pDec, pPBEParameter, PBEParameter_PDU);
// save last error from TLS madness
SetLastError(dwErr);
return fRet;
}
// this function will take a SafeContents structure and format it as an array
// array of SAFE_BAGs with all the date for the SAGE_BAGs containted in a single
// buffer. it also adds the local key ID attribute to the cert which has
// the same thumbprint as the thumbprint passed in
static
BOOL
SetupCertBags(
SafeContents *pSafeCnts,
SAFE_BAG **ppCertBags,
DWORD *pcNumCertBags,
DWORD dwLocalKeyID,
BYTE *pbCertThumbprint
)
{
BOOL fRet = TRUE;
DWORD dwErr;
SAFE_BAG *pSafeBags = NULL;
DWORD cNumSafeBags = 0;
DWORD cbBytesNeeded = 0;
BYTE *pbCurrentBufferLocation = NULL;
X509Bag *pX509Bag = NULL;
CertCRLBag *pCertCRLBag = NULL;
HCERTSTORE hCertStore = NULL;
CRYPT_DATA_BLOB cryptDataBlob;
PCCERT_CONTEXT pCertContext = NULL;
DWORD dwSafeBagIndex = 0;
DWORD dwKeyID = 0;
CRYPT_ATTR_BLOB keyID;
DWORD cbEncodedLocalKeyID = 0;
BYTE *pbEncodedLocalKeyID = NULL;
ASN1decoding_t pDec = GetDecoder();
keyID.pbData = (BYTE *) &dwKeyID;
keyID.cbData = sizeof(DWORD);
dwKeyID = dwLocalKeyID;
// decode the safe bag content, should be a CertCrlBag
assert(pSafeCnts->count == 1);
if (0 != PkiAsn1Decode(
pDec,
(void **)&pCertCRLBag,
CertCRLBag_PDU,
(BYTE *) pSafeCnts->value->safeBagContent.value,
pSafeCnts->value->safeBagContent.length))
goto SetPFXDecodeError;
// decode the X509bag
assert(pCertCRLBag->count == 1);
if (0 != PkiAsn1Decode(
pDec,
(void **)&pX509Bag,
X509Bag_PDU,
(BYTE *) pCertCRLBag->value[0].value.value,
pCertCRLBag->value[0].value.length))
goto SetPFXDecodeError;
// encode the keyID so it is ready to be added to a SAFE_BAGs attributes
if (!CryptEncodeObject(
X509_ASN_ENCODING,
X509_OCTET_STRING,
&keyID,
NULL,
&cbEncodedLocalKeyID)) {
goto ErrorReturn;
}
if (NULL == (pbEncodedLocalKeyID = (BYTE *) SSAlloc(cbEncodedLocalKeyID)))
goto ErrorReturn;
if (!CryptEncodeObject(
X509_ASN_ENCODING,
X509_OCTET_STRING,
&keyID,
pbEncodedLocalKeyID,
&cbEncodedLocalKeyID)) {
goto ErrorReturn;
}
// open a cert store with the SignedData buffer we got from the SafeContents passed in,
// this will allow access to all the certs as X509 encoded blobs, and it
// will give access to the thumbprints so a cert can be matched with the
// private key
cryptDataBlob.pbData = (BYTE *) pX509Bag->certOrCRL.content.value;
cryptDataBlob.cbData = pX509Bag->certOrCRL.content.length;
hCertStore = CertOpenStore(
CERT_STORE_PROV_PKCS7,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
NULL,
0,
&cryptDataBlob);
if (NULL == hCertStore) {
goto ErrorReturn;
}
// calculate how much space is needed to fit the array of SAFE_BAGs and
// all their data into one contiguous buffer
while (NULL != (pCertContext = CertEnumCertificatesInStore(
hCertStore,
pCertContext))) {
DWORD cbEncodedCertBag = 0;
cNumSafeBags++;
cbBytesNeeded += sizeof(SAFE_BAG);
// get the size for wrapping an encoded cert into an encoded cert bag
if (!MakeEncodedCertBag(
pCertContext->pbCertEncoded,
pCertContext->cbCertEncoded,
NULL,
&cbEncodedCertBag)) {
goto ErrorReturn;
}
cbBytesNeeded += cbEncodedCertBag;
cbBytesNeeded += strlen(szOID_PKCS_12_CERT_BAG) + 1;
}
// add bytes to cbBytesNeeded so there is enough space to add the
// LocalKeyID attribute to ONE of the certificates
cbBytesNeeded += sizeof(CRYPT_ATTRIBUTE);
cbBytesNeeded += sizeof(CRYPT_ATTR_BLOB);
cbBytesNeeded += strlen(szOID_PKCS_12_LOCAL_KEY_ID) + 1;
cbBytesNeeded += cbEncodedLocalKeyID;
// allocate the one big buffer
if (NULL == (pSafeBags = (SAFE_BAG *) SSAlloc(cbBytesNeeded)))
goto ErrorReturn;
memset(pSafeBags, 0, cbBytesNeeded);
// set the current buffer location to the end of the SAFE_BAG array which
// is at the head of the buffer
pbCurrentBufferLocation = ((BYTE *) pSafeBags) + (sizeof(SAFE_BAG) * cNumSafeBags);
// get the X509 blob for each cert and fill in the array of SAFE_BAGs
pCertContext = NULL;
dwSafeBagIndex = 0;
while (NULL != (pCertContext = CertEnumCertificatesInStore(
hCertStore,
pCertContext))) {
BYTE *pbLocalThumbprint = NULL;
DWORD cbLocalThumbprint = 0;
BYTE *pbEncodedCertBag = NULL;
DWORD cbEncodedCertBag = 0;
// copy the bag type OID
pSafeBags[dwSafeBagIndex].pszBagTypeOID = (LPSTR) pbCurrentBufferLocation;
strcpy((LPSTR)pbCurrentBufferLocation, szOID_PKCS_12_CERT_BAG);
pbCurrentBufferLocation += strlen(szOID_PKCS_12_CERT_BAG) + 1;
// wrap the encoded cert into an encoded certbag
// get the size for wrapping an encoded cert into an encoded cert bag
if (!MakeEncodedCertBag(
pCertContext->pbCertEncoded,
pCertContext->cbCertEncoded,
NULL,
&cbEncodedCertBag)) {
goto ErrorReturn;
}
if (NULL == (pbEncodedCertBag = (BYTE *) SSAlloc(cbEncodedCertBag)))
goto ErrorReturn;
if (!MakeEncodedCertBag(
pCertContext->pbCertEncoded,
pCertContext->cbCertEncoded,
pbEncodedCertBag,
&cbEncodedCertBag)) {
SSFree(pbEncodedCertBag);
goto ErrorReturn;
}
// copy the encoded certbag
pSafeBags[dwSafeBagIndex].BagContents.cbData = cbEncodedCertBag;
pSafeBags[dwSafeBagIndex].BagContents.pbData = pbCurrentBufferLocation;
memcpy(pbCurrentBufferLocation, pbEncodedCertBag, cbEncodedCertBag);
pbCurrentBufferLocation += cbEncodedCertBag;
// we don't need the encoded cert bag anymore
SSFree(pbEncodedCertBag);
// check to see if this cert is the cert that matches the private key by
// comparing the thumbprints
// Get the thumbprint
if (!CertGetCertificateContextProperty(
pCertContext,
CERT_SHA1_HASH_PROP_ID,
NULL,
&cbLocalThumbprint)) {
CertFreeCertificateContext(pCertContext);
goto ErrorReturn;
}
if (NULL == (pbLocalThumbprint = (BYTE *) SSAlloc(cbLocalThumbprint))) {
CertFreeCertificateContext(pCertContext);
goto ErrorReturn;
}
if (!CertGetCertificateContextProperty(
pCertContext,
CERT_SHA1_HASH_PROP_ID,
pbLocalThumbprint,
&cbLocalThumbprint)) {
CertFreeCertificateContext(pCertContext);
SSFree(pbLocalThumbprint);
goto ErrorReturn;
}
// compare thumbprints
if (memcmp(pbCertThumbprint, pbLocalThumbprint, cbLocalThumbprint) == 0) {
// the thumbprints match so add a single attribute with a single value which
pSafeBags[dwSafeBagIndex].Attributes.cAttr = 1;
pSafeBags[dwSafeBagIndex].Attributes.rgAttr = (CRYPT_ATTRIBUTE *) pbCurrentBufferLocation;
pbCurrentBufferLocation += sizeof(CRYPT_ATTRIBUTE);
pSafeBags[dwSafeBagIndex].Attributes.rgAttr[0].pszObjId = (LPSTR) pbCurrentBufferLocation;
strcpy((LPSTR) pbCurrentBufferLocation, szOID_PKCS_12_LOCAL_KEY_ID);
pbCurrentBufferLocation += strlen(szOID_PKCS_12_LOCAL_KEY_ID) + 1;
pSafeBags[dwSafeBagIndex].Attributes.rgAttr[0].cValue = 1;
pSafeBags[dwSafeBagIndex].Attributes.rgAttr[0].rgValue = (CRYPT_ATTR_BLOB *) pbCurrentBufferLocation;
pbCurrentBufferLocation += sizeof(CRYPT_ATTR_BLOB);
pSafeBags[dwSafeBagIndex].Attributes.rgAttr[0].rgValue[0].cbData = cbEncodedLocalKeyID;
pSafeBags[dwSafeBagIndex].Attributes.rgAttr[0].rgValue[0].pbData = pbCurrentBufferLocation;
memcpy(pbCurrentBufferLocation, pbEncodedLocalKeyID, cbEncodedLocalKeyID);
pbCurrentBufferLocation += cbEncodedLocalKeyID;
}
else {
// otherwise the certificate bag has no attributes in it
pSafeBags[dwSafeBagIndex].Attributes.cAttr = 0;
pSafeBags[dwSafeBagIndex].Attributes.rgAttr = NULL;
}
SSFree(pbLocalThumbprint);
dwSafeBagIndex++;
}
// return the safe bag array and the number of safe bags in the array
*ppCertBags = pSafeBags;
*pcNumCertBags = cNumSafeBags;
goto Ret;
SetPFXDecodeError:
SetLastError(CRYPT_E_BAD_ENCODE);
ErrorReturn:
fRet = FALSE;
if (pSafeBags)
SSFree(pSafeBags);
*ppCertBags = NULL;
*pcNumCertBags = 0;
Ret:
// save last error from TLS madness
dwErr = GetLastError();
PkiAsn1FreeDecoded(pDec, pCertCRLBag, CertCRLBag_PDU);
PkiAsn1FreeDecoded(pDec, pX509Bag, X509Bag_PDU);
if (pbEncodedLocalKeyID)
SSFree(pbEncodedLocalKeyID);
if (hCertStore)
CertCloseStore(hCertStore, 0);
// save last error from TLS madness
SetLastError(dwErr);
return fRet;
}
// this function will calculate the number of bytes needed for an
// attribute
static
DWORD
CalculateSizeOfAttributes(
CRYPT_ATTRIBUTES *pAttributes
)
{
DWORD cbBytesNeeded = 0;
DWORD i,j;
for (i=0; i<pAttributes->cAttr; i++) {
cbBytesNeeded += sizeof(CRYPT_ATTRIBUTE);
cbBytesNeeded += strlen(pAttributes->rgAttr[i].pszObjId) + 1;
for (j=0; j<pAttributes->rgAttr[i].cValue; j++) {
cbBytesNeeded += sizeof(CRYPT_ATTR_BLOB);
cbBytesNeeded += pAttributes->rgAttr[i].rgValue[j].cbData;
}
}
return cbBytesNeeded;
}
// this function will take two SAFE_BAG arrays and concatenate them into
// a SAFE_CONTENT structure. also, the SAFE_CONTENT structure and all
// it's supporting data will be in a single contiguous buffer
static
BOOL
ConcatenateSafeBagsIntoSafeContents(
SAFE_BAG *pSafeBagArray1,
DWORD cSafeBagArray1,
SAFE_BAG *pSafeBagArray2,
DWORD cSafeBagArray2,
SAFE_CONTENTS **ppSafeContents
)
{
BOOL fRet = TRUE;
DWORD cbBytesNeeded = 0;
DWORD i,j;
SAFE_CONTENTS *pSafeContents = NULL;
DWORD dwSafeBagIndex = 0;
BYTE *pbCurrentBufferLocation = NULL;
cbBytesNeeded += sizeof(SAFE_CONTENTS);
cbBytesNeeded += sizeof(SAFE_BAG) * (cSafeBagArray1 + cSafeBagArray2);
for (i=0; i<cSafeBagArray1; i++) {
cbBytesNeeded += strlen(pSafeBagArray1[i].pszBagTypeOID) + 1;
cbBytesNeeded += pSafeBagArray1[i].BagContents.cbData;
cbBytesNeeded += CalculateSizeOfAttributes(&pSafeBagArray1[i].Attributes);
}
for (i=0; i<cSafeBagArray2; i++) {
cbBytesNeeded += strlen(pSafeBagArray2[i].pszBagTypeOID) + 1;
cbBytesNeeded += pSafeBagArray2[i].BagContents.cbData;
cbBytesNeeded += CalculateSizeOfAttributes(&pSafeBagArray2[i].Attributes);
}
if (NULL == (pSafeContents = (SAFE_CONTENTS *) SSAlloc(cbBytesNeeded)))
goto ErrorReturn;
memset(pSafeContents, 0, cbBytesNeeded);
pbCurrentBufferLocation = ((BYTE *) pSafeContents) + sizeof(SAFE_CONTENTS);
pSafeContents->cSafeBags = cSafeBagArray1 + cSafeBagArray2;
pSafeContents->pSafeBags = (SAFE_BAG *) pbCurrentBufferLocation;
pbCurrentBufferLocation += sizeof(SAFE_BAG) * (cSafeBagArray1 + cSafeBagArray2);
for (i=0; i<cSafeBagArray1; i++) {
pSafeContents->pSafeBags[dwSafeBagIndex].pszBagTypeOID = (LPSTR) pbCurrentBufferLocation;
strcpy((LPSTR) pbCurrentBufferLocation, pSafeBagArray1[i].pszBagTypeOID);
pbCurrentBufferLocation += strlen(pSafeBagArray1[i].pszBagTypeOID) + 1;
pSafeContents->pSafeBags[dwSafeBagIndex].BagContents.cbData = pSafeBagArray1[i].BagContents.cbData;
pSafeContents->pSafeBags[dwSafeBagIndex].BagContents.pbData = pbCurrentBufferLocation;
memcpy(pbCurrentBufferLocation, pSafeBagArray1[i].BagContents.pbData, pSafeBagArray1[i].BagContents.cbData);
pbCurrentBufferLocation += pSafeBagArray1[i].BagContents.cbData;
pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.cAttr = pSafeBagArray1[i].Attributes.cAttr;
if (pSafeBagArray1[i].Attributes.cAttr != 0) {
pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr = (CRYPT_ATTRIBUTE *) pbCurrentBufferLocation;
pbCurrentBufferLocation += sizeof(CRYPT_ATTRIBUTE) * pSafeBagArray1[i].Attributes.cAttr;
}
else {
pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr = NULL;
}
for (j=0; j<pSafeBagArray1[i].Attributes.cAttr; j++) {
pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr[j].pszObjId = (LPSTR) pbCurrentBufferLocation;
strcpy((LPSTR) pbCurrentBufferLocation, pSafeBagArray1[i].Attributes.rgAttr[j].pszObjId);
pbCurrentBufferLocation += strlen(pSafeBagArray1[i].Attributes.rgAttr[j].pszObjId) + 1;
pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr[j].cValue = 1;
pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr[j].rgValue = (CRYPT_ATTR_BLOB *) pbCurrentBufferLocation;
pbCurrentBufferLocation += sizeof(CRYPT_ATTR_BLOB);
pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr[j].rgValue[0].cbData =
pSafeBagArray1[i].Attributes.rgAttr[j].rgValue[0].cbData;
pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr[j].rgValue[0].pbData = pbCurrentBufferLocation;
memcpy(
pbCurrentBufferLocation,
pSafeBagArray1[i].Attributes.rgAttr[j].rgValue[0].pbData,
pSafeBagArray1[i].Attributes.rgAttr[j].rgValue[0].cbData);
pbCurrentBufferLocation += pSafeBagArray1[i].Attributes.rgAttr[j].rgValue[0].cbData;
}
dwSafeBagIndex++;
}
for (i=0; i<cSafeBagArray2; i++) {
pSafeContents->pSafeBags[dwSafeBagIndex].pszBagTypeOID = (LPSTR) pbCurrentBufferLocation;
strcpy((LPSTR) pbCurrentBufferLocation, pSafeBagArray2[i].pszBagTypeOID);
pbCurrentBufferLocation += strlen(pSafeBagArray2[i].pszBagTypeOID) + 1;
pSafeContents->pSafeBags[dwSafeBagIndex].BagContents.cbData = pSafeBagArray2[i].BagContents.cbData;
pSafeContents->pSafeBags[dwSafeBagIndex].BagContents.pbData = pbCurrentBufferLocation;
memcpy(pbCurrentBufferLocation, pSafeBagArray2[i].BagContents.pbData, pSafeBagArray2[i].BagContents.cbData);
pbCurrentBufferLocation += pSafeBagArray2[i].BagContents.cbData;
pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.cAttr = pSafeBagArray2[i].Attributes.cAttr;
if (pSafeBagArray2[i].Attributes.cAttr != 0) {
pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr = (CRYPT_ATTRIBUTE *) pbCurrentBufferLocation;
pbCurrentBufferLocation += sizeof(CRYPT_ATTRIBUTE) * pSafeBagArray2[i].Attributes.cAttr;
}
else {
pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr = NULL;
}
for (j=0; j<pSafeBagArray2[i].Attributes.cAttr; j++) {
pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr[j].pszObjId = (LPSTR) pbCurrentBufferLocation;
strcpy((LPSTR) pbCurrentBufferLocation, pSafeBagArray2[i].Attributes.rgAttr[j].pszObjId);
pbCurrentBufferLocation += strlen(pSafeBagArray2[i].Attributes.rgAttr[j].pszObjId) + 1;
pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr[j].cValue = 1;
pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr[j].rgValue = (CRYPT_ATTR_BLOB *) pbCurrentBufferLocation;
pbCurrentBufferLocation += sizeof(CRYPT_ATTR_BLOB);
pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr[j].rgValue[0].cbData =
pSafeBagArray2[i].Attributes.rgAttr[j].rgValue[0].cbData;
pSafeContents->pSafeBags[dwSafeBagIndex].Attributes.rgAttr[j].rgValue[0].pbData = pbCurrentBufferLocation;
memcpy(
pbCurrentBufferLocation,
pSafeBagArray2[i].Attributes.rgAttr[j].rgValue[0].pbData,
pSafeBagArray2[i].Attributes.rgAttr[j].rgValue[0].cbData);
pbCurrentBufferLocation += pSafeBagArray2[i].Attributes.rgAttr[j].rgValue[0].cbData;
}
dwSafeBagIndex++;
}
*ppSafeContents = pSafeContents;
goto Ret;
ErrorReturn:
fRet = FALSE;
Ret:
return fRet;
}
BOOL
PFXAPI
NSCPImportBlob
(
LPCWSTR szPassword,
PBYTE pbIn,
DWORD cbIn,
SAFE_CONTENTS **ppSafeContents
)
{
BOOL fRet = TRUE;
DWORD dwErr;
int iEncrType;
OID oid = NULL;
PFX *psPfx = NULL;
EncryptedData *pEncrData = NULL;
RSAData *pRSAData = NULL;
PBEParameter *pPBEParameter = NULL;
SafeContents *pSafeCnts = NULL;
AuthenticatedSafe *pAuthSafe = NULL;
SAFE_BAG *pKeyBag = NULL;
SAFE_BAG *pCertBag = NULL;
BYTE *pCertThumbprint = NULL;
DWORD cNumCertBags = 0;
ASN1decoding_t pDec = GetDecoder();
// Crack the PFX blob
if (0 != PkiAsn1Decode(
pDec,
(void **)&psPfx,
PFX_PDU,
pbIn,
cbIn))
goto SetPFXDecodeError;
// info blurted into psPfx(PFX) - ensure content present
if (0 == (psPfx->authSafe.bit_mask & content_present))
goto SetPFXDecodeError;
// UNDONE: tear apart MACData
// Check authsafe(ContentInfo)
// could be data/signeddata
// UNDONE: only support szOID_RSA_data
if (!INSCP_Asn1FromObjectID( &psPfx->authSafe.contentType, &oid))
goto ErrorReturn;
if (0 != strcmp( oid, szOID_RSA_data))
goto SetPFXDecodeError;
SSFree(oid);
oid = NULL;
// content is data: decode
if (0 != PkiAsn1Decode(
pDec,
(void **)&pRSAData,
RSAData_PDU,
(BYTE *) psPfx->authSafe.content.value,
psPfx->authSafe.content.length))
goto SetPFXDecodeError;
// now we have octet string: this is an encoded authSafe
if (0 != PkiAsn1Decode(
pDec,
(void **)&pAuthSafe,
AuthenticatedSafe_PDU,
pRSAData->value,
pRSAData->length))
goto SetPFXDecodeError;
// check version of the safe
if (pAuthSafe->bit_mask & version_present)
#ifdef OSS_CRYPT_ASN1
if (pAuthSafe->version != v1)
#else
if (pAuthSafe->version != Version_v1)
#endif // OSS_CRYPT_ASN1
goto SetPFXDecodeError;
// require (officially optional) pieces
// NSCP: transport mode is used but count is encoded incorrectly
// if (0 == (pAuthSafe->bit_mask & transportMode_present))
// goto PFXDecodeError;
if (0 == (pAuthSafe->bit_mask & privacySalt_present))
goto SetPFXDecodeError;
if (0 == (pAuthSafe->bit_mask & baggage_present))
goto SetPFXDecodeError;
// could be encryptedData/envelopedData
// UNDONE: only support szOID_RSA_encryptedData
if (!INSCP_Asn1FromObjectID( &pAuthSafe->safe.contentType, &oid))
goto ErrorReturn;
if (0 != strcmp( oid, szOID_RSA_encryptedData))
goto SetPFXDecodeError;
SSFree(oid);
oid = NULL;
//
// we have pAuthSafe->safe data as RSA_encryptedData
// we have pAuthSafe->privacySalt to help us decrypt it
// we have pAuthSafe->baggage
// decode content to encryptedData
if (0 != PkiAsn1Decode(
pDec,
(void **)&pEncrData,
EncryptedData_PDU,
(BYTE *) pAuthSafe->safe.content.value,
pAuthSafe->safe.content.length))
goto SetPFXDecodeError;
// chk version
if (pEncrData->version != 0)
goto SetPFXDecodeError;
// chk content present, type
if (0 == (pEncrData->encryptedContentInfo.bit_mask & encryptedContent_present))
goto SetPFXDecodeError;
if (!INSCP_Asn1FromObjectID(&pEncrData->encryptedContentInfo.contentType, &oid))
goto ErrorReturn;
if (0 != strcmp( oid, szOID_RSA_data))
goto SetPFXDecodeError;
SSFree(oid);
oid = NULL;
// chk encr alg present, type
if (0 == (pEncrData->encryptedContentInfo.contentEncryptionAlg.bit_mask & parameters_present))
goto SetPFXDecodeError;
if (!INSCP_Asn1FromObjectID(&pEncrData->encryptedContentInfo.contentEncryptionAlg.algorithm, &oid))
goto ErrorReturn;
if (0 != PkiAsn1Decode(
pDec,
(void **)&pPBEParameter,
PBEParameter_PDU,
(BYTE *) pEncrData->encryptedContentInfo.contentEncryptionAlg.parameters.value,
pEncrData->encryptedContentInfo.contentEncryptionAlg.parameters.length))
goto SetPFXDecodeError;
if (0 == strcmp( oid, OLD_szOID_PKCS_12_pbeWithSHA1And40BitRC2))
{
iEncrType = RC2_40;
}
else if (0 == strcmp( oid, OLD_szOID_PKCS_12_pbeWithSHA1And40BitRC4))
{
iEncrType = RC4_40;
}
else if (0 == strcmp( oid, OLD_szOID_PKCS_12_pbeWithSHA1And128BitRC2))
{
iEncrType = RC2_128;
}
else if (0 == strcmp( oid, OLD_szOID_PKCS_12_pbeWithSHA1And128BitRC4))
{
iEncrType = RC4_128;
}
else if (0 == strcmp( oid, OLD_szOID_PKCS_12_pbeWithSHA1AndTripleDES))
{
iEncrType = TripleDES;
}
else
goto SetPFXAlgIDError;
SSFree(oid);
oid = NULL;
// DECRYPT encryptedData
if (!NSCPPasswordDecryptData(
iEncrType,
szPassword,
pAuthSafe->privacySalt.value, // privacy salt
pAuthSafe->privacySalt.length/8,
pPBEParameter->iterationCount,
pPBEParameter->salt.value, // pkcs5 salt
pPBEParameter->salt.length,
&pEncrData->encryptedContentInfo.encryptedContent.value,
(PDWORD)&pEncrData->encryptedContentInfo.encryptedContent.length))
goto SetPFXDecryptError;
// decode plaintext encryptedData
if (0 != PkiAsn1Decode(
pDec,
(void **)&pSafeCnts,
SafeContents_PDU,
pEncrData->encryptedContentInfo.encryptedContent.value,
pEncrData->encryptedContentInfo.encryptedContent.length))
goto SetPFXDecodeError;
// get private keys out of baggage
if (!ExtractKeyFromBaggage(
pAuthSafe->baggage,
&pKeyBag,
szPassword,
1, // this parameter is the Local Key ID to add to the key bags attributes
&pCertThumbprint)) {
goto ErrorReturn;
}
// set up the cert bag
if (!SetupCertBags(
pSafeCnts,
&pCertBag,
&cNumCertBags,
1, // this parameter is the Local Key ID to add to the cert bags attributes
pCertThumbprint)) {
goto ErrorReturn;
}
ConcatenateSafeBagsIntoSafeContents(
pKeyBag,
1,
pCertBag,
cNumCertBags,
ppSafeContents);
goto Ret;
SetPFXAlgIDError:
SetLastError(NTE_BAD_ALGID);
goto ErrorReturn;
SetPFXDecodeError:
SetLastError(CRYPT_E_BAD_ENCODE);
goto ErrorReturn;
SetPFXDecryptError:
SetLastError(NTE_FAIL);
goto ErrorReturn;
ErrorReturn:
fRet = FALSE;
Ret:
// save last error from TLS madness
dwErr = GetLastError();
PkiAsn1FreeDecoded(pDec, psPfx, PFX_PDU);
PkiAsn1FreeDecoded(pDec, pRSAData, RSAData_PDU);
PkiAsn1FreeDecoded(pDec, pAuthSafe, AuthenticatedSafe_PDU);
PkiAsn1FreeDecoded(pDec, pEncrData, EncryptedData_PDU);
PkiAsn1FreeDecoded(pDec, pPBEParameter, PBEParameter_PDU);
PkiAsn1FreeDecoded(pDec, pSafeCnts, SafeContents_PDU);
if (oid != NULL)
SSFree(oid);
if (pKeyBag)
SSFree(pKeyBag);
if (pCertBag)
SSFree(pCertBag);
if (pCertThumbprint)
SSFree(pCertThumbprint);
// save last error from TLS madness
SetLastError(dwErr);
return fRet; // return bogus handle
}
BOOL
PFXAPI
IsNetscapePFXBlob(CRYPT_DATA_BLOB* pPFX)
{
PFX *psPfx = NULL;
ASN1decoding_t pDec = GetDecoder();
// Crack the PFX blob
if (0 == PkiAsn1Decode(
pDec,
(void **)&psPfx,
PFX_PDU,
pPFX->pbData,
pPFX->cbData))
{
PkiAsn1FreeDecoded(pDec, psPfx, PFX_PDU);
return TRUE;
}
return FALSE;
}
/*
BOOL FNSCPDumpSafeCntsToHPFX(SafeContents* pSafeCnts, HPFX hpfx)
{
PPFX_INFO ppfx = (PPFX_INFO)hpfx;
// sort and dump bags into correct areas
ObjectID oKeyBag, oCertBag;
DWORD dw;
ZeroMemory(&oKeyBag, sizeof(ObjectID));
ZeroMemory(&oCertBag, sizeof(ObjectID));
if (!INSCP_Asn1ToObjectID( &szOID_PKCS_12_KeyBagIDs, &oKeyBag))
return FALSE;
if (!INSCP_Asn1ToObjectID( &szOID_PKCS_12_CertCrlBagIDs, &oCertBag))
return FALSE;
for (dw=pSafeCnts->count; dw>0; --dw)
{
if (INSCP_EqualObjectIDs(&pSafeCnts->value->safeBagType,
&oKeyBag) )
{
// inc size
ppfx->cKeys++;
if (ppfx->rgKeys)
ppfx->rgKeys = (void**)SSReAlloc(ppfx->rgKeys, ppfx->cKeys * sizeof(SafeBag*));
else
ppfx->rgKeys = (void**)SSAlloc(ppfx->cKeys * sizeof(SafeBag*));
// assign to keys
ppfx->rgKeys[ppfx->cKeys-1] = &pSafeCnts->value[dw];
}
else if (INSCP_EqualObjectIDs(&pSafeCnts->value->safeBagType,
&oCertBag) )
{
// inc size
ppfx->cCertcrls++;
if (ppfx->rgCertcrls)
ppfx->rgCertcrls = (void**)SSReAlloc(ppfx->rgCertcrls, ppfx->cCertcrls * sizeof(SafeBag*));
else
ppfx->rgCertcrls = (void**)SSAlloc(ppfx->cCertcrls * sizeof(SafeBag*));
// assign to certs/crls
ppfx->rgCertcrls[ppfx->cCertcrls-1] = &pSafeCnts->value[dw];
}
else
{
// inc size
ppfx->cSecrets++;
if (ppfx->rgSecrets)
ppfx->rgSecrets = (void**)SSReAlloc(ppfx->rgSecrets, ppfx->cSecrets * sizeof(SafeBag*));
else
ppfx->rgSecrets = (void**)SSAlloc(ppfx->cSecrets * sizeof(SafeBag*));
// assign to safebag
ppfx->rgSecrets[ppfx->cSecrets-1] = &pSafeCnts->value[dw];
}
}
return TRUE;
}
*/