--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/boottimeintegritycheck/src/IntegrityCheck.cpp Tue Jan 26 15:20:08 2010 +0200
@@ -0,0 +1,2858 @@
+/*
+* Copyright (c) 2005-2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "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: Implementation of boot time integrity check program.
+*
+*/
+
+
+// INCLUDE FILES
+
+#include <e32cons.h>
+#include <f32file.h>
+#include <cctcertinfo.h> // TCapabilitySet
+#include <s32file.h>
+#include <signed.h> // VerifySignatureL
+#include <x500dn.h> // ExactMatchL
+#include <x509cert.h> // x509
+#include <swi/hashcontainer.h>
+#include <swi/sisregistrysession.h>
+#include <swi/sisregistryentry.h>
+#include <swi/sisregistrypackage.h>
+#include <hash.h>
+#include <etelmm.h> // For serial number size
+
+#include "IntegrityCheck.h"
+#include "InfoServerClient.h"
+#include "IntegrityCheckDefs.h"
+#include "IntegrityCheckClient.h"
+#include "IntegrityCheckDebug.h"
+
+
+// CONSTANTS
+
+_LIT(KBTICThreadName,"BootIntegrityCheck");
+_LIT(KBTICCertStoreZ,"z:\\resource\\swicertstore.dat");
+_LIT(KBTICCertStoreCName,"updatedswicertstore.dat");
+_LIT(KBTICCertStoreCPath,"c:\\resource\\swicertstore\\dat\\");
+_LIT(KBTICDriveC,"c:\\");
+_LIT(KBTICDriveCWildcard,"c:\\*");
+_LIT(KBTICExtensionExe,"*.exe");
+_LIT(KBTICSerialNumberFile,"*imei.txt");
+_LIT(KBTICStarWildcard,"*\\");
+/*
+#ifdef __BTIC_BINARIES_CHECK_ENABLED
+_LIT(KBTICSysPathC,"c:\\sys\\bin\\");
+_LIT(KBTICCertStoreC,
+ "c:\\resource\\swicertstore\\dat\\updatedswicertstore.dat");
+_LIT(KBTICSysPathCWildcard,"c:\\sys\\bin\\*");
+_LIT(KBTICExtensionDll,"*.dll");
+_LIT(KBTICExtensionDat,"*.dat");
+#endif //__BTIC_BINARIES_CHECK_ENABLED
+*/
+const TInt KBTICCapaCount = 2; //Number of capabilities.
+const TUint64 KBTIC_DRM = 64; //0000 0000 0000 0000 0000 0000 0100 0000
+const TUint64 KBTIC_TCB = 1; //0000 0000 0000 0000 0000 0000 0000 0001
+const TInt KBTICCabaWordOffset = 17; //File heder offset for capa. word @ 64bit.
+const TInt KBTICHashSize = 20;
+const TInt KBTICTryToOpen = 240; //Try to open file. (240 x 0.5sec = 120sec)
+const TInt KBTICTryToCreate = 5; // Try to create process.
+const TUint KBTICObserverTime = 1000000; // 1sec.
+const TUint KBTICRunCount = 10;
+
+// MACROS
+
+using namespace Swi;
+
+// DATA TYPES
+
+// FUNCTION PROTOTYPES
+
+LOCAL_C TInt ThreadStartL();
+
+LOCAL_C TInt ReadCertificatesL(
+ RFs& aFs,
+ const TDesC& aPath,
+ RPointerArray<CX509Certificate>& aX509CertArray,
+ RPointerArray<TCapabilitySet>& aCapabilityArray );
+
+LOCAL_C TBool ValidateCertStoreL(
+ RFs& aFs,
+ RPointerArray<CX509Certificate>& aX509CertArray,
+ RPointerArray<TCapabilitySet>& aCapaArray,
+ const TDesC& aCertStoreFileName,
+ const TDesC& aCertStoreFilePath );
+
+LOCAL_C TBool ValidateProvisonerCertStoreL(
+ RFs& aFs,
+ RPointerArray<CX509Certificate>& aX509CertArray,
+ RPointerArray<TCapabilitySet>& aCapaArray,
+ const TDesC& aCertStoreFileName,
+ const TDesC& aCertStoreFilePath,
+ RSisRegistryEntry& aEntry );
+
+LOCAL_C TBool ValidateSymbianCertStoreL(
+ RFs& aFs,
+ RPointerArray<CX509Certificate>& aX509CertArray,
+ RPointerArray<TCapabilitySet>& aCapaArray,
+ RSisRegistryEntry& aEntry,
+ RPointerArray<HBufC>& aUpdaterExePaths );
+
+LOCAL_C TBool RunUpdaterL( RFs& aFs, RPointerArray<HBufC>& aUpdaterExePaths );
+
+LOCAL_C TBool DeleteAllFilesL( RFs& aFs, const TDesC& aFolderPath );
+
+LOCAL_C TBool SearchFilesFromArrayL(
+ RPointerArray<HBufC>& aSourceArray,
+ const TDesC& aDriveAndPath,
+ RPointerArray<HBufC>& aStringArray,
+ RPointerArray<HBufC>& aFilesArray );
+
+LOCAL_C TBool SearchValidCertificateL(
+ RSisRegistryEntry& aEntry,
+ RPointerArray<CX509Certificate>& aX509CertArray,
+ RPointerArray<TCapabilitySet>& aCertCapaArray,
+ TUint64 aCapability );
+
+LOCAL_C TCapability GetCapability( TUint64 aCapability );
+
+LOCAL_C TBool VerifyHashL(
+ RSisRegistryEntry& aEntry,
+ RPointerArray<HBufC>& aPathArray,
+ RPointerArray<HBufC8>& aHashArray );
+
+LOCAL_C TBool CompareToRegisteryHashL(
+ RSisRegistryEntry& aEntry,
+ TDesC& aEntryFile,
+ TDesC8& aHashBuffer );
+
+LOCAL_C TBool CheckSerialNumberL( RFs& aFs, const TDesC& aFileName );
+
+LOCAL_C void CorruptFileL( RFs& aFs, const TDesC& aFileName );
+
+LOCAL_C TBool CheckCapabilityWordAndCalcHashL(
+ RFs& aFs,
+ TBool aCheckCapa,
+ TUint64* aCapaVector,
+ RPointerArray<HBufC>& aSourceArray,
+ RPointerArray<HBufC>& aFilesArray,
+ RPointerArray<HBufC8>& aHashArray,
+ RArray<TUint64>& aCapaArray );
+/*
+#ifdef __BTIC_BINARIES_CHECK_ENABLED
+
+LOCAL_C void RenameFileL( RFs& aFs, const TDesC& aFileName );
+
+LOCAL_C void UniteCertArraysL(
+ RPointerArray<CX509Certificate>& aTargetCertArray,
+ RPointerArray<CX509Certificate>& aSourceCertArray );
+
+LOCAL_C void UniteCapaArraysL(
+ RPointerArray<TCapabilitySet>& aTargetCapaArray,
+ RPointerArray<TCapabilitySet>& aSourceCapaArray );
+
+LOCAL_C void CheckBinariesL(
+ RFs& aFs,
+ RPointerArray<CX509Certificate>& aX509CertArray,
+ RPointerArray<TCapabilitySet>& aCertCapaArray );
+
+LOCAL_C void FindFilesL(
+ RFs& aFs,
+ const TDesC& aPath,
+ const TDesC& aSearchString,
+ RPointerArray<HBufC>& aFoundFilesArray );
+
+LOCAL_C TBool FindMatchFromSisPackageL(
+ RFs& aFs,
+ RPointerArray<HBufC>& aFilesArray,
+ RPointerArray<HBufC8>& aHashArray,
+ RArray<TUint64>& aCapaArray,
+ RPointerArray<CX509Certificate>& aX509CertArray,
+ RPointerArray<TCapabilitySet>& aCertCapaArray );
+
+#endif //__BTIC_BINARIES_CHECK_ENABLED
+*/
+
+// FORWARD DECLARATIONS
+
+// LOCAL FUNCTION PROTOTYPES
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// E32Main()
+// Main for ARM environment.
+// Returns: KErrNone if successful
+// Othervice some system error code.
+// -----------------------------------------------------------------------------
+//
+GLDEF_C TInt E32Main()
+ {
+ BTIC_TRACE_PRINT_ALLOC_CELLS("[BOOT INTECRITY CHECK] Main cell count = %d");
+ TInt err = KErrNone;
+
+ CTrapCleanup* cleanup = CTrapCleanup::New();
+
+ if ( !cleanup )
+ {
+ return KErrNoMemory;
+ }
+
+ TRAP( err, ThreadStartL() );
+
+ BTIC_TRACE_PRINT_NUM("[BOOT INTECRITY CHECK] Main TRAP error = %d", err);
+
+ delete cleanup;
+
+ BTIC_TRACE_PRINT_ALLOC_CELLS("[BOOT INTECRITY CHECK] Main cell count = %d");
+ return err;
+ }
+
+
+// -----------------------------------------------------------------------------
+// ThreadStart()
+//
+// This is programs main.
+// -----------------------------------------------------------------------------
+//
+LOCAL_C TInt ThreadStartL()
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] START PROGRAM");
+ __UHEAP_MARK;
+ BTIC_TRACE_PRINT_ALLOC_CELLS("Start Cell count = %d");
+
+ BTIC_TRACE_PRINT("Rename thread to BootIntegrityCheck");
+ // Rename thread as SecEnvInit.
+ User::RenameThread( KBTICThreadName );
+
+ // This should be read with feature manager etc. but since we
+ // only support certificate database checking this is ok.
+ TBool binariesCheckEnbled = EFalse;
+
+ TBool certFileFound = EFalse;
+ TInt err = KErrNone;
+ TInt pushToStack = 0;
+
+ // GET BOOT REASON
+
+ BTIC_TRACE_PRINT("Get boot reason");
+ TBool bootReasonFormat = EFalse;
+ RIntegrityCheckClient bticServer;
+
+ err = bticServer.Connect();
+ BTIC_TRACE_PRINT_NUM("BTIC Server connect error = %d", err );
+
+ if ( err == KErrNone )
+ {
+ CleanupClosePushL( bticServer );
+ TInt bootReason = KErrNone;
+
+ // Get boot reason from btic server.
+ err = bticServer.GetSWBootReason( bootReason );
+ BTIC_TRACE_PRINT_NUM("GetSWBootReason error = %d", err );
+
+ if ( err == KErrNone )
+ {
+ BTIC_TRACE_PRINT_NUM("Boot Reason number = %d", bootReason );
+
+ if ( bootReason == EBTICRestoreFactorySetDeep )
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] Boot reason: FORMAT");
+ bootReasonFormat = ETrue;
+ }
+ }
+ CleanupStack::PopAndDestroy(); //bticServer
+ }
+
+ // OPEN FILE SERVER
+ BTIC_TRACE_PRINT("Open FS session");
+
+ RFs fs;
+ // Connect to file server.
+ User::LeaveIfError( fs.Connect() );
+ CleanupClosePushL( fs );
+ pushToStack++;
+
+ // Find SWICertStore.dat in C drive.
+ TFindFile find( fs );
+ TBool certStoreOk = EFalse;
+ CDir* entryList = NULL;
+ HBufC* certStoreFilePath = NULL;
+ HBufC* certStoreFileName = NULL;
+
+ BTIC_TRACE_PRINT("Find C SWI certificate store");
+
+ // Get all files from folder.
+ if ( KErrNone == fs.GetDir (
+ KBTICCertStoreCPath,
+ KEntryAttNormal,
+ ESortByName|EDirsFirst,
+ entryList ) )
+ {
+ if ( entryList )
+ {
+ CleanupStack::PushL( entryList );
+
+ TInt count = entryList->Count();
+
+ // If file is found.
+ if ( count )
+ {
+ BTIC_TRACE_PRINT("Store file found");
+
+ // Get the highest version certstore file
+ const TEntry& entry = (*entryList)[count - 1];
+
+ // Make temp buffer for file path.
+ TBuf<KMaxFileName> path( KBTICCertStoreCPath );
+ path.Append( entry.iName );
+
+ certStoreFilePath = path.AllocLC();
+ pushToStack++;
+
+ certStoreFileName = entry.iName.AllocLC();
+ pushToStack++;
+
+ certFileFound = ETrue;
+
+ CleanupStack::Pop(); //certStoreFilePath
+ CleanupStack::Pop(); //certStoreFileName
+ CleanupStack::PopAndDestroy( 1, entryList );
+ CleanupStack::PushL( certStoreFilePath );
+ CleanupStack::PushL( certStoreFileName );
+ }
+ else
+ {
+ BTIC_TRACE_PRINT("No store file present");
+ CleanupStack::PopAndDestroy( 1, entryList );
+ }
+ }
+ }
+
+ BTIC_TRACE_PRINT("Check boot reason");
+ // Check boot reason. If certificate store file is found start active file
+ // observer which checks that file is deleted. If not continue checking.
+ if ( bootReasonFormat )
+ {
+ BTIC_TRACE_PRINT("Boot reason format");
+ if( certFileFound )
+ {
+ BTIC_TRACE_PRINT("Start active file observer");
+ TInt status = KErrUnknown;
+
+ // Create active scheduler.
+ CActiveScheduler* threadScheduler = new CActiveScheduler;
+ CleanupStack::PushL( threadScheduler );
+ pushToStack++;
+
+ CActiveScheduler::Install( threadScheduler );
+
+ // Create file observer object.
+ CActiveFileObserver* observer =
+ CActiveFileObserver::NewL( fs, *certStoreFilePath, status );
+ CleanupStack::PushL( observer );
+ pushToStack++;
+
+ BTIC_TRACE_PRINT("Start active scheduler");
+ CActiveScheduler::Start();
+
+ BTIC_TRACE_PRINT_NUM("File observer status = %d", status );
+
+ if ( status == KErrNone )
+ {
+ // Boot reason is fromat and certificate file is deleted.
+ // Stop checking and exit.
+ BTIC_TRACE_PRINT("Stop checking and exit");
+ certFileFound = EFalse;
+ binariesCheckEnbled = EFalse;
+ }
+ }
+ else
+ {
+ // Boot reason is fromat and no certificate file is found.
+ // Stop checking and exit.
+ BTIC_TRACE_PRINT("Stop checking and exit");
+ certFileFound = EFalse;
+ binariesCheckEnbled = EFalse;
+ }
+ }
+
+
+ BTIC_TRACE_PRINT_NUM("Updated store read enabled(1) = %d",certFileFound);
+ BTIC_TRACE_PRINT_NUM("Binaries check enabled(0) = %d",binariesCheckEnbled);
+
+ // Create pointer array for root certificates.
+ RPointerArray<CX509Certificate> x509CertArray;
+ RPointerArray<TCapabilitySet> certCapaArray;
+ TInt fileError = 0;
+
+ // Read root certificates if needed.
+ if ( certFileFound || binariesCheckEnbled )
+ {
+ // Get root certificates to x509 format.
+ fileError =
+ ReadCertificatesL(
+ fs,
+ KBTICCertStoreZ,
+ x509CertArray,
+ certCapaArray );
+
+ // Can't read root certificates or array is empty.
+ // Let's return and try this in next boot.
+ if ( fileError || x509CertArray.Count() == 0 )
+ {
+ BTIC_TRACE_PRINT("ERROR Can't read root certificates ! ! !");
+ CleanupStack::PopAndDestroy( pushToStack );
+ x509CertArray.ResetAndDestroy();
+ certCapaArray.ResetAndDestroy();
+ User::Leave( fileError );
+ }
+ }
+
+ // Create temporary pointer array for C-drive updated certificates.
+ RPointerArray<CX509Certificate> tempCertArray;
+ RPointerArray<TCapabilitySet> tempCapaArray;
+
+ // If candidate for certstore file is found read it and validate file.
+ if ( certFileFound )
+ {
+ BTIC_TRACE_PRINT("Read certificates from C");
+
+ // Read certificates from C drive and set them to x509 format
+ TRAP( err ,
+ fileError = ReadCertificatesL(
+ fs,
+ *certStoreFilePath,
+ tempCertArray,
+ tempCapaArray ) );
+
+ BTIC_TRACE_PRINT_NUM("C read file error (0) = %d", fileError );
+ BTIC_TRACE_PRINT_NUM("C read Trap err (0) = %d", err );
+
+ // If ReadCertificatesL function leaves, we assume that something is
+ // tampered and the file is corrupted. However if function returns
+ // an error code, file is not corrupted.
+ if ( err )
+ {
+ fileError = err;
+ TRAP_IGNORE( CorruptFileL( fs, *certStoreFilePath ) );
+ }
+
+ // If there is no error when constructing a permanent file store object
+ // let's continue.
+ if ( fileError == KErrNone )
+ {
+ BTIC_TRACE_PRINT("Validate cert store");
+
+ // Validate the certstore in C if certs are found.
+ TRAP( err,
+ certStoreOk = ValidateCertStoreL(
+ fs,
+ x509CertArray,
+ certCapaArray,
+ *certStoreFileName,
+ *certStoreFilePath ) );
+
+ BTIC_TRACE_PRINT_NUM("Trap err (0) = %d", err );
+ BTIC_TRACE_PRINT_NUM("Cert storage valid (1) = %d", certStoreOk );
+
+ // If validation fails or function leaves we will assume
+ // that database is tempered and it will be corrupted.
+ // In practice this mean that all binaries signed with
+ // certificates in C database will be corrupted.
+ if ( ! certStoreOk || err != KErrNone )
+ {
+ TRAP_IGNORE( CorruptFileL( fs, *certStoreFilePath ) );
+ }
+
+ BTIC_TRACE_PRINT("\nStore validation complete");
+ }
+ }
+/*
+#ifdef __BTIC_BINARIES_CHECK_ENABLED
+
+ // If found cert store is valid unite arrays.
+ if ( certStoreOk )
+ {
+ UniteCertArraysL( x509CertArray, tempCertArray );
+ // Reset tempCertArray because x509CertArray owns entrys now.
+ tempCertArray.Reset();
+
+ UniteCapaArraysL( certCapaArray, tempCapaArray );
+ // Reset tempCapaArray because certCapaArray owns entrys now.
+ tempCapaArray.Reset();
+ }
+
+ // Check that certificates are found before checking binaries.
+ if ( x509CertArray.Count() )
+ {
+ // Check that cert array and capa array has same amount of entrys.
+ // If amount is diffrent do not check binaries. Something is wrong.
+ if ( x509CertArray.Count() == certCapaArray.Count() )
+ {
+ // Check that binaries found in C: are istalled from a valid SIS
+ // pagaces and binary's hash is valid.
+ CheckBinariesL( fs, x509CertArray, certCapaArray );
+
+ BTIC_TRACE_PRINT("\nBinaries check complete\n");
+ }
+ }
+
+#endif //__BTIC_BINARIES_CHECK_ENABLED
+*/
+
+ BTIC_TRACE_PRINT("\nProgram complete\n");
+ // DELETE ALL ARRAYS AND ARRAY CONTENT
+ x509CertArray.ResetAndDestroy();
+ tempCertArray.ResetAndDestroy();
+ certCapaArray.ResetAndDestroy();
+ tempCapaArray.ResetAndDestroy();
+
+ CleanupStack::PopAndDestroy( pushToStack ); //fs, buffers
+
+ BTIC_TRACE_PRINT("UHEAP MARK END");
+ __UHEAP_MARKEND;
+ BTIC_TRACE_PRINT_ALLOC_CELLS("End Cell count = %d");
+
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] PROGRAM END");
+ return KErrNone;
+ }
+
+
+// -----------------------------------------------------------------------------
+// ReadCertificatesL
+//
+// This function reads certificates from certificate storage and adds them in to
+// given cert array if certificate can grant TCB or/and DRM. Also certificates
+// capability set is added to given capability array.
+// Given path must be valid one, othervice function returns error code.
+//
+// Returns: KErrNone if successful
+// Othervice some system-wide error code.
+// -----------------------------------------------------------------------------
+//
+LOCAL_C TInt ReadCertificatesL(
+ RFs& aFs, // File server handle
+ const TDesC& aPath, // Path to storage file.
+ RPointerArray<CX509Certificate>& aX509CertArray, // Cert array.
+ RPointerArray<TCapabilitySet>& aCapabilityArray )// Capability array.
+ {
+ TInt err = KErrNone;
+ RFile file;
+
+ err = file.Open( aFs, aPath, EFileRead );
+
+ if ( err == KErrNone )
+ {
+ CleanupClosePushL( file );
+
+ CPermanentFileStore* certStore = NULL;
+
+ // Trap FromL if file is not in correct form it may leave.
+ TRAP( err, certStore = CPermanentFileStore::FromL( file ) );
+
+ if ( certStore && err == KErrNone )
+ {
+ CleanupStack::Pop( &file ); // Now owned by store.
+ CleanupStack::PushL( certStore );
+
+ // Read id of cert list stream
+ TStreamId streamId;
+ RStoreReadStream stream;
+ stream.OpenLC( *certStore, certStore->Root() );
+ stream >> streamId;
+ CleanupStack::PopAndDestroy( &stream );
+
+ // Read the certificate list
+ RStoreReadStream certEntryStream;
+ certEntryStream.OpenLC( *certStore, streamId );
+
+ // Count entrys from stream.
+ TInt count = certEntryStream.ReadInt32L();
+ BTIC_TRACE_PRINT_NUM("CertEntryStream count = %d", count );
+
+ HBufC8* certDataBuf = NULL;
+
+ for ( TInt index = 0 ; index < count ; index++ )
+ {
+ // Read data from stream.
+ CRootCertificateEntry* entry =
+ CRootCertificateEntry::NewLC( certEntryStream );
+
+ // Get certificate's capabilties from entry.
+ TCapabilitySet* capaSet =
+ new( ELeave ) TCapabilitySet( entry->Capabilities() );
+ CleanupStack::PushL( capaSet );
+
+ // Check that certificate can grant TCB or DRM capabiltiy.
+ if ( capaSet->HasCapability( GetCapability( KBTIC_TCB ) ) ||
+ capaSet->HasCapability( GetCapability( KBTIC_DRM ) ) )
+ {
+ // Append certificates capability set to array.
+ User::LeaveIfError( aCapabilityArray.Append( capaSet ) );
+
+ CleanupStack::Pop( capaSet );
+
+ // Open certificate data stream. This is actual x509 certificate.
+ RStoreReadStream stream;
+ stream.OpenLC( *certStore, entry->DataStreamId() );
+
+ // Get x509 size.
+ TInt size = entry->Size();
+
+ // Since we do not have so meny certs in device let's make alloc
+ // inside of the loop.
+ certDataBuf = HBufC8::NewMaxLC( size );
+
+ TPtr8 dataBufPtr = certDataBuf->Des();
+
+ // Read x509 binary data to buffer.
+ stream.ReadL( dataBufPtr, size );
+
+ // Create x509 certificate object from binary data.
+ CX509Certificate* x509Cert =
+ CX509Certificate::NewLC( *certDataBuf );
+
+ // Append x509 certificate object to pointer array.
+ User::LeaveIfError( aX509CertArray.Append( x509Cert ) );
+
+ CleanupStack::Pop( x509Cert );
+ x509Cert = NULL;
+ CleanupStack::PopAndDestroy( certDataBuf );
+ certDataBuf = NULL;
+ CleanupStack::PopAndDestroy( &stream );
+ }
+ else
+ {
+ // Delete capaSet if certificate has not TCB or DRM.
+ CleanupStack::PopAndDestroy( capaSet );
+ capaSet = NULL;
+ }
+
+ CleanupStack::PopAndDestroy( entry );
+ entry = NULL;
+ }
+
+ CleanupStack::PopAndDestroy( 2 );//certStore, certEntryStream
+ }
+ else
+ {
+ // Clean up file is FromL leaves.
+ CleanupStack::PopAndDestroy( &file );
+ BTIC_TRACE_PRINT("ERROR CPermanentFileStore - Can not read certs.");
+ }
+ }
+
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] ReadCertificatesL <---");
+
+ return err;
+ }
+
+
+// -----------------------------------------------------------------------------
+// ValidateCertStoreL()
+//
+// This function checks that updated SWI certstore in C drive has been installed
+// from valid SIS pacage.
+// SIS pacage must have valid certificate and exe with a TCB capabilities.
+//
+// NOTE this function assumes that Certprovisioner tool has imei.txt file.
+//
+// Returns: ETure if successful
+// EFalse othervice
+// -----------------------------------------------------------------------------
+//
+LOCAL_C TBool ValidateCertStoreL(
+ RFs& aFs, // File server handle
+ RPointerArray<CX509Certificate>& aX509CertArray,// Certificate array
+ RPointerArray<TCapabilitySet>& aCapaArray, // Capability array
+ const TDesC& aCertStoreFileName,
+ const TDesC& aCertStoreFilePath )
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] ValidateCertStoreL v2->");
+ __UHEAP_MARK;
+
+ TBool storeOK = EFalse;
+
+ RPointerArray<HBufC> updaterExePaths;
+
+ Swi::RSisRegistrySession sisRegSession;
+
+ // Leave if we can not connect to sis register. Othervice we have a risk
+ // that valid files will be renamed if updated certstore is left out.
+ User::LeaveIfError( sisRegSession.Connect() );
+
+ CleanupClosePushL( sisRegSession );
+
+ RPointerArray<CSisRegistryPackage> sisPackages;
+
+ // Find installed packages.
+ sisRegSession.InstalledPackagesL( sisPackages );
+
+ Swi::RSisRegistryEntry entry;
+
+ TInt packageUID;
+
+ BTIC_TRACE_PRINT("Find matching UID");
+
+ // If CertProvisioner tool has install updatedswicertstore file.
+ if ( aCertStoreFileName.Compare( KBTICCertStoreCName ) == KErrNone )
+ {
+ BTIC_TRACE_PRINT("UID -> KBTICCertProvUID");
+ packageUID = KBTICCertProvUID;
+ }
+ else
+ {
+ BTIC_TRACE_PRINT("UID -> KBTICSymbianSWIUpdaterUID");
+ packageUID = KBTICSymbianSWIUpdaterUID;
+ }
+
+ TBool entryOpen = EFalse;
+
+ // Search correct sis pagace and open entry to it.
+ for( TInt index = 0; index < sisPackages.Count(); index++)
+ {
+ BTIC_TRACE_PRINT_NUM("Search entry from sis reg. index = %d", index );
+
+ if ( sisPackages[index]->Uid() == TUid::Uid( packageUID ) )
+ {
+ BTIC_TRACE_PRINT("Open entry");
+
+ User::LeaveIfError( entry.Open(
+ sisRegSession, TUid::Uid( packageUID ) ) );
+
+ CleanupClosePushL( entry );
+
+ entryOpen = ETrue;
+ break;
+ }
+ }
+
+ // Validate cert storage.
+ if ( entryOpen )
+ {
+ TBool controllerOk = EFalse;
+
+#ifdef __BTIC_VERIFY_CONTROLLER
+ // Check that sis controller is valid.
+ controllerOk = entry.VerifyControllerSignatureL( aX509CertArray );
+
+ BTIC_TRACE_PRINT("Controller verify ENABLED");
+ BTIC_TRACE_PRINT_NUM("Controller verify result (1) = %d", controllerOk );
+#else
+ // If controller verify is disabled set boolen to true.
+ controllerOk = ETrue;
+ BTIC_TRACE_PRINT("Controller verify DISABLED" );
+#endif
+
+ if ( controllerOk )
+ {
+ if ( packageUID == KBTICCertProvUID )
+ {
+ storeOK = ValidateProvisonerCertStoreL(
+ aFs,
+ aX509CertArray,
+ aCapaArray,
+ aCertStoreFileName,
+ aCertStoreFilePath,
+ entry );
+ }
+ else
+ {
+ storeOK = ValidateSymbianCertStoreL(
+ aFs,
+ aX509CertArray,
+ aCapaArray,
+ entry,
+ updaterExePaths );
+ }
+ }
+ }
+
+ // Cleanup array.
+ sisPackages.ResetAndDestroy();
+
+ if ( entryOpen )
+ {
+ CleanupStack::PopAndDestroy(); //RSisRegistryEntry
+ }
+
+ CleanupStack::PopAndDestroy(); //RSisRegistrySession
+
+ // Ok Symbian store is valid, let's run Symbian updater exe.
+ // NOTE SisRegistry server etc. has file handle open, so we should
+ // close SisRegistryEntry before running updater.
+ if ( storeOK && packageUID == KBTICSymbianSWIUpdaterUID )
+ {
+ storeOK = RunUpdaterL( aFs, updaterExePaths );
+ }
+
+ updaterExePaths.ResetAndDestroy();
+
+ BTIC_TRACE_PRINT("UHEAP MARK END");
+ __UHEAP_MARKEND;
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] ValidateCertStoreL v2 <-");
+
+ return storeOK;
+ }
+
+
+// -----------------------------------------------------------------------------
+// ValidateProvisonerCertStoreL()
+//
+//
+//
+//
+// Returns: ETure if successful
+// EFalse othervice
+// -----------------------------------------------------------------------------
+//
+LOCAL_C TBool ValidateProvisonerCertStoreL(
+ RFs& aFs, // File server handle
+ RPointerArray<CX509Certificate>& aX509CertArray,// Certificate array
+ RPointerArray<TCapabilitySet>& aCapaArray, // Capability array
+ const TDesC& aCertStoreFileName,
+ const TDesC& aCertStoreFilePath,
+ RSisRegistryEntry& aEntry )
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] ValidateProvisonerStoreL --->");
+ __UHEAP_MARK;
+
+ TBool retOK = EFalse;
+ // installedFiles array owns entry's files.
+ RPointerArray<HBufC> installedFilesArray;
+ RPointerArray<HBufC> foundFilesArray;
+ RPointerArray<HBufC> fileArray; // Files that need to be cheked.
+ RPointerArray<HBufC8> hashArray; // Hash for each fileArray's file.
+ RArray<TUint64> capaArray;
+ RPointerArray<HBufC> stringArray;
+ HBufC* string = NULL;
+
+ TUint64* capaVector = new( ELeave ) TUint64[KBTICCapaCount];
+ CleanupArrayDeletePushL( capaVector );
+ capaVector[0] = KBTIC_TCB;
+
+ // Get all installed files from this sis register entry
+ // to installedFilesArray.
+ aEntry.FilesL( installedFilesArray );
+
+ // Search all exes from array.
+ if ( installedFilesArray.Count() > 0 )
+ {
+ string = KBTICExtensionExe().AllocLC();
+ User::LeaveIfError( stringArray.Append( string ) );
+ CleanupStack::Pop();
+
+ retOK = SearchFilesFromArrayL(
+ installedFilesArray,
+ KBTICDriveCWildcard,
+ stringArray,
+ foundFilesArray );
+ }
+
+ // Find a exe that has TCB capapility and calculate hash over the file.
+ if ( retOK )
+ {
+ retOK = CheckCapabilityWordAndCalcHashL(
+ aFs,
+ ETrue,
+ capaVector,
+ foundFilesArray,
+ fileArray,
+ hashArray,
+ capaArray );
+ }
+
+ // Validate certificate from this entry and check that
+ // certificate can grant the capability which is neede for the exe (TCB).
+ if ( retOK )
+ {
+ retOK = SearchValidCertificateL(
+ aEntry,
+ aX509CertArray,
+ aCapaArray,
+ KBTIC_TCB );
+ }
+
+ // Calculate hash over each exe file found in this entry.
+ // Let's be confident that server is not tempered.
+ if ( retOK )
+ {
+ retOK = EFalse;
+
+ // Ok so now we should have one TCB file in fileArray and 2 other
+ // files in foundFilesArray. We do not need to calculate hash over
+ // TCB files again, so let's remove TCB files from array.
+ TInt countExe = foundFilesArray.Count();
+ TInt countTCB = fileArray.Count();
+ TBool removeFile = EFalse;
+
+ for ( TInt i = countExe-1; i >= 0 ; i-- )
+ {
+ removeFile = EFalse;
+
+ for ( TInt k = countTCB-1; k >= 0; k-- )
+ {
+ // If fileArray has this path remove it.
+ if ( (fileArray[k]->Compare( *foundFilesArray[i] ))
+ == KErrNone )
+ {
+ removeFile = ETrue;
+ }
+ }
+
+ if ( removeFile )
+ {
+ foundFilesArray.Remove( i );
+ }
+ }
+
+ // Compress array so we don not have null pointers on it.
+ foundFilesArray.Compress();
+
+ // If all files are removed something is wrong. Return False.
+ if ( foundFilesArray.Count() )
+ {
+ // Ok let's calculate hashes for the other exes.
+ retOK = CheckCapabilityWordAndCalcHashL(
+ aFs,
+ EFalse,
+ 0,
+ foundFilesArray,
+ fileArray,
+ hashArray,
+ capaArray );
+ }
+ }
+
+ // Remove previous strings from array.
+ stringArray.ResetAndDestroy();
+ // Remove pointers from array. Let's not calc. hash again.
+ foundFilesArray.Reset();
+
+ // Search imei.txt file from array and check that device's serial number
+ // is found in the file. NOTE file name must be imei.txt.
+ if ( retOK )
+ {
+ retOK = EFalse;
+
+ string = KBTICSerialNumberFile().AllocLC();
+ User::LeaveIfError( stringArray.Append( string ) );
+ CleanupStack::Pop();
+
+ TBool foundFile = SearchFilesFromArrayL(
+ installedFilesArray,
+ KBTICDriveCWildcard,
+ stringArray,
+ foundFilesArray );
+
+ if ( foundFile && foundFilesArray.Count() )
+ {
+ retOK = CheckSerialNumberL( aFs, *foundFilesArray[0] );
+ }
+ }
+
+ // Calculate hash over each file (*.dat and imei.txt) and check that
+ // sisregistery has same hash (*.exe,*.dat,imei.txt).
+ if ( retOK )
+ {
+ retOK = EFalse;
+
+ // Note that certstore path from sis reg. points to private
+ // directory not file's current logation. So we have to switch
+ // file paths to get correct hash.
+
+ // Remove previous strings from array.
+ stringArray.ResetAndDestroy();
+
+ string = HBufC::NewLC(
+ aCertStoreFileName.Length() +
+ sizeof( KBTICStarWildcard ) );
+ TPtr stringPtr = string->Des();
+
+ // Append certstorage name and wildcard (*\\) to string for search.
+ // String should be = "*\\filename.dat" Let's add "\\" to string
+ // so search do not accept eg. Öfilename.dat etc.
+ stringPtr.Copy( KBTICStarWildcard );
+ stringPtr.Append( aCertStoreFileName );
+
+ User::LeaveIfError( stringArray.Append( string ) );
+ CleanupStack::Pop(); //String
+
+ // Search correct certstorage file from installedFilesArray.(sis reg.)
+ TBool foundFile = SearchFilesFromArrayL(
+ installedFilesArray,
+ KBTICDriveCWildcard,
+ stringArray,
+ foundFilesArray );
+
+ if ( foundFile )
+ {
+ BTIC_TRACE_PRINT("Correct CertStore file found");
+
+ // Get original certstorage path from array.
+ HBufC* sisRegPath = foundFilesArray[foundFilesArray.Count() - 1];
+
+ // Remove original path from array.
+ foundFilesArray.Remove( foundFilesArray.Count() - 1 );
+ CleanupStack::PushL( sisRegPath ); //sisRegPath
+
+ // Get current certstorage path.
+ HBufC* currentPath = aCertStoreFilePath.AllocLC();
+
+ // Set current path to array. So now we get correct hash.
+ foundFilesArray.Append( currentPath );
+ CleanupStack::Pop(); //currentPath
+
+ BTIC_TRACE_PRINT("Calculate HASH for files");
+
+ // Calculate hash over files in foundFilesArray and add result to
+ // filesArray and hashArray
+ CheckCapabilityWordAndCalcHashL(
+ aFs,
+ EFalse,
+ 0,
+ foundFilesArray,
+ fileArray,
+ hashArray,
+ capaArray );
+
+ // Ok now we have correct hash but certstore path is not
+ // correct for sis register. So we have to copy original
+ // certstorage file path from sis reg. to filesArray.
+
+ // Remove currentPath entry from array.
+ fileArray.Remove( fileArray.Count() - 1 );
+
+ // Delete currentPath buffer. We need to delete buffer because
+ // we call only reset for foundFilesArray. Reset do not delete
+ // buffer.
+ delete currentPath;
+
+ // Append orginal path from sis reg. for hash checking.
+ fileArray.Append( sisRegPath );
+ CleanupStack::Pop(); //sisRegPath
+
+ // Check that sis registery entry has same hash as we have.
+ retOK = VerifyHashL( aEntry, fileArray, hashArray );
+
+ }
+ }
+
+ CleanupStack::PopAndDestroy(); //capaVector
+
+ // Reset only. InstalledFiles array owns buffers.
+ foundFilesArray.Reset();
+ fileArray.Reset();
+ hashArray.ResetAndDestroy();
+ installedFilesArray.ResetAndDestroy();
+ stringArray.ResetAndDestroy();
+ capaArray.Close();
+
+ BTIC_TRACE_PRINT("UHEAP MARK END");
+ __UHEAP_MARKEND;
+
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] ValidateProvisonerStoreL <---");
+
+ return retOK;
+ }
+
+
+// -----------------------------------------------------------------------------
+// ValidateSymbianCertStoreL()
+//
+//
+//
+//
+// Returns: ETure if successful
+// EFalse othervice
+// -----------------------------------------------------------------------------
+//
+LOCAL_C TBool ValidateSymbianCertStoreL(
+ RFs& aFs, // File server handle
+ RPointerArray<CX509Certificate>& aX509CertArray,// Certificate array
+ RPointerArray<TCapabilitySet>& aCapaArray, // Capability array
+ RSisRegistryEntry& aEntry,
+ RPointerArray<HBufC>& aUpdaterExePaths )
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] ValidateSymbianStoreL v2 --->");
+
+ TBool retOK = EFalse;
+ // installedFiles array owns entry's files.
+ RPointerArray<HBufC> installedFilesArray;
+ RPointerArray<HBufC> foundFilesArray;
+ RPointerArray<HBufC> fileArray; // Files that need to be cheked.
+ RPointerArray<HBufC8> hashArray; // Hash for each fileArray's file.
+ RArray<TUint64> capaArray;
+ RPointerArray<HBufC> stringArray;
+ HBufC* string = NULL;
+
+ TUint64* capaVector = new( ELeave ) TUint64[KBTICCapaCount];
+ CleanupArrayDeletePushL( capaVector );
+ capaVector[0] = KBTIC_TCB;
+
+ // Get all installed files from this sis register entry
+ // to installedFilesArray.
+ aEntry.FilesL( installedFilesArray );
+
+ // Search all exes from array.
+ if ( installedFilesArray.Count() > 0 )
+ {
+ string = KBTICExtensionExe().AllocLC();
+ User::LeaveIfError( stringArray.Append( string ) );
+ CleanupStack::Pop();
+
+ retOK = SearchFilesFromArrayL(
+ installedFilesArray,
+ KBTICDriveCWildcard,
+ stringArray,
+ foundFilesArray );
+ }
+
+ // Find a exe that has TCB capapility and calculate hash over the file.
+ if ( retOK )
+ {
+ retOK = CheckCapabilityWordAndCalcHashL(
+ aFs,
+ ETrue,
+ capaVector,
+ foundFilesArray,
+ fileArray,
+ hashArray,
+ capaArray );
+ }
+
+ // Validate certificate from this entry and check that
+ // certificate can grant the capability which is neede for the exe (TCB).
+ if ( retOK )
+ {
+ retOK = SearchValidCertificateL(
+ aEntry,
+ aX509CertArray,
+ aCapaArray,
+ KBTIC_TCB );
+ }
+
+ // Check that sis registery has same hash as we have.
+ if ( retOK )
+ {
+ retOK = VerifyHashL( aEntry, fileArray, hashArray );
+ }
+
+ // Return exe's path to caller. NOTE Updater exe can not be executed
+ // before SisRegistryEntry is closed.
+ if ( retOK )
+ {
+ // We will assume that updater has only one exe with TCB.
+ HBufC* path = fileArray[0]->AllocLC();
+ // Append path to pointer array.
+ User::LeaveIfError( aUpdaterExePaths.Append( path ) );
+ CleanupStack::Pop(); //path
+ }
+
+ CleanupStack::PopAndDestroy(); //capaVector
+
+ // Reset only. InstalledFiles array owns buffers.
+ foundFilesArray.Reset();
+ fileArray.Reset();
+ hashArray.ResetAndDestroy();
+ installedFilesArray.ResetAndDestroy();
+ stringArray.ResetAndDestroy();
+ capaArray.Close();
+
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] ValidateSymbianStoreL v2 <---");
+
+ return retOK;
+ }
+
+
+// -----------------------------------------------------------------------------
+// RunUpdaterL()
+//
+// Returns: ETure if successful
+// EFalse othervice
+// -----------------------------------------------------------------------------
+//
+LOCAL_C TBool RunUpdaterL( RFs& aFs, RPointerArray<HBufC>& aUpdaterExePaths )
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] RunUpdaterL ->");
+ // SIS register do not have hash values for storage file if it is provided
+ // by Symbian SWI updater exe. We have to remove current storage file
+ // and run exe again to get a verified swicertstorage in folder.
+
+ TBool retOK = EFalse;
+
+ BTIC_TRACE_PRINT("Delete old store file(s)");
+ // Delete all files from dat folder. If delete fails storage file is
+ // corrupted.
+ // NOTE that SisRegistry Server has some closing time so we must try this
+ // in loop.
+ for ( TInt loop = 0; loop < KBTICTryToOpen; loop++ )
+ {
+ if ( DeleteAllFilesL( aFs, KBTICCertStoreCPath ) )
+ {
+ // We will assume that updater has only on exe with TCB.
+ HBufC* updaterExePath = aUpdaterExePaths[0];
+
+ RProcess process;
+
+ BTIC_TRACE_PRINT("Run updater exe to get new store file");
+
+ for ( TInt i = 0; i < KBTICTryToCreate; i++ )
+ {
+ BTIC_TRACE_PRINT("Try to create Updater process");
+
+ if ( process.Create( *updaterExePath, KNullDesC ) == KErrNone )
+ {
+ // Run updater exe again.
+ process.Resume();
+ // Get rid of our handle.
+ process.Close();
+
+ retOK = ETrue;
+
+ BTIC_TRACE_PRINT("Updater process started OK");
+ break;
+ }
+ }
+
+ // Break the loop if delete is succesful.
+ break;
+ }
+ else
+ {
+ BTIC_TRACE_PRINT_NUM("Wait 0.5 sec. Attempt nr.%d", loop );
+ User::After( 500000 );
+ }
+ }
+
+ return retOK;
+ }
+
+// -----------------------------------------------------------------------------
+// DeleteAllFiles()
+//
+// Delete all files from given folder.
+//
+// Returns: ETure if successful
+// EFalse othervice
+// -----------------------------------------------------------------------------
+//
+LOCAL_C TBool DeleteAllFilesL( RFs& aFs, const TDesC& aFolderPath )
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] DeleteAllFilesL ");
+
+ TBool folderEmpty = EFalse;
+ CDir* entryList = NULL;
+ TBuf<KMaxFileName> path;
+
+ // Get all files from folder.
+ if ( KErrNone ==
+ aFs.GetDir (
+ aFolderPath,
+ KEntryAttNormal,
+ ESortByName|EDirsFirst,
+ entryList ) )
+ {
+ if ( entryList )
+ {
+ CleanupStack::PushL( entryList );
+
+ TInt delCount = KErrNone;
+ TInt count = entryList->Count();
+
+ for ( TInt index = 0; index < count; index++ )
+ {
+ // Get file name.
+ const TEntry& entry = (*entryList)[index];
+
+ // Set path to file.
+ path.Copy( aFolderPath );
+ path.Append( entry.iName );
+
+ // Remove Read Only attribute.
+ TInt err = aFs.SetAtt( path, 0, KEntryAttReadOnly );
+ BTIC_TRACE_PRINT_NUM("Remove Read Only attrib. = %d", err );
+
+ if ( KErrNone == aFs.Delete( path ) )
+ {
+ delCount++;
+ BTIC_TRACE_PRINT_NUM("Delete file with index = %d", index);
+ }
+ }
+
+ // If all files are removed.
+ if ( delCount == count )
+ {
+ folderEmpty = ETrue;
+ BTIC_TRACE_PRINT("All files removed");
+ }
+
+ CleanupStack::PopAndDestroy( 1, entryList );
+ }
+ }
+
+ return folderEmpty;
+ }
+
+
+// -----------------------------------------------------------------------------
+// SearchFilesFromArrayL
+//
+// This function search file names containing given string from aSourceArray and
+// add found file (path) to an aFilesArray. Search is limited to specified drive
+// and path.
+// Note this function only adds source arrays pointers to files array. It dos not
+// create new heap descriptor.
+//
+//
+// Returns: ETure if successful
+// EFalse othervice
+// -----------------------------------------------------------------------------
+//
+LOCAL_C TBool SearchFilesFromArrayL(
+ RPointerArray<HBufC>& aSourceArray, // Array for searching.
+ const TDesC& aDriveAndPath, // Accepted drive or/and path.
+ RPointerArray<HBufC>& aStringArray, // String to be searched from path.
+ RPointerArray<HBufC>& aFilesArray ) // Result array.
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] SearchFilesFromArrayL --->");
+
+ TBool retVal = EFalse;
+
+ TInt count = aSourceArray.Count();
+ TInt stringCount = aStringArray.Count();
+
+ // This loop gos through all paths from aSourceArray.
+ for ( TInt index = 0; index < count; index++ )
+ {
+ HBufC* filePath = aSourceArray[index];
+
+ // Convert descriptor to lower case so we don't get problems with
+ // Match or Compare functions.
+ TPtr filePathPtr = filePath->Des();
+ filePathPtr.LowerCase();
+
+ // Check that file is in correct directory.
+ TInt offsetA = filePath->Match( aDriveAndPath );
+
+ if ( offsetA >= 0 )
+ {
+ // This loop gos through all strings what we are looking for.
+ for ( TInt indexB = 0; indexB < stringCount; indexB++ )
+ {
+ // Search string from file path.
+ TInt offset = filePath->Match( *aStringArray[indexB] );
+
+ if ( offset >= 0 )
+ {
+ User::LeaveIfError( aFilesArray.Append( filePath ) );
+
+ retVal = ETrue;
+ }
+ }
+ }
+ }
+
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] SearchFilesFromArrayL <---");
+
+ return retVal;
+ }
+
+
+// -----------------------------------------------------------------------------
+// SearchValidCertificateL
+//
+// This function validates entry's certificate against to certificate found in
+// given array. It check also that certificate has rigth to grant given
+// capability.
+//
+// Note This function only validates first chain.
+//
+// Returns: ETure if successful
+// EFalse othervice
+// -----------------------------------------------------------------------------
+//
+LOCAL_C TBool SearchValidCertificateL(
+ RSisRegistryEntry& aEntry, // SIS Registery entry
+ RPointerArray<CX509Certificate>& aX509CertArray,// Array for certificates
+ RPointerArray<TCapabilitySet>& aCertCapaArray, // Array for certs capability
+ TUint64 aCapability ) // Needed capabiltiy
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] SearchValidCertificate v2.1 --->");
+
+ RPointerArray<HBufC8> binaryCertChainArray;
+ // Get certificates in binary format.
+ aEntry.CertificateChainsL( binaryCertChainArray );
+
+ TInt chainCount = binaryCertChainArray.Count();
+ BTIC_TRACE_PRINT_NUM("Entry chain count (1) = %d", chainCount );
+
+ TBool retVal = EFalse;
+
+ RPointerArray<CX509Certificate> chainCertArray;
+
+ // Check all entry's chains
+ for ( TInt chain = 0; chain < chainCount; chain++ )
+ {
+ BTIC_TRACE_PRINT_NUM("Check chain nr = %d", chain);
+
+ TPtr8 chainData = binaryCertChainArray[chain]->Des();
+
+ TInt pos = 0;
+ TInt end = chainData.Length();
+
+ // Get all certificates from chain.
+ while ( pos < end )
+ {
+ CX509Certificate* decoded =
+ CX509Certificate::NewLC( chainData, pos );
+
+ // Add x509 certificate to pointter array.
+ User::LeaveIfError( chainCertArray.Append( decoded ) );
+
+ CleanupStack::Pop( decoded );
+ }
+
+ TInt chainCertCount = chainCertArray.Count();
+ BTIC_TRACE_PRINT_NUM("Chain's certificate count = %d", chainCertCount);
+
+ // Search certificate issued to root and verify signature against the root.
+ if ( chainCertCount > 0 )
+ {
+ BTIC_TRACE_PRINT("Validate last cert against root");
+ // Last cert in chain should be issued to root.
+ const CX509Certificate* x509LastChainCert = chainCertArray[chainCertCount-1];
+
+ TInt rootCertCount = aX509CertArray.Count();
+ BTIC_TRACE_PRINT_NUM("Root cert array count = %d", rootCertCount);
+ TBool rootFound = EFalse;
+ TInt rootIndex = 0;
+
+ // Find matching root certificate and validate certificates.
+ for ( rootIndex = 0; rootIndex < rootCertCount; rootIndex++ )
+ {
+ BTIC_TRACE_PRINT_NUM("Root cert index = %d", rootIndex );
+
+ const CX509Certificate* x509RootCert = aX509CertArray[rootIndex];
+
+ // Compare entry cert's issuer to root cert's subject.
+ if ( x509LastChainCert->IssuerName().ExactMatchL(
+ x509RootCert->SubjectName() ) )
+ {
+ BTIC_TRACE_PRINT("Root found for this chain");
+ BTIC_TRACE_PRINT("Verify signature");
+
+ // Verify signature
+ if ( x509LastChainCert->VerifySignatureL(
+ x509RootCert->PublicKey().KeyData() ) )
+ {
+ BTIC_TRACE_PRINT("Signature OK");
+ rootFound = ETrue;
+ break; // Break loop.
+ }
+ }
+ }
+
+ // If root is found we have correct chain.
+ if ( rootFound )
+ {
+ // If Chain has more then one certificate, verify chain.
+ if ( chainCertCount > 1 )
+ {
+ BTIC_TRACE_PRINT("Verify certificate chain");
+ TBool chainOK = ETrue;
+ TInt certindex;
+
+ for ( certindex = 0; certindex < chainCertCount-1; certindex++ )
+ {
+ BTIC_TRACE_PRINT_NUM("Cert index = %d", certindex);
+ BTIC_TRACE_PRINT_NUM("Signature Cert index = %d", certindex+1);
+
+ const CX509Certificate* cert = chainCertArray[certindex];
+ const CX509Certificate* signatureCert =
+ chainCertArray[certindex+1];
+
+ // Compare issuer name to subject name.
+ if ( cert->IssuerName().ExactMatchL(
+ signatureCert->SubjectName() ) )
+ {
+ BTIC_TRACE_PRINT("Issuer match found.");
+ BTIC_TRACE_PRINT("Verify signature against next cert");
+ // Validate certificate
+ if ( ! cert->VerifySignatureL(
+ signatureCert->PublicKey().KeyData() ) )
+ {
+ // Chain is broken. Validation failed.
+ BTIC_TRACE_PRINT("ERROR Chain broken, validation failed");
+ chainOK = EFalse;
+ break;
+ }
+ }
+ else
+ {
+ // Issuer do not match. Validation failed.
+ BTIC_TRACE_PRINT("ERROR Chain broken, issuer error");
+ chainOK = EFalse;
+ break;
+ }
+ }
+
+ if ( chainOK )
+ {
+ BTIC_TRACE_PRINT("Entry's chain valid");
+ retVal = ETrue;
+ }
+
+ }
+ // Chain has only one certificate, root.
+ else
+ {
+ BTIC_TRACE_PRINT("Entry's chain has only one certificate");
+ retVal = ETrue;
+ }
+
+ }
+ else
+ {
+ BTIC_TRACE_PRINT("No root found for this chain");
+ retVal = EFalse;
+ }
+
+ // Check that matching root certificate has same capablitiy
+ // as aCapability parameter.
+ if ( aCapability && retVal )
+ {
+ TCapabilitySet* rootCapaSet = aCertCapaArray[rootIndex];
+
+ retVal = rootCapaSet->HasCapability( GetCapability( aCapability ) );
+ }
+
+ // Reset array for next chain.
+ chainCertArray.ResetAndDestroy();
+ }
+
+ // If this is a valid certificate chain, break to loop.
+ if ( retVal )
+ {
+ break;
+ }
+
+ } // FOR LOOP
+
+ binaryCertChainArray.ResetAndDestroy();
+
+
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] SearchValidCertificate v2.1 <---");
+
+ return retVal;
+ }
+
+
+// -----------------------------------------------------------------------------
+// GetCapability
+//
+// This function converts 64 bit capability integer to Symbian capability
+// enumeration.
+//
+// Returns: ECapabilityTCB if capabilty is TCB
+// ECapabilityDRM if capabilty is DRM
+// ECapability_Denied if capability not found
+// -----------------------------------------------------------------------------
+//
+LOCAL_C TCapability GetCapability( TUint64 aCapability )
+ {
+ if ( aCapability == KBTIC_TCB )
+ {
+ return ECapabilityTCB;
+ }
+
+ else if ( aCapability == KBTIC_DRM )
+ {
+ return ECapabilityDRM;
+ }
+
+ else
+ {
+ BTIC_TRACE_PRINT("! ! ERROR GetCapability -> ECapability_Denied ! !");
+ return ECapability_Denied;
+ }
+ }
+
+
+// -----------------------------------------------------------------------------
+// VerifyHashL
+//
+// This function compare file's hash to hash found in SIS Register.
+//
+// Returns: ETure if all compare operations was successful.
+// EFalse other vice
+// -----------------------------------------------------------------------------
+//
+LOCAL_C TBool VerifyHashL(
+ RSisRegistryEntry& aEntry,
+ RPointerArray<HBufC>& aPathArray,
+ RPointerArray<HBufC8>& aHashArray )
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] VerifyHashL --->");
+ __UHEAP_MARK;
+
+ TBool retVal = EFalse;
+ TInt hashOk = 0;
+ TInt count = aPathArray.Count();
+
+ for ( TInt index = 0; index < count; index++ )
+ {
+ // Take first file
+ HBufC* path = aPathArray[index];
+ HBufC8* hash = aHashArray[index];
+
+ if ( CompareToRegisteryHashL(
+ aEntry,
+ *path,
+ *hash ) )
+ {
+ hashOk++;
+ }
+ }
+
+ // If all hashes are ok return ETrue.
+ if ( hashOk == count )
+ {
+ BTIC_TRACE_PRINT("\nAll hashes are ok\n");
+ retVal = ETrue;
+ }
+
+ __UHEAP_MARKEND;
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] VerifyHashL <---");
+
+ return retVal;
+ }
+
+
+// -----------------------------------------------------------------------------
+// CompareToRegisteryHashL
+//
+// Note this function returns EFalse is HashL function leaves.
+//
+// Returns: ETure if hash is valid.
+// EFalse if hash was not valid.
+// -----------------------------------------------------------------------------
+//
+LOCAL_C TBool CompareToRegisteryHashL(
+ RSisRegistryEntry& aEntry,
+ TDesC& aEntryFile,
+ TDesC8& aHashBuffer )
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] CompareToRegisteryHashL --->");
+
+ TInt err = 0;
+ TBool hashOk = EFalse;
+ CHashContainer* hashContainer = NULL;
+
+ BTIC_TRACE_PRINT("Get hash for file: ");
+ BTIC_TRACE_PRINT_RAW( aEntryFile );
+
+ BTIC_TRACE_PRINT("RSisRegistryEntry.HashL()");
+ // Get hashConteiner for given file.
+ TRAP( err, hashContainer = aEntry.HashL( aEntryFile ) );
+
+ if ( err == KErrNone && hashContainer )
+ {
+ CleanupStack::PushL( hashContainer );
+
+ // Get hash data from hashConteiner.
+ TBufC8<KBTICHashSize> hashFromReg( hashContainer->Data() );
+
+ if ( hashFromReg.Compare( aHashBuffer ) == 0 )
+ {
+ hashOk = ETrue;
+
+ BTIC_TRACE_PRINT("Hash ok");
+ }
+
+ CleanupStack::PopAndDestroy(); //hashContainer
+ }
+ else
+ {
+ // If HashL function leaves, return false.
+ hashOk = EFalse;
+ BTIC_TRACE_PRINT_NUM("ERROR RSisRegistryEntry HashL = %d", err );
+ }
+
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] CompareToRegisteryHashL <---");
+
+ return hashOk;
+ }
+
+
+// -----------------------------------------------------------------------------
+// CheckSerialNumberL
+//
+// This function opens IMEI file and checks that device's serial number is found
+// in the file.
+//
+// Returns: ETure if serial number is found or some error with server.
+// EFalse if serial number not found
+// -----------------------------------------------------------------------------
+//
+LOCAL_C TBool CheckSerialNumberL( RFs& aFs, const TDesC& aFileName )
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] CheckSerialNumberL --->");
+ __UHEAP_MARK;
+
+ TBool matchFound = EFalse;
+
+ RInfoServerClient server;
+
+ // Connect to server.
+ TInt err = server.Connect();
+
+ BTIC_TRACE_PRINT_NUM("Server connect error = %d", err );
+
+ if ( err == KErrNone )
+ {
+ CleanupClosePushL( server );
+
+ TBuf<RMobilePhone::KPhoneSerialNumberSize> deviceSerialNumber;
+
+ // Get device serial number from server.
+ err = server.GetSerialNumber( deviceSerialNumber );
+
+ RFile file;
+
+ if ( err == KErrNone )
+ {
+ // Open text file.
+ User::LeaveIfError( file.Open( aFs, aFileName, EFileRead ) );
+ CleanupClosePushL( file );
+
+ TInt size;
+ file.Size( size );
+
+ HBufC8* content = HBufC8::NewLC( size );
+ TPtr8 ptr(content->Des());
+
+ // Read content
+ User::LeaveIfError( file.Read( ptr, size ) );
+
+ TLex8 input( ptr );
+ TBool lineEnd( EFalse );
+ TChar ch;
+
+ TBuf<RMobilePhone::KPhoneSerialNumberSize> serialNumber;
+
+ while ( ! input.Eos() )
+ {
+ ch = input.Get();
+
+ if ( ( ch != '\n' ) && ( ch != '\r' ) )
+ {
+ // Check that we have space for next number.
+ if ( serialNumber.Size() < serialNumber.MaxSize() )
+ {
+ serialNumber.Append( ch );
+ }
+ else
+ {
+ // Buffer size is 50 and it should be enoug, if not
+ // then something is wrong. Let's break to loop and
+ // return false.
+ break;
+ }
+ }
+ else
+ {
+ lineEnd = ETrue;
+ }
+
+ if ( ( lineEnd ) || ( input.Eos() ) )
+ {
+ if ( deviceSerialNumber == serialNumber )
+ {
+ BTIC_TRACE_PRINT("Correct serial number found");
+ matchFound = ETrue;
+ break;
+ }
+
+ serialNumber.FillZ(0);
+ serialNumber.SetLength(0);
+ lineEnd = EFalse;
+ }
+ }
+ CleanupStack::PopAndDestroy( 2 ); //file, content
+ }
+ CleanupStack::PopAndDestroy(); //client
+ }
+
+ __UHEAP_MARKEND;
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] CheckSerialNumberL <---");
+
+ return matchFound;
+ }
+
+
+// -----------------------------------------------------------------------------
+// CorruptFileL
+//
+// This function corrupts certificate file so that certs can not be read.
+// -----------------------------------------------------------------------------
+//
+LOCAL_C void CorruptFileL( RFs& aFs, const TDesC& aFileName )
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] ! ! CORRUPT STORE FILE ! !");
+
+ TFindFile find( aFs );
+
+ TUint8 byteVector[8] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF };
+
+ // Find given file in C drive.
+ if ( find.FindByDir( aFileName, KBTICDriveC ) == KErrNone )
+ {
+ RFile file;
+ TInt err;
+
+ for ( TInt loop = 0; loop < KBTICTryToOpen; loop++ )
+ {
+ err = file.Open( aFs, aFileName, EFileRead | EFileWrite );
+ BTIC_TRACE_PRINT_NUM("File Open error = %d", err );
+
+ // If file is open or it has ReadOnly attribute wait and try again.
+ if ( err )
+ {
+ BTIC_TRACE_PRINT_NUM("Wait 0.5 sec. Attempt nr.%d", loop );
+ User::After( 500000 );
+
+ TInt seterr = aFs.SetAtt( aFileName, 0, KEntryAttReadOnly );
+ BTIC_TRACE_PRINT_NUM("Remove Read Only attrib. = %d", seterr );
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ // Leave if error.
+ User::LeaveIfError( err );
+
+ CleanupClosePushL( file );
+
+ TInt size = 0;
+ file.Size( size );
+
+ HBufC8* fileData = HBufC8::NewLC( size );
+ TPtr8 dataPtr = fileData->Des();
+
+ HBufC8* newFileData = HBufC8::NewLC( size + sizeof( byteVector ) );
+ TPtr8 newDataPtr = newFileData->Des();
+
+ file.Read( dataPtr );
+ // Copy corrupted bytes to buffer.
+ newDataPtr.Copy( &byteVector[0], sizeof( byteVector ) );
+ // Copy original file data to buffer.
+ newDataPtr.Append( dataPtr );
+ // Write data at start of file.
+ file.Write( 0, *newFileData );
+
+ file.Flush();
+
+ CleanupStack::PopAndDestroy( 3 );
+
+ BTIC_TRACE_PRINT("File corrupted" );
+ }
+ }
+
+
+// -----------------------------------------------------------------------------
+// CheckCapabilityWordAndCalcHashL
+//
+// This function reads capability word from file heder and compares that to given
+// capability (aCapaVector). If there is more then one whanted capability the
+// first match is selected. If match is found file path is added to aFilesArray
+// and hash is calculated over the binary and found capa is added to array.
+// If aCheckCapa is set as EFalse, capability word is not checked and all files
+// from aSourceArray is added to aFilesArray.
+// Note aCapaArray conteins only matched capability. Not all file's capabilities.
+//
+// Returns: ETure if successful
+// EFalse othervice
+// -----------------------------------------------------------------------------
+//
+LOCAL_C TBool CheckCapabilityWordAndCalcHashL(
+ RFs& aFs, // File server handle
+ TBool aCheckCapa, // Enables capability check.
+ TUint64* aCapaVector, // Vector con. capa. that are checked.
+ RPointerArray<HBufC>& aSourceArray, // Files to be checked.
+ RPointerArray<HBufC>& aFilesArray, // Passed files
+ RPointerArray<HBufC8>& aHashArray, // File's hash
+ RArray<TUint64>& aCapaArray ) // File's capability.
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] CheckCapaWordAndCalcHashL v3.1 ->");
+
+ TFindFile find( aFs );
+
+ TInt pathCount = aSourceArray.Count();
+
+ TBool retVal = EFalse;
+ TInt index;
+ TInt err;
+
+ CSHA1* sha = CSHA1::NewL();
+ CleanupStack::PushL( sha );
+
+ RFile file;
+
+ for ( index = 0; index < pathCount; index++ )
+ {
+ BTIC_TRACE_PRINT_NUM("File array index = %d", index );
+
+ HBufC* path = aSourceArray[index];
+
+ BTIC_TRACE_PRINT("File path: ");
+ BTIC_TRACE_PRINT_RAW( *path );
+
+ err = file.Open( aFs, *path, EFileShareReadersOnly );
+
+ if ( err == KErrNone )
+ {
+ CleanupClosePushL( file );
+
+ TInt size = 0;
+ file.Size( size );
+
+ // Alloc buffer for file.
+ HBufC8* buffer = HBufC8::NewLC( size );
+
+ if ( buffer )
+ {
+ TPtr8 bufferPtr = buffer->Des();
+
+ // Read file binary to buffer.
+ err = file.Read( bufferPtr );
+
+ if ( err == KErrNone || buffer->Length() != 0 )
+ {
+ TUint64 capa = 0;
+ TBool capabilityOk = EFalse;
+
+ // Check capability if needed.
+ if ( aCheckCapa )
+ {
+ // Get pointer to heap buffer.
+ const TUint8* ptr = buffer->Ptr();
+
+ // Capapility word (64bit) is found in 0x88 bytes after
+ // file heder offset. 0x88 = 136 bytes/8=17 words@64.
+ TUint64 word = ((TUint64*)ptr)[KBTICCabaWordOffset];
+
+ for ( TInt iCapa = 0; iCapa < KBTICCapaCount; iCapa++ )
+ {
+ BTIC_TRACE_PRINT_NUM("Capa index = %d", iCapa );
+
+ capa = aCapaVector[iCapa];
+
+ if ( (word & capa) == capa )
+ {
+ BTIC_TRACE_PRINT("Capability match found");
+ capabilityOk = ETrue;
+ break;
+ }
+ }
+ }
+
+ // If capa check is not needed calculate hash over the file.
+ // Capability is set as zero.
+ else
+ {
+ BTIC_TRACE_PRINT("Capability NOT REGUIRED");
+ capabilityOk = ETrue;
+ }
+
+ if ( capabilityOk )
+ {
+ BTIC_TRACE_PRINT("Append file information to array");
+
+ // Add found capability to array
+ User::LeaveIfError( aCapaArray.Append( capa ) );
+
+ // Append pointer to files path.
+ User::LeaveIfError( aFilesArray.Append( path ) );
+
+ HBufC8* hash = HBufC8::NewLC( KBTICHashSize );
+ TPtr8 hashPtr = hash->Des();
+
+ sha->Reset();
+
+ // Calucalte hash over file's binary.
+ hashPtr.Copy( sha->Hash( bufferPtr ) );
+
+ // Check that digest has correct length.
+ if ( hash->Length() != KBTICHashSize )
+ {
+ BTIC_TRACE_PRINT("\nERROR HASH SIZE");
+ User::Leave( KErrGeneral );
+ }
+
+ // Add file's hash to array
+ User::LeaveIfError( aHashArray.Append( hash ) );
+
+ CleanupStack::Pop(); // hash;
+
+ retVal = ETrue;
+ }
+ }
+ else
+ {
+ BTIC_TRACE_PRINT_NUM("\nERROR File read = %d", err );
+ User::Leave( KErrGeneral );
+ }
+ }
+ else
+ {
+ BTIC_TRACE_PRINT("\nERROR HBufC8 buffer alloc failed");
+ User::Leave( KErrGeneral );
+ }
+
+ CleanupStack::PopAndDestroy( 2 ); // file, fileBuffer
+ }
+ else
+ {
+ BTIC_TRACE_PRINT_NUM("\nERROR File open = %d", err );
+ User::Leave( KErrGeneral );
+ }
+ }
+
+ CleanupStack::PopAndDestroy(); // sha
+
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] CheckCapaWordAndCalcHashL v3 <---");
+
+ return retVal;
+ }
+
+/*
+#ifdef __BTIC_BINARIES_CHECK_ENABLED
+
+
+// -----------------------------------------------------------------------------
+// RenameFileL
+//
+// This function renames given file by replacing existing file extension to .bak
+// -----------------------------------------------------------------------------
+//
+LOCAL_C void RenameFileL( RFs& aFs, const TDesC& aFileName )
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] ! ! ! RenameFileL --->");
+
+ _LIT( KBTICFileExtensionBak,".bak" );
+
+ TFindFile find( aFs );
+
+ // Find given file in C drive.
+ if ( find.FindByDir( aFileName, KBTICSysPathC ) == KErrNone )
+ {
+ TInt length = aFileName.Length();
+ HBufC* newName = HBufC::NewLC( length + sizeof( KBTICFileExtensionBak ) );
+ TPtr newNamePtr = newName->Des();
+
+ newNamePtr.Copy( aFileName );
+ // Add ".bak" extension to file name.
+ newNamePtr.Append( KBTICFileExtensionBak );
+
+ // Rename file.
+ TInt err = aFs.Rename( aFileName, *newName );
+
+ // If error try ones more.
+ if ( err != KErrNone )
+ {
+ aFs.Rename( aFileName, *newName );
+ }
+ }
+
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] ! ! ! RenameFileL <---");
+ }
+
+
+// -----------------------------------------------------------------------------
+// UniteCertArraysL
+//
+// Function append source array's pointers to target array.
+// -----------------------------------------------------------------------------
+//
+LOCAL_C void UniteCertArraysL(
+ RPointerArray<CX509Certificate>& aTargetCertArray,
+ RPointerArray<CX509Certificate>& aSourceCertArray )
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] UniteCertArraysL --->");
+
+ TInt count = aSourceCertArray.Count();
+
+ if ( count > 0 )
+ {
+ for ( TInt index = 0; index < count; index++ )
+ {
+ CX509Certificate* x509Cert = aSourceCertArray[index];
+ // Note if append fails -> some binaries will be corrupted.
+ aTargetCertArray.Append( x509Cert );
+ }
+ }
+
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] UniteCertArraysL <---");
+ }
+
+
+// -----------------------------------------------------------------------------
+// UniteCapaArraysL
+//
+// Function append source array's pointers to target array.
+// -----------------------------------------------------------------------------
+//
+LOCAL_C void UniteCapaArraysL(
+ RPointerArray<TCapabilitySet>& aTargetCapaArray,
+ RPointerArray<TCapabilitySet>& aSourceCapaArray )
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] UniteCapaArraysL --->");
+
+ TInt count = aSourceCapaArray.Count();
+
+ if ( count > 0 )
+ {
+ for ( TInt index = 0; index < count; index++ )
+ {
+ TCapabilitySet* capaSet = aSourceCapaArray[index];
+ // Note if append fails -> some binaries will be corrupted.
+ aTargetCapaArray.Append( capaSet );
+ }
+ }
+
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] UniteCapaArraysL <---");
+ }
+
+
+// -----------------------------------------------------------------------------
+// CheckBinariesL
+//
+// This function checks all exe or dll binarys conteining TCB and DRM capability
+// in C:\sys\bin directory. It calculates hash over the binary and compares that
+// to one found in SIS Registery. It check also that SIS pacage's certificate
+// has rigth to grant TCB or DRM capabiltity.
+// If some file in C:\sys\bin directory is not found in SIS Registery it is
+// renamed.
+//
+// -----------------------------------------------------------------------------
+//
+LOCAL_C void CheckBinariesL(
+ RFs& aFs,
+ RPointerArray<CX509Certificate>& aX509CertArray,
+ RPointerArray<TCapabilitySet>& aCertCapaArray )
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] CheckBinariesL --->");
+ __UHEAP_MARK;
+
+ TInt pushToStack = 0;
+ TInt err = 0;
+
+ RPointerArray<HBufC> allFilesArray;
+
+ // Find all exe files from c:\sys\bin.
+ FindFilesL( aFs, KBTICSysPathC, KBTICExtensionExe, allFilesArray );
+ // Find all dll files from c:\sys\bin.
+ FindFilesL( aFs, KBTICSysPathC, KBTICExtensionDll, allFilesArray );
+
+ TInt count = allFilesArray.Count();
+
+ if ( count > 0 )
+ {
+ RPointerArray<HBufC> filesArray;
+ RPointerArray<HBufC8> hashArray;
+ RArray<TUint64> capaArray;
+
+ TBool foundFiles = EFalse;
+
+ // Copy whanted capabilities to array.
+ TUint64* capaVector = new( ELeave ) TUint64[KBTICCapaCount];
+ CleanupArrayDeletePushL( capaVector );
+ capaVector[0] = KBTIC_TCB;
+ capaVector[1] = KBTIC_DRM;
+
+ // Find files conteining whanted capability and calculate hash over file.
+
+ // NOTE NOTE currently this function addends only one capability to
+ // capaArray. This must be changed if all capabilities should be
+ // checked from certificate.
+
+ foundFiles = CheckCapabilityWordAndCalcHashL(
+ aFs,
+ ETrue,
+ capaVector,
+ allFilesArray,
+ filesArray,
+ hashArray,
+ capaArray );
+
+ CleanupStack::PopAndDestroy(); //capaVector
+
+ if ( foundFiles && err == KErrNone )
+ {
+ // Find match for fileArray's files from SIS registery
+ // Check that file's (binary) hash matches to SIS registery's hash
+ // Check that SIS registery cert. is valid and has file's capability.
+ FindMatchFromSisPackageL(
+ aFs,
+ filesArray,
+ hashArray,
+ capaArray,
+ aX509CertArray,
+ aCertCapaArray );
+
+ count = filesArray.Count();
+
+ BTIC_TRACE_PRINT_NUM("Files array count = %d (should be 0 )", count );
+
+ // Rename all files which was not found in sis registery.
+ if ( count )
+ {
+ for ( TInt index = 0; index < count; index++ )
+ {
+ HBufC* filePath = filesArray[index];
+
+ RenameFileL( aFs, *filePath );
+ }
+ }
+ }
+
+ filesArray.Reset(); // Reset only. allFilesArray owns heap memory.
+ hashArray.ResetAndDestroy();
+ }
+
+ allFilesArray.ResetAndDestroy();
+
+ CleanupStack::PopAndDestroy( pushToStack ); //searchPath
+
+ BTIC_TRACE_PRINT("UHEAP MARK END");
+ __UHEAP_MARKEND;
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] CheckBinariesL <---");
+ }
+
+
+// -----------------------------------------------------------------------------
+// FindFilesL
+//
+// This function searches one or more files that conteins given string in file
+// name. File names are added to array with complete path.
+// -----------------------------------------------------------------------------
+//
+LOCAL_C void FindFilesL(
+ RFs& aFs, // File server handle.
+ const TDesC& aPath, // Search directory and drive.
+ const TDesC& aSearchString, // String to be found in file name.
+ RPointerArray<HBufC>& aFoundFilesArray )// Result files.
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] FindFilesL --->");
+
+ TInt err = 0;
+ TFindFile find( aFs );
+ CDir* dirList = NULL;
+ HBufC* path;
+
+ TFileName searchExtension;
+ searchExtension.Copy( aSearchString );
+
+ // Find files from searchPath directory. Note that dirlist
+ // contains only file name not path to it.
+ err = find.FindWildByPath( searchExtension, &aPath, dirList );
+
+ TInt pathLength = aPath.Length();
+
+ if ( err == KErrNone && dirList )
+ {
+ CleanupStack::PushL( dirList );
+
+ // Get the count of find files.
+ TInt count = dirList->Count();
+
+ BTIC_TRACE_PRINT_NUM("Dir list count = %d", count );
+
+ for ( TInt index = 0; index < count; index++ )
+ {
+ path = HBufC::NewLC( pathLength + (*dirList)[index].iName.Length() );
+ TPtr ptrPath = path->Des();
+
+ // Copy system path to buffer.
+ ptrPath.Copy( KBTICSysPathC );
+ // Append files name to path buffer.
+ ptrPath.Append( (*dirList)[index].iName );
+
+ ptrPath.LowerCase();
+
+ aFoundFilesArray.Append( path );
+
+ CleanupStack::Pop(); //path
+ }
+
+ CleanupStack::Pop(); //dirList
+ delete dirList;
+ }
+
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] FindFilesL <---");
+ }
+
+
+
+// -----------------------------------------------------------------------------
+// FindMatchFromSisPackageL
+//
+// This function search given files from SIS Registery. Function removes file
+// from aFilesArray alway when it is found in Registery. If aFilesArray contains
+// files after function return those files are not found in SIS Registery.
+//
+// Returns: ETure if successful
+// EFalse othervice
+// -----------------------------------------------------------------------------
+//
+LOCAL_C TBool FindMatchFromSisPackageL(
+ RFs& aFs, // File server handle
+ RPointerArray<HBufC>& aFilesArray, // Files to be checked
+ RPointerArray<HBufC8>& aHashArray, // File's hash
+ RArray<TUint64>& aCapaArray, // File's capability
+ RPointerArray<CX509Certificate>& aX509CertArray, // Cert array
+ RPointerArray<TCapabilitySet>& aCertCapaArray ) // Cert's capability
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] FindMatchFromSisPackageL --->");
+ __UHEAP_MARK;
+
+ TInt err = KErrNone;
+ TBool allOK = EFalse;
+
+ Swi::RSisRegistrySession sisRegSession;
+
+ err = sisRegSession.Connect();
+
+ if ( err == KErrNone )
+ {
+ CleanupClosePushL( sisRegSession );
+
+ RPointerArray<CSisRegistryPackage> sisPackages;
+
+ // Find installed packages.
+ sisRegSession.InstalledPackagesL( sisPackages );
+
+ TBool entryOpen = EFalse;
+ TInt entryFilesCount = 0;
+ TInt fileCount = 0;
+ Swi::RSisRegistryEntry entry;
+ // Array for entrys files. This owns heap memory.
+ RPointerArray<HBufC> installedFiles;
+ // Array for dll and exe files found in sis registery.
+ RPointerArray<HBufC> entryFiles;
+ // Array for wild card string to be search from file list.
+ RPointerArray<HBufC> stringArray;
+ HBufC* string;
+
+ // Add wild card strings to array.
+ string = KBTICExtensionExe().AllocLC();
+ User::LeaveIfError( stringArray.Append( string ) );
+ CleanupStack::Pop();
+
+ string = KBTICExtensionDll().AllocLC();
+ User::LeaveIfError( stringArray.Append( string ) );
+ CleanupStack::Pop();
+
+ // Open sis registery entry and search paths to installed exes and dlls.
+ for( TInt index = 0; index < sisPackages.Count(); index++)
+ {
+ BTIC_TRACE_PRINT_NUM("entry loop Index = %d", index );
+
+ // If error happens make leave. If some pacage is left out we can
+ // not continue, because all files found in C must be found also
+ // in sis registery.
+ User::LeaveIfError(
+ entry.OpenL( sisRegSession, *sisPackages[index] ) );
+
+ CleanupClosePushL( entry );
+ entryOpen = ETrue;
+
+ // Get this entrys installed files.
+ entry.FilesL( installedFiles );
+
+ if ( installedFiles.Count() > 0 )
+ {
+ // Search match for string array conten from entrys files.
+ // Note that heap memory is owned by installeFiles array.
+ SearchFilesFromArrayL(
+ installedFiles,
+ KBTICSysPathCWildcard,
+ stringArray,
+ entryFiles );
+ }
+
+ entryFilesCount = entryFiles.Count();
+
+ BTIC_TRACE_PRINT_NUM("Entry files count = %d", entryFilesCount );
+
+ if ( entryFilesCount > 0 )
+ {
+ TBool pagaceCertValid = EFalse;
+
+ // Go torug all file paths from entryFiles aray.
+ for ( TInt indexB = 0; indexB < entryFilesCount; indexB++ )
+ {
+ BTIC_TRACE_PRINT_NUM("file path loop IndexB = %d", indexB );
+
+ // Get file's path from sis pagace entry.
+ HBufC* entryFile = entryFiles[indexB];
+
+ fileCount = aFilesArray.Count();
+
+ // Compare registery file path to files found in C:\sys\bin.
+ for ( TInt indexC = fileCount - 1; indexC >= 0; indexC-- )
+ {
+ // Get file's path from array conteining dlls and exes.
+ HBufC* file = aFilesArray[indexC];
+
+ TInt result = entryFile->CompareC( *file );
+
+ BTIC_TRACE_PRINT_NUM("\nCompare result = %d", result );
+
+ // If result is zero match is found.
+ if ( result == 0 )
+ {
+ BTIC_TRACE_PRINT("File path Match found" );
+
+ // Get file's hash
+ HBufC8* hash = aHashArray[indexC];
+
+ BTIC_TRACE_PRINT("CompareToRegisteryHashL -->" );
+
+ TBool hashOk = CompareToRegisteryHashL(
+ entry,
+ *entryFile,
+ *hash );
+
+ BTIC_TRACE_PRINT("CompareToRegisteryHashL <--" );
+
+
+ if ( hashOk )
+ {
+ BTIC_TRACE_PRINT("HASH OK");
+
+ // Check if entry cert is already valid.
+ if ( ! pagaceCertValid )
+ {
+ BTIC_TRACE_PRINT("Validate pagace cert");
+
+ // Validate entry's certificate and
+ // check that certificate has correct
+ // capablities.
+ TBool certOk = SearchValidCertificateL(
+ entry,
+ aX509CertArray,
+ aCertCapaArray,
+ aCapaArray[indexC] );
+
+ if ( certOk )
+ {
+ BTIC_TRACE_PRINT("Pagace CERT VALID - OK");
+
+ // Validate pagace cert. only once.
+ pagaceCertValid = ETrue;
+ }
+ else
+ {
+ // Rename file if cert is not ok.
+
+ RenameFileL( aFs, *entryFile );
+ // Should we rename all files in this
+ // entry or only this one.
+ }
+ }
+ }
+ else
+ {
+ BTIC_TRACE_PRINT("HASH Error -> Rename file");
+ // If hash is false rename file.
+ RenameFileL( aFs, *entryFile );
+ }
+
+ // Set arrays entry to zero so we will not
+ // compear it twice. We do not have to delete
+ // entry because aFilesArray do not own heap
+ // memory.
+ aFilesArray.Remove( indexC );
+
+ //Remove also hash and capa entry from array.
+ HBufC8* hashBuffer = aHashArray[indexC];
+ delete hashBuffer;
+ aHashArray.Remove( indexC);
+
+ aCapaArray.Remove( indexC );
+
+ break;
+ }
+ }
+ }
+ }
+
+ if ( entryOpen )
+ {
+ BTIC_TRACE_PRINT("Clear ENTRY and installedFiles array");
+
+ CleanupStack::PopAndDestroy(); //entry
+ entryFiles.Reset(); //Reset only.
+ installedFiles.ResetAndDestroy();
+ }
+
+ // Break entry loop if all files are removed.
+ if ( aFilesArray.Count() == 0 )
+ {
+ BTIC_TRACE_PRINT("NO MORE EXE/DLL FILES -> BREAK LOOP");
+ break;
+ }
+ }
+
+ stringArray.ResetAndDestroy();
+ CleanupStack::PopAndDestroy(); // sisRegSession
+
+ allOK = ETrue;
+ }
+
+
+ BTIC_TRACE_PRINT("UHEAP MARK END");
+ __UHEAP_MARKEND;
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] FindMatchFromSisPackageL <---");
+
+ return allOK;
+ }
+
+
+#endif //__BTIC_BINARIES_CHECK_ENABLED
+*/
+
+// =========================== CRootCertificateEntry ===========================
+
+// -----------------------------------------------------------------------------
+// NewLC()
+//
+// -----------------------------------------------------------------------------
+//
+CRootCertificateEntry* CRootCertificateEntry::NewLC( RReadStream& aStream )
+ {
+ CRootCertificateEntry* self = new(ELeave) CRootCertificateEntry();
+ CleanupStack::PushL(self);
+
+ self->InternalizeL( aStream );
+
+ return self;
+ }
+
+
+// -----------------------------------------------------------------------------
+// CRootCertificateEntry()
+//
+// -----------------------------------------------------------------------------
+//
+CRootCertificateEntry::CRootCertificateEntry()
+ {
+ }
+
+
+// -----------------------------------------------------------------------------
+// ~CRootCertificateEntry()
+//
+// -----------------------------------------------------------------------------
+//
+CRootCertificateEntry::~CRootCertificateEntry()
+ {
+ iApplications.Close();
+ }
+
+
+// -----------------------------------------------------------------------------
+// InternalizeL()
+//
+// -----------------------------------------------------------------------------
+//
+void CRootCertificateEntry::InternalizeL( RReadStream& aStream )
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] InternalizeL");
+
+ iX509CertificateType = aStream.ReadUint8L();
+
+ iSize = aStream.ReadInt32L();
+
+ aStream >> iLabel;
+
+ iCertId = aStream.ReadInt32L();
+
+ iCACertificateType = aStream.ReadUint8L();
+
+ aStream >> iSubjectKeyId;
+
+ aStream >> iIssuerKeyId;
+
+ TInt count = aStream.ReadInt32L();
+
+ for ( TInt i = 0 ; i < count ; ++i )
+ {
+ TUid id;
+ aStream >> id;
+ User::LeaveIfError( iApplications.Append( id ) );
+ }
+
+ iTrusted = !!aStream.ReadUint8L(); // converts TUint8 to TBool
+
+ aStream >> iDataStreamId;
+
+ TPckg<TCapabilitySet> capsPckg( iCapabilities );
+ aStream >> capsPckg;
+
+ iMandatory = !!aStream.ReadUint8L();
+ }
+
+
+// -----------------------------------------------------------------------------
+// DataStreamId()
+//
+// -----------------------------------------------------------------------------
+//
+TStreamId CRootCertificateEntry::DataStreamId() const
+ {
+ return iDataStreamId;
+ }
+
+
+// -----------------------------------------------------------------------------
+// Capabilities()
+//
+// -----------------------------------------------------------------------------
+//
+const TCapabilitySet& CRootCertificateEntry::Capabilities() const
+ {
+ return iCapabilities;
+ }
+
+// -----------------------------------------------------------------------------
+// Size()
+//
+// -----------------------------------------------------------------------------
+//
+TInt CRootCertificateEntry::Size() const
+ {
+ return iSize;
+ }
+
+
+// -----------------------------------------------------------------------------
+// CertID()
+//
+// -----------------------------------------------------------------------------
+//
+TInt CRootCertificateEntry::CertID() const
+ {
+ return iCertId;
+ }
+
+
+
+// =========================== CActiveFileObserver ============================
+
+// -----------------------------------------------------------------------------
+// CActiveFileObserver::CActiveFileObserver()
+// -----------------------------------------------------------------------------
+//
+CActiveFileObserver::CActiveFileObserver( RFs& aFs, TInt& aResult)
+ : CActive( EPriorityNormal ),
+ iFs( aFs ),
+ iResult( aResult )
+ {
+ }
+
+
+// -----------------------------------------------------------------------------
+// CActiveFileObserver::~CActiveFileObserver()
+// Destructor
+// -----------------------------------------------------------------------------
+//
+CActiveFileObserver::~CActiveFileObserver()
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] ~CActiveFileObserver");
+ // Cancel the outstanding request. This calls DoCancel().
+ Cancel();
+ // Close timer.
+ iRTimer.Close();
+
+ if ( iPath )
+ {
+ delete iPath;
+ iPath = NULL;
+ }
+ }
+
+
+// -----------------------------------------------------------------------------
+// CActiveFileObserver* CActiveFileObserver::NewL()
+// Factory method.
+// -----------------------------------------------------------------------------
+//
+CActiveFileObserver* CActiveFileObserver::NewL(
+ RFs& aFs,
+ const TDesC& aPath,
+ TInt& aResult )
+ {
+ CActiveFileObserver* observer =
+ new(ELeave) CActiveFileObserver( aFs, aResult );
+
+ CleanupStack::PushL( observer );
+
+ observer->ConstructL( aPath );
+
+ CleanupStack::Pop();
+
+ return observer;
+ }
+
+
+// -----------------------------------------------------------------------------
+// CActiveFileObserver::ConstructL()
+// Second-phase constructor.
+// -----------------------------------------------------------------------------
+//
+void CActiveFileObserver::ConstructL( const TDesC& aPath )
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] CActiveFileObserver::ConstructL");
+
+ iRunCount = 0;
+
+ iPath = HBufC::NewL( aPath.Length() );
+ TPtr iPathPtr = iPath->Des();
+ iPathPtr.Copy( aPath );
+
+ iRTimer.CreateLocal();
+
+ // Add to scheduler.
+ CActiveScheduler::Add( this );
+
+ // Issue first timer request.
+ IssueRequest();
+ }
+
+
+// -----------------------------------------------------------------------------
+// CActiveFileObserver::DoCancel()
+// Cancel function for active object.
+// -----------------------------------------------------------------------------
+//
+void CActiveFileObserver::DoCancel()
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] CActiveFileObserver::DoCancel");
+ // Cancel outstanding request.
+ iRTimer.Cancel();
+ }
+
+
+// -----------------------------------------------------------------------------
+// CActiveFileObserver::RunError()
+// Handles a leave occurring in the request completion event handler RunL.
+// -----------------------------------------------------------------------------
+//
+TInt CActiveFileObserver::RunError( TInt aError )
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] CActiveFileObserver::RunError");
+ iResult = aError;
+ BTIC_TRACE_PRINT_NUM("[BOOT INTE.] RunError: err = %d", aError );
+ return aError;
+ }
+
+
+// -----------------------------------------------------------------------------
+// CActiveFileObserver::IssueRequest()
+// This function issues new
+// -----------------------------------------------------------------------------
+void CActiveFileObserver::IssueRequest()
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] CActiveFileObserver::IssueRequest");
+ //iFs.NotifyChange( ENotifyEntry, iStatus, *iPath );
+ iRunCount++;
+
+ iRTimer.After( iStatus, KBTICObserverTime );
+
+ // Wait request to complete.
+ SetActive();
+ }
+
+
+// -----------------------------------------------------------------------------
+// CActiveFileObserver::RunL()
+// This function handles active object’s request completion event
+// -----------------------------------------------------------------------------
+//
+void CActiveFileObserver::RunL()
+ {
+ BTIC_TRACE_PRINT("[BOOT INTECRITY CHECK] CActiveFileObserver::RunL");
+
+ TInt err = KErrNone;
+ RFile file;
+ // Try to open the file.
+ err = file.Open( iFs, *iPath, EFileShareReadersOrWriters | EFileRead );
+
+ BTIC_TRACE_PRINT_NUM("[BOOT INTE.] RunL: file open err = %d", err );
+
+ if ( err == KErrNone )
+ {
+ // Close the file.
+ file.Close();
+
+ if ( iRunCount < KBTICRunCount )
+ {
+ // Make new request.
+ IssueRequest();
+ }
+ else
+ {
+ BTIC_TRACE_PRINT("[BOOT INTE.] RunL: File not deleted -> CANCEL");
+ // File is not deleted. Stop active observer
+ // and continue data base checking.
+ iResult = KErrCancel;
+ Deque();
+ CActiveScheduler::Stop();
+ }
+ }
+ else if ( err == KErrNotFound || err == KErrPathNotFound )
+ {
+ // Ok file is deleted. Stop active observer and return.
+ BTIC_TRACE_PRINT("[BOOT INTE.] RunL: File deleted -> OK");
+ iResult = KErrNone;
+ Deque();
+ CActiveScheduler::Stop();
+ }
+ else
+ {
+ // Some other file open error etc. KErrInUse. Let's continue.
+
+ if ( iRunCount < KBTICRunCount )
+ {
+ // Make new request.
+ IssueRequest();
+ }
+ else
+ {
+ BTIC_TRACE_PRINT("[BOOT INTE.] RunL: File not deleted -> CANCEL");
+ // File is not deleted. Stop active observer
+ // and continue data base checking.
+ iResult = KErrCancel;
+ Deque();
+ CActiveScheduler::Stop();
+ }
+ }
+ }
+
+//EOF