|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: pfx.cpp
//
// Contents: PFX: Personal Information Exchange.
//
// Functions:
//
// History: 02-Aug-96 kevinr created
// 01-May-97 mattt modified for pstore provider usage
// 07-Jul-97 mattt modified for crypt32 inclusion
//
//--------------------------------------------------------------------------
#include "global.hxx"
#define _PFX_SOURCE_
extern "C" { #include "pfxpkcs.h" // ASN1-generated
}
#include "pfxhelp.h"
#include "pfxcmn.h"
#include "crypttls.h"
#include "pfxcrypt.h"
#include "shacomm.h"
#include "dbgdef.h"
#define CURRENT_PFX_VERSION 0x3
// fwd
BOOL FPFXDumpSafeCntsToHPFX(SafeContents* pSafeCnts, HPFX hpfx);
static HCRYPTASN1MODULE hPFXAsn1Module;
BOOL InitPFX() { #ifdef OSS_CRYPT_ASN1
if (0 == (hPFXAsn1Module = I_CryptInstallAsn1Module(pfxpkcs, 0, NULL)) ) return FALSE; #else
PFXPKCS_Module_Startup(); if (0 == (hPFXAsn1Module = I_CryptInstallAsn1Module( PFXPKCS_Module, 0, NULL))) { PFXPKCS_Module_Cleanup(); return FALSE; } #endif // OSS_CRYPT_ASN1
return TRUE; }
BOOL TerminatePFX() { I_CryptUninstallAsn1Module(hPFXAsn1Module); #ifndef OSS_CRYPT_ASN1
PFXPKCS_Module_Cleanup(); #endif // OSS_CRYPT_ASN1
return TRUE; }
static inline ASN1encoding_t GetEncoder(void) { return I_CryptGetAsn1Encoder(hPFXAsn1Module); } static inline ASN1decoding_t GetDecoder(void) { return I_CryptGetAsn1Decoder(hPFXAsn1Module); }
//+-------------------------------------------------------------------------
// Function: IPFX_Asn1ToObjectID
//
// Synopsis: Convert a dotted string oid to an ASN1 ObjectID
//
// Returns: FALSE iff failed
//--------------------------------------------------------------------------
BOOL IPFX_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: IPFX_Asn1FromObjectID
//
// Synopsis: Convert an ASN1 ObjectID to a dotted string oid
//
// Returns: FALSE iff failed
//--------------------------------------------------------------------------
BOOL IPFX_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: IPFX_EqualObjectIDs
//
// Compare 2 OSS object id's.
//
// Returns: FALSE iff !equal
//--------------------------------------------------------------------------
BOOL WINAPI IPFX_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; }
//+-------------------------------------------------------------------------
// Function: PfxExportCreate
//
// Synopsis: Prepare the PFX for export
//
// Returns: NULL iff failed
//--------------------------------------------------------------------------
HPFX PFXAPI PfxExportCreate ( LPCWSTR szPassword ) { PPFX_INFO ppfx = NULL; PCCERT_CONTEXT pcctx = NULL;
// Create the HPFX
if (NULL == (ppfx = (PPFX_INFO)SSAlloc(sizeof(PFX_INFO)))) goto PfxInfoAllocError; ZeroMemory(ppfx, sizeof(PFX_INFO));
if (szPassword) { if (NULL == (ppfx->szPassword = (LPWSTR)SSAlloc(WSZ_BYTECOUNT(szPassword)) )) goto PfxInfoAllocError;
CopyMemory(ppfx->szPassword, szPassword, WSZ_BYTECOUNT(szPassword)); } else { ppfx->szPassword = NULL; }
CommonReturn: // free pcctx
return (HPFX)ppfx;
ErrorReturn: PfxCloseHandle((HPFX)ppfx); ppfx = NULL; goto CommonReturn;
TRACE_ERROR(PfxInfoAllocError) }
BOOL ASNFreeSafeBag(SafeBag* pBag) { DWORD iAttr, iAnys;
if (pBag->safeBagAttribs.value) { if (pBag->safeBagContent.value) { SSFree(pBag->safeBagContent.value); pBag->safeBagContent.value = NULL; }
for (iAttr=0; iAttr<pBag->safeBagAttribs.count; iAttr++) { for (iAnys=0; iAnys<pBag->safeBagAttribs.value[iAttr].attributeValue.count; iAnys++) { if (pBag->safeBagAttribs.value[iAttr].attributeValue.value[iAnys].value) SSFree(pBag->safeBagAttribs.value[iAttr].attributeValue.value[iAnys].value); pBag->safeBagAttribs.value[iAttr].attributeValue.value[iAnys].value = NULL; } SSFree(pBag->safeBagAttribs.value[iAttr].attributeValue.value); }
SSFree(pBag->safeBagAttribs.value); pBag->safeBagAttribs.value = NULL; pBag->safeBagAttribs.count = 0; } SSFree(pBag);
return TRUE; }
//+-------------------------------------------------------------------------
// Function: PfxCloseHandle
//
// Synopsis: Free all resources associated with the hpfx
//
// Returns: error code
//--------------------------------------------------------------------------
BOOL PFXAPI PfxCloseHandle ( IN HPFX hpfx) { BOOL fRet = FALSE; PPFX_INFO pPfx = (PPFX_INFO)hpfx; DWORD i;
if (pPfx) { if (pPfx->szPassword) SSFree(pPfx->szPassword); // keys struct
for (i=0; i<pPfx->cKeys; i++) { ASNFreeSafeBag((SafeBag*)pPfx->rgKeys[i]); pPfx->rgKeys[i] = NULL; }
SSFree(pPfx->rgKeys); pPfx->rgKeys = NULL; pPfx->cKeys = 0;
// shrouded keys
for (i=0; i<pPfx->cShroudedKeys; i++) { ASNFreeSafeBag((SafeBag*)pPfx->rgShroudedKeys[i]); pPfx->rgShroudedKeys[i] = NULL; }
SSFree(pPfx->rgShroudedKeys); pPfx->rgShroudedKeys = NULL; pPfx->cShroudedKeys = 0;
// certcrl struct
for (i=0; i<pPfx->cCertcrls; i++) { ASNFreeSafeBag((SafeBag*)pPfx->rgCertcrls[i]); pPfx->rgCertcrls[i] = NULL; }
SSFree(pPfx->rgCertcrls); pPfx->rgCertcrls = NULL; pPfx->cCertcrls = 0;
// secrets struct
for (i=0; i<pPfx->cSecrets; i++) { ASNFreeSafeBag((SafeBag*)pPfx->rgSecrets[i]); pPfx->rgSecrets[i] = NULL; }
SSFree(pPfx->rgSecrets); pPfx->rgSecrets = NULL; pPfx->cSecrets = 0;
SSFree(pPfx); }
fRet = TRUE;
//Ret:
return fRet; }
BOOL MakeEncodedCertBag( BYTE *pbEncodedCert, DWORD cbEncodedCert, BYTE *pbEncodedCertBag, DWORD *pcbEncodedCertBag ) { BOOL fRet = TRUE; DWORD dwErr;
OctetStringType encodedCert; DWORD cbCertAsOctetString = 0; BYTE *pbCertAsOctetString = NULL; DWORD dwBytesNeeded = 0; CertBag certBag; BYTE *pbEncoded = NULL; DWORD cbEncoded = 0; ASN1encoding_t pEnc = GetEncoder();
// wrap the encoded cert in an OCTET_STRING
encodedCert.length = cbEncodedCert; encodedCert.value = pbEncodedCert;
if (0 != PkiAsn1Encode( pEnc, &encodedCert, OctetStringType_PDU, &pbCertAsOctetString, &cbCertAsOctetString)) goto SetPFXEncodeError; // setup and encode the CertBag
// convert the X509Cert oid from a string to an ASN1 ObjectIdentifier
if (!IPFX_Asn1ToObjectID(szOID_PKCS_12_x509Cert, &certBag.certType)) { goto ErrorReturn; }
certBag.value.length = cbCertAsOctetString; certBag.value.value = pbCertAsOctetString;
if (0 != PkiAsn1Encode( pEnc, &certBag, CertBag_PDU, &pbEncoded, &cbEncoded)) goto SetPFXEncodeError;
// check to see if the caller has enough space for the data
if ((0 != *pcbEncodedCertBag) && (*pcbEncodedCertBag < cbEncoded)) { goto ErrorReturn; } else if (0 != *pcbEncodedCertBag) { memcpy(pbEncodedCertBag, pbEncoded, cbEncoded); } goto CommonReturn; SetPFXEncodeError: SetLastError(CRYPT_E_BAD_ENCODE); ErrorReturn: fRet = FALSE; CommonReturn:
// save last error from TLS madness
dwErr = GetLastError();
*pcbEncodedCertBag = cbEncoded;
PkiAsn1FreeEncoded(pEnc, pbCertAsOctetString);
PkiAsn1FreeEncoded(pEnc, pbEncoded);
// save last error from TLS madness
SetLastError(dwErr);
return fRet; }
BOOL GetEncodedCertFromEncodedCertBag( BYTE *pbEncodedCertBag, DWORD cbEncodedCertBag, BYTE *pbEncodedCert, DWORD *pcbEncodedCert) { BOOL fRet = TRUE; DWORD dwErr;
CertBag *pCertBag = NULL; OID oid = NULL; OctetStringType *pEncodedCert = NULL; ASN1decoding_t pDec = GetDecoder();
// decode the cert bag
if (0 != PkiAsn1Decode( pDec, (void **)&pCertBag, CertBag_PDU, pbEncodedCertBag, cbEncodedCertBag)) goto SetPFXDecodeError;
// make sure this is a X509 cert since that is all we support
if (!IPFX_Asn1FromObjectID(&pCertBag->certType, &oid)) goto ErrorReturn;
// only support SHA1
if (0 != strcmp( oid, szOID_PKCS_12_x509Cert)) goto SetPFXDecodeError; // strip off the octet string wrapper of the encoded cert
if (0 != PkiAsn1Decode( pDec, (void **)&pEncodedCert, OctetStringType_PDU, (BYTE *) pCertBag->value.value, pCertBag->value.length)) goto SetPFXDecodeError;
// check to see if the caller has enough space for the data
if ((0 != *pcbEncodedCert) && (*pcbEncodedCert < (DWORD) pEncodedCert->length)) { goto ErrorReturn; } else if (0 != *pcbEncodedCert) { memcpy(pbEncodedCert, pEncodedCert->value, pEncodedCert->length); }
goto CommonReturn;
SetPFXDecodeError: SetLastError(CRYPT_E_BAD_ENCODE); ErrorReturn: fRet = FALSE; CommonReturn:
// save last error from TLS madness
dwErr = GetLastError();
if (pEncodedCert) *pcbEncodedCert = pEncodedCert->length;
PkiAsn1FreeDecoded(pDec, pCertBag, CertBag_PDU); PkiAsn1FreeDecoded(pDec, pEncodedCert, OctetStringType_PDU);
if (oid) SSFree(oid);
// save last error from TLS madness
SetLastError(dwErr);
return fRet; }
BOOL GetSaltAndIterationCount( BYTE *pbParameters, DWORD cbParameters, BYTE **ppbSalt, DWORD *pcbSalt, int *piIterationCount ) { BOOL fRet = TRUE; DWORD dwErr;
PBEParameter *pPBEParameter = NULL; ASN1decoding_t pDec = GetDecoder(); if (0 != PkiAsn1Decode( pDec, (void **)&pPBEParameter, PBEParameter_PDU, pbParameters, cbParameters)) goto SetPFXDecodeError;
if (NULL == (*ppbSalt = (BYTE *) SSAlloc(pPBEParameter->salt.length))) goto ErrorReturn;
memcpy(*ppbSalt, pPBEParameter->salt.value, pPBEParameter->salt.length); *pcbSalt = pPBEParameter->salt.length; *piIterationCount = pPBEParameter->iterationCount;
goto Ret;
SetPFXDecodeError: SetLastError(CRYPT_E_BAD_ENCODE); fRet = FALSE; goto Ret;
ErrorReturn: fRet = FALSE; Ret:
// save last error from TLS madness
dwErr = GetLastError();
PkiAsn1FreeDecoded(pDec, pPBEParameter, PBEParameter_PDU);
// save last error from TLS madness
SetLastError(dwErr);
return fRet;
}
BOOL SetSaltAndIterationCount( BYTE **ppbParameters, DWORD *pcbParameters, BYTE *pbSalt, DWORD cbSalt, int iIterationCount ) { BOOL fRet = TRUE; DWORD dwErr;
PBEParameter sPBEParameter; sPBEParameter.salt.length = cbSalt; sPBEParameter.salt.value = pbSalt; sPBEParameter.iterationCount = iIterationCount;
BYTE *pbEncoded = NULL; DWORD cbEncoded; ASN1encoding_t pEnc = GetEncoder();
if (0 != PkiAsn1Encode( pEnc, &sPBEParameter, PBEParameter_PDU, &pbEncoded, &cbEncoded)) goto SetPFXDecodeError;
if (NULL == (*ppbParameters = (BYTE *) SSAlloc(cbEncoded))) goto ErrorReturn;
memcpy(*ppbParameters, pbEncoded, cbEncoded); *pcbParameters = cbEncoded;
goto Ret;
SetPFXDecodeError: SetLastError(CRYPT_E_BAD_ENCODE); fRet = FALSE; goto Ret;
ErrorReturn: fRet = FALSE; Ret:
// save last error from TLS madness
dwErr = GetLastError();
PkiAsn1FreeEncoded(pEnc, pbEncoded);
// save last error from TLS madness
SetLastError(dwErr);
return fRet;
}
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
// wrap up data from pfx_info.safeContents area
BOOL PFXAPI PfxExportBlob ( HPFX hpfx, PBYTE pbOut, DWORD* pcbOut, DWORD dwFlags ) { BOOL fRet = FALSE; BOOL fSizeOnly = (pbOut==NULL);
DWORD dwErr; PPFX_INFO ppfx = (PPFX_INFO)hpfx;
BYTE rgbSafeMac[A_SHA_DIGEST_LEN]; BYTE rgbMacSalt[A_SHA_DIGEST_LEN];
OID oid = NULL; EncryptedData EncrData; MAKEZERO(EncrData); OctetStringType OctetStr; MAKEZERO(OctetStr); AuthenticatedSafes AuthSafes; MAKEZERO(AuthSafes); PBEParameter PbeParam; MAKEZERO(PbeParam); ContentInfo rgCntInfo[2]; MAKEZERO(rgCntInfo); SafeContents SafeCnts; MAKEZERO(SafeCnts); PFX sPfx; MAKEZERO(sPfx);
BYTE *pbEncoded = NULL; DWORD cbEncoded; ASN1encoding_t pEnc = GetEncoder();
PBYTE pbEncrData = NULL; DWORD cbEncrData;
DWORD i;
// multi bags with differing security levels
int iLevel, iBagSecurityLevels = 0; BOOL fNoSecurity, fLowSecurity, fHighSecurity; DWORD dwEncrAlg;
HCRYPTPROV hVerifyProv = NULL;
if (!CryptAcquireContext(&hVerifyProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) goto ErrorOut;
// Encode all SafeBags
fNoSecurity = (ppfx->cShroudedKeys != 0); // no encr on these items
fLowSecurity = ((ppfx->cSecrets + ppfx->cCertcrls) != 0); // low level crypto on these items
fHighSecurity = (ppfx->cKeys != 0); // high level crypto on these items
iBagSecurityLevels = (fNoSecurity ? 1:0) + (fLowSecurity ? 1:0) + (fHighSecurity ? 1:0); assert(iBagSecurityLevels <= (sizeof(rgCntInfo)/sizeof(rgCntInfo[0])) );
for (iLevel=0; iLevel<iBagSecurityLevels; iLevel++) { // clean up these each time through loop
if (SafeCnts.value) { SSFree(SafeCnts.value); MAKEZERO(SafeCnts); } if (PbeParam.salt.value) { SSFree(PbeParam.salt.value); MAKEZERO(PbeParam); } if (EncrData.encryptedContentInfo.contentEncryptionAlg.parameters.value) { PkiAsn1FreeEncoded( pEnc, EncrData.encryptedContentInfo.contentEncryptionAlg.parameters.value); MAKEZERO(EncrData); } if (pbEncrData) { SSFree(pbEncrData); pbEncrData = NULL; }
if (fNoSecurity) { // no security: bag already shrouded
SafeCnts.count = ppfx->cShroudedKeys; if (NULL == (SafeCnts.value = (SafeBag*) SSAlloc(SafeCnts.count * sizeof(SafeBag)) )) goto SetPfxAllocError;
ZeroMemory(SafeCnts.value, SafeCnts.count * sizeof(SafeBag));
for (i=0; i<(ppfx->cShroudedKeys); i++) CopyMemory(&SafeCnts.value[i], ppfx->rgShroudedKeys[i], sizeof(SafeBag));
// bag already shrouded!
dwEncrAlg = 0;
// done with no security setup
fNoSecurity = FALSE; } else if (fLowSecurity) { DWORD dw = 0;
// do low security (keys/secrets)
SafeCnts.count = ppfx->cSecrets + ppfx->cCertcrls; if (NULL == (SafeCnts.value = (SafeBag*) SSAlloc(SafeCnts.count * sizeof(SafeBag)) )) goto SetPfxAllocError;
ZeroMemory(SafeCnts.value, SafeCnts.count * sizeof(SafeBag));
for (i=0; i<(ppfx->cSecrets); i++, dw++) CopyMemory(SafeCnts.value, ppfx->rgSecrets[i], sizeof(SafeBag)); for (i=0; i<(ppfx->cCertcrls); i++, dw++) CopyMemory(&SafeCnts.value[dw], ppfx->rgCertcrls[i], sizeof(SafeBag));
// encr alg present, type
EncrData.encryptedContentInfo.contentEncryptionAlg.bit_mask |= parameters_present; if (!IPFX_Asn1ToObjectID(szOID_PKCS_12_pbeWithSHA1And40BitRC2, &EncrData.encryptedContentInfo.contentEncryptionAlg.algorithm)) goto ErrorOut;
dwEncrAlg = RC2_40;
// done with low security setup
fLowSecurity = FALSE; } else if (fHighSecurity) { // high security: need strength for unencr keys
SafeCnts.count = ppfx->cKeys; if (NULL == (SafeCnts.value = (SafeBag*) SSAlloc(SafeCnts.count * sizeof(SafeBag)) )) goto SetPfxAllocError;
ZeroMemory(SafeCnts.value, SafeCnts.count * sizeof(SafeBag));
for (i=0; i<(ppfx->cKeys); i++) CopyMemory(&SafeCnts.value[i], ppfx->rgKeys[i], sizeof(SafeBag));
// encr alg present, type
EncrData.encryptedContentInfo.contentEncryptionAlg.bit_mask |= parameters_present; if (!IPFX_Asn1ToObjectID(szOID_PKCS_12_pbeWithSHA1And3KeyTripleDES, &EncrData.encryptedContentInfo.contentEncryptionAlg.algorithm)) goto ErrorOut;
// bag already shrouded!
dwEncrAlg = TripleDES;
// done with high security setup
fHighSecurity = FALSE; } else break; // no more bags
// encode safecontents
if (0 != PkiAsn1Encode( pEnc, &SafeCnts, SafeContents_PDU, &pbEncoded, &cbEncoded)) goto SetPFXEncodeError;
if (dwEncrAlg == 0) { // no encryption?
OctetStr.length = cbEncoded; OctetStr.value = pbEncoded;
// jam octet string into contentInfo
if (0 != PkiAsn1Encode( pEnc, &OctetStr, OctetStringType_PDU, &pbEncoded, &cbEncoded)) goto SetPFXEncodeError;
if (OctetStr.value) { PkiAsn1FreeEncoded(pEnc, OctetStr.value); OctetStr.value = NULL; }
// set up content info struct
if (!IPFX_Asn1ToObjectID( szOID_RSA_data, &rgCntInfo[iLevel].contentType)) goto ErrorOut;
rgCntInfo[iLevel].content.length = cbEncoded; rgCntInfo[iLevel].content.value = pbEncoded; rgCntInfo[iLevel].bit_mask = content_present; } else { cbEncrData = cbEncoded; if (NULL == (pbEncrData = (PBYTE)SSAlloc(cbEncoded)) ) goto SetPfxAllocError;
CopyMemory(pbEncrData, pbEncoded, cbEncrData); PkiAsn1FreeEncoded(pEnc, pbEncoded);
// PBE Param
PbeParam.iterationCount = PKCS12_ENCR_PWD_ITERATIONS; if (NULL == (PbeParam.salt.value = (BYTE *) SSAlloc(PBE_SALT_LENGTH) )) goto SetPfxAllocError;
PbeParam.salt.length = PBE_SALT_LENGTH;
if (!CryptGenRandom(hVerifyProv, PBE_SALT_LENGTH, PbeParam.salt.value)) goto ErrorOut;
if (0 != PkiAsn1Encode( pEnc, &PbeParam, PBEParameter_PDU, &pbEncoded, &cbEncoded)) goto SetPFXEncodeError;
EncrData.encryptedContentInfo.contentEncryptionAlg.parameters.length = cbEncoded; EncrData.encryptedContentInfo.contentEncryptionAlg.parameters.value = pbEncoded;
// ENCRYPT safeContents into encryptedData
// using szPassword (in place)
if (!PFXPasswordEncryptData( dwEncrAlg,
ppfx->szPassword, // pwd itself
(fSizeOnly) ? 1 : PbeParam.iterationCount, // don't do iterations if only returning size
PbeParam.salt.value, // pkcs5 salt
PbeParam.salt.length,
&pbEncrData, &cbEncrData)) goto SetPFXEncryptError;
// encode content to encryptedContentInfo
EncrData.encryptedContentInfo.bit_mask |= encryptedContent_present; if (!IPFX_Asn1ToObjectID(szOID_RSA_data, &EncrData.encryptedContentInfo.contentType)) goto ErrorOut; EncrData.encryptedContentInfo.encryptedContent.length = cbEncrData; EncrData.encryptedContentInfo.encryptedContent.value = pbEncrData;
if (0 != PkiAsn1Encode( pEnc, &EncrData, EncryptedData_PDU, &pbEncoded, &cbEncoded)) goto SetPFXEncodeError;
// jam octet string into contentInfo
// set up content info struct
if (!IPFX_Asn1ToObjectID( szOID_RSA_encryptedData, &rgCntInfo[iLevel].contentType)) goto ErrorOut;
rgCntInfo[iLevel].content.length = cbEncoded; rgCntInfo[iLevel].content.value = pbEncoded; rgCntInfo[iLevel].bit_mask = content_present; } }
AuthSafes.count = iBagSecurityLevels; AuthSafes.value = rgCntInfo;
// set up authenticated safe struct
if (0 != PkiAsn1Encode( pEnc, &AuthSafes, AuthenticatedSafes_PDU, &pbEncoded, &cbEncoded)) goto SetPFXEncodeError;
{ sPfx.macData.bit_mask = macIterationCount_present; sPfx.macData.safeMac.digest.length = sizeof(rgbSafeMac); sPfx.macData.safeMac.digest.value = rgbSafeMac;
// COMPATIBILITY MODE: export with macIterationCount == 1
if (dwFlags & PKCS12_ENHANCED_STRENGTH_ENCODING) sPfx.macData.macIterationCount = PKCS12_MAC_PWD_ITERATIONS; else sPfx.macData.macIterationCount = 1;
if (!IPFX_Asn1ToObjectID( szOID_OIWSEC_sha1, &sPfx.macData.safeMac.digestAlgorithm.algorithm)) goto ErrorOut;
sPfx.macData.macSalt.length = sizeof(rgbMacSalt); sPfx.macData.macSalt.value = rgbMacSalt;
if (!CryptGenRandom(hVerifyProv, sPfx.macData.macSalt.length, sPfx.macData.macSalt.value)) goto ErrorOut; // create MAC
if (!FGenerateMAC( ppfx->szPassword, sPfx.macData.macSalt.value, // pb salt
sPfx.macData.macSalt.length, // cb salt
(fSizeOnly) ? 1 : sPfx.macData.macIterationCount, // don't do iterations if only returning size
pbEncoded, // pb data
cbEncoded, // cb data
sPfx.macData.safeMac.digest.value)) goto SetPFXPasswordError; } sPfx.bit_mask |= macData_present; // stream to octet string
OctetStr.length = cbEncoded; OctetStr.value = pbEncoded; if (0 != PkiAsn1Encode( pEnc, &OctetStr, OctetStringType_PDU, &pbEncoded, &cbEncoded)) goto SetPFXEncodeError; // take encoded authsafes octet string, encode in PFX pdu
if (!IPFX_Asn1ToObjectID( szOID_RSA_data, &sPfx.authSafes.contentType)) goto ErrorOut; sPfx.authSafes.content.length = cbEncoded; sPfx.authSafes.content.value = pbEncoded; sPfx.authSafes.bit_mask = content_present; sPfx.version = CURRENT_PFX_VERSION; if (0 != PkiAsn1Encode( pEnc, &sPfx, PFX_PDU, &pbEncoded, &cbEncoded)) goto SetPFXEncodeError;
fRet = TRUE; goto Ret;
SetPFXEncodeError: SetLastError(CRYPT_E_BAD_ENCODE); goto Ret;
SetPFXPasswordError: SetLastError(ERROR_INVALID_PASSWORD); goto Ret;
SetPFXEncryptError: SetLastError(NTE_FAIL); goto Ret;
SetPfxAllocError: SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto Ret;
ErrorOut: // error already set; just return failure
Ret: // save last error from TLS madness
dwErr = GetLastError(); if (hVerifyProv) CryptReleaseContext(hVerifyProv, 0);
if (EncrData.encryptedContentInfo.contentEncryptionAlg.parameters.value) PkiAsn1FreeEncoded( pEnc, EncrData.encryptedContentInfo.contentEncryptionAlg.parameters.value);
for(iLevel=0; iLevel<iBagSecurityLevels; iLevel++) { if (rgCntInfo[iLevel].content.value) PkiAsn1FreeEncoded( pEnc, rgCntInfo[iLevel].content.value); }
PkiAsn1FreeEncoded(pEnc, OctetStr.value); PkiAsn1FreeEncoded(pEnc, sPfx.authSafes.content.value);
if (pbEncrData) SSFree(pbEncrData);
if (SafeCnts.value) SSFree(SafeCnts.value);
if (PbeParam.salt.value) SSFree(PbeParam.salt.value);
if (fRet) { if (pbOut == NULL) { // report size only
*pcbOut = cbEncoded; } else if (*pcbOut < cbEncoded) { // report that we need a bigger buffer
*pcbOut = cbEncoded; fRet = FALSE; } else { // give full results
CopyMemory( pbOut, pbEncoded, cbEncoded); *pcbOut = cbEncoded; } } else *pcbOut = 0;
PkiAsn1FreeEncoded(pEnc, pbEncoded);
// save last error from TLS madness
SetLastError(dwErr);
return fRet; }
HPFX PFXAPI PfxImportBlob ( LPCWSTR szPassword, PBYTE pbIn, DWORD cbIn, DWORD dwFlags ) { PPFX_INFO ppfx = NULL; BOOL fRet = FALSE; DWORD dwErr;
int iEncrType; OID oid = NULL; DWORD iAuthSafes; // # of safes in a pfx bag
PFX *psPfx = NULL; OctetStringType *pOctetString = NULL; AuthenticatedSafes *pAuthSafes = NULL; PBEParameter *pPBEParameter = NULL; EncryptedData *pEncrData = NULL; SafeContents *pSafeCnts = NULL; OctetStringType *pNonEncryptedOctetString = NULL;
DWORD cbDecrData; PBYTE pbDecrData = NULL;
BYTE *pbEncoded = NULL; DWORD cbEncoded; ASN1decoding_t pDec = GetDecoder();
// alloc return struct
if (NULL == (ppfx = (PFX_INFO*)SSAlloc(sizeof(PFX_INFO)) )) goto SetPfxAllocError;
ZeroMemory(ppfx, sizeof(PFX_INFO));
// Crack the PFX blob
if (0 != PkiAsn1Decode( pDec, (void **)&psPfx, PFX_PDU, pbIn, cbIn)) goto SetPFXDecodeError; // check version of the PFX bag
if (psPfx->version != CURRENT_PFX_VERSION) goto SetPFXDecodeError;
// info blurted into psPfx(PFX) - ensure content present
if (0 == (psPfx->authSafes.bit_mask & content_present)) goto SetPFXDecodeError;
// could be data/signeddata
// UNDONE: only support szOID_RSA_data
if (!IPFX_Asn1FromObjectID( &psPfx->authSafes.contentType, &oid)) goto ErrorOut; if (0 != strcmp( oid, szOID_RSA_data)) goto SetPFXDecodeError; SSFree(oid); // DSIE: Bug 144526.
oid = NULL;
// content is data: decode
if (0 != PkiAsn1Decode( pDec, (void **)&pOctetString, OctetStringType_PDU, (BYTE *) psPfx->authSafes.content.value, psPfx->authSafes.content.length)) goto SetPFXDecodeError;
if (0 != (psPfx->bit_mask & macData_present)) { BYTE rgbMAC[A_SHA_DIGEST_LEN];
if (!IPFX_Asn1FromObjectID( &psPfx->macData.safeMac.digestAlgorithm.algorithm, &oid)) goto ErrorOut;
// only support SHA1
if (0 != strcmp( oid, szOID_OIWSEC_sha1)) goto SetPFXDecodeError; SSFree(oid); // DSIE: Bug 144526.
oid = NULL;
if (psPfx->macData.safeMac.digest.length != A_SHA_DIGEST_LEN) goto SetPFXIntegrityError;
// check MAC
// if there is no iterationCount then 1 is the default
if (!(psPfx->macData.bit_mask & macIterationCount_present)) { if (!FGenerateMAC( szPassword, psPfx->macData.macSalt.value, // pb salt
psPfx->macData.macSalt.length, // cb salt
1, pOctetString->value, // pb data
pOctetString->length, // cb data
rgbMAC)) goto SetPFXIntegrityError; } else { if (!FGenerateMAC( szPassword, psPfx->macData.macSalt.value, // pb salt
psPfx->macData.macSalt.length, // cb salt
(DWORD)psPfx->macData.macIterationCount, pOctetString->value, // pb data
pOctetString->length, // cb data
rgbMAC)) goto SetPFXIntegrityError; }
if (0 != memcmp(rgbMAC, psPfx->macData.safeMac.digest.value, A_SHA_DIGEST_LEN)) goto SetPFXIntegrityError; } // now we have octet string: this is an encoded authSafe
if (0 != PkiAsn1Decode( pDec, (void **)&pAuthSafes, AuthenticatedSafes_PDU, pOctetString->value, pOctetString->length)) goto SetPFXDecodeError; // handle multiple safes
for (iAuthSafes = 0; iAuthSafes < pAuthSafes->count; iAuthSafes++) { // could be encryptedData/envelopedData
// check to see if the content is szOID_RSA_encryptedData or szOID_RSA_data
if (!IPFX_Asn1FromObjectID( &pAuthSafes->value[iAuthSafes].contentType, &oid)) goto ErrorOut; if (0 == strcmp( oid, szOID_RSA_encryptedData)) { SSFree(oid); // DSIE: Bug 144526.
oid = NULL; // decode content to encryptedData
if (0 != PkiAsn1Decode( pDec, (void **)&pEncrData, EncryptedData_PDU, (BYTE *) pAuthSafes->value[iAuthSafes].content.value, pAuthSafes->value[iAuthSafes].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 (!IPFX_Asn1FromObjectID(&pEncrData->encryptedContentInfo.contentType, &oid)) goto ErrorOut; if (0 != strcmp( oid, szOID_RSA_data)) goto SetPFXDecodeError; SSFree(oid); // DSIE: Bug 144526.
oid = NULL;
// chk encr alg present, type
if (0 == (pEncrData->encryptedContentInfo.contentEncryptionAlg.bit_mask & parameters_present)) goto SetPFXDecodeError; if (!IPFX_Asn1FromObjectID(&pEncrData->encryptedContentInfo.contentEncryptionAlg.algorithm, &oid)) goto ErrorOut;
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, szOID_PKCS_12_pbeWithSHA1And40BitRC2)) { iEncrType = RC2_40; } else if (0 == strcmp( oid, szOID_PKCS_12_pbeWithSHA1And40BitRC4)) { iEncrType = RC4_40; } else if (0 == strcmp( oid, szOID_PKCS_12_pbeWithSHA1And128BitRC2)) { iEncrType = RC2_128; } else if (0 == strcmp( oid, szOID_PKCS_12_pbeWithSHA1And128BitRC4)) { iEncrType = RC4_128; } else if (0 == strcmp( oid, szOID_PKCS_12_pbeWithSHA1And3KeyTripleDES)) { // FIX - we need to differentiate between 2 and 3 key triple des
iEncrType = TripleDES; } else goto SetPFXAlgIDError; SSFree(oid); // DSIE: Bug 144526.
oid = NULL;
// DECRYPT encryptedData using szPassword (in place)
cbDecrData = pEncrData->encryptedContentInfo.encryptedContent.length; if (NULL == (pbDecrData = (PBYTE)SSAlloc(pEncrData->encryptedContentInfo.encryptedContent.length)) ) goto SetPfxAllocError;
CopyMemory(pbDecrData, pEncrData->encryptedContentInfo.encryptedContent.value, cbDecrData);
if (!PFXPasswordDecryptData( iEncrType, // encr type
szPassword,
pPBEParameter->iterationCount, pPBEParameter->salt.value, // pkcs5 salt
pPBEParameter->salt.length,
&pbDecrData, (PDWORD)&cbDecrData)) goto SetPFXDecryptError; // set up to decode the SafeContents
cbEncoded = cbDecrData; pbEncoded = pbDecrData; } else if (0 == strcmp( oid, szOID_RSA_data)) { SSFree(oid); // DSIE: Bug 144526.
oid = NULL;
// strip off the octet string wrapper
if (0 != PkiAsn1Decode( pDec, (void **)&pNonEncryptedOctetString, OctetStringType_PDU, (BYTE *) pAuthSafes->value[iAuthSafes].content.value, pAuthSafes->value[iAuthSafes].content.length)) goto SetPFXDecodeError;
// the safe isn't encrypted, so just setup to decode the data as SafeContents
cbEncoded = pNonEncryptedOctetString->length; pbEncoded = pNonEncryptedOctetString->value; } else { SSFree(oid); // DSIE: Bug 144526.
oid = NULL; goto SetPFXDecodeError; } // decode the SafeContents, it is either the plaintext encryptedData or the original data
if (0 != PkiAsn1Decode( pDec, (void **)&pSafeCnts, SafeContents_PDU, pbEncoded, cbEncoded)) goto SetPFXDecodeError;
// tear pSafeCnts apart, mash into ppfx
if (!FPFXDumpSafeCntsToHPFX(pSafeCnts, ppfx)) goto SetPFXDecodeError;
// loop cleanup
if (pEncrData) { PkiAsn1FreeDecoded(pDec, pEncrData, EncryptedData_PDU); pEncrData = NULL; }
if (pPBEParameter) { PkiAsn1FreeDecoded(pDec, pPBEParameter, PBEParameter_PDU); pPBEParameter = NULL; }
if (pNonEncryptedOctetString) { PkiAsn1FreeDecoded(pDec, pNonEncryptedOctetString, OctetStringType_PDU); pNonEncryptedOctetString = NULL; }
PkiAsn1FreeDecoded(pDec, pSafeCnts, SafeContents_PDU); pSafeCnts = NULL; if (pbDecrData) { SSFree(pbDecrData); pbDecrData = NULL; } }
fRet = TRUE; goto Ret;
SetPFXAlgIDError: SetLastError(NTE_BAD_ALGID); goto Ret;
SetPFXIntegrityError: SetLastError(ERROR_INVALID_PASSWORD); goto Ret;
SetPFXDecodeError: SetLastError(CRYPT_E_BAD_ENCODE); goto Ret;
SetPFXDecryptError: SetLastError(NTE_FAIL); goto Ret;
SetPfxAllocError: SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto Ret;
ErrorOut: Ret:
// save any error conditions
dwErr = GetLastError();
PkiAsn1FreeDecoded(pDec, psPfx, PFX_PDU); PkiAsn1FreeDecoded(pDec, pOctetString, OctetStringType_PDU); PkiAsn1FreeDecoded(pDec, pAuthSafes, AuthenticatedSafes_PDU); PkiAsn1FreeDecoded(pDec, pEncrData, EncryptedData_PDU); PkiAsn1FreeDecoded(pDec, pPBEParameter, PBEParameter_PDU); PkiAsn1FreeDecoded(pDec, pSafeCnts, SafeContents_PDU);
// DSIE: Bug 144526.
if (oid) SSFree(oid);
if (pbDecrData) SSFree(pbDecrData);
if (!fRet) { if (ppfx) SSFree(ppfx);
ppfx = NULL; }
// restore error conditions AFTER GetDecoder() calls, since TLS will clobber
SetLastError(dwErr);
return (HPFX)ppfx; }
BOOL FPFXDumpSafeCntsToHPFX(SafeContents* pSafeCnts, HPFX hpfx) { PPFX_INFO ppfx = (PPFX_INFO)hpfx;
// sort and dump bags into correct areas
ObjectID oKeyBag, oCertBag, oShroudedKeyBag; DWORD dw, iAttr, iAnys;
ZeroMemory(&oKeyBag, sizeof(ObjectID)); ZeroMemory(&oCertBag, sizeof(ObjectID)); ZeroMemory(&oShroudedKeyBag, sizeof(ObjectID));
if (!IPFX_Asn1ToObjectID( &szOID_PKCS_12_KEY_BAG, &oKeyBag)) return FALSE;
if (!IPFX_Asn1ToObjectID( &szOID_PKCS_12_CERT_BAG, &oCertBag)) return FALSE;
if (!IPFX_Asn1ToObjectID( &szOID_PKCS_12_SHROUDEDKEY_BAG, &oShroudedKeyBag)) return FALSE;
for (dw=0; dw<pSafeCnts->count; dw++) { SafeBag* pBag;
// new begin
// assign value to keys
if (NULL == (pBag = (SafeBag*)SSAlloc(sizeof(SafeBag)) )) goto SetPfxAllocError;
CopyMemory(pBag, &pSafeCnts->value[dw], sizeof (SafeBag)); // obj id is static
// alloc content
if (NULL == (pBag->safeBagContent.value = (PBYTE)SSAlloc(pBag->safeBagContent.length) )) goto SetPfxAllocError;
CopyMemory(pBag->safeBagContent.value, pSafeCnts->value[dw].safeBagContent.value, pBag->safeBagContent.length);
// alloc attributes
if (pBag->bit_mask & safeBagAttribs_present) { if (NULL == (pBag->safeBagAttribs.value = (Attribute*)SSAlloc(sizeof(Attribute) * pSafeCnts->value[dw].safeBagAttribs.count) )) goto SetPfxAllocError;
for (iAttr=0; iAttr < pSafeCnts->value[dw].safeBagAttribs.count; iAttr++) { // copy static section of attribute
CopyMemory(&pBag->safeBagAttribs.value[iAttr], &pSafeCnts->value[dw].safeBagAttribs.value[iAttr], sizeof(Attribute));
// Alloc Attribute Anys
if (pSafeCnts->value[dw].safeBagAttribs.value[iAttr].attributeValue.count != 0) { if (NULL == (pBag->safeBagAttribs.value[iAttr].attributeValue.value = (Any*)SSAlloc(pSafeCnts->value[dw].safeBagAttribs.value[iAttr].attributeValue.count * sizeof(Any)) )) goto SetPfxAllocError;
CopyMemory(pBag->safeBagAttribs.value[iAttr].attributeValue.value, pSafeCnts->value[dw].safeBagAttribs.value[iAttr].attributeValue.value, sizeof(Any)); for (iAnys=0; iAnys<pBag->safeBagAttribs.value[iAttr].attributeValue.count; iAnys++) { if (NULL == (pBag->safeBagAttribs.value[iAttr].attributeValue.value[iAnys].value = (PBYTE)SSAlloc(pSafeCnts->value[dw].safeBagAttribs.value[iAttr].attributeValue.value[iAnys].length) )) goto SetPfxAllocError;
CopyMemory(pBag->safeBagAttribs.value[iAttr].attributeValue.value[iAnys].value, pSafeCnts->value[dw].safeBagAttribs.value[iAttr].attributeValue.value[iAnys].value, pSafeCnts->value[dw].safeBagAttribs.value[iAttr].attributeValue.value[iAnys].length); } } else { pBag->safeBagAttribs.value[iAttr].attributeValue.value = NULL; } } } // new end
if (IPFX_EqualObjectIDs(&pSafeCnts->value[dw].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*));
if (ppfx->rgKeys == NULL) goto SetPfxAllocError;
// assign to keys
ppfx->rgKeys[ppfx->cKeys-1] = pBag; } else if (IPFX_EqualObjectIDs(&pSafeCnts->value[dw].safeBagType, &oShroudedKeyBag) ) { // inc size
ppfx->cShroudedKeys++; if (ppfx->rgShroudedKeys) ppfx->rgShroudedKeys = (void**)SSReAlloc(ppfx->rgShroudedKeys, ppfx->cShroudedKeys * sizeof(SafeBag*)); else ppfx->rgShroudedKeys = (void**)SSAlloc(ppfx->cShroudedKeys * sizeof(SafeBag*));
if (ppfx->rgShroudedKeys == NULL) goto SetPfxAllocError;
// assign to keys
ppfx->rgShroudedKeys[ppfx->cShroudedKeys-1] = pBag; } else if (IPFX_EqualObjectIDs(&pSafeCnts->value[dw].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*));
if (ppfx->rgCertcrls == NULL) goto SetPfxAllocError;
// assign to certs/crls
ppfx->rgCertcrls[ppfx->cCertcrls-1] = pBag; } 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*));
if (ppfx->rgSecrets == NULL) goto SetPfxAllocError;
// assign to safebag
ppfx->rgSecrets[ppfx->cSecrets-1] = pBag; } }
return TRUE;
SetPfxAllocError: SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; }
BOOL CopyASNtoCryptSafeBag( SAFE_BAG* pCryptBag, SafeBag* pAsnBag) { DWORD iAttrs, iAttr;
// ensure target is zeroed
ZeroMemory(pCryptBag, sizeof(SAFE_BAG));
if (!IPFX_Asn1FromObjectID( &pAsnBag->safeBagType, &pCryptBag->pszBagTypeOID)) return FALSE;
// copy bag contents
pCryptBag->BagContents.cbData = pAsnBag->safeBagContent.length; if (NULL == (pCryptBag->BagContents.pbData = (PBYTE)SSAlloc(pCryptBag->BagContents.cbData) )) goto SetPfxAllocError;
CopyMemory(pCryptBag->BagContents.pbData, pAsnBag->safeBagContent.value, pCryptBag->BagContents.cbData);
pCryptBag->Attributes.cAttr = pAsnBag->safeBagAttribs.count; if (NULL == (pCryptBag->Attributes.rgAttr = (CRYPT_ATTRIBUTE*)SSAlloc(pCryptBag->Attributes.cAttr * sizeof(CRYPT_ATTRIBUTE)) )) goto SetPfxAllocError;
// sizeof attribute data
for (iAttrs=0; iAttrs<pAsnBag->safeBagAttribs.count; iAttrs++) { // pAsnBag->safeBagAttribs.value === attribute struct
if (!IPFX_Asn1FromObjectID( &pAsnBag->safeBagAttribs.value[iAttrs].attributeType, &pCryptBag->Attributes.rgAttr[iAttrs].pszObjId)) continue;
pCryptBag->Attributes.rgAttr[iAttrs].cValue = pAsnBag->safeBagAttribs.value[iAttrs].attributeValue.count; if (NULL == (pCryptBag->Attributes.rgAttr[iAttrs].rgValue = (CRYPT_ATTR_BLOB*)SSAlloc(pAsnBag->safeBagAttribs.value[iAttrs].attributeValue.count * sizeof(CRYPT_ATTR_BLOB)) )) goto SetPfxAllocError;
for (iAttr=0; iAttr<pAsnBag->safeBagAttribs.value[iAttrs].attributeValue.count; iAttr++) { // alloc and copy: for every attribute in attrs
pCryptBag->Attributes.rgAttr[iAttrs].rgValue[iAttr].cbData = pAsnBag->safeBagAttribs.value[iAttrs].attributeValue.value[iAttr].length; if (NULL == (pCryptBag->Attributes.rgAttr[iAttrs].rgValue[iAttr].pbData = (PBYTE)SSAlloc(pCryptBag->Attributes.rgAttr[iAttrs].rgValue[iAttr].cbData) )) goto SetPfxAllocError;
CopyMemory(pCryptBag->Attributes.rgAttr[iAttrs].rgValue[iAttr].pbData, pAsnBag->safeBagAttribs.value[iAttrs].attributeValue.value[iAttr].value, pCryptBag->Attributes.rgAttr[iAttrs].rgValue[iAttr].cbData); } }
return TRUE;
SetPfxAllocError: SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; }
BOOL CopyCrypttoASNSafeBag( SAFE_BAG* pCryptBag, SafeBag* pAsnBag) { DWORD iAttrs, iAttr; // ensure target is zeroed
ZeroMemory(pAsnBag, sizeof(SafeBag));
if (!IPFX_Asn1ToObjectID( pCryptBag->pszBagTypeOID, &pAsnBag->safeBagType)) return FALSE;
pAsnBag->safeBagContent.length = pCryptBag->BagContents.cbData; if (NULL == (pAsnBag->safeBagContent.value = (PBYTE)SSAlloc(pAsnBag->safeBagContent.length) )) goto SetPfxAllocError;
CopyMemory(pAsnBag->safeBagContent.value, pCryptBag->BagContents.pbData, pAsnBag->safeBagContent.length); pAsnBag->safeBagAttribs.count = pCryptBag->Attributes.cAttr; if (NULL == (pAsnBag->safeBagAttribs.value = (Attribute*) SSAlloc(pAsnBag->safeBagAttribs.count * sizeof(Attribute)) )) goto SetPfxAllocError;
//
// always set the present bit for backwards compatibility
//
pAsnBag->bit_mask = safeBagAttribs_present;
for (iAttrs=0; iAttrs<pCryptBag->Attributes.cAttr; iAttrs++) { //pAsnBag->bit_mask = safeBagAttribs_present;
if (!IPFX_Asn1ToObjectID( pCryptBag->Attributes.rgAttr[iAttrs].pszObjId, &pAsnBag->safeBagAttribs.value[iAttrs].attributeType)) continue;
pAsnBag->safeBagAttribs.value[iAttrs].attributeValue.count = pCryptBag->Attributes.rgAttr[iAttrs].cValue; if (NULL == (pAsnBag->safeBagAttribs.value[iAttrs].attributeValue.value = (Any*)SSAlloc(pAsnBag->safeBagAttribs.value[iAttrs].attributeValue.count * sizeof(Any)) )) goto SetPfxAllocError;
for (iAttr=0; iAttr<pCryptBag->Attributes.rgAttr[iAttrs].cValue; iAttr++) { // for every attribute in attrs
pAsnBag->safeBagAttribs.value[iAttrs].attributeValue.value[iAttr].length = pCryptBag->Attributes.rgAttr[iAttrs].rgValue[iAttr].cbData; if (NULL == (pAsnBag->safeBagAttribs.value[iAttrs].attributeValue.value[iAttr].value = (PBYTE)SSAlloc(pAsnBag->safeBagAttribs.value[iAttrs].attributeValue.value[iAttr].length) )) goto SetPfxAllocError;
CopyMemory(pAsnBag->safeBagAttribs.value[iAttrs].attributeValue.value[iAttr].value, pCryptBag->Attributes.rgAttr[iAttrs].rgValue[iAttr].pbData, pAsnBag->safeBagAttribs.value[iAttrs].attributeValue.value[iAttr].length); } } return TRUE;
SetPfxAllocError: SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; }
// new entry points for loading up the HPFX
BOOL PfxGetKeysAndCerts( HPFX hPfx, SAFE_CONTENTS* pContents ) { PFX_INFO* pPfx = (PFX_INFO*)hPfx; SafeBag* pAsnBag; SAFE_BAG* pCryptBag; DWORD iTotal, iBag; DWORD cSafeBags;
pContents->cSafeBags = 0; cSafeBags = pPfx->cKeys + pPfx->cCertcrls + pPfx->cShroudedKeys; if (NULL == (pContents->pSafeBags = (SAFE_BAG*)SSAlloc(cSafeBags * sizeof(SAFE_BAG)) )) // make an array of safe bag *s
goto SetPfxAllocError;
pContents->cSafeBags = cSafeBags;
for (iBag=0, iTotal=0; iBag<pPfx->cKeys; iBag++, iTotal++) { pCryptBag = &pContents->pSafeBags[iTotal]; pAsnBag = (SafeBag*)pPfx->rgKeys[iBag];
if (!CopyASNtoCryptSafeBag(pCryptBag, pAsnBag)) continue; }
iTotal = iBag;
for (iBag=0; iBag<pPfx->cShroudedKeys; iBag++, iTotal++) { pCryptBag = &pContents->pSafeBags[iTotal]; pAsnBag = (SafeBag*)pPfx->rgShroudedKeys[iBag];
if (!CopyASNtoCryptSafeBag(pCryptBag, pAsnBag)) continue; }
for (iBag=0; iBag<pPfx->cCertcrls; iBag++, iTotal++) { pCryptBag = &pContents->pSafeBags[iTotal]; pAsnBag = (SafeBag*)pPfx->rgCertcrls[iBag];
if (!CopyASNtoCryptSafeBag(pCryptBag, pAsnBag)) continue; }
return TRUE;
SetPfxAllocError: SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; }
BOOL PfxAddSafeBags( HPFX hPfx, SAFE_BAG* pSafeBags, DWORD cSafeBags ) { PFX_INFO* pPfx = (PFX_INFO*)hPfx; DWORD i;
for (i=0; i<cSafeBags; i++) { if (0 == strcmp(pSafeBags[i].pszBagTypeOID, szOID_PKCS_12_KEY_BAG)) { pPfx->cKeys++; if (pPfx->rgKeys) pPfx->rgKeys = (void**)SSReAlloc(pPfx->rgKeys, pPfx->cKeys*sizeof(SafeBag*)); else pPfx->rgKeys = (void**)SSAlloc(pPfx->cKeys*sizeof(SafeBag*));
if (pPfx->rgKeys == NULL) goto SetPfxAllocError; if (NULL == (pPfx->rgKeys[pPfx->cKeys-1] = (SafeBag*)SSAlloc(sizeof(SafeBag)) )) goto SetPfxAllocError;
if (!CopyCrypttoASNSafeBag(&pSafeBags[i], (SafeBag*)pPfx->rgKeys[pPfx->cKeys-1])) continue; } else if (0 == strcmp(pSafeBags[i].pszBagTypeOID, szOID_PKCS_12_SHROUDEDKEY_BAG)) { pPfx->cShroudedKeys++; if (pPfx->rgShroudedKeys) pPfx->rgShroudedKeys = (void**)SSReAlloc(pPfx->rgShroudedKeys, pPfx->cShroudedKeys*sizeof(SafeBag*)); else pPfx->rgShroudedKeys = (void**)SSAlloc(pPfx->cShroudedKeys*sizeof(SafeBag*));
if (pPfx->rgShroudedKeys == NULL) goto SetPfxAllocError;
if (NULL == (pPfx->rgShroudedKeys[pPfx->cShroudedKeys-1] = (SafeBag*)SSAlloc(sizeof(SafeBag)) )) goto SetPfxAllocError;
if (!CopyCrypttoASNSafeBag(&pSafeBags[i], (SafeBag*)pPfx->rgShroudedKeys[pPfx->cShroudedKeys-1])) continue; } else if (0 == strcmp(pSafeBags[i].pszBagTypeOID, szOID_PKCS_12_CERT_BAG)) { pPfx->cCertcrls++; if (pPfx->rgCertcrls) pPfx->rgCertcrls = (void**)SSReAlloc(pPfx->rgCertcrls, pPfx->cCertcrls*sizeof(SafeBag*)); else pPfx->rgCertcrls = (void**)SSAlloc(pPfx->cCertcrls*sizeof(SafeBag*));
if (pPfx->rgCertcrls == NULL) goto SetPfxAllocError;
if (NULL == (pPfx->rgCertcrls[pPfx->cCertcrls-1] = (SafeBag*)SSAlloc(sizeof(SafeBag)) )) goto SetPfxAllocError;
if (!CopyCrypttoASNSafeBag(&pSafeBags[i], (SafeBag*)pPfx->rgCertcrls[pPfx->cCertcrls-1])) continue; } else if (0 == strcmp(pSafeBags[i].pszBagTypeOID, szOID_PKCS_12_SECRET_BAG)) { pPfx->cSecrets++; if (pPfx->rgSecrets) pPfx->rgSecrets = (void**)SSReAlloc(pPfx->rgSecrets, pPfx->cSecrets*sizeof(SafeBag*)); else pPfx->rgSecrets = (void**)SSAlloc(pPfx->cSecrets*sizeof(SafeBag*));
if (pPfx->rgSecrets == NULL) goto SetPfxAllocError;
if (NULL == (pPfx->rgSecrets[pPfx->cSecrets-1] = (SafeBag*)SSAlloc(sizeof(SafeBag)) )) goto SetPfxAllocError;
if (!CopyCrypttoASNSafeBag(&pSafeBags[i], (SafeBag*)pPfx->rgSecrets[pPfx->cSecrets-1])) continue; } else { #if DBG
OutputDebugString(pSafeBags[i].pszBagTypeOID); #endif
continue; }
}
return TRUE;
SetPfxAllocError: SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; }
BOOL PFXAPI IsRealPFXBlob(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; }
|