/*
* Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
* This file contains the implementation of the CPkcs12Parser class, to parse the PKCS#12 file.
*
*/
/**
@file
@internalTechnology
*/
// System Include
#include <f32file.h>
//User Include
#include "tpkcs12common.h"
using namespace PKCS12;
/**
Description:constructor
@internalTechnology:
@test
*/
CPkcs12Parser::CPkcs12Parser()
{
}
/**
Description:destructor
@internalTechnology:
@test
*/
CPkcs12Parser::~CPkcs12Parser()
{
delete iIntegrityPassword;
delete iRawData;
delete iPkcs12Header;
iArraySafecontentBag.ResetAndDestroy();
iArrayBagData.ResetAndDestroy();
}
/**
Description:Function is intended to creates a new CPKCS12Parser object.
@return:CPKCS12Parser* : parser object to parse the PKCS12 file
@internalTechnology
@test
*/
CPkcs12Parser* CPkcs12Parser::NewL()
{
CPkcs12Parser* parser = NewLC();
CleanupStack::Pop(parser);
return parser;
}
/**
Description:Function is intended to creates a new CPKCS12Parser object.
@return:CPKCS12Parser* : parser object to parse the PKCS12 file
@test
*/
CPkcs12Parser* CPkcs12Parser::NewLC()
{
CPkcs12Parser* parser = new (ELeave) CPkcs12Parser();
CleanupStack::PushL(parser);
return parser;
}
/**
Description:Function is intended to set the integrity password
@param aIntegrityPassword, contains the integrity password
@internalTechnology
@test
*/
void CPkcs12Parser::SetIntegrityPasswordL(const TDesC& aIntegrityPassword)
{
iIntegrityPassword = aIntegrityPassword.AllocL();
}
/**
Description:Function is intended to set the privacy password(s)
@param aPrivacyPassword, contains the privacy passwords.The ownership is not transferred
@internalTechnology
@test
*/
void CPkcs12Parser::SetPrivacyPassword(RPointerArray<TDesC>& aPrivacyPassword)
{
iPrivacyPassword = &aPrivacyPassword;
}
/**
Description:Function is intended to set the test data.
It opens the data file and stores it in the buffer.
@param aDatapath, contains the path of the PKCS12 file
@internalTechnology
@test
*/
void CPkcs12Parser::SetDataL(const TDesC& aDatapath)
{
if(iRawData)
{
delete iRawData ;
iRawData = NULL;
}
RFs fs;
//connects the file server
User::LeaveIfError (fs.Connect());
//opens the data file
CleanupClosePushL(fs);
RFile file;
User::LeaveIfError(file.Open(fs, aDatapath, EFileRead)) ;
CleanupClosePushL(file);
TInt fileSize = 0;
User::LeaveIfError(file.Size(fileSize));
iRawData = HBufC8::NewL(fileSize);
TPtr8 rawData(iRawData->Des());
rawData.SetLength(fileSize);
file.Read (rawData);
CleanupStack::PopAndDestroy(&file);
//closes the file session
CleanupStack::PopAndDestroy(&fs);
}
/**
Description:Function is intended to parse the PKCS#12 data
@leave:- if the number of contentinfos and number of privacy passwords does not match.
@internalTechnology
@test
*/
void CPkcs12Parser::ParseL()
{
//creates the CDecPkcs12 object
CDecPkcs12* decPkcs12 = NULL;
TRAPD(error, decPkcs12 = CDecPkcs12::NewL(*iRawData));
if(error == KErrNone)
CleanupStack::PushL(decPkcs12);
//Creates a CPfxHeader object
iPkcs12Header = CPfxHeader::NewL(*decPkcs12 , error);
if(error != KErrNone)
{
return ;
}
const CDecPkcs12MacData* macData = decPkcs12->MacData();
TRAPD(err,macData->VerifyIntegrityL(iIntegrityPassword->Des()));
if(err)
{
iPkcs12Header->SetPkcs12ActualError(err);
CleanupStack::PopAndDestroy(decPkcs12);
return;
}
//get the ContentInfo collection
const RPointerArray<CPKCS7ContentInfo>& contentInfos = decPkcs12->AuthenticatedSafeContents();
TInt contentInfoCount = contentInfos.Count();
//put the content info count in the Header
iPkcs12Header->SetContentInfoCount(contentInfoCount) ;
// start iterate through the contentinfos
for(TInt index = 0 ; index < contentInfoCount; index++)
{
TInt contentType = contentInfos[index]->ContentType() ;
TPtrC8 contentData = contentInfos[index]->ContentData();
if( contentData == KNullDesC8())
{
iPkcs12Header->SetPkcs12ActualError(0);
continue;
}
CDecPkcs12SafeContents* pkcs12SafeContents = NULL;
switch(contentType)
{
case CPKCS7ContentInfo::EContentTypeData:
{
TRAPD(error1,pkcs12SafeContents = CDecPkcs12SafeContents::NewL(*contentInfos[index]));
if(error1)
{
iPkcs12Header->SetPkcs12ActualError(error1);
CSafeBagData* bagData = NULL;
bagData = CreateBagDataL(index,contentType);
iArrayBagData.AppendL(bagData) ;
CleanupStack::PopAndDestroy(decPkcs12);
return;
}
CleanupStack::PushL(pkcs12SafeContents);
break;
}
case CPKCS7ContentInfo::EContentTypeEncryptedData:
{
if(contentInfoCount != iPrivacyPassword->Count())
{
User::Leave(KErrArgument);
}
TRAPD(error2,pkcs12SafeContents = CDecPkcs12SafeContents::NewL(*contentInfos[index],
*((*iPrivacyPassword)[index]) ) );
if(error2)
{
iPkcs12Header->SetPkcs12ActualError(error2);
CSafeBagData* bagData = NULL;
bagData = CreateBagDataL(index,contentType);
iArrayBagData.AppendL(bagData) ;
CleanupStack::PopAndDestroy(decPkcs12);
return;
}
CleanupStack::PushL(pkcs12SafeContents);
break;
}
case CPKCS7ContentInfo::EContentTypeEnvelopedData:
{
//creates a Bagdata object in the heap to store the content type.
CSafeBagData* bagData = CreateBagDataL(index+1 ,contentType);
iArrayBagData.AppendL(bagData) ;
//continue in the loop
continue;
}
default:
{
//continue in the loop
continue;
}
}
// Get the safebags count.
const RPointerArray<CDecPkcs12SafeBag>& safeBags = pkcs12SafeContents->SafeContentsBags();
TInt safeBagCount = safeBags.Count();
//start parsing the bags
for (TInt bagsCount=0; bagsCount < safeBagCount; bagsCount++)
{
TRAPD(error3,ParseSafeBagL(index+1, contentType , *safeBags[bagsCount]));
if(error3 != KErrNone)
{
iPkcs12Header->SetPkcs12ActualError(error3);
CSafeBagData* bagData = NULL;
bagData = CreateBagDataL(index,contentType);
iArrayBagData.AppendL(bagData) ;
CleanupStack::PopAndDestroy(2,decPkcs12);
return;
}
}
CleanupStack::PopAndDestroy(pkcs12SafeContents);
}
CleanupStack::PopAndDestroy(decPkcs12);
}
/**
Description: Creates a CSafeBagData to store the safebag details
@param:aContentInfo, the contentinfo number of the safe bag
@param:aContentType, the content type of the safe contents.
@return:a pointer to CSafeBagData, which is used to store the safebag details
@internalTechnology:
@test:
*/
CSafeBagData* CPkcs12Parser::CreateBagDataL(TInt aContentInfo, TInt aContentType)
{
CSafeBagData* bagData = CSafeBagData::NewL();
if ( iPkcs12Header->Pkcs12ActualError() == KErrNone )
{
//set the contentinfo # and content type in CSafeBagData
bagData->SetContentInfoNumber(aContentInfo);
bagData->SetBagNumber(++iSafebagNumber );
// set the content type in CSafeBagData
bagData->SetContentInfoType(aContentType);
}
return bagData ;
}
/**
Description:To parse the safebags
@param:aContentInfoIndex content info number
@param:aContentType contentinfo type
@param:aSafeBag reference to the CDecPkcs12SafeBag
@internalTechnology:
@test:
*/
void CPkcs12Parser::ParseSafeBagL(TInt aContentInfo,TInt aContentType,CDecPkcs12SafeBag& aSafeBag)
{
//get the bag type
CDecPkcs12SafeBag::TBagId bagType = aSafeBag.BagID();
switch(bagType)
{
case CDecPkcs12SafeBag::ESafeContentsBag:
{
CDecPkcs12SafeContentsBag* safeContentsBag = static_cast<CDecPkcs12SafeContentsBag *>(&aSafeBag);
// increment the count
iPkcs12Header->IncrementSafecontentBagCount();
// parsing code to parse SafeContentsBag
ParseSafeContentBagL(*safeContentsBag, aContentInfo ,aContentType );
break;
}
case CDecPkcs12SafeBag::EKeyBag:
{
CDecPkcs12KeyBag* keyBag = static_cast<CDecPkcs12KeyBag *>(&aSafeBag);
//create the CSafeBagData object in heap to store the bag details
CSafeBagData* bagData = CreateBagDataL(aContentInfo,aContentType);
CleanupStack::PushL(bagData);
ParseKeyBag(*keyBag , *bagData);
//get the safeBag attributes
BagAttributesL(*keyBag ,*bagData) ;
iArrayBagData.AppendL(bagData) ;
CleanupStack::Pop(bagData);
break;
}
case CDecPkcs12SafeBag::EShroudedKeyBag:
{
CDecPkcs12ShroudedKeyBag* shroudedkeyBag = static_cast<CDecPkcs12ShroudedKeyBag *>(&aSafeBag);
//create the CSafeBagData object in heap to store the bag details
CSafeBagData* bagData = CreateBagDataL(aContentInfo,aContentType );
CleanupStack::PushL(bagData);
ParseShroudedKeyBagL(*shroudedkeyBag , *bagData ,aContentInfo );
//get the safeBag attributes
BagAttributesL(*shroudedkeyBag ,*bagData) ;
iArrayBagData.AppendL(bagData) ;
CleanupStack::Pop(bagData);
break;
}
case CDecPkcs12SafeBag::ECertBag:
{
CDecPkcs12CertBag* certBag = static_cast<CDecPkcs12CertBag *>(&aSafeBag);
//create the CSafeBagData object in heap to store the bag details
CSafeBagData* bagData = CreateBagDataL(aContentInfo,aContentType);
CleanupStack::PushL(bagData);
ParseCertBag(*certBag , *bagData);
// Get the bag Attributes
BagAttributesL(*certBag , *bagData) ;
iArrayBagData.AppendL(bagData) ;
CleanupStack::Pop(bagData);
break;
}
case CDecPkcs12SafeBag::ECrlBag:
{
//create the CSafeBagData object in heap to store the bag details
CSafeBagData* bagData = CreateBagDataL(aContentInfo,aContentType);;
CleanupStack::PushL(bagData);
//set the bagId in CSafeBagData
bagData->SetBagType(bagType) ;
//increment the count - unsupported
iPkcs12Header->IncrementCrlBagCount();
iArrayBagData.AppendL(bagData) ;
CleanupStack::Pop(bagData);
break;
}
case CDecPkcs12SafeBag::ESecretBag:
{
//create the CSafeBagData object in heap to store the bag details
CSafeBagData* bagData = CreateBagDataL(aContentInfo,aContentType );
CleanupStack::PushL(bagData);
//set the iBagId in CSafeBagData
bagData->SetBagType(bagType) ;
//increment the count - unsupported
iPkcs12Header->IncrementSecretBagCount();
iArrayBagData.AppendL(bagData) ;
CleanupStack::Pop(bagData);
break;
}
default:
{
}
}
}
/**
Description:Function is intended to get the attributes of Safebag
@param-aSafeBag: reference to the CDecPkcs12SafeBag.
@param-abagData: reference to the CSafeBagData
@internalTechnology:
@test
*/
void CPkcs12Parser::BagAttributesL(const CDecPkcs12SafeBag& aSafeBag,CSafeBagData& aBagData )
{
const RPointerArray<CDecPkcs12Attribute>& safeBagAttributes = aSafeBag.BagAttributes();
TInt attributeCount = safeBagAttributes.Count() ;
for (TInt index = 0;index < attributeCount; index++ )
{
//get the attribute object pointer
CDecPkcs12Attribute* attribute = safeBagAttributes[index];
//create the CSafeBagAttribute object in heap.
CSafeBagAttribute* bagAttr = CSafeBagAttribute::NewL(*safeBagAttributes[index]);
CleanupStack::PushL(bagAttr);
//get the attribute values
const RPointerArray<TDesC8>& attrValues = attribute->AttributeValue();
//append the pointer in the iAttributeIDs array
aBagData.iAttributeIDs.AppendL(bagAttr) ;
CleanupStack::Pop(bagAttr);
//store the attribute values
TInt numberOfAttributes = bagAttr->AttributeValueCount();
for(TInt attrvalCnt = 0 ; attrvalCnt < numberOfAttributes ; attrvalCnt++)
{
//get the atribute value and store the it address in the aBagData.iAttributeValues array
HBufC8* ptr = attrValues[attrvalCnt]->AllocLC();
aBagData.iAttributeValues.AppendL(ptr);
CleanupStack::Pop(ptr);
}
}
}
/**
Description:Function is intended to parse the keybag
@param-aKeyBag: reference to the keybag
@param-abagData: reference to the CSafeBagData
@internalTechnology:
@test:
*/
void CPkcs12Parser::ParseKeyBag(CDecPkcs12KeyBag& aKeyBag , CSafeBagData& aBagData)
{
//set the bagID
aBagData.SetBagType( CDecPkcs12SafeBag::EKeyBag );
// Get the Algorithm(RSA key or DSA key) ID
CDecPKCS8Data* pkcs8Data = aKeyBag.PrivateKeyInfoL();
aBagData.SetPrivateKeyInfoVersion(pkcs8Data->Version() );
TAlgorithmId algorithmId = pkcs8Data->Algorithm();
// Set the Algorithm Id in CSafeBagData
aBagData.SetKeyType( algorithmId );
//set the bag value in CSafeBagData
aBagData.SetBagValue( aKeyBag.BagValue());
// increment the count
iPkcs12Header->IncrementKeyBagCount();
delete pkcs8Data;
}
/**
Description:Function is intended to parse the ShroudedKeyBag
@param-aShroudedkeyBag: pointer to the CDecPkcs12ShroudedKeyBag
@param-abagData: reference to the CSafeBagData
@param- aPassIndex: the index of the array from where the privacy password is to be taken
@internalTechnology:
@test
*/
void CPkcs12Parser::ParseShroudedKeyBagL(CDecPkcs12ShroudedKeyBag& aShroudedkeyBag , CSafeBagData& aBagData , TInt aPassIndex)
{
//set the bag Id in CSafeBagData
aBagData.SetBagType( CDecPkcs12SafeBag::EShroudedKeyBag );
// Get the Algorithm(RSA key or DSA key) ID
CDecPKCS8Data* pkcs8Data = aShroudedkeyBag.PrivateKeyInfoL(*(*iPrivacyPassword)[aPassIndex-1]);
if(pkcs8Data)
{
aBagData.SetPrivateKeyInfoVersion(pkcs8Data->Version() );
TAlgorithmId algorithm = pkcs8Data->Algorithm();
// Set the Algorithm Id in CSafeBagData
aBagData.SetKeyType(algorithm);
CASN1EncSequence* seq = NULL ;
switch(algorithm)
{
case ERSA:
{
CPKCS8KeyPairRSA* keypair = static_cast<CPKCS8KeyPairRSA*>(pkcs8Data->KeyPairData());
const CRSAPrivateKey& priv = keypair->PrivateKey();
const CRSAPublicKey& publicKey = keypair->PublicKey();
TRSAPrivateKeyType keytype = priv.PrivateKeyType();
switch(keytype)
{
case EStandardCRT:
{
const CRSAPrivateKeyCRT* privateKeyCRT = static_cast<const CRSAPrivateKeyCRT*>(&priv);
seq = TASN1EncPKCS8::EncodeL(*privateKeyCRT, publicKey,pkcs8Data->PKCS8Attributes());
break;
}
case EStandard:
{
User::Leave(KErrNotSupported);
}
default:
{
User::Leave(KErrNotSupported);
}
}
break;
}
case EDSA:
{
CPKCS8KeyPairDSA* keypair = static_cast<CPKCS8KeyPairDSA*>(pkcs8Data->KeyPairData());
const CDSAPrivateKey& priv = keypair->PrivateKey();
seq = TASN1EncPKCS8::EncodeL(priv , pkcs8Data->PKCS8Attributes());
break;
}
default:
User::Leave(KErrNotSupported);
}
HBufC8* bufSeq = HBufC8::NewMaxLC(seq->LengthDER());
TPtr8 temp(bufSeq->Des());
TUint pos = 0;
seq->WriteDERL(temp ,pos);
aBagData.SetEncodedShroudedKey(temp);
CleanupStack::PopAndDestroy();
delete pkcs8Data;
}
//set the bag value in CSafeBagData
aBagData.SetBagValue(aShroudedkeyBag.BagValue()) ;
// increment the count
iPkcs12Header->IncrementShroudedKeyBagCount();
}
/**
Description:Function is intended to parse the certbag
@param-aCertBag: pointer to the CDecPkcs12CertBag
@param-abagData: reference to the CSafeBagData
@internalTechnology:
@test
*/
void CPkcs12Parser::ParseCertBag(CDecPkcs12CertBag& aCertBag , CSafeBagData& aBagData)
{
//set the bagID
aBagData.SetBagType( CDecPkcs12SafeBag::ECertBag );
aBagData.SetCertificateId(aCertBag.CertId());
//set the bag value in CSafeBagData
aBagData.SetBagValue(aCertBag.CertValue());
//set the X509Certificate
aBagData.SetX509Certificate((aCertBag.X509CertificateL()) );
// increment the count
iPkcs12Header->IncrementCertBagCount();
}
/**
Description:Function is intended to parse the safecontentbag
@param-safeContentsBag: reference to the CDecPkcs12SafeContentsBag
@param-aContentinfo: contentinfo number
@param- aContentType : contentinfo type
@internalTechnology
@test
*/
void CPkcs12Parser::ParseSafeContentBagL(CDecPkcs12SafeContentsBag& aSafeContntBag, TInt aContentinfo , TInt aContentType )
{
const RPointerArray<CDecPkcs12SafeBag>& safebags = aSafeContntBag.SafeBags();
// Get the safe bag count
TInt safeBagCount = safebags.Count();
//Create a CSafeContentBag , store the bag number and the number of bags in it,append it in the array
CSafeContentBag* safecontentbag = CSafeContentBag::NewL() ;
if(safecontentbag)
{
safecontentbag->SetBagNumber(iPkcs12Header->SafecontentBagCount()) ;
safecontentbag->SetSafeBagCount(safeBagCount) ;
CleanupStack::PushL(&iArraySafecontentBag);
iArraySafecontentBag.AppendL(safecontentbag) ;
CleanupStack::Pop(&iArraySafecontentBag);
}
if(safeBagCount>0)
{
TInt loopindex = 0 ;
while(loopindex < safeBagCount )
{
ParseSafeBagL(aContentinfo ,aContentType, *(safebags[loopindex]));
loopindex++;
}//end while
}
}