/*
* Copyright (c) 2007-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:
*
*/
#include <s32mem.h>
#include <s32file.h>
#include "texternpbeparams.h"
CTestAction* CExternPbeParams::NewL(
RFs& aFs, CConsoleBase& aConsole,
Output& aOut, const TTestActionSpec& aTestActionSpec)
/**
Factory function allocates new instance of CExternPbeParams and extracts
the element body from the supplied test action spec.
@param aFs Used to parse XML script file.
@param aConsole Required by CTestAction.
@param aOut Required by CTestAction.
@param aTestActionSpec Action specification contains type, name, and
XML contents.
@return New instance of CExternPbeParams, which is owned
by the caller.
*/
{
CExternPbeParams* self = new(ELeave) CExternPbeParams(aConsole, aOut, aFs);
CleanupStack::PushL(self);
self->ConstructL(aTestActionSpec);
CleanupStack::Pop(self);
return self;
}
CExternPbeParams::CExternPbeParams(CConsoleBase& aConsole, Output& aOut, RFs& aFs)
/**
This constructor exists to record the file server session and to initialize
the CTestAction superclass.
@param aConsole Required by CTestAction.
@param aOut Required by CTestAction.
@param aFs Used to read from and write to files in PerformAction,
which stores and restores the externalized params.
*/
: CTestAction(aConsole, aOut),
iFs(aFs)
{
// empty.
}
void CExternPbeParams::ConstructL(const TTestActionSpec& aTestActionSpec)
/**
Second phase initialization initializes the superclass and
makes a copy of the test element.
@param aTestActionSpec Action specification contains type, name, and
XML contents.
*/
{
CTestAction::ConstructL(aTestActionSpec);
iBody = aTestActionSpec.iActionBody.AllocL();
// iBody is deconstructed in DoPerformPrerequisite
}
CExternPbeParams::~CExternPbeParams()
/**
Free resources allocated in ConstructL. Specifically,
deletes the copy of the element body text.
*/
{
delete iBody;
}
// -------- implement CTestAction --------
void CExternPbeParams::DoPerformPrerequisite(TRequestStatus& aStatus)
/**
Override CTestAction by deconstructing element body allocated
in ConstructL.
If this function fails then DoPerformPostrequisite must still
be called.
@param aStatus This status is completed when the prerequisite
has finished. (This implementation is actually
synchronous so the request will already be completed
when it returns.)
*/
{
TRAPD(r, DoPerformPrerequisiteL());
iActionState = CTestAction::EAction;
TRequestStatus* ps = &aStatus;
User::RequestComplete(ps, r);
}
void CExternPbeParams::DoPerformPrerequisiteL()
/**
Helper function for DoPerformPrerequisite contains resource allocation
functions which can leave.
Extracts cipher, salt, iv, iter count, and kdf values.
*/
{
_LIT8(KOrigFileName, "orig-filename");
iOrigFileName = ReadStringLC(*iBody, KOrigFileName);
CleanupStack::Pop(iOrigFileName);
_LIT8(KExpCipherElemName, "expected-cipher");
iExpCipher = ReadDecStringL(*iBody, KExpCipherElemName);
_LIT8(KExpSaltElemName, "expected-salt");
iExpSalt = ReadHexStringL(*iBody, KExpSaltElemName);
_LIT8(KExpIvElemName, "expected-iv");
iExpIv = ReadHexStringL(*iBody, KExpIvElemName);
_LIT8(KExpIterCountElemName, "expected-iter-count");
iExpIterCount = ReadDecStringL(*iBody, KExpIterCountElemName);
_LIT8(KExpKdfElemName, "expected-kdf");
iExpKdf = ReadDecStringL(*iBody, KExpKdfElemName);
}
void CExternPbeParams::DoPerformPostrequisite(TRequestStatus& aStatus)
/**
Implements CTestAction by cleaning up data allocated in DoPerformPrerequisiteL.
@param aStatus This status is completed to indicate the
postrequisite has finished. (This function
is synchronous so the status is completed before
this function returns.)
*/
{
delete iExpIv;
iExpIv = 0;
delete iExpSalt;
iExpSalt = 0;
delete iOrigFileName;
iOrigFileName = NULL;
iFinished = ETrue;
TRequestStatus* ps = &aStatus;
User::RequestComplete(ps, KErrNone);
}
void CExternPbeParams::PerformAction(TRequestStatus& aStatus)
/**
Implements CTestAction by running the actual tests. This
consists of:
Reading an externalized CPBEncryptParms object and testing the
cipher, salt, iv, iteration count, and KDF are as expected.
Externalizing the object to memory.
Testing the two externalizations are binary identical.
Creating an equivalent object from scratch and externalizing it.
Testing the externalizations are binary identical.
As well as testing the objects can be stored reliably, this
test also ensures that old (pre-PKCS#12) files can still be
read and, and that objects are stored in the old format if they
do not use any PKCS#12-specific features. (I.e., they use the
default PKCS#5 KDF.)
@param aStatus This request status is completed when
the action has finished, successfully
or otherwise. This implementation is
synchronous, and so the status is actually
completed before this function returns.
*/
{
TFileName fn;
fn.Copy(*iOrigFileName); // convert from narrow
// ensure reference file matches re-externalized form
TRAPD(r,
TestDecodeMatchesScriptL(fn);
TestReExternMatchesL(fn);
TestScratchExternL(fn) );
iResult = (r == KErrNone);
iActionState = CTestAction::EPostrequisite;
TRequestStatus* status = &aStatus;
User::RequestComplete(status, KErrNone);
}
CPBEncryptParms* CExternPbeParams::InternalizeEncryptionParamsLC(const TDesC& aFileName)
/**
Construct a CPBEncryptParms object from the externalized
form in the named file.
@param aFileName File which contains externalized form.
@return Internalized encryption parameters object
which is placed on the cleanup stack.
*/
{
RFileReadStream frs;
TInt r = frs.Open(iFs, aFileName, EFileStream | EFileRead);
User::LeaveIfError(r);
CleanupClosePushL(frs);
CPBEncryptParms* pbep = CPBEncryptParms::NewL(frs);
CleanupStack::PopAndDestroy(&frs);
CleanupStack::PushL(pbep);
return pbep;
}
void CExternPbeParams::TestDecodeMatchesScriptL(const TDesC& aFileName)
/**
Test whether the encryption parameters which were externalized
to the supplied file match those specified in the script file.
@param aFileName Name of file which contains externalized form.
@leave KErrGeneral The internalized form doesn't match the parameters
in the script.
*/
{
CPBEncryptParms* pbep = InternalizeEncryptionParamsLC(aFileName);
TBool match =
pbep->Cipher() == iExpCipher
&& pbep->Salt() == *iExpSalt
&& pbep->Iterations() == iExpIterCount;
match = match && pbep->Kdf() == iExpKdf;
if (! match)
User::Leave(KErrGeneral);
CleanupStack::PopAndDestroy(pbep);
}
void CExternPbeParams::CompareAgainstTestFileL(
const TDesC& aFileName, const CPBEncryptParms& aParams)
/**
Externalize the supplied parameters object and ensure it matches the
test file.
@param aFileName File which contains externalized parameters.
@param aParams Test object to externalize.
@leave KErrGeneral The externalized forms do not match.
*/
{
// open a file stream on the externalized form
RFileReadStream frs;
TInt r = frs.Open(iFs, aFileName, EFileStream | EFileRead);
User::LeaveIfError(r);
CleanupClosePushL(frs);
// externalize the object to memory
const TInt KMaxBufferLen = 128;
HBufC8* reExtBuf = HBufC8::NewLC(KMaxBufferLen);
TPtr8 reDes = reExtBuf->Des();
RDesWriteStream dws(reDes);
CleanupClosePushL(dws);
aParams.ExternalizeL(dws);
dws.CommitL();
// ensure the externalized forms are equal
RDesReadStream drs(reDes);
TInt fLen = frs.Source()->SizeL();
TInt mLen = drs.Source()->SizeL();
if (fLen != mLen)
User::Leave(KErrGeneral);
TBuf8<1> fByte;
TBuf8<1> mByte;
for (TInt i = 0; i < fLen; ++i)
{
frs.ReadL(fByte, 1);
drs.ReadL(mByte, 1);
if (fByte != mByte)
User::Leave(KErrGeneral);
}
CleanupStack::PopAndDestroy(3, &frs); // frs, reExtBuf, dws
}
void CExternPbeParams::TestReExternMatchesL(const TDesC& aFileName)
/**
Read the CPBEncryptParms object which is externalized in
the named file, re-externalize it, and check the two
representations are binary equivalent.
@param aFileName Name of file which contains externalized form.
@leave KErrGeneral The externalized forms are different.
*/
{
CPBEncryptParms* pbep = InternalizeEncryptionParamsLC(aFileName);
CompareAgainstTestFileL(aFileName, *pbep);
CleanupStack::PopAndDestroy(pbep);
}
void CExternPbeParams::TestScratchExternL(const TDesC& aFileName)
/**
Construct a CPBEncryptParams object from the parameter values
in the script file. Test it matches the test file.
@param aFileName Test file which contains externalized parameters.
*/
{
CPBEncryptParms* pbep = CPBEncryptParms::NewLC(
static_cast<TPBECipher>(iExpCipher),
*iExpSalt,
*iExpIv,
iExpIterCount);
pbep->SetKdf(static_cast<CPBEncryptParms::TKdf>(iExpKdf));
CompareAgainstTestFileL(aFileName, *pbep);
CleanupStack::PopAndDestroy(pbep);
}
void CExternPbeParams::DoReportAction(void)
/**
Implements CTestAction but is empty.
*/
{
// empty.
}
void CExternPbeParams::DoCheckResult(TInt /*aError*/)
/**
Implements CTestAction but is empty.
*/
{
// empty.
}
// -------- support functions --------
HBufC8* CExternPbeParams::ReadHexStringL(const TDesC8& aBody, const TDesC8& aTag)
/**
Convert a string in the test script to an 8-bit buffer. The string
is a sequence of hex digits, e.g. "abcdef01", which is converted to a
descriptor containing the matching bytes {0xab, 0xcd, 0xef, 0x01}.
@param aBody Body of parent element.
@param aTag Bare tag name. This function extracts the text
between "<aTag>" and "</aTag>".
@return Newly-allocated buffer containing matching bytes.
This is owned by the caller.
*/
{
HBufC8* scriptString = ReadStringLC(aBody, aTag);
TInt textLen = scriptString->Length();
if ((textLen % 2) != 0)
User::Leave(KErrCorrupt);
TInt byteCount = textLen / 2;
HBufC8* procString = HBufC8::NewMaxLC(byteCount);
TPtr8 procDes = procString->Des();
for (TInt i = 0; i < byteCount; ++i)
{
TUint8 byteVal;
TInt r = TLex8(scriptString->Mid(i * 2, 2)).Val(byteVal, EHex);
User::LeaveIfError(r);
procDes[i] = byteVal;
}
CleanupStack::Pop(procString);
CleanupStack::PopAndDestroy(scriptString);
return procString;
}
TInt CExternPbeParams::ReadDecStringL(const TDesC8& aBody, const TDesC8& aTag)
/**
Finds a decimal text string in the script and returns the
integer value which it represents.
@param aBody Body of parent element.
@param aTag Bare tag name. This function extracts the text
between "<aTag>" and "</aTag>".
@return Integer value encoded in the script file.
*/
{
HBufC8* scriptString = ReadStringLC(aBody, aTag);
TInt value;
User::LeaveIfError(TLex8(*scriptString).Val(value));
CleanupStack::PopAndDestroy(scriptString);
return value;
}
HBufC8* CExternPbeParams::ReadStringLC(const TDesC8& aBody, const TDesC8& aTag)
/**
Extracts a string from the supplied script file.
@param aBody Body of parent element.
@param aTag Bare tag name. This function extracts the text
between "<aTag>" and "</aTag>".
@return A copy of the string allocated on the heap. The
string is placed on the cleanup stack.
*/
{
TBuf8<32> startTag;
startTag.Format(_L8("<%S>"), &aTag);
TBuf8<32> endTag;
endTag.Format(_L8("</%S>"), &aTag);
TInt pos = 0;
TInt r;
const TPtrC8 contents = Input::ParseElement(
aBody, startTag, endTag, pos, r);
User::LeaveIfError(r);
return contents.AllocLC();
}
/**
This code was originally in PerformAction to create the initial
data files.
// GENERATE PKCS5 TEST PARAMS FILE
RFileWriteStream fws;
r = fws.Replace(iFs, _L("c:\\tpbe\\pkcs5-orig.dat"), EFileStream | EFileWrite);
User::LeaveIfError(r);
CleanupClosePushL(fws);
_LIT8(KSalt, "SALT4567");
_LIT8(KIv, "IV23456789abcdef");
const TInt KIterCount = 1234;
CPBEncryptParms* pbep = CPBEncryptParms::NewLC(
ECipherAES_CBC_256, KSalt, KIv, KIterCount);
pbep->ExternalizeL(fws);
fws.CommitL();
CleanupStack::PopAndDestroy(2, &fws);
#ifdef SYMBIAN_PKCS12
// GENERATE PKCS12 TEST PARAMS FILE
RFileWriteStream fws;
r = fws.Replace(iFs, _L("c:\\tpbe\\pkcs12-first.dat"), EFileStream | EFileWrite);
User::LeaveIfError(r);
CleanupClosePushL(fws);
_LIT8(KSalt, "SALT4567");
_LIT8(KIv, "IV23456789abcdef");
const TInt KIterCount = 1234;
CPBEncryptParms* pbep = CPBEncryptParms::NewLC(
ECipherAES_CBC_256, KSalt, KIv, KIterCount);
pbep->SetKdf(CPBEncryptParms::EKdfPkcs12);
pbep->ExternalizeL(fws);
fws.CommitL();
CleanupStack::PopAndDestroy(2, &fws);
#endif // #ifdef SYMBIAN_PKCS12
*/