os/security/cryptoservices/filebasedcertificateandkeystores/source/certapps/server/CFSCertAppsServer.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
/*
sl@0
     2
* Copyright (c) 2002-2010 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     3
* All rights reserved.
sl@0
     4
* This component and the accompanying materials are made available
sl@0
     5
* under the terms of the License "Eclipse Public License v1.0"
sl@0
     6
* which accompanies this distribution, and is available
sl@0
     7
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     8
*
sl@0
     9
* Initial Contributors:
sl@0
    10
* Nokia Corporation - initial contribution.
sl@0
    11
*
sl@0
    12
* Contributors:
sl@0
    13
*
sl@0
    14
* Description: 
sl@0
    15
*
sl@0
    16
*/
sl@0
    17
sl@0
    18
sl@0
    19
#include "CFSCertAppsServer.h"
sl@0
    20
#include "CCertAppsSession.h"
sl@0
    21
#include "CCertAppsConduit.h"
sl@0
    22
#include "fstokencliserv.h"
sl@0
    23
#include "fstokenutil.h"
sl@0
    24
sl@0
    25
#include <certstorepatchdata.h>
sl@0
    26
#include <certificateapps.h>
sl@0
    27
#include <u32hal.h> 
sl@0
    28
#include <e32svr.h>
sl@0
    29
sl@0
    30
// Filename where all data is stored
sl@0
    31
_LIT(KCertAppsFilename,"certclients.dat");
sl@0
    32
_LIT(KCertAppsFile,"certclients*.dat");
sl@0
    33
sl@0
    34
CFSCertAppsServer* CFSCertAppsServer::NewL()
sl@0
    35
	{
sl@0
    36
	CFSCertAppsServer* self = new (ELeave) CFSCertAppsServer();
sl@0
    37
	CleanupStack::PushL(self);
sl@0
    38
	self->ConstructL();
sl@0
    39
	CleanupStack::Pop(self);
sl@0
    40
	return self;
sl@0
    41
	}
sl@0
    42
sl@0
    43
CFSCertAppsServer::CFSCertAppsServer()
sl@0
    44
	{
sl@0
    45
	}
sl@0
    46
sl@0
    47
void CFSCertAppsServer::ConstructL()
sl@0
    48
	{
sl@0
    49
	iConduit = CCertAppsConduit::NewL(*this);
sl@0
    50
	
sl@0
    51
	// Connect to the filesystem
sl@0
    52
	User::LeaveIfError(iFs.Connect());
sl@0
    53
sl@0
    54
	iPatchableConst = KAggregateCertStore;
sl@0
    55
	
sl@0
    56
	#ifdef __WINS__
sl@0
    57
		// For the emulator allow the constant to be patched via epoc.ini
sl@0
    58
		UserSvr::HalFunction(EHalGroupEmulator, EEmulatorHalIntProperty,
sl@0
    59
		(TAny*)"KAggregateCertStore", &iPatchableConst); // read emulator property (if present)
sl@0
    60
	#endif		
sl@0
    61
	
sl@0
    62
	// Retrieves the store
sl@0
    63
	OpenStoreL();
sl@0
    64
	}
sl@0
    65
sl@0
    66
CFSCertAppsServer::~CFSCertAppsServer()
sl@0
    67
	{
sl@0
    68
	delete iStore;
sl@0
    69
 	iFs.Close();
sl@0
    70
	iClients.Close();
sl@0
    71
	delete iConduit;
sl@0
    72
	}
sl@0
    73
sl@0
    74
CCertAppsSession* CFSCertAppsServer::CreateSessionL()
sl@0
    75
	{
sl@0
    76
	return CCertAppsSession::NewL(*iConduit); 
sl@0
    77
	}
sl@0
    78
sl@0
    79
