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