|
1 /* |
|
2 * Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <s32mem.h> |
|
20 #include <s32file.h> |
|
21 #include "texternpbeparams.h" |
|
22 |
|
23 |
|
24 CTestAction* CExternPbeParams::NewL( |
|
25 RFs& aFs, CConsoleBase& aConsole, |
|
26 Output& aOut, const TTestActionSpec& aTestActionSpec) |
|
27 /** |
|
28 Factory function allocates new instance of CExternPbeParams and extracts |
|
29 the element body from the supplied test action spec. |
|
30 |
|
31 @param aFs Used to parse XML script file. |
|
32 @param aConsole Required by CTestAction. |
|
33 @param aOut Required by CTestAction. |
|
34 @param aTestActionSpec Action specification contains type, name, and |
|
35 XML contents. |
|
36 @return New instance of CExternPbeParams, which is owned |
|
37 by the caller. |
|
38 */ |
|
39 { |
|
40 CExternPbeParams* self = new(ELeave) CExternPbeParams(aConsole, aOut, aFs); |
|
41 CleanupStack::PushL(self); |
|
42 self->ConstructL(aTestActionSpec); |
|
43 CleanupStack::Pop(self); |
|
44 return self; |
|
45 } |
|
46 |
|
47 CExternPbeParams::CExternPbeParams(CConsoleBase& aConsole, Output& aOut, RFs& aFs) |
|
48 /** |
|
49 This constructor exists to record the file server session and to initialize |
|
50 the CTestAction superclass. |
|
51 |
|
52 @param aConsole Required by CTestAction. |
|
53 @param aOut Required by CTestAction. |
|
54 @param aFs Used to read from and write to files in PerformAction, |
|
55 which stores and restores the externalized params. |
|
56 */ |
|
57 : CTestAction(aConsole, aOut), |
|
58 iFs(aFs) |
|
59 { |
|
60 // empty. |
|
61 } |
|
62 |
|
63 void CExternPbeParams::ConstructL(const TTestActionSpec& aTestActionSpec) |
|
64 /** |
|
65 Second phase initialization initializes the superclass and |
|
66 makes a copy of the test element. |
|
67 |
|
68 @param aTestActionSpec Action specification contains type, name, and |
|
69 XML contents. |
|
70 */ |
|
71 { |
|
72 CTestAction::ConstructL(aTestActionSpec); |
|
73 iBody = aTestActionSpec.iActionBody.AllocL(); |
|
74 |
|
75 // iBody is deconstructed in DoPerformPrerequisite |
|
76 } |
|
77 |
|
78 CExternPbeParams::~CExternPbeParams() |
|
79 /** |
|
80 Free resources allocated in ConstructL. Specifically, |
|
81 deletes the copy of the element body text. |
|
82 */ |
|
83 { |
|
84 delete iBody; |
|
85 } |
|
86 |
|
87 // -------- implement CTestAction -------- |
|
88 |
|
89 void CExternPbeParams::DoPerformPrerequisite(TRequestStatus& aStatus) |
|
90 /** |
|
91 Override CTestAction by deconstructing element body allocated |
|
92 in ConstructL. |
|
93 |
|
94 If this function fails then DoPerformPostrequisite must still |
|
95 be called. |
|
96 |
|
97 @param aStatus This status is completed when the prerequisite |
|
98 has finished. (This implementation is actually |
|
99 synchronous so the request will already be completed |
|
100 when it returns.) |
|
101 */ |
|
102 { |
|
103 TRAPD(r, DoPerformPrerequisiteL()); |
|
104 |
|
105 iActionState = CTestAction::EAction; |
|
106 TRequestStatus* ps = &aStatus; |
|
107 User::RequestComplete(ps, r); |
|
108 } |
|
109 |
|
110 void CExternPbeParams::DoPerformPrerequisiteL() |
|
111 /** |
|
112 Helper function for DoPerformPrerequisite contains resource allocation |
|
113 functions which can leave. |
|
114 |
|
115 Extracts cipher, salt, iv, iter count, and kdf values. |
|
116 */ |
|
117 { |
|
118 _LIT8(KOrigFileName, "orig-filename"); |
|
119 iOrigFileName = ReadStringLC(*iBody, KOrigFileName); |
|
120 CleanupStack::Pop(iOrigFileName); |
|
121 |
|
122 _LIT8(KExpCipherElemName, "expected-cipher"); |
|
123 iExpCipher = ReadDecStringL(*iBody, KExpCipherElemName); |
|
124 _LIT8(KExpSaltElemName, "expected-salt"); |
|
125 iExpSalt = ReadHexStringL(*iBody, KExpSaltElemName); |
|
126 _LIT8(KExpIvElemName, "expected-iv"); |
|
127 iExpIv = ReadHexStringL(*iBody, KExpIvElemName); |
|
128 _LIT8(KExpIterCountElemName, "expected-iter-count"); |
|
129 iExpIterCount = ReadDecStringL(*iBody, KExpIterCountElemName); |
|
130 _LIT8(KExpKdfElemName, "expected-kdf"); |
|
131 iExpKdf = ReadDecStringL(*iBody, KExpKdfElemName); |
|
132 } |
|
133 |
|
134 void CExternPbeParams::DoPerformPostrequisite(TRequestStatus& aStatus) |
|
135 /** |
|
136 Implements CTestAction by cleaning up data allocated in DoPerformPrerequisiteL. |
|
137 |
|
138 @param aStatus This status is completed to indicate the |
|
139 postrequisite has finished. (This function |
|
140 is synchronous so the status is completed before |
|
141 this function returns.) |
|
142 */ |
|
143 { |
|
144 delete iExpIv; |
|
145 iExpIv = 0; |
|
146 delete iExpSalt; |
|
147 iExpSalt = 0; |
|
148 delete iOrigFileName; |
|
149 iOrigFileName = NULL; |
|
150 |
|
151 iFinished = ETrue; |
|
152 TRequestStatus* ps = &aStatus; |
|
153 User::RequestComplete(ps, KErrNone); |
|
154 } |
|
155 |
|
156 void CExternPbeParams::PerformAction(TRequestStatus& aStatus) |
|
157 /** |
|
158 Implements CTestAction by running the actual tests. This |
|
159 consists of: |
|
160 |
|
161 Reading an externalized CPBEncryptParms object and testing the |
|
162 cipher, salt, iv, iteration count, and KDF are as expected. |
|
163 |
|
164 Externalizing the object to memory. |
|
165 |
|
166 Testing the two externalizations are binary identical. |
|
167 |
|
168 Creating an equivalent object from scratch and externalizing it. |
|
169 |
|
170 Testing the externalizations are binary identical. |
|
171 |
|
172 As well as testing the objects can be stored reliably, this |
|
173 test also ensures that old (pre-PKCS#12) files can still be |
|
174 read and, and that objects are stored in the old format if they |
|
175 do not use any PKCS#12-specific features. (I.e., they use the |
|
176 default PKCS#5 KDF.) |
|
177 |
|
178 @param aStatus This request status is completed when |
|
179 the action has finished, successfully |
|
180 or otherwise. This implementation is |
|
181 synchronous, and so the status is actually |
|
182 completed before this function returns. |
|
183 */ |
|
184 { |
|
185 TFileName fn; |
|
186 fn.Copy(*iOrigFileName); // convert from narrow |
|
187 |
|
188 // ensure reference file matches re-externalized form |
|
189 |
|
190 TRAPD(r, |
|
191 TestDecodeMatchesScriptL(fn); |
|
192 TestReExternMatchesL(fn); |
|
193 TestScratchExternL(fn) ); |
|
194 |
|
195 iResult = (r == KErrNone); |
|
196 iActionState = CTestAction::EPostrequisite; |
|
197 TRequestStatus* status = &aStatus; |
|
198 User::RequestComplete(status, KErrNone); |
|
199 } |
|
200 |
|
201 CPBEncryptParms* CExternPbeParams::InternalizeEncryptionParamsLC(const TDesC& aFileName) |
|
202 /** |
|
203 Construct a CPBEncryptParms object from the externalized |
|
204 form in the named file. |
|
205 |
|
206 @param aFileName File which contains externalized form. |
|
207 @return Internalized encryption parameters object |
|
208 which is placed on the cleanup stack. |
|
209 */ |
|
210 { |
|
211 RFileReadStream frs; |
|
212 TInt r = frs.Open(iFs, aFileName, EFileStream | EFileRead); |
|
213 User::LeaveIfError(r); |
|
214 CleanupClosePushL(frs); |
|
215 CPBEncryptParms* pbep = CPBEncryptParms::NewL(frs); |
|
216 CleanupStack::PopAndDestroy(&frs); |
|
217 CleanupStack::PushL(pbep); |
|
218 return pbep; |
|
219 } |
|
220 |
|
221 void CExternPbeParams::TestDecodeMatchesScriptL(const TDesC& aFileName) |
|
222 /** |
|
223 Test whether the encryption parameters which were externalized |
|
224 to the supplied file match those specified in the script file. |
|
225 |
|
226 @param aFileName Name of file which contains externalized form. |
|
227 @leave KErrGeneral The internalized form doesn't match the parameters |
|
228 in the script. |
|
229 */ |
|
230 { |
|
231 CPBEncryptParms* pbep = InternalizeEncryptionParamsLC(aFileName); |
|
232 |
|
233 TBool match = |
|
234 pbep->Cipher() == iExpCipher |
|
235 && pbep->Salt() == *iExpSalt |
|
236 && pbep->Iterations() == iExpIterCount; |
|
237 |
|
238 match = match && pbep->Kdf() == iExpKdf; |
|
239 |
|
240 if (! match) |
|
241 User::Leave(KErrGeneral); |
|
242 |
|
243 CleanupStack::PopAndDestroy(pbep); |
|
244 } |
|
245 |
|
246 void CExternPbeParams::CompareAgainstTestFileL( |
|
247 const TDesC& aFileName, const CPBEncryptParms& aParams) |
|
248 /** |
|
249 Externalize the supplied parameters object and ensure it matches the |
|
250 test file. |
|
251 |
|
252 @param aFileName File which contains externalized parameters. |
|
253 @param aParams Test object to externalize. |
|
254 @leave KErrGeneral The externalized forms do not match. |
|
255 */ |
|
256 { |
|
257 // open a file stream on the externalized form |
|
258 RFileReadStream frs; |
|
259 TInt r = frs.Open(iFs, aFileName, EFileStream | EFileRead); |
|
260 User::LeaveIfError(r); |
|
261 CleanupClosePushL(frs); |
|
262 |
|
263 // externalize the object to memory |
|
264 const TInt KMaxBufferLen = 128; |
|
265 HBufC8* reExtBuf = HBufC8::NewLC(KMaxBufferLen); |
|
266 TPtr8 reDes = reExtBuf->Des(); |
|
267 RDesWriteStream dws(reDes); |
|
268 CleanupClosePushL(dws); |
|
269 aParams.ExternalizeL(dws); |
|
270 dws.CommitL(); |
|
271 |
|
272 // ensure the externalized forms are equal |
|
273 RDesReadStream drs(reDes); |
|
274 TInt fLen = frs.Source()->SizeL(); |
|
275 TInt mLen = drs.Source()->SizeL(); |
|
276 if (fLen != mLen) |
|
277 User::Leave(KErrGeneral); |
|
278 |
|
279 TBuf8<1> fByte; |
|
280 TBuf8<1> mByte; |
|
281 for (TInt i = 0; i < fLen; ++i) |
|
282 { |
|
283 frs.ReadL(fByte, 1); |
|
284 drs.ReadL(mByte, 1); |
|
285 if (fByte != mByte) |
|
286 User::Leave(KErrGeneral); |
|
287 } |
|
288 |
|
289 CleanupStack::PopAndDestroy(3, &frs); // frs, reExtBuf, dws |
|
290 } |
|
291 |
|
292 void CExternPbeParams::TestReExternMatchesL(const TDesC& aFileName) |
|
293 /** |
|
294 Read the CPBEncryptParms object which is externalized in |
|
295 the named file, re-externalize it, and check the two |
|
296 representations are binary equivalent. |
|
297 |
|
298 @param aFileName Name of file which contains externalized form. |
|
299 @leave KErrGeneral The externalized forms are different. |
|
300 */ |
|
301 { |
|
302 CPBEncryptParms* pbep = InternalizeEncryptionParamsLC(aFileName); |
|
303 |
|
304 CompareAgainstTestFileL(aFileName, *pbep); |
|
305 |
|
306 CleanupStack::PopAndDestroy(pbep); |
|
307 } |
|
308 |
|
309 void CExternPbeParams::TestScratchExternL(const TDesC& aFileName) |
|
310 /** |
|
311 Construct a CPBEncryptParams object from the parameter values |
|
312 in the script file. Test it matches the test file. |
|
313 |
|
314 @param aFileName Test file which contains externalized parameters. |
|
315 */ |
|
316 { |
|
317 CPBEncryptParms* pbep = CPBEncryptParms::NewLC( |
|
318 static_cast<TPBECipher>(iExpCipher), |
|
319 *iExpSalt, |
|
320 *iExpIv, |
|
321 iExpIterCount); |
|
322 |
|
323 pbep->SetKdf(static_cast<CPBEncryptParms::TKdf>(iExpKdf)); |
|
324 |
|
325 CompareAgainstTestFileL(aFileName, *pbep); |
|
326 |
|
327 CleanupStack::PopAndDestroy(pbep); |
|
328 } |
|
329 |
|
330 void CExternPbeParams::DoReportAction(void) |
|
331 /** |
|
332 Implements CTestAction but is empty. |
|
333 */ |
|
334 { |
|
335 // empty. |
|
336 } |
|
337 |
|
338 void CExternPbeParams::DoCheckResult(TInt /*aError*/) |
|
339 /** |
|
340 Implements CTestAction but is empty. |
|
341 */ |
|
342 { |
|
343 // empty. |
|
344 } |
|
345 |
|
346 |
|
347 // -------- support functions -------- |
|
348 |
|
349 |
|
350 HBufC8* CExternPbeParams::ReadHexStringL(const TDesC8& aBody, const TDesC8& aTag) |
|
351 /** |
|
352 Convert a string in the test script to an 8-bit buffer. The string |
|
353 is a sequence of hex digits, e.g. "abcdef01", which is converted to a |
|
354 descriptor containing the matching bytes {0xab, 0xcd, 0xef, 0x01}. |
|
355 |
|
356 @param aBody Body of parent element. |
|
357 @param aTag Bare tag name. This function extracts the text |
|
358 between "<aTag>" and "</aTag>". |
|
359 @return Newly-allocated buffer containing matching bytes. |
|
360 This is owned by the caller. |
|
361 */ |
|
362 { |
|
363 HBufC8* scriptString = ReadStringLC(aBody, aTag); |
|
364 |
|
365 TInt textLen = scriptString->Length(); |
|
366 if ((textLen % 2) != 0) |
|
367 User::Leave(KErrCorrupt); |
|
368 TInt byteCount = textLen / 2; |
|
369 HBufC8* procString = HBufC8::NewMaxLC(byteCount); |
|
370 TPtr8 procDes = procString->Des(); |
|
371 for (TInt i = 0; i < byteCount; ++i) |
|
372 { |
|
373 TUint8 byteVal; |
|
374 TInt r = TLex8(scriptString->Mid(i * 2, 2)).Val(byteVal, EHex); |
|
375 User::LeaveIfError(r); |
|
376 procDes[i] = byteVal; |
|
377 } |
|
378 |
|
379 CleanupStack::Pop(procString); |
|
380 CleanupStack::PopAndDestroy(scriptString); |
|
381 return procString; |
|
382 } |
|
383 |
|
384 TInt CExternPbeParams::ReadDecStringL(const TDesC8& aBody, const TDesC8& aTag) |
|
385 /** |
|
386 Finds a decimal text string in the script and returns the |
|
387 integer value which it represents. |
|
388 |
|
389 @param aBody Body of parent element. |
|
390 @param aTag Bare tag name. This function extracts the text |
|
391 between "<aTag>" and "</aTag>". |
|
392 @return Integer value encoded in the script file. |
|
393 */ |
|
394 { |
|
395 HBufC8* scriptString = ReadStringLC(aBody, aTag); |
|
396 |
|
397 TInt value; |
|
398 User::LeaveIfError(TLex8(*scriptString).Val(value)); |
|
399 CleanupStack::PopAndDestroy(scriptString); |
|
400 return value; |
|
401 } |
|
402 |
|
403 HBufC8* CExternPbeParams::ReadStringLC(const TDesC8& aBody, const TDesC8& aTag) |
|
404 /** |
|
405 Extracts a string from the supplied script file. |
|
406 |
|
407 @param aBody Body of parent element. |
|
408 @param aTag Bare tag name. This function extracts the text |
|
409 between "<aTag>" and "</aTag>". |
|
410 @return A copy of the string allocated on the heap. The |
|
411 string is placed on the cleanup stack. |
|
412 */ |
|
413 { |
|
414 TBuf8<32> startTag; |
|
415 startTag.Format(_L8("<%S>"), &aTag); |
|
416 TBuf8<32> endTag; |
|
417 endTag.Format(_L8("</%S>"), &aTag); |
|
418 |
|
419 TInt pos = 0; |
|
420 TInt r; |
|
421 const TPtrC8 contents = Input::ParseElement( |
|
422 aBody, startTag, endTag, pos, r); |
|
423 User::LeaveIfError(r); |
|
424 |
|
425 return contents.AllocLC(); |
|
426 } |
|
427 |
|
428 /** |
|
429 This code was originally in PerformAction to create the initial |
|
430 data files. |
|
431 |
|
432 // GENERATE PKCS5 TEST PARAMS FILE |
|
433 RFileWriteStream fws; |
|
434 r = fws.Replace(iFs, _L("c:\\tpbe\\pkcs5-orig.dat"), EFileStream | EFileWrite); |
|
435 User::LeaveIfError(r); |
|
436 CleanupClosePushL(fws); |
|
437 |
|
438 _LIT8(KSalt, "SALT4567"); |
|
439 _LIT8(KIv, "IV23456789abcdef"); |
|
440 const TInt KIterCount = 1234; |
|
441 CPBEncryptParms* pbep = CPBEncryptParms::NewLC( |
|
442 ECipherAES_CBC_256, KSalt, KIv, KIterCount); |
|
443 pbep->ExternalizeL(fws); |
|
444 fws.CommitL(); |
|
445 CleanupStack::PopAndDestroy(2, &fws); |
|
446 |
|
447 #ifdef SYMBIAN_PKCS12 |
|
448 // GENERATE PKCS12 TEST PARAMS FILE |
|
449 RFileWriteStream fws; |
|
450 r = fws.Replace(iFs, _L("c:\\tpbe\\pkcs12-first.dat"), EFileStream | EFileWrite); |
|
451 User::LeaveIfError(r); |
|
452 CleanupClosePushL(fws); |
|
453 |
|
454 _LIT8(KSalt, "SALT4567"); |
|
455 _LIT8(KIv, "IV23456789abcdef"); |
|
456 const TInt KIterCount = 1234; |
|
457 CPBEncryptParms* pbep = CPBEncryptParms::NewLC( |
|
458 ECipherAES_CBC_256, KSalt, KIv, KIterCount); |
|
459 pbep->SetKdf(CPBEncryptParms::EKdfPkcs12); |
|
460 pbep->ExternalizeL(fws); |
|
461 fws.CommitL(); |
|
462 CleanupStack::PopAndDestroy(2, &fws); |
|
463 #endif // #ifdef SYMBIAN_PKCS12 |
|
464 |
|
465 */ |