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