os/security/cryptoservices/filebasedcertificateandkeystores/source/certapps/server/CFSCertAppsServer.cpp
Update contrib.
2 * Copyright (c) 2002-2010 Nokia Corporation and/or its subsidiary(-ies).
4 * This component and the accompanying materials are made available
5 * under the terms of the License "Eclipse Public License v1.0"
6 * which accompanies this distribution, and is available
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
9 * Initial Contributors:
10 * Nokia Corporation - initial contribution.
19 #include "CFSCertAppsServer.h"
20 #include "CCertAppsSession.h"
21 #include "CCertAppsConduit.h"
22 #include "fstokencliserv.h"
23 #include "fstokenutil.h"
25 #include <certstorepatchdata.h>
26 #include <certificateapps.h>
30 // Filename where all data is stored
31 _LIT(KCertAppsFilename,"certclients.dat");
32 _LIT(KCertAppsFile,"certclients*.dat");
34 CFSCertAppsServer* CFSCertAppsServer::NewL()
36 CFSCertAppsServer* self = new (ELeave) CFSCertAppsServer();
37 CleanupStack::PushL(self);
39 CleanupStack::Pop(self);
43 CFSCertAppsServer::CFSCertAppsServer()
47 void CFSCertAppsServer::ConstructL()
49 iConduit = CCertAppsConduit::NewL(*this);
51 // Connect to the filesystem
52 User::LeaveIfError(iFs.Connect());
54 iPatchableConst = KAggregateCertStore;
57 // For the emulator allow the constant to be patched via epoc.ini
58 UserSvr::HalFunction(EHalGroupEmulator, EEmulatorHalIntProperty,
59 (TAny*)"KAggregateCertStore", &iPatchableConst); // read emulator property (if present)
62 // Retrieves the store
66 CFSCertAppsServer::~CFSCertAppsServer()
74 CCertAppsSession* CFSCertAppsServer::CreateSessionL()
76 return CCertAppsSession::NewL(*iConduit);
79 void CFSCertAppsServer::AddL(const TCertificateAppInfo& aClient)
81 // see if application already exists. If so, then leave
83 if (FindApplication(aClient.Id()))
85 User::Leave(KErrAlreadyExists);
87 User::LeaveIfError(iClients.Append(aClient));
88 TRAPD(err, ReplaceAndCommitL(-1));
91 // We must remove the client from iClients if we didn't manage
92 // to add it to the store
93 iClients.Remove(iClients.Count() - 1);
98 void CFSCertAppsServer::RemoveL(const TUid& aUid)
100 // Make sure the application for that uid exists
102 if (!FindApplication(aUid, &i))
104 User::Leave(KErrNotFound);
107 ReplaceAndCommitL(i);
109 // We managed to remove it from the store, so we remove it from the
114 TInt CFSCertAppsServer::ApplicationCountL() const
116 return iClients.Count();
119 void CFSCertAppsServer::ApplicationsL(RArray<TCertificateAppInfo>& aAppArray) const
121 // Make a copy of the array
122 TInt count = iClients.Count();
124 for (TInt i = 0; i < count; ++i)
126 aAppArray.AppendL(iClients[i]);
130 void CFSCertAppsServer::ApplicationL(const TUid& aUid, TCertificateAppInfo& aInfo) const
132 const TCertificateAppInfo* app = FindApplication(aUid);
134 // leave if not found
137 User::Leave(KErrNotFound);
140 // make a copy and return to client
144 const TCertificateAppInfo* CFSCertAppsServer::FindApplication(const TUid& aUid, TInt* aIndex) const
146 // This helper function tries to find an application with the given
147 // Uid. It returns NULL if not found. aIndex returns the index into
148 // the array successful
149 const TCertificateAppInfo* retVal = NULL;
150 TInt end = iClients.Count();
151 for (TInt i = 0; i < end; ++i)
153 if (iClients[i].Id() == aUid)
155 // check if an index is required to be returned
160 retVal = &iClients[i];
168 void CFSCertAppsServer::AggregateStoreFileL(const TDesC& aFile)
170 ASSERT(iPatchableConst);
172 // if patchable constant is enabled
173 // 1. open read-only permanent file store on each file.
174 // 2. open certificate client entry list of each store.
175 // 3. aggregate the entries.
177 User::LeaveIfError(file.Open(iFs, aFile, EFileRead));
178 CleanupClosePushL(file);
179 CPermanentFileStore* store = CPermanentFileStore::FromL(file);
180 // now owned by store
181 CleanupStack::Pop(&file);
182 CleanupStack::PushL(store);
184 // Read id of cert list stream
186 RStoreReadStream stream;
187 stream.OpenLC(*store, store->Root());
189 CleanupStack::PopAndDestroy(&stream);
191 // Read the certificate's clients entry list
192 stream.OpenLC(*store, streamId);
193 TInt count = stream.ReadInt32L();
194 RArray<TCertificateAppInfo> entryList;
195 for (TInt i = 0 ; i < count ; i++)
197 TCertificateAppInfo clientInfo;
198 stream >> clientInfo;
199 entryList.AppendL(clientInfo);
201 CleanupStack::PopAndDestroy(&stream);
202 CleanupClosePushL(entryList);
204 MergeCertificateEntryListL(entryList);
205 // cleanup entryList and store instances.
206 CleanupStack::PopAndDestroy(2,store);
209 TBool CFSCertAppsServer::FindUid(const TUid& aUid)
211 TInt end = iClients.Count();
212 for (TInt i = 0; i < end; ++i)
214 if (iClients[i].Id() == aUid)
222 void CFSCertAppsServer::MergeCertificateEntryListL(const RArray<TCertificateAppInfo>& aSourceList)
224 ASSERT(iPatchableConst);
226 // if patchable constant is enabled
227 TInt sourceCount = aSourceList.Count();
228 for(TInt i = 0; i < sourceCount; i++)
230 // compare if the uid pre-exists in the composite list.
231 if (!FindUid(aSourceList[i].Id()))
233 // Aggregation: append this entry to the composite list.
234 iClients.AppendL(aSourceList[i]);
236 // Eclipsing: Higher order store cert client entries with same UIDs take precedence over lower order
237 // store cert client entries therefore the later are not included in the composite cert client entry list.
238 // Higher order store client entries are ones which are aggregated prior to other client entries.
242 void CFSCertAppsServer::OpenCompositeStoreL(const TDesC& aFilename)
244 ASSERT(iPatchableConst);
246 // 1. create a new empty certstore file under system drive with the name 'certclients.dat'.
247 // 2. this will be the composite store and the instances 'iEntryList' and 'iStore' will be initialized with this.
248 // 3. make private rom drive path where certstore files are located.
249 // 4. collect the certstore file names in a list.
250 // 5. make private rom drive path on each file.
251 // 6. populate the composite store with certificate client entries present in rom drive certstores.
253 // create a new empty certstore file 'certclients.dat' under system drive.
254 CreateStoreL(aFilename);
255 // restore permanent store on it
256 // this will be the composite store after complete aggregation.
257 ReadStoreContentsL(aFilename);
260 romFilename.CreateL(KMaxFilenameLength);
261 CleanupClosePushL(romFilename);
262 FileUtils::MakePrivateROMFilenameL(iFs, KCertAppsFile, romFilename);
263 CDir* filenameList = NULL;
264 User::LeaveIfError(iFs.GetDir(romFilename, KEntryAttNormal, ESortByName|EDescending, filenameList));
265 CleanupStack::PopAndDestroy(&romFilename);
266 CleanupStack::PushL(filenameList);
267 TInt count = filenameList->Count();
269 // aggregate ROM stores iteratively
270 for(TInt index = 0; index < count; index++)
273 fileName.CreateL(KMaxFileName);
274 CleanupClosePushL(fileName);
275 FileUtils::MakePrivateROMFilenameL(iFs, ((*filenameList)[index]).iName, fileName);
276 // if there is any corrupt certstore present then we will simply ignore its
277 // aggregation and proceed with aggregating remaining stores.
278 TRAP_IGNORE(AggregateStoreFileL(fileName));
279 CleanupStack::PopAndDestroy(&fileName);
281 // write the 'iClients' to the composite store.
282 ReplaceAndCommitL(-1);
283 CleanupStack::PopAndDestroy(filenameList);
286 // this logic should be handled by a superclass or mixin
287 void CFSCertAppsServer::OpenStoreL()
290 filename.CreateL(KMaxFilenameLength);
291 CleanupClosePushL(filename);
292 FileUtils::MakePrivateFilenameL(iFs, KCertAppsFilename, filename);
294 // Attempt to open the store
295 // need to test opening corrupt store
296 TRAPD(err, ReadStoreContentsL(filename));
298 if (err == KErrNoMemory || err == KErrInUse)
305 // Couldn't open RAM based store, copy from ROM
306 FileUtils::EnsurePathL(iFs, filename);
310 OpenCompositeStoreL(filename);
315 romFilename.CreateL(KMaxFilenameLength);
316 CleanupClosePushL(romFilename);
317 FileUtils::MakePrivateROMFilenameL(iFs, KCertAppsFilename, romFilename);
319 if (FileUtils::ExistsL(iFs, romFilename))
321 FileUtils::CopyL(iFs, romFilename, filename);
325 CreateStoreL(filename);
327 CleanupStack::PopAndDestroy(&romFilename);
328 //Retry open, and leave on failure
329 ReadStoreContentsL(filename);
332 CleanupStack::PopAndDestroy(&filename);
336 void CFSCertAppsServer::ReadStoreContentsL(const TDesC& aFilename)
338 // Make sure the store is not read-only
339 User::LeaveIfError(iFs.SetAtt(aFilename, KEntryAttNormal, KEntryAttReadOnly));
342 User::LeaveIfError(file.Open(iFs, aFilename, EFileRead | EFileWrite));
343 CleanupClosePushL(file);
344 CPermanentFileStore* store = CPermanentFileStore::FromL(file);
345 CleanupStack::Pop(&file);
346 CleanupStack::PushL(store);
348 // now read the root stream to get the id of our main stream
349 RStoreReadStream readStream;
350 readStream.OpenLC(*store, store->Root());
351 readStream >> iId; // This can leave
352 CleanupStack::PopAndDestroy(&readStream);
354 // finally, restore the stream which contains the client arrays.
355 // First long is the number of entries, then each entry
356 readStream.OpenLC(*store, iId);
357 TInt count = readStream.ReadInt32L();
358 for (TInt i = 0; i < count; ++i)
360 TCertificateAppInfo clientInfo;
361 readStream >> clientInfo;
362 User::LeaveIfError(iClients.Append(clientInfo));
364 CleanupStack::PopAndDestroy(&readStream);
368 CleanupStack::Pop(store);
371 void CFSCertAppsServer::CreateStoreL(const TDesC& aFilename)
373 // If for some reason we can't complete the creation of the store, we want
374 // to be sure that we don't leave a half-constructed store on the device
375 // as we will then be in trouble when we try to open the store
376 TCleanupItem deleteStoreFile(DeleteStoreFile, this);
377 CleanupStack::PushL(deleteStoreFile);
379 iFs.Delete(aFilename); // ignore errors
382 User::LeaveIfError(file.Create(iFs, aFilename, EFileWrite));
383 CleanupClosePushL(file);
385 CPermanentFileStore* store = CPermanentFileStore::NewL(file);
386 CleanupStack::Pop(&file); // now owned by store
387 CleanupStack::PushL(store);
388 store->SetTypeL(KPermanentFileStoreLayoutUid);
390 RStoreWriteStream clientsStream;
391 TStreamId id = clientsStream.CreateLC(*store);
392 WriteClientArrayL(clientsStream);
393 CleanupStack::PopAndDestroy(&clientsStream);
395 RStoreWriteStream rootStream;
396 TStreamId rootId = rootStream.CreateLC(*store);
398 rootStream.CommitL();
399 CleanupStack::PopAndDestroy(&rootStream);
401 store->SetRootL(rootId);
404 CleanupStack::PopAndDestroy(store);
405 CleanupStack::Pop(); // deleteStoreFile
408 void CFSCertAppsServer::RevertStore(TAny* aStore)
410 // this is a CleanupItem
411 __ASSERT_DEBUG(aStore, PanicServer(EPanicNotInitialised));
413 CPermanentFileStore* store = reinterpret_cast<CPermanentFileStore *>(aStore);
417 void CFSCertAppsServer::DeleteStoreFile(TAny *aThis)
419 __ASSERT_DEBUG(aThis, PanicServer(EPanicNotInitialised));
421 // should call non-static member
423 CFSCertAppsServer* self = reinterpret_cast<CFSCertAppsServer*>(aThis);
425 // Something strange has occurred if we can't get the ramStorePath.
426 // Since we can't leave we have to ignore the error
427 TFileName ramStorePath;
428 TRAPD(err, FileUtils::MakePrivateFilenameL(self->iFs, KCertAppsFilename, ramStorePath));
431 self->iFs.Delete(ramStorePath);
435 void CFSCertAppsServer::ReplaceAndCommitL(TInt aExcludedIndex)
437 TCleanupItem cleanupStore(RevertStore, iStore);
438 CleanupStack::PushL(cleanupStore);
441 iStore->ReclaimL(); // do we need to reclaim
444 RStoreWriteStream outputStream;
445 outputStream.ReplaceLC(*iStore, iId);
447 WriteClientArrayL(outputStream, aExcludedIndex);
449 CleanupStack::PopAndDestroy(&outputStream);
451 CleanupStack::Pop(); // cleanupStore
454 void CFSCertAppsServer::WriteClientArrayL(RWriteStream& stream, TInt aExcludedIndex) const
456 // the count of elements to be written is the arraycount - 1 if we exclude
457 // something, otherwise the arraycount
458 TInt arrayEnd = iClients.Count();
459 TInt count = (aExcludedIndex < 0) ? (arrayEnd) : (arrayEnd - 1);
461 stream.WriteInt32L(count);
463 for (TInt i = 0; i < arrayEnd; ++i)
465 if (i != aExcludedIndex)
467 stream << iClients[i]; // This can leave