void CFSCertAppsServer::AddL(const TCertificateAppInfo& aClient)
sl@0
    80
	{
sl@0
    81
	// see if application already exists. If so, then leave
sl@0
    82
	
sl@0
    83
	if (FindApplication(aClient.Id()))
sl@0
    84
		{
sl@0
    85
		User::Leave(KErrAlreadyExists);
sl@0
    86
		}
sl@0
    87
	User::LeaveIfError(iClients.Append(aClient));
sl@0
    88
	TRAPD(err, ReplaceAndCommitL(-1));
sl@0
    89
	if (err != KErrNone)
sl@0
    90
		{
sl@0
    91
		// We must remove the client from iClients if we didn't manage 
sl@0
    92
		// to add it to the store
sl@0
    93
		iClients.Remove(iClients.Count() - 1);
sl@0
    94
		User::Leave(err);
sl@0
    95
		}
sl@0
    96
	}
sl@0
    97
sl@0
    98
void CFSCertAppsServer::RemoveL(const TUid& aUid)
sl@0
    99
	{
sl@0
   100
	// Make sure the application for that uid exists
sl@0
   101
	TInt i;
sl@0
   102
	if (!FindApplication(aUid, &i))
sl@0
   103
		{
sl@0
   104
		User::Leave(KErrNotFound);
sl@0
   105
		}
sl@0
   106
sl@0
   107
	ReplaceAndCommitL(i);
sl@0
   108
	
sl@0
   109
	// We managed to remove it from the store, so we remove it from the
sl@0
   110
	// iClients array
sl@0
   111
	iClients.Remove(i);
sl@0
   112
	}
sl@0
   113
sl@0
   114
TInt CFSCertAppsServer::ApplicationCountL() const
sl@0
   115
	{
sl@0
   116
	return iClients.Count();
sl@0
   117
	}
sl@0
   118
sl@0
   119
void CFSCertAppsServer::ApplicationsL(RArray<TCertificateAppInfo>& aAppArray) const
sl@0
   120
	{
sl@0
   121
	// Make a copy of the array
sl@0
   122
	TInt count = iClients.Count();
sl@0
   123
sl@0
   124
	for (TInt i = 0; i < count; ++i)
sl@0
   125
		{
sl@0
   126
		aAppArray.AppendL(iClients[i]);
sl@0
   127
		}
sl@0
   128
	}
sl@0
   129
sl@0
   130
void CFSCertAppsServer::ApplicationL(const TUid& aUid, TCertificateAppInfo& aInfo) const
sl@0
   131
	{
sl@0
   132
	const TCertificateAppInfo* app = FindApplication(aUid);
sl@0
   133
sl@0
   134
	// leave if not found
sl@0
   135
	if (!app)
sl@0
   136
		{
sl@0
   137
		User::Leave(KErrNotFound);
sl@0
   138
		}
sl@0
   139
sl@0
   140
	// make a copy and return to client
sl@0
   141
	aInfo = *app;
sl@0
   142
	}
sl@0
   143
sl@0
   144
const TCertificateAppInfo* CFSCertAppsServer::FindApplication(const TUid& aUid, TInt* aIndex) const
sl@0
   145
	{
sl@0
   146
	// This helper function tries to find an application with the given
sl@0
   147
	// Uid. It returns NULL if not found. aIndex returns the index into
sl@0
   148
	// the array successful
sl@0
   149
	const TCertificateAppInfo* retVal = NULL;
sl@0
   150
	TInt end = iClients.Count();
sl@0
   151
	for (TInt i = 0; i < end; ++i)
sl@0
   152
		{
sl@0
   153
		if (iClients[i].Id() == aUid)
sl@0
   154
			{
sl@0
   155
			// check if an index is required to be returned
sl@0
   156
			if (aIndex)
sl@0
   157
				{
sl@0
   158
				*aIndex = i;
sl@0
   159
				}
sl@0
   160
			retVal = &iClients[i];
sl@0
   161
			break;
sl@0
   162
			}
sl@0
   163
		}
sl@0
   164
sl@0
   165
	return retVal;
sl@0
   166
	}
sl@0
   167
sl@0
   168
void CFSCertAppsServer::AggregateStoreFileL(const TDesC& aFile)
sl@0
   169
	{
sl@0
   170
	ASSERT(iPatchableConst);
sl@0
   171
sl@0
   172
	// if patchable constant is enabled
sl@0
   173
	// 1. open read-only permanent file store on each file.
sl@0
   174
	// 2. open certificate client entry list of each store.
sl@0
   175
	// 3. aggregate the entries.
sl@0
   176
	RFile file;
sl@0
   177
	User::LeaveIfError(file.Open(iFs, aFile, EFileRead));
sl@0
   178
	CleanupClosePushL(file);
sl@0
   179
	CPermanentFileStore* store = CPermanentFileStore::FromL(file);
sl@0
   180
	// now owned by store
sl@0
   181
	CleanupStack::Pop(&file); 
sl@0
   182
	CleanupStack::PushL(store);
sl@0
   183
sl@0
   184
	// Read id of cert list stream
sl@0
   185
	TStreamId streamId;
sl@0
   186
	RStoreReadStream stream;
sl@0
   187
	stream.OpenLC(*store, store->Root());
sl@0
   188
	stream >> streamId;
sl@0
   189
	CleanupStack::PopAndDestroy(&stream);
sl@0
   190
	
sl@0
   191
	// Read the certificate's clients entry list
sl@0
   192
	stream.OpenLC(*store, streamId);
sl@0
   193
	TInt count = stream.ReadInt32L();
sl@0
   194
	RArray<TCertificateAppInfo> entryList;
sl@0
   195
	for (TInt i = 0 ; i < count ; i++)
sl@0
   196
		{
sl@0
   197
		TCertificateAppInfo clientInfo;
sl@0
   198
		stream >> clientInfo;
sl@0
   199
		entryList.AppendL(clientInfo);
sl@0
   200
		}
sl@0
   201
	CleanupStack::PopAndDestroy(&stream);
sl@0
   202
	CleanupClosePushL(entryList);
sl@0
   203
sl@0
   204
	MergeCertificateEntryListL(entryList);
sl@0
   205
	// cleanup entryList and store instances.
sl@0
   206
	CleanupStack::PopAndDestroy(2,store);		
sl@0
   207
	}
sl@0
   208
sl@0
   209
TBool CFSCertAppsServer::FindUid(const TUid& aUid)
sl@0
   210
	{
sl@0
   211
	TInt end = iClients.Count();
sl@0
   212
	for (TInt i = 0; i < end; ++i)
sl@0
   213
		{
sl@0
   214
		if (iClients[i].Id() == aUid)
sl@0
   215
			{
sl@0
   216
			return ETrue;
sl@0
   217
			}
sl@0
   218
		}
sl@0
   219
	return EFalse;
sl@0
   220
	}
sl@0
   221
sl@0
   222
void CFSCertAppsServer::MergeCertificateEntryListL(const RArray<TCertificateAppInfo>& aSourceList)
sl@0
   223
	{
sl@0
   224
	ASSERT(iPatchableConst);
sl@0
   225
sl@0
   226
	// if patchable constant is enabled
sl@0
   227
	TInt sourceCount = aSourceList.Count();
sl@0
   228
	for(TInt i = 0; i < sourceCount; i++)
sl@0
   229
		{
sl@0
   230
		// compare if the uid pre-exists in the composite list.
sl@0
   231
		if (!FindUid(aSourceList[i].Id()))
sl@0
   232
			{
sl@0
   233
			// Aggregation: append this entry to the composite list.
sl@0
   234
			iClients.AppendL(aSourceList[i]);
sl@0
   235
			}
sl@0
   236
		// Eclipsing: Higher order store cert client entries with same UIDs take precedence over lower order  
sl@0
   237
		// store cert client entries therefore the later are not included in the composite cert client entry list.
sl@0
   238
		// Higher order store client entries are ones which are aggregated prior to other client entries. 
sl@0
   239
		}
sl@0
   240
	}
sl@0
   241
sl@0
   242
void CFSCertAppsServer::OpenCompositeStoreL(const TDesC& aFilename)
sl@0
   243
	{
sl@0
   244
	ASSERT(iPatchableConst);
sl@0
   245
sl@0
   246
	// 1. create a new empty certstore file under system drive with the name 'certclients.dat'. 
sl@0
   247
	// 2. this will be the composite store and the instances 'iEntryList' and 'iStore' will be initialized with this.
sl@0
   248
	// 3. make private rom drive path where certstore files are located.
sl@0
   249
	// 4. collect the certstore file names in a list.
sl@0
   250
	// 5. make private rom drive path on each file.
sl@0
   251
	// 6. populate the composite store with certificate client entries present in rom drive certstores.
sl@0
   252
	
sl@0
   253
	// create a new empty certstore file 'certclients.dat' under system drive.
sl@0
   254
	CreateStoreL(aFilename);	
sl@0
   255
	// restore permanent store on it 
sl@0
   256
	// this will be the composite store after complete aggregation. 
sl@0
   257
	ReadStoreContentsL(aFilename);
sl@0
   258
		
sl@0
   259
	RBuf romFilename;
sl@0
   260
	romFilename.CreateL(KMaxFilenameLength);
sl@0
   261
	CleanupClosePushL(romFilename);
sl@0
   262
	FileUtils::MakePrivateROMFilenameL(iFs, KCertAppsFile, romFilename);
sl@0
   263
	CDir* filenameList = NULL;
sl@0
   264
	User::LeaveIfError(iFs.GetDir(romFilename, KEntryAttNormal, ESortByName|EDescending, filenameList));
sl@0
   265
	CleanupStack::PopAndDestroy(&romFilename);
sl@0
   266
	CleanupStack::PushL(filenameList);
sl@0
   267
	TInt count = filenameList->Count();
sl@0
   268
	
sl@0
   269
	// aggregate ROM stores iteratively 
sl@0
   270
	for(TInt index = 0; index < count; index++)		
sl@0
   271
		{
sl@0
   272
		RBuf fileName;
sl@0
   273
		fileName.CreateL(KMaxFileName);
sl@0
   274
		CleanupClosePushL(fileName);	
sl@0
   275
		FileUtils::MakePrivateROMFilenameL(iFs, ((*filenameList)[index]).iName, fileName);
sl@0
   276
		// if there is any corrupt certstore present then we will simply ignore its
sl@0
   277
		// aggregation and proceed with aggregating remaining stores.
sl@0
   278
		TRAP_IGNORE(AggregateStoreFileL(fileName));
sl@0
   279
		CleanupStack::PopAndDestroy(&fileName);	
sl@0
   280
		}
sl@0
   281
	// write the 'iClients' to the composite store.	
sl@0
   282
	ReplaceAndCommitL(-1);	
sl@0
   283
	CleanupStack::PopAndDestroy(filenameList);
sl@0
   284
	}
sl@0
   285
sl@0
   286
// this logic should be handled by a superclass or mixin
sl@0
   287
void CFSCertAppsServer::OpenStoreL()
sl@0
   288
	{
sl@0
   289
	RBuf filename;
sl@0
   290
	filename.CreateL(KMaxFilenameLength);
sl@0
   291
	CleanupClosePushL(filename);		
sl@0
   292
	FileUtils::MakePrivateFilenameL(iFs, KCertAppsFilename, filename);
sl@0
   293
sl@0
   294
	// Attempt to open the store
sl@0
   295
	// need to test opening corrupt store
sl@0
   296
	TRAPD(err, ReadStoreContentsL(filename));
sl@0
   297
sl@0
   298
	if (err == KErrNoMemory || err == KErrInUse)
sl@0
   299
		{
sl@0
   300
		User::Leave(err);
sl@0
   301
		}
sl@0
   302
	
sl@0
   303
	if (err != KErrNone)
sl@0
   304
		{
sl@0
   305
		// Couldn't open RAM based store, copy from ROM	
sl@0
   306
		FileUtils::EnsurePathL(iFs, filename);		
sl@0
   307
	
sl@0
   308
		if(iPatchableConst)
sl@0
   309
			{
sl@0
   310
			OpenCompositeStoreL(filename);
sl@0
   311
			}
sl@0
   312
		else
sl@0
   313
			{
sl@0
   314
			RBuf romFilename;
sl@0
   315
			romFilename.CreateL(KMaxFilenameLength);
sl@0
   316
			CleanupClosePushL(romFilename);			
sl@0
   317
			FileUtils::MakePrivateROMFilenameL(iFs, KCertAppsFilename, romFilename);
sl@0
   318
			
sl@0
   319
			if (FileUtils::ExistsL(iFs, romFilename))
sl@0
   320
				{
sl@0
   321
				FileUtils::CopyL(iFs, romFilename, filename);
sl@0
   322
				}
sl@0
   323
			else
sl@0
   324
				{
sl@0
   325
				CreateStoreL(filename);
sl@0
   326
				}
sl@0
   327
			CleanupStack::PopAndDestroy(&romFilename);
sl@0
   328
			//Retry open, and leave on failure
sl@0
   329
			ReadStoreContentsL(filename);			
sl@0
   330
			}
sl@0
   331
		}
sl@0
   332
	CleanupStack::PopAndDestroy(&filename);
sl@0
   333
	ASSERT(iStore);
sl@0
   334
	}
sl@0
   335
sl@0
   336
void CFSCertAppsServer::ReadStoreContentsL(const TDesC& aFilename)
sl@0
   337
	{
sl@0
   338
	// Make sure the store is not read-only
sl@0
   339
	User::LeaveIfError(iFs.SetAtt(aFilename, KEntryAttNormal, KEntryAttReadOnly));
sl@0
   340
sl@0
   341
	RFile file;
sl@0
   342
	User::LeaveIfError(file.Open(iFs, aFilename, EFileRead | EFileWrite));
sl@0
   343
	CleanupClosePushL(file);
sl@0
   344
	CPermanentFileStore* store = CPermanentFileStore::FromL(file);
sl@0
   345
	CleanupStack::Pop(&file);
sl@0
   346
	CleanupStack::PushL(store);
sl@0
   347
sl@0
   348
	// now read the root stream to get the id of our main stream
sl@0
   349
	RStoreReadStream readStream;
sl@0
   350
	readStream.OpenLC(*store, store->Root());
sl@0
   351
	readStream >> iId;	// This can leave
sl@0
   352
	CleanupStack::PopAndDestroy(&readStream);
sl@0
   353
sl@0
   354
	// finally, restore the stream which contains the client arrays.
sl@0
   355
	// First long is the number of entries, then each entry 
sl@0
   356
	readStream.OpenLC(*store, iId);
sl@0
   357
	TInt count = readStream.ReadInt32L();
sl@0
   358
	for (TInt i = 0; i < count; ++i)
sl@0
   359
		{
sl@0
   360
		TCertificateAppInfo clientInfo;
sl@0
   361
		readStream >> clientInfo;
sl@0
   362
		User::LeaveIfError(iClients.Append(clientInfo));
sl@0
   363
		}
sl@0
   364
	CleanupStack::PopAndDestroy(&readStream);
sl@0
   365
sl@0
   366
	ASSERT(!iStore);
sl@0
   367
	iStore = store;
sl@0
   368
	CleanupStack::Pop(store);
sl@0
   369
	}
sl@0
   370
sl@0
   371
void CFSCertAppsServer::CreateStoreL(const TDesC& aFilename)
sl@0
   372
	{
sl@0
   373
	// If for some reason we can't complete the creation of the store, we want
sl@0
   374
	// to be sure that we don't leave a half-constructed store on the device
sl@0
   375
	// as we will then be in trouble when we try to open the store
sl@0
   376
	TCleanupItem deleteStoreFile(DeleteStoreFile, this);
sl@0
   377
	CleanupStack::PushL(deleteStoreFile);
sl@0
   378
sl@0
   379
	iFs.Delete(aFilename); // ignore errors
sl@0
   380
sl@0
   381
	RFile file;
sl@0
   382
	User::LeaveIfError(file.Create(iFs, aFilename, EFileWrite));
sl@0
   383
	CleanupClosePushL(file);
sl@0
   384
	
sl@0
   385
	CPermanentFileStore* store = CPermanentFileStore::NewL(file);
sl@0
   386
	CleanupStack::Pop(&file); // now owned by store
sl@0
   387
	CleanupStack::PushL(store);
sl@0
   388
	store->SetTypeL(KPermanentFileStoreLayoutUid);
sl@0
   389
sl@0
   390
	RStoreWriteStream clientsStream;
sl@0
   391
	TStreamId id = clientsStream.CreateLC(*store);
sl@0
   392
	WriteClientArrayL(clientsStream);
sl@0
   393
	CleanupStack::PopAndDestroy(&clientsStream);
sl@0
   394
sl@0
   395
	RStoreWriteStream rootStream;
sl@0
   396
	TStreamId rootId = rootStream.CreateLC(*store);
sl@0
   397
	rootStream << id;
sl@0
   398
	rootStream.CommitL();
sl@0
   399
	CleanupStack::PopAndDestroy(&rootStream);
sl@0
   400
sl@0
   401
	store->SetRootL(rootId);
sl@0
   402
	store->CommitL();
sl@0
   403
sl@0
   404
	CleanupStack::PopAndDestroy(store);
sl@0
   405
	CleanupStack::Pop(); // deleteStoreFile
sl@0
   406
	}
sl@0
   407
sl@0
   408
void CFSCertAppsServer::RevertStore(TAny* aStore)
sl@0
   409
	{
sl@0
   410
	// this is a CleanupItem
sl@0
   411
	__ASSERT_DEBUG(aStore, PanicServer(EPanicNotInitialised));
sl@0
   412
sl@0
   413
	CPermanentFileStore* store = reinterpret_cast<CPermanentFileStore *>(aStore);
sl@0
   414
	store->Revert();
sl@0
   415
	}
sl@0
   416
sl@0
   417
void CFSCertAppsServer::DeleteStoreFile(TAny *aThis)
sl@0
   418
	{
sl@0
   419
	__ASSERT_DEBUG(aThis, PanicServer(EPanicNotInitialised));
sl@0
   420
sl@0
   421
	// should call non-static member
sl@0
   422
	
sl@0
   423
	CFSCertAppsServer* self = reinterpret_cast<CFSCertAppsServer*>(aThis);
sl@0
   424
sl@0
   425
	// Something strange has occurred if we can't get the ramStorePath.
sl@0
   426
	// Since we can't leave we have to ignore the error
sl@0
   427
	TFileName ramStorePath;
sl@0
   428
	TRAPD(err, FileUtils::MakePrivateFilenameL(self->iFs, KCertAppsFilename, ramStorePath));
sl@0
   429
	if (!err)
sl@0
   430
		{
sl@0
   431
		self->iFs.Delete(ramStorePath);
sl@0
   432
		}
sl@0
   433
	}
sl@0
   434
sl@0
   435
void CFSCertAppsServer::ReplaceAndCommitL(TInt aExcludedIndex)
sl@0
   436
	{
sl@0
   437
	TCleanupItem cleanupStore(RevertStore, iStore);
sl@0
   438
	CleanupStack::PushL(cleanupStore);
sl@0
   439
sl@0
   440
	// compact the store 
sl@0
   441
	iStore->ReclaimL(); // do we need to reclaim
sl@0
   442
	iStore->CompactL();
sl@0
   443
sl@0
   444
	RStoreWriteStream outputStream;
sl@0
   445
	outputStream.ReplaceLC(*iStore, iId);
sl@0
   446
sl@0
   447
	WriteClientArrayL(outputStream, aExcludedIndex);
sl@0
   448
sl@0
   449
	CleanupStack::PopAndDestroy(&outputStream);
sl@0
   450
	iStore->CommitL();
sl@0
   451
	CleanupStack::Pop(); // cleanupStore
sl@0
   452
	}
sl@0
   453
sl@0
   454
void CFSCertAppsServer::WriteClientArrayL(RWriteStream& stream, TInt aExcludedIndex) const
sl@0
   455
	{
sl@0
   456
	// the count of elements to be written is the arraycount - 1 if we exclude 
sl@0
   457
	// something, otherwise the arraycount
sl@0
   458
	TInt arrayEnd = iClients.Count();
sl@0
   459
	TInt count = (aExcludedIndex < 0) ? (arrayEnd) : (arrayEnd - 1);
sl@0
   460
sl@0
   461
	stream.WriteInt32L(count);
sl@0
   462
sl@0
   463
	for (TInt i = 0; i < arrayEnd; ++i)
sl@0
   464
		{
sl@0
   465
		if (i != aExcludedIndex)
sl@0
   466
			{
sl@0
   467
			stream << iClients[i];	// This can leave
sl@0
   468
			}
sl@0
   469
		}
sl@0
   470
	stream.CommitL();
sl@0
   471
	}