|
1 /* |
|
2 * Copyright (c) 2004-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 |
|
21 |
|
22 #include "restorecontroller.h" |
|
23 |
|
24 #include "arrayutils.h" |
|
25 #include "sisinfo.h" |
|
26 #include "sisuid.h" |
|
27 #include "sisversion.h" |
|
28 #include "sissupportedlanguages.h" |
|
29 #include "sisinstallblock.h" |
|
30 #include "sishash.h" |
|
31 #include "userselections.h" |
|
32 #include "siselseif.h" |
|
33 #include "log.h" |
|
34 #include "securitycheckutil.h" |
|
35 #include "siscapabilities.h" |
|
36 #include "certchainconstraints.h" |
|
37 #include "sisregistryfiledescription.h" |
|
38 #include "sistruststatus.h" |
|
39 #include "secutils.h" |
|
40 |
|
41 #include <f32file.h> |
|
42 |
|
43 using namespace Swi; |
|
44 using namespace Swi::Sis; |
|
45 |
|
46 // |
|
47 // TRestoreFileInformation |
|
48 // |
|
49 |
|
50 TRestoreFileInformation::TRestoreFileInformation(CFileDescription& aFileDescription, CApplication& aParentApplication) |
|
51 : iFileDescription(aFileDescription), |
|
52 iParentApplication(aParentApplication) |
|
53 { |
|
54 } |
|
55 |
|
56 |
|
57 // |
|
58 // CRestoreController |
|
59 // |
|
60 |
|
61 void CRestoreController::ConstructL(TDesC8& aController) |
|
62 { |
|
63 iSystemDriveChar = RFs::GetSystemDriveChar(); |
|
64 |
|
65 // Read the controllers from the buffer |
|
66 InternalizeControllersL(aController); |
|
67 |
|
68 //We also create a dummy plan for use when writing the |
|
69 //registry entries |
|
70 TInt augmentationIndex(0); |
|
71 TInt noOfMatchingLanguages = iMatchingSupportedLanguagesArray.Count(); |
|
72 TInt matchingLanguageCount = 0; |
|
73 for (TInt i = 0; i < iControllers.Count(); i++) |
|
74 { |
|
75 |
|
76 CPlan* plan = CPlan::NewL(); |
|
77 CleanupStack::PushL(plan); |
|
78 User::LeaveIfError(iInstallPlans.Append(plan)); |
|
79 CleanupStack::Pop(plan); |
|
80 |
|
81 CApplication* application = CApplication::NewLC(); |
|
82 |
|
83 CController* controller = iControllers[i]; |
|
84 |
|
85 DEBUG_PRINTF3(_L8("Restore - Metadata controller %d is of type %d"), |
|
86 i, controller->Info().InstallType()); |
|
87 |
|
88 // Set the install type |
|
89 switch (controller->Info().InstallType()) |
|
90 { |
|
91 case EInstInstallation: |
|
92 application->SetInstall(*controller); |
|
93 application->UserSelections().SetDrive(iInstallDrive); |
|
94 |
|
95 //if there are macthing languages then populate iMatchingDeviceLanguages array of application object |
|
96 if ( noOfMatchingLanguages ) |
|
97 { |
|
98 while( iMatchingSupportedLanguagesArray[matchingLanguageCount] != ELangNone) |
|
99 { |
|
100 application->PopulateMatchingDeviceLanguagesL(iMatchingSupportedLanguagesArray[matchingLanguageCount++]); |
|
101 } |
|
102 } |
|
103 break; |
|
104 |
|
105 case EInstPartialUpgrade: |
|
106 application->SetPartialUpgrade(*controller); |
|
107 application->UserSelections().SetDrive(iInstallDrive); |
|
108 // Carry forwards the in-rom flag |
|
109 if (i == 0 || iTopLevelApplications[0]->IsInROM()) |
|
110 { |
|
111 // If the first controller is a parial upgrade then |
|
112 // it must be a partial upgrade to a ROM stub. |
|
113 // If there are multiple PUs then they must also be in-rom |
|
114 application->SetInROM(); |
|
115 } |
|
116 if ( noOfMatchingLanguages ) |
|
117 { |
|
118 TInt i = 0; |
|
119 while( iMatchingSupportedLanguagesArray[i] != ELangNone) |
|
120 { |
|
121 application->PopulateMatchingDeviceLanguagesL(iMatchingSupportedLanguagesArray[i++]); |
|
122 } |
|
123 } |
|
124 break; |
|
125 |
|
126 case EInstAugmentation: |
|
127 application->SetAugmentation(*controller); |
|
128 application->UserSelections().SetDrive(iAugmentationDrives[augmentationIndex++]); |
|
129 |
|
130 //if there are macthing languages then populate iMatchingDeviceLanguages array of application object |
|
131 if ( noOfMatchingLanguages ) |
|
132 { |
|
133 while( iMatchingSupportedLanguagesArray[matchingLanguageCount] != ELangNone) |
|
134 { |
|
135 application->PopulateMatchingDeviceLanguagesL(iMatchingSupportedLanguagesArray[matchingLanguageCount++]); |
|
136 } |
|
137 } |
|
138 break; |
|
139 |
|
140 default: |
|
141 User::Leave(KErrNotSupported); |
|
142 break; |
|
143 |
|
144 } |
|
145 |
|
146 TPtrC8* buf = iControllerBinaries[i]; |
|
147 |
|
148 application->SetController(*controller); |
|
149 |
|
150 CSisCertificateVerifier* verifier = CSisCertificateVerifier::NewLC(controller, *buf, iSecurityManager, application); |
|
151 User::LeaveIfError(iVerifiers.Append(verifier)); |
|
152 CleanupStack::Pop(verifier); |
|
153 |
|
154 TInt languageIndex = SetApplicationLanguageL(*application); |
|
155 |
|
156 //This is the first controller, add it to the plan |
|
157 User::LeaveIfError(iTopLevelApplications.Append(application)); |
|
158 plan->SetApplication(application); // ownership transferred. |
|
159 |
|
160 const CVersion& version = controller->Info().Version(); |
|
161 TVersion appVersion(version.Major(), version.Minor(), version.Build()); |
|
162 |
|
163 plan->SetApplicationInformationL(controller->Info().Names()[languageIndex]->Data(), |
|
164 controller->Info().VendorNames()[languageIndex]->Data(), |
|
165 appVersion); |
|
166 |
|
167 CleanupStack::Pop(application); |
|
168 } |
|
169 } |
|
170 |
|
171 /** |
|
172 Locates the relevant file description in the controller and adds the file |
|
173 to be restored to the list of files for the new SIS registry object. |
|
174 |
|
175 This also checks the hash of the file if needed and generates an appropriate temporary |
|
176 filename to be used by integrity services. |
|
177 |
|
178 @param aFile file handle to temporary restore file. |
|
179 @param aTempFileName temporary filename to use with integrity services. |
|
180 @param aHashCheckRequried whether the restore files hash must be checked against the controllers |
|
181 */ |
|
182 void CRestoreController::AddFileDescriptionL(RFile& aFile, TDesC& aTarget, TDes& aTempFilename, TBool aHashCheckRequired) |
|
183 { |
|
184 // Lookup file information and check the hash if needed |
|
185 TRestoreFileInformation info = LookupFileInformationL(aFile, aTarget, aHashCheckRequired); |
|
186 |
|
187 // Add the file description to the plan |
|
188 CApplication& application = info.ParentApplication(); |
|
189 application.AddFileL(info.FileDescription(), application.UserSelections().Drive()); |
|
190 |
|
191 // Construct the temporary file name for this file |
|
192 TParsePtrC parse(aTarget); |
|
193 _LIT(KTemporaryFileFormat, "%c:%Stfile-%d-%d-%d-"); |
|
194 TUint driveCh(iSystemDriveChar); |
|
195 aTempFilename.Format(KTemporaryFileFormat, driveCh, &KSysInstallTempPath, |
|
196 application.ControllerL().Info().Uid().Uid().iUid, application.AbsoluteDataIndex(), info.FileDescription().Index()); |
|
197 |
|
198 // Append a hex representation of a hash of the filename. We need the |
|
199 // temporary filename to be effectively unique, but the filename itself |
|
200 // may be too long. |
|
201 |
|
202 // Use the real target path (after path subsitution) minus the drive letter. |
|
203 HBufC* hashBuf = SecUtils::HexHashL(aTarget.Right(aTarget.Length() - 1)); |
|
204 aTempFilename.Append(*hashBuf); |
|
205 delete hashBuf; |
|
206 |
|
207 // finally, remove this file from the list of files to add entries for |
|
208 for (TInt i = 0; i < iInstalledFiles.Count(); ++i) |
|
209 { |
|
210 HBufC* filename = iInstalledFiles[i]; |
|
211 if (aTarget.CompareF(*filename) == 0) |
|
212 { |
|
213 delete filename; |
|
214 iInstalledFiles.Remove(i); |
|
215 break; |
|
216 } |
|
217 } |
|
218 } |
|
219 |
|
220 void CRestoreController::AddEmbeddedAppsAndFilesL() |
|
221 { |
|
222 //for each application/controller pair, add fake file and embedded package descriptions |
|
223 for (TInt i = 0; i < iTopLevelApplications.Count(); ++i) |
|
224 { |
|
225 DoAddEmbeddedAppsAndFilesL(iTopLevelApplications[i]->ControllerL().InstallBlock(), *iTopLevelApplications[i]); |
|
226 } |
|
227 } |
|
228 |
|
229 // Preserves the links between embedded applications in the registry, so uninstalling the |
|
230 // top level package will attempt to uninstall the packages below it in the tree |
|
231 // However, these applications are not processed as part of the restore |
|
232 // hence they are entirely fake |
|
233 |
|
234 void CRestoreController::DoAddEmbeddedAppsAndFilesL( |
|
235 const CInstallBlock& aInstallBlock, CApplication& aApplication) |
|
236 { |
|
237 |
|
238 const RPointerArray<CController>& controllers = aInstallBlock.EmbeddedControllers(); |
|
239 |
|
240 TInt i; |
|
241 for (i = 0; i < controllers.Count(); ++i) |
|
242 { |
|
243 |
|
244 CController* controller = controllers[i]; |
|
245 |
|
246 CApplication* application = CApplication::NewLC(); |
|
247 application->SetController(*controller); |
|
248 SetApplicationLanguageL(*application); |
|
249 aApplication.AddEmbeddedApplicationL(application); // Ownership transfered |
|
250 CleanupStack::Pop(application); |
|
251 |
|
252 } |
|
253 |
|
254 const RPointerArray<CFileDescription>& fileDescriptions = aInstallBlock.FileDescriptions(); |
|
255 TChar foldedDrive = aApplication.UserSelections().Drive(); |
|
256 if (foldedDrive != 255) |
|
257 { |
|
258 foldedDrive.Fold(); // don't convert 'no drive selection' to the y drive |
|
259 } |
|
260 |
|
261 for (i = 0; i < fileDescriptions.Count(); ++i) |
|
262 { |
|
263 const TDesC& description = fileDescriptions[i]->Target().Data(); |
|
264 if (description.Length() != 0) |
|
265 { |
|
266 TChar sisDrive = description[0]; |
|
267 if (sisDrive == '$') |
|
268 { |
|
269 sisDrive = iFs.GetSystemDriveChar(); |
|
270 } |
|
271 sisDrive.Fold(); |
|
272 |
|
273 for (TInt j = 0; j < iInstalledFiles.Count(); j++) |
|
274 { |
|
275 HBufC* filename = iInstalledFiles[j]; |
|
276 TChar targetDrive = (*filename)[0]; |
|
277 targetDrive.Fold(); |
|
278 |
|
279 // if the file description matches this filename (taking into account drive letter) |
|
280 // add it to the application. |
|
281 // This may not be 100% the correct file description, but it will be close enough |
|
282 if (description.Mid(1).CompareF(filename->Mid(1)) == 0 && |
|
283 ((targetDrive == foldedDrive) || (targetDrive == sisDrive))) |
|
284 { |
|
285 aApplication.AddFileL(*fileDescriptions[i], aApplication.UserSelections().Drive()); |
|
286 // Cut down the search space some |
|
287 delete filename; |
|
288 iInstalledFiles.Remove(j); |
|
289 break; |
|
290 } |
|
291 } |
|
292 } |
|
293 } |
|
294 |
|
295 const RPointerArray<CIf>& ifBlocks = aInstallBlock.IfStatements(); |
|
296 |
|
297 for (i = 0; i < ifBlocks.Count(); ++i) |
|
298 { |
|
299 |
|
300 CIf* ifBlock = ifBlocks[i]; |
|
301 DoAddEmbeddedAppsAndFilesL(ifBlock->InstallBlock(), aApplication); |
|
302 |
|
303 const RPointerArray<CElseIf>& elseBlocks = ifBlock->ElseIfs(); |
|
304 |
|
305 for (TInt j = 0; j < elseBlocks.Count(); j++) |
|
306 { |
|
307 |
|
308 CElseIf* elseBlock = elseBlocks[j]; |
|
309 DoAddEmbeddedAppsAndFilesL(elseBlock->InstallBlock(), aApplication); |
|
310 |
|
311 } |
|
312 |
|
313 } |
|
314 |
|
315 } |
|
316 // Creates a TPtrC8* which points to the data of controllers stored in MetaData which was backedup. |
|
317 // Not using HBufC8::NewLC as it allocates memory afresh for the data. |
|
318 TPtrC8* CRestoreController::CreateRawControllerPtrLC(RDesReadStream& aStream, const TUint8* aBasePtr, TInt& aOffset ) |
|
319 { |
|
320 TCardinality card; |
|
321 aStream>>card; |
|
322 TInt tmpLen = (TInt)card; |
|
323 //Right shift TCardinality by one as its LSB is not |
|
324 // used to represent the length of the descriptor |
|
325 TInt len = ((TInt)card) >> 1; |
|
326 |
|
327 //TCardinality uses |
|
328 // 1 Byte to store the length if it is between 0-127 |
|
329 // 2 Bytes if length is between 128-16383 |
|
330 // 4 Bytes if length > 16383 |
|
331 |
|
332 if ( tmpLen < 128 ) |
|
333 aOffset+=1; |
|
334 else if ( tmpLen < 16384 ) |
|
335 aOffset+=2; |
|
336 else |
|
337 aOffset+=4; |
|
338 |
|
339 TPtrC8* controllerBuf = new (ELeave)TPtrC8(); |
|
340 controllerBuf->Set(aBasePtr+aOffset,len); |
|
341 CleanupStack::PushL(controllerBuf); |
|
342 |
|
343 aOffset += len; |
|
344 |
|
345 while( len-- ) |
|
346 aStream.ReadInt8L(); |
|
347 |
|
348 return controllerBuf; |
|
349 } |
|
350 |
|
351 void CRestoreController::InternalizeControllersL(TDesC8& aController) |
|
352 { |
|
353 |
|
354 RDesReadStream stream(aController); |
|
355 CleanupClosePushL(stream); |
|
356 TInt offset = 0; |
|
357 const TUint8* basePtr = aController.Ptr(); |
|
358 |
|
359 // Drive letter to install to |
|
360 iInstallDrive = TChar(stream.ReadUint32L()); |
|
361 offset+=4; |
|
362 |
|
363 // We need to count the augmentations to know how many selected drives to |
|
364 // read after the list of files. |
|
365 TInt augmentationsCount(0); |
|
366 |
|
367 TInt controllerCount = stream.ReadInt32L(); |
|
368 DEBUG_PRINTF2(_L8("Restore - Metadata consists of %d seperate controllers"), |
|
369 controllerCount); |
|
370 offset+=4; |
|
371 |
|
372 while (controllerCount--) |
|
373 { |
|
374 TPtrC8* controllerBuf = CreateRawControllerPtrLC(stream,basePtr,offset); |
|
375 |
|
376 User::LeaveIfError(iControllerBinaries.Append(controllerBuf)); |
|
377 CleanupStack::Pop(controllerBuf); |
|
378 |
|
379 // Create a CController object from the binary |
|
380 |
|
381 CDesDataProvider* provider = CDesDataProvider::NewLC(*controllerBuf); |
|
382 CController* controller = CController::NewLC(*provider, EAssumeType); |
|
383 User::LeaveIfError(iControllers.Append(controller)); |
|
384 CleanupStack::Pop(controller); |
|
385 if (controller->Info().InstallType() == EInstAugmentation) |
|
386 { |
|
387 augmentationsCount++; |
|
388 } |
|
389 CleanupStack::PopAndDestroy(provider); |
|
390 |
|
391 } |
|
392 |
|
393 // Trap this to make the metadata file format BC |
|
394 TInt filesCount = 0; |
|
395 TRAPD(err, filesCount = stream.ReadInt32L()); |
|
396 // If this is an old style backup metadata file, it won't include this section |
|
397 if (err == KErrNone) |
|
398 { |
|
399 while (filesCount--) |
|
400 { |
|
401 HBufC* filename = HBufC::NewLC(stream, KMaxTInt); |
|
402 User::LeaveIfError(iInstalledFiles.Append(filename)); |
|
403 CleanupStack::Pop(filename); |
|
404 } |
|
405 |
|
406 // Trap reading augmentations' selected drives, which appear after the |
|
407 // file list in metadata files created after the fix for DEF087124. |
|
408 // Leave if the read fails beyond the first augmentation, since we should |
|
409 // have all or none. |
|
410 for (TInt i = 0; i < augmentationsCount; i++) |
|
411 { |
|
412 if (err == KErrNone) |
|
413 { |
|
414 TChar selectedDrive(iInstallDrive); |
|
415 TRAP(err, selectedDrive = stream.ReadInt32L()); |
|
416 if (i != 0) |
|
417 { |
|
418 User::LeaveIfError(err); |
|
419 } |
|
420 iAugmentationDrives.AppendL(selectedDrive); |
|
421 } |
|
422 else |
|
423 { |
|
424 // If we failed on reading the first drive, fill the rest of |
|
425 // the array with the selected drive for the base package. |
|
426 iAugmentationDrives.AppendL(iInstallDrive); |
|
427 } |
|
428 } |
|
429 } |
|
430 |
|
431 // Reading the array of matching device supported languages |
|
432 TRAP(err, InternalizeArrayL(iMatchingSupportedLanguagesArray,stream)); |
|
433 |
|
434 CleanupStack::PopAndDestroy(&stream); |
|
435 } |
|
436 |
|
437 |
|
438 CRestoreController* CRestoreController::NewL(TDesC8& aController, CSecurityManager& aSecurityManager, RFs& aFs) |
|
439 { |
|
440 |
|
441 CRestoreController* self = CRestoreController::NewLC(aController, aSecurityManager, aFs); |
|
442 CleanupStack::Pop(self); |
|
443 return self; |
|
444 |
|
445 } |
|
446 |
|
447 CRestoreController* CRestoreController::NewLC(TDesC8& aController, CSecurityManager& aSecurityManager, RFs& aFs) |
|
448 { |
|
449 |
|
450 CRestoreController* self = new (ELeave) CRestoreController(aSecurityManager, aFs); |
|
451 CleanupStack::PushL(self); |
|
452 self->ConstructL(aController); |
|
453 return self; |
|
454 |
|
455 } |
|
456 |
|
457 CRestoreController::CRestoreController(CSecurityManager& aSecurityManager, RFs& aFs) |
|
458 : iFs(aFs), iSecurityManager(aSecurityManager) |
|
459 { |
|
460 } |
|
461 /** |
|
462 Finds the matching file description in the controller and checks the hash if required. |
|
463 |
|
464 @param aFile handle to the file to restore |
|
465 @param aTarget path that the file handle should be restored. |
|
466 @param aHashCheckRequired if the target path is TCB protected and a hash check is required. |
|
467 */ |
|
468 TRestoreFileInformation CRestoreController::LookupFileInformationL(RFile& aFile, TDesC& aTarget, TBool aHashCheckRequired) |
|
469 |
|
470 |
|
471 { |
|
472 CFileDescription* desc = NULL; |
|
473 |
|
474 // Search through the controllers backwards in case an executable has been ugpraded with |
|
475 // a partial upgrade |
|
476 TBool foundMatch = EFalse; |
|
477 TInt i = iControllers.Count() - 1; |
|
478 CApplication* application = NULL; |
|
479 while (i >= 0 && ! foundMatch) |
|
480 { |
|
481 CController* controller = iControllers[i]; |
|
482 application = iTopLevelApplications[i]; |
|
483 TChar drive = application->UserSelections().Drive(); |
|
484 desc = FindFileDescriptionL(controller->InstallBlock(), aFile, aTarget, aHashCheckRequired, drive); |
|
485 |
|
486 if (desc) |
|
487 { |
|
488 foundMatch = ETrue; |
|
489 } |
|
490 else |
|
491 { |
|
492 --i; // Check the next controller |
|
493 } |
|
494 } |
|
495 |
|
496 if (aHashCheckRequired && ! foundMatch) |
|
497 { |
|
498 // Previously the code would return either KErrNotFound or KErrSISWouldOverWrite |
|
499 // both of these errors are incorrect and SBE does not depend on the exact error code |
|
500 // in this scenario. |
|
501 // N.B. It is already possible for KErrSecurityError to be returned so the backup |
|
502 // client MUST be able to handle this. |
|
503 DEBUG_PRINTF2(_L("No matching hash for file %S"), &aTarget); |
|
504 User::Leave(KErrSecurityError); |
|
505 } |
|
506 else if (! foundMatch) |
|
507 { |
|
508 // It's difficult to report VerifyOnRestore mis-matches as a security error because |
|
509 // the file could be present in multiple controllers and in multiple install blocks |
|
510 // with and without the VerifyOnRestore flag set |
|
511 DEBUG_PRINTF2(_L("No match in controller for %S"), &aTarget); |
|
512 User::Leave(KErrNotFound); |
|
513 } |
|
514 |
|
515 // This is where things get really interesting ... |
|
516 // The restore machine invokes a restore processor for each controller in turn |
|
517 // and as well as checking the exe header the restore processor builds a list of SIDs |
|
518 // as it goes. |
|
519 // When the files are installed private directories are checked against the list of SIDs. |
|
520 // BUT |
|
521 // If the exe has been upgraded via a partial upgrade then the application pointer here will |
|
522 // refer to the partial upgrade that hasn't been checked yet so the SID isn't known and the processor |
|
523 // will reject the restore of files to that private dir. |
|
524 // Reversing the order of processing the controllers doesn't help because if the exe |
|
525 // hasn't been upgraded but the PU deploys a file to the exe's private dir then again the SID |
|
526 // isn't known so the install will be rejected. |
|
527 |
|
528 // The work around is to associate all of the files supplied by SBE for PUs with |
|
529 // the first application which will be the SA |
|
530 // It's not safe blindly do this for all applications because this would incorrectly associate |
|
531 // the augmenation's files with the SP |
|
532 if (application->IsPartialUpgrade()) |
|
533 { |
|
534 application = iTopLevelApplications[0]; |
|
535 } |
|
536 TRestoreFileInformation result(*desc, *application); |
|
537 return result; |
|
538 } |
|
539 |
|
540 CFileDescription* CRestoreController::FindFileDescriptionL( |
|
541 const CInstallBlock& aInstallBlock, RFile& aFile, TDesC& aTarget, TBool aHashCheckRequired, const TChar& aDrive) |
|
542 { |
|
543 const RPointerArray<CFileDescription> descriptions = aInstallBlock.FileDescriptions(); |
|
544 CFileDescription* result = NULL; |
|
545 |
|
546 for (TInt j = 0; j < descriptions.Count(); j++) |
|
547 { |
|
548 CFileDescription* description = descriptions[j]; |
|
549 const TDesC& descTarget = (description->Target()).Data(); |
|
550 |
|
551 // We'll acknowledge that the file matches the description iff: |
|
552 // a) The hashes match |
|
553 // b) The targets match, taking into account wildcard drive letters |
|
554 |
|
555 // substitute the drive letter and replace any relevant paths |
|
556 HBufC* transDest = |
|
557 iSecurityManager.SecurityPolicy().ResolveTargetFileNameLC(descTarget, aDrive); |
|
558 |
|
559 // check if this file matches the file name |
|
560 TBool match = (transDest->Left(1).CompareF(aTarget.Left(1)) == 0) |
|
561 &&(transDest->Mid(1) == aTarget.Mid(1)); |
|
562 |
|
563 // if it does, do we also need to do as hash check to approve this file? |
|
564 if ((aHashCheckRequired || (description->OperationOptions() & EInstVerifyOnRestore)) && match) |
|
565 { |
|
566 // If the file is TCB protected OR the VerifyOnRestore flag is set the |
|
567 // a match is only valid if the hash also matches |
|
568 const CHash& hash = description->Hash(); |
|
569 TSISHashAlgorithm algorithm = hash.Algorithm(); |
|
570 CMessageDigest* temp = CalculateHashL(aFile, algorithm); |
|
571 CleanupStack::PushL(temp); |
|
572 match = (temp->Final() == hash.Data()); |
|
573 DEBUG_PRINTF3(_L("Checking hash candiate for file %S pass = %d"), &aTarget, match); |
|
574 CleanupStack::PopAndDestroy(temp); |
|
575 } |
|
576 CleanupStack::PopAndDestroy(transDest); |
|
577 if (match) |
|
578 { |
|
579 return description; |
|
580 } |
|
581 } |
|
582 |
|
583 const RPointerArray<CIf>& ifBlocks = aInstallBlock.IfStatements(); |
|
584 for (TInt i = 0; i < ifBlocks.Count(); i++) |
|
585 { |
|
586 CIf* ifBlock = ifBlocks[i]; |
|
587 if (NULL != (result = FindFileDescriptionL(ifBlock->InstallBlock(), aFile, aTarget, aHashCheckRequired, aDrive))) |
|
588 { |
|
589 return result; |
|
590 } |
|
591 |
|
592 const RPointerArray<CElseIf>& elseBlocks = ifBlock->ElseIfs(); |
|
593 for (TInt j = 0; j < elseBlocks.Count(); j++) |
|
594 { |
|
595 CElseIf* elseBlock = elseBlocks[j]; |
|
596 if (NULL != (result = FindFileDescriptionL(elseBlock->InstallBlock(), aFile, aTarget, aHashCheckRequired, aDrive))) |
|
597 { |
|
598 return result; |
|
599 } |
|
600 } |
|
601 } |
|
602 return result; |
|
603 } |
|
604 |
|
605 |
|
606 CMessageDigest* CRestoreController::CalculateHashL(RFile& aFile, TSISHashAlgorithm aAlgorithm) |
|
607 { |
|
608 HBufC8* buf = HBufC8::NewLC(1024); |
|
609 TPtr8 bufPtr(buf->Des()); |
|
610 TInt seekPos = 0; |
|
611 aFile.Seek(ESeekStart, seekPos); |
|
612 CMessageDigest* digest = NULL; |
|
613 |
|
614 switch (aAlgorithm) |
|
615 { |
|
616 case EHashAlgSHA1: |
|
617 digest = CSHA1::NewL(); |
|
618 break; |
|
619 |
|
620 default: |
|
621 User::Leave(KErrNotSupported); |
|
622 break; |
|
623 } |
|
624 |
|
625 while (KErrNone == aFile.Read(bufPtr) && bufPtr.Length() != 0) |
|
626 { |
|
627 digest->Update(bufPtr); |
|
628 } |
|
629 |
|
630 CleanupStack::PopAndDestroy(buf); |
|
631 return digest; |
|
632 } |
|
633 |
|
634 TInt CRestoreController::SetApplicationLanguageL(CApplication& aApplication) |
|
635 { |
|
636 |
|
637 // We set either the current locale if available, or the default |
|
638 // language. |
|
639 |
|
640 TLanguage locale = User::Language(); |
|
641 const CSupportedLanguages& languages = aApplication.ControllerL().SupportedLanguages(); |
|
642 TInt langIndex = 0; |
|
643 |
|
644 for (TInt i = 0; i < languages.Count(); i++) |
|
645 { |
|
646 |
|
647 if (locale == languages[i]) |
|
648 { |
|
649 |
|
650 langIndex = i; |
|
651 break; |
|
652 |
|
653 } |
|
654 |
|
655 } |
|
656 |
|
657 aApplication.UserSelections().SetLanguage(languages[langIndex]); |
|
658 return langIndex; |
|
659 |
|
660 } |
|
661 |
|
662 |
|
663 CRestoreController::~CRestoreController() |
|
664 { |
|
665 |
|
666 iControllers.ResetAndDestroy(); |
|
667 iVerifiers.ResetAndDestroy(); |
|
668 iControllerBinaries.ResetAndDestroy(); |
|
669 iInstallPlans.ResetAndDestroy(); |
|
670 iTopLevelApplications.Reset(); // These pointers owned by the plan |
|
671 iInstalledFiles.ResetAndDestroy(); |
|
672 iAugmentationDrives.Close(); |
|
673 iMatchingSupportedLanguagesArray.Close(); |
|
674 } |
|
675 |
|
676 |
|
677 // |
|
678 // CSisCertificateVerifier |
|
679 // |
|
680 |
|
681 |
|
682 CRestoreController::CSisCertificateVerifier* CRestoreController::CSisCertificateVerifier::NewL(CController* aController, TDesC8& aControllerBinary, CSecurityManager& aSecurityManager, CApplication* aApplication) |
|
683 { |
|
684 |
|
685 CSisCertificateVerifier* self = CSisCertificateVerifier::NewLC(aController, aControllerBinary, aSecurityManager, aApplication); |
|
686 CleanupStack::Pop(self); |
|
687 return self; |
|
688 |
|
689 } |
|
690 |
|
691 CRestoreController::CSisCertificateVerifier* CRestoreController::CSisCertificateVerifier::NewLC(CController* aController, TDesC8& aControllerBinary, CSecurityManager& aSecurityManager, CApplication* aApplication) |
|
692 { |
|
693 |
|
694 CSisCertificateVerifier* self = new (ELeave) CSisCertificateVerifier(aController, aSecurityManager, aApplication,aControllerBinary); |
|
695 CleanupStack::PushL(self); |
|
696 return self; |
|
697 |
|
698 } |
|
699 |
|
700 CRestoreController::CSisCertificateVerifier::CSisCertificateVerifier(CController* aController, CSecurityManager& aSecurityManager, CApplication* aApplication, TDesC8& aControllerBinary) |
|
701 : CActive(CActive::EPriorityStandard), |
|
702 iSecurityManager(aSecurityManager), |
|
703 iApplication(aApplication),iControllerBinary(aControllerBinary) |
|
704 { |
|
705 |
|
706 iController = aController; |
|
707 CActiveScheduler::Add(this); |
|
708 |
|
709 } |
|
710 |
|
711 void CRestoreController::CSisCertificateVerifier::StartL(TRequestStatus& aStatus) |
|
712 { |
|
713 |
|
714 iWatcherStatus = &aStatus; |
|
715 aStatus = KRequestPending; |
|
716 |
|
717 TBool isEmbedded = ETrue; |
|
718 |
|
719 iSecurityManager.VerifyControllerL( |
|
720 iControllerBinary, |
|
721 *iController, |
|
722 &iResult, |
|
723 iValidationResults, |
|
724 iCerts, |
|
725 &iGrantableCapabilitySet, |
|
726 iAllowUnsigned, |
|
727 isEmbedded, |
|
728 iStatus); |
|
729 |
|
730 SetActive(); |
|
731 |
|
732 } |
|
733 |
|
734 void CRestoreController::CSisCertificateVerifier::RunL() |
|
735 { |
|
736 DEBUG_PRINTF2(_L8("Restore - Controller verification complete, verification status was %d"), |
|
737 iResult); |
|
738 |
|
739 TBool verified = EFalse; |
|
740 switch (iResult) |
|
741 { |
|
742 default: |
|
743 // BC break, unknown validation code, abort |
|
744 User::Leave(KErrNotSupported); |
|
745 break; |
|
746 |
|
747 case EValidationSucceeded: |
|
748 // Chain was validated |
|
749 // Increase the trust status of this install process |
|
750 iController->SetTrust(ESisPackageCertificateChainValidatedToTrustAnchor); |
|
751 iController->TrustStatus().SetValidationStatus(EValidatedToAnchor); |
|
752 verified = ETrue; |
|
753 break; |
|
754 case ESignatureNotPresent: |
|
755 // This is a special case because we need to look at the policy |
|
756 // setting to determine if unsigned SIS files are allowed at all. |
|
757 // Display security warning dialog. |
|
758 iController->SetTrust(ESisPackageUnsignedOrSelfSigned); |
|
759 iController->TrustStatus().SetValidationStatus(EUnsigned); |
|
760 if (iAllowUnsigned) |
|
761 { |
|
762 verified = ETrue; |
|
763 } |
|
764 break; |
|
765 case ESignatureSelfSigned: |
|
766 iController->SetTrust(ESisPackageCertificateChainNoTrustAnchor); |
|
767 iController->TrustStatus().SetValidationStatus(EValidated); |
|
768 verified = ETrue; |
|
769 break; |
|
770 case ECertificateValidationError: |
|
771 case ENoCertificate: |
|
772 case ENoCodeSigningExtension: |
|
773 case ENoSupportedPolicyExtension: |
|
774 // Unable to validate the chain |
|
775 // We apply the same policy as per unsigned SIS files |
|
776 iController->SetTrust(ESisPackageValidationFailed); |
|
777 iController->TrustStatus().SetValidationStatus(EInvalid); |
|
778 break; |
|
779 case ESignatureCouldNotBeValidated: |
|
780 case EMandatorySignatureMissing: |
|
781 iController->TrustStatus().SetValidationStatus(EInvalid); |
|
782 break; |
|
783 } |
|
784 |
|
785 if (verified) |
|
786 { |
|
787 TRAPD(err, CheckDeviceIdConstraintsL();CheckCapabilitiesL()); |
|
788 if (err) |
|
789 { |
|
790 DEBUG_PRINTF(_L8("Restore - Device ID or Capability Check Failed")); |
|
791 User::RequestComplete(iWatcherStatus, err); |
|
792 } |
|
793 else |
|
794 { |
|
795 User::RequestComplete(iWatcherStatus, KErrNone); |
|
796 } |
|
797 } |
|
798 else |
|
799 { |
|
800 User::RequestComplete(iWatcherStatus, KErrCorrupt); |
|
801 } |
|
802 } |
|
803 |
|
804 |
|
805 void CRestoreController::CSisCertificateVerifier::DoCancel() |
|
806 { |
|
807 |
|
808 iSecurityManager.Cancel(); |
|
809 |
|
810 } |
|
811 |
|
812 CRestoreController::CSisCertificateVerifier::~CSisCertificateVerifier() |
|
813 { |
|
814 |
|
815 Cancel(); |
|
816 iValidationResults.ResetAndDestroy(); |
|
817 iCerts.ResetAndDestroy(); |
|
818 |
|
819 } |
|
820 |
|
821 void CRestoreController::CSisCertificateVerifier::CheckDeviceIdConstraintsL() |
|
822 { |
|
823 const CCertChainConstraints* certChainConstraints = iController->CertChainConstraints(); |
|
824 |
|
825 const RPointerArray<HBufC>& deviceIDs=iSecurityManager.DeviceIDsInfo(); |
|
826 SecurityCheckUtil::CheckDeviceIdConstraintsL(certChainConstraints, deviceIDs); |
|
827 } |
|
828 |
|
829 void CRestoreController::CSisCertificateVerifier::CheckCapabilitiesL() |
|
830 { |
|
831 TCapabilitySet requestedCaps; |
|
832 requestedCaps.SetEmpty(); |
|
833 const RPointerArray<CSisRegistryFileDescription>& sidFdList=iApplication->FilesToAdd(); |
|
834 TInt count=sidFdList.Count(); |
|
835 for (TInt i=0; i<count; i++) |
|
836 { |
|
837 const HBufC8* rawFileHeaderCaps = sidFdList[i]->CapabilitiesData(); |
|
838 if (rawFileHeaderCaps) |
|
839 { |
|
840 const TInt KCapSetSize=sizeof(TUint32); // size of a capability bit set |
|
841 const TInt KCapSetSizeBits=8*KCapSetSize; |
|
842 const TInt KNumCapSets=rawFileHeaderCaps->Size()/KCapSetSize; |
|
843 for (TInt set=0; set<KNumCapSets; set++) |
|
844 { |
|
845 TUint32 capsValue=*(reinterpret_cast<const TUint32*>(rawFileHeaderCaps->Ptr())+set); |
|
846 for (TInt capIndex=0; capIndex<KCapSetSizeBits; capIndex++) |
|
847 { |
|
848 if (capsValue & (0x1<<capIndex)) |
|
849 { |
|
850 TCapability cap=static_cast<TCapability>(capIndex+set*KCapSetSizeBits); |
|
851 requestedCaps.AddCapability(cap); |
|
852 } |
|
853 } |
|
854 } |
|
855 } |
|
856 } |
|
857 |
|
858 //Get the CertChainConstraint instance built by the SecurityManager. |
|
859 const CCertChainConstraints* certChainConstraints = iController->CertChainConstraints(); |
|
860 |
|
861 //Get the capbibilies contrained from the CertChainConstraints |
|
862 TCapabilitySet initCapConstraints=certChainConstraints->ValidCapabilities(); |
|
863 TCapabilitySet supportedCapabilitiesByBoth=initCapConstraints; |
|
864 |
|
865 //build the capability constraints from the constrained capabilities and root capbilities |
|
866 supportedCapabilitiesByBoth.Intersection(iGrantableCapabilitySet); |
|
867 |
|
868 // We have a set of granted capabilities, which is the intersection of iCapabilitySet and |
|
869 // Capbilities constraints(filled in the security manager). |
|
870 // Let's see if that's enough for the files to be installed. |
|
871 requestedCaps.Remove(supportedCapabilitiesByBoth); |
|
872 |
|
873 // Any capabilities left in requestedCaps after this are not signed for and not in the certs constraints. |
|
874 // Check if any of them are system capabilities. If so, bail out. |
|
875 TCapabilitySet requiredExtraSysCaps(requestedCaps); |
|
876 SecurityCheckUtil::RemoveUserCaps(requiredExtraSysCaps, iSecurityManager); |
|
877 if (SecurityCheckUtil::NotEmpty(requiredExtraSysCaps)) |
|
878 { |
|
879 DEBUG_PRINTF(_L8("Restore - Controller requires more system capabilities than are signed for")); |
|
880 User::Leave(KErrSecurityError); |
|
881 } |
|
882 else if (SecurityCheckUtil::NotEmpty(requestedCaps)) //Required more user capabilities then |
|
883 { |
|
884 // User capabilities are supported by the CertChainConstraints, but not by root certificates. |
|
885 if (!initCapConstraints.HasCapabilities(requestedCaps)) |
|
886 { |
|
887 DEBUG_PRINTF(_L8("Restore - Controller requires user capabilities that are not supported by devcert constraints")); |
|
888 // User capabilities are not all supported by the CertChainConstraints. |
|
889 User::Leave(KErrSecurityError); |
|
890 } |
|
891 } |
|
892 } |