os/security/cryptoservices/filebasedcertificateandkeystores/source/certapps/server/CFSCertAppsServer.cpp
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/security/cryptoservices/filebasedcertificateandkeystores/source/certapps/server/CFSCertAppsServer.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,471 @@
1.4 +/*
1.5 +* Copyright (c) 2002-2010 Nokia Corporation and/or its subsidiary(-ies).
1.6 +* All rights reserved.
1.7 +* This component and the accompanying materials are made available
1.8 +* under the terms of the License "Eclipse Public License v1.0"
1.9 +* which accompanies this distribution, and is available
1.10 +* at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.11 +*
1.12 +* Initial Contributors:
1.13 +* Nokia Corporation - initial contribution.
1.14 +*
1.15 +* Contributors:
1.16 +*
1.17 +* Description:
1.18 +*
1.19 +*/
1.20 +
1.21 +
1.22 +#include "CFSCertAppsServer.h"
1.23 +#include "CCertAppsSession.h"
1.24 +#include "CCertAppsConduit.h"
1.25 +#include "fstokencliserv.h"
1.26 +#include "fstokenutil.h"
1.27 +
1.28 +#include <certstorepatchdata.h>
1.29 +#include <certificateapps.h>
1.30 +#include <u32hal.h>
1.31 +#include <e32svr.h>
1.32 +
1.33 +// Filename where all data is stored
1.34 +_LIT(KCertAppsFilename,"certclients.dat");
1.35 +_LIT(KCertAppsFile,"certclients*.dat");
1.36 +
1.37 +CFSCertAppsServer* CFSCertAppsServer::NewL()
1.38 + {
1.39 + CFSCertAppsServer* self = new (ELeave) CFSCertAppsServer();
1.40 + CleanupStack::PushL(self);
1.41 + self->ConstructL();
1.42 + CleanupStack::Pop(self);
1.43 + return self;
1.44 + }
1.45 +
1.46 +CFSCertAppsServer::CFSCertAppsServer()
1.47 + {
1.48 + }
1.49 +
1.50 +void CFSCertAppsServer::ConstructL()
1.51 + {
1.52 + iConduit = CCertAppsConduit::NewL(*this);
1.53 +
1.54 + // Connect to the filesystem
1.55 + User::LeaveIfError(iFs.Connect());
1.56 +
1.57 + iPatchableConst = KAggregateCertStore;
1.58 +
1.59 + #ifdef __WINS__
1.60 + // For the emulator allow the constant to be patched via epoc.ini
1.61 + UserSvr::HalFunction(EHalGroupEmulator, EEmulatorHalIntProperty,
1.62 + (TAny*)"KAggregateCertStore", &iPatchableConst); // read emulator property (if present)
1.63 + #endif
1.64 +
1.65 + // Retrieves the store
1.66 + OpenStoreL();
1.67 + }
1.68 +
1.69 +CFSCertAppsServer::~CFSCertAppsServer()
1.70 + {
1.71 + delete iStore;
1.72 + iFs.Close();
1.73 + iClients.Close();
1.74 + delete iConduit;
1.75 + }
1.76 +
1.77 +CCertAppsSession* CFSCertAppsServer::CreateSessionL()
1.78 + {
1.79 + return CCertAppsSession::NewL(*iConduit);
1.80 + }
1.81 +
1.82 +void CFSCertAppsServer::AddL(const TCertificateAppInfo& aClient)
1.83 + {
1.84 + // see if application already exists. If so, then leave
1.85 +
1.86 + if (FindApplication(aClient.Id()))
1.87 + {
1.88 + User::Leave(KErrAlreadyExists);
1.89 + }
1.90 + User::LeaveIfError(iClients.Append(aClient));
1.91 + TRAPD(err, ReplaceAndCommitL(-1));
1.92 + if (err != KErrNone)
1.93 + {
1.94 + // We must remove the client from iClients if we didn't manage
1.95 + // to add it to the store
1.96 + iClients.Remove(iClients.Count() - 1);
1.97 + User::Leave(err);
1.98 + }
1.99 + }
1.100 +
1.101 +void CFSCertAppsServer::RemoveL(const TUid& aUid)
1.102 + {
1.103 + // Make sure the application for that uid exists
1.104 + TInt i;
1.105 + if (!FindApplication(aUid, &i))
1.106 + {
1.107 + User::Leave(KErrNotFound);
1.108 + }
1.109 +
1.110 + ReplaceAndCommitL(i);
1.111 +
1.112 + // We managed to remove it from the store, so we remove it from the
1.113 + // iClients array
1.114 + iClients.Remove(i);
1.115 + }
1.116 +
1.117 +TInt CFSCertAppsServer::ApplicationCountL() const
1.118 + {
1.119 + return iClients.Count();
1.120 + }
1.121 +
1.122 +void CFSCertAppsServer::ApplicationsL(RArray<TCertificateAppInfo>& aAppArray) const
1.123 + {
1.124 + // Make a copy of the array
1.125 + TInt count = iClients.Count();
1.126 +
1.127 + for (TInt i = 0; i < count; ++i)
1.128 + {
1.129 + aAppArray.AppendL(iClients[i]);
1.130 + }
1.131 + }
1.132 +
1.133 +void CFSCertAppsServer::ApplicationL(const TUid& aUid, TCertificateAppInfo& aInfo) const
1.134 + {
1.135 + const TCertificateAppInfo* app = FindApplication(aUid);
1.136 +
1.137 + // leave if not found
1.138 + if (!app)
1.139 + {
1.140 + User::Leave(KErrNotFound);
1.141 + }
1.142 +
1.143 + // make a copy and return to client
1.144 + aInfo = *app;
1.145 + }
1.146 +
1.147 +const TCertificateAppInfo* CFSCertAppsServer::FindApplication(const TUid& aUid, TInt* aIndex) const
1.148 + {
1.149 + // This helper function tries to find an application with the given
1.150 + // Uid. It returns NULL if not found. aIndex returns the index into
1.151 + // the array successful
1.152 + const TCertificateAppInfo* retVal = NULL;
1.153 + TInt end = iClients.Count();
1.154 + for (TInt i = 0; i < end; ++i)
1.155 + {
1.156 + if (iClients[i].Id() == aUid)
1.157 + {
1.158 + // check if an index is required to be returned
1.159 + if (aIndex)
1.160 + {
1.161 + *aIndex = i;
1.162 + }
1.163 + retVal = &iClients[i];
1.164 + break;
1.165 + }
1.166 + }
1.167 +
1.168 + return retVal;
1.169 + }
1.170 +
1.171 +void CFSCertAppsServer::AggregateStoreFileL(const TDesC& aFile)
1.172 + {
1.173 + ASSERT(iPatchableConst);
1.174 +
1.175 + // if patchable constant is enabled
1.176 + // 1. open read-only permanent file store on each file.
1.177 + // 2. open certificate client entry list of each store.
1.178 + // 3. aggregate the entries.
1.179 + RFile file;
1.180 + User::LeaveIfError(file.Open(iFs, aFile, EFileRead));
1.181 + CleanupClosePushL(file);
1.182 + CPermanentFileStore* store = CPermanentFileStore::FromL(file);
1.183 + // now owned by store
1.184 + CleanupStack::Pop(&file);
1.185 + CleanupStack::PushL(store);
1.186 +
1.187 + // Read id of cert list stream
1.188 + TStreamId streamId;
1.189 + RStoreReadStream stream;
1.190 + stream.OpenLC(*store, store->Root());
1.191 + stream >> streamId;
1.192 + CleanupStack::PopAndDestroy(&stream);
1.193 +
1.194 + // Read the certificate's clients entry list
1.195 + stream.OpenLC(*store, streamId);
1.196 + TInt count = stream.ReadInt32L();
1.197 + RArray<TCertificateAppInfo> entryList;
1.198 + for (TInt i = 0 ; i < count ; i++)
1.199 + {
1.200 + TCertificateAppInfo clientInfo;
1.201 + stream >> clientInfo;
1.202 + entryList.AppendL(clientInfo);
1.203 + }
1.204 + CleanupStack::PopAndDestroy(&stream);
1.205 + CleanupClosePushL(entryList);
1.206 +
1.207 + MergeCertificateEntryListL(entryList);
1.208 + // cleanup entryList and store instances.
1.209 + CleanupStack::PopAndDestroy(2,store);
1.210 + }
1.211 +
1.212 +TBool CFSCertAppsServer::FindUid(const TUid& aUid)
1.213 + {
1.214 + TInt end = iClients.Count();
1.215 + for (TInt i = 0; i < end; ++i)
1.216 + {
1.217 + if (iClients[i].Id() == aUid)
1.218 + {
1.219 + return ETrue;
1.220 + }
1.221 + }
1.222 + return EFalse;
1.223 + }
1.224 +
1.225 +void CFSCertAppsServer::MergeCertificateEntryListL(const RArray<TCertificateAppInfo>& aSourceList)
1.226 + {
1.227 + ASSERT(iPatchableConst);
1.228 +
1.229 + // if patchable constant is enabled
1.230 + TInt sourceCount = aSourceList.Count();
1.231 + for(TInt i = 0; i < sourceCount; i++)
1.232 + {
1.233 + // compare if the uid pre-exists in the composite list.
1.234 + if (!FindUid(aSourceList[i].Id()))
1.235 + {
1.236 + // Aggregation: append this entry to the composite list.
1.237 + iClients.AppendL(aSourceList[i]);
1.238 + }
1.239 + // Eclipsing: Higher order store cert client entries with same UIDs take precedence over lower order
1.240 + // store cert client entries therefore the later are not included in the composite cert client entry list.
1.241 + // Higher order store client entries are ones which are aggregated prior to other client entries.
1.242 + }
1.243 + }
1.244 +
1.245 +void CFSCertAppsServer::OpenCompositeStoreL(const TDesC& aFilename)
1.246 + {
1.247 + ASSERT(iPatchableConst);
1.248 +
1.249 + // 1. create a new empty certstore file under system drive with the name 'certclients.dat'.
1.250 + // 2. this will be the composite store and the instances 'iEntryList' and 'iStore' will be initialized with this.
1.251 + // 3. make private rom drive path where certstore files are located.
1.252 + // 4. collect the certstore file names in a list.
1.253 + // 5. make private rom drive path on each file.
1.254 + // 6. populate the composite store with certificate client entries present in rom drive certstores.
1.255 +
1.256 + // create a new empty certstore file 'certclients.dat' under system drive.
1.257 + CreateStoreL(aFilename);
1.258 + // restore permanent store on it
1.259 + // this will be the composite store after complete aggregation.
1.260 + ReadStoreContentsL(aFilename);
1.261 +
1.262 + RBuf romFilename;
1.263 + romFilename.CreateL(KMaxFilenameLength);
1.264 + CleanupClosePushL(romFilename);
1.265 + FileUtils::MakePrivateROMFilenameL(iFs, KCertAppsFile, romFilename);
1.266 + CDir* filenameList = NULL;
1.267 + User::LeaveIfError(iFs.GetDir(romFilename, KEntryAttNormal, ESortByName|EDescending, filenameList));
1.268 + CleanupStack::PopAndDestroy(&romFilename);
1.269 + CleanupStack::PushL(filenameList);
1.270 + TInt count = filenameList->Count();
1.271 +
1.272 + // aggregate ROM stores iteratively
1.273 + for(TInt index = 0; index < count; index++)
1.274 + {
1.275 + RBuf fileName;
1.276 + fileName.CreateL(KMaxFileName);
1.277 + CleanupClosePushL(fileName);
1.278 + FileUtils::MakePrivateROMFilenameL(iFs, ((*filenameList)[index]).iName, fileName);
1.279 + // if there is any corrupt certstore present then we will simply ignore its
1.280 + // aggregation and proceed with aggregating remaining stores.
1.281 + TRAP_IGNORE(AggregateStoreFileL(fileName));
1.282 + CleanupStack::PopAndDestroy(&fileName);
1.283 + }
1.284 + // write the 'iClients' to the composite store.
1.285 + ReplaceAndCommitL(-1);
1.286 + CleanupStack::PopAndDestroy(filenameList);
1.287 + }
1.288 +
1.289 +// this logic should be handled by a superclass or mixin
1.290 +void CFSCertAppsServer::OpenStoreL()
1.291 + {
1.292 + RBuf filename;
1.293 + filename.CreateL(KMaxFilenameLength);
1.294 + CleanupClosePushL(filename);
1.295 + FileUtils::MakePrivateFilenameL(iFs, KCertAppsFilename, filename);
1.296 +
1.297 + // Attempt to open the store
1.298 + // need to test opening corrupt store
1.299 + TRAPD(err, ReadStoreContentsL(filename));
1.300 +
1.301 + if (err == KErrNoMemory || err == KErrInUse)
1.302 + {
1.303 + User::Leave(err);
1.304 + }
1.305 +
1.306 + if (err != KErrNone)
1.307 + {
1.308 + // Couldn't open RAM based store, copy from ROM
1.309 + FileUtils::EnsurePathL(iFs, filename);
1.310 +
1.311 + if(iPatchableConst)
1.312 + {
1.313 + OpenCompositeStoreL(filename);
1.314 + }
1.315 + else
1.316 + {
1.317 + RBuf romFilename;
1.318 + romFilename.CreateL(KMaxFilenameLength);
1.319 + CleanupClosePushL(romFilename);
1.320 + FileUtils::MakePrivateROMFilenameL(iFs, KCertAppsFilename, romFilename);
1.321 +
1.322 + if (FileUtils::ExistsL(iFs, romFilename))
1.323 + {
1.324 + FileUtils::CopyL(iFs, romFilename, filename);
1.325 + }
1.326 + else
1.327 + {
1.328 + CreateStoreL(filename);
1.329 + }
1.330 + CleanupStack::PopAndDestroy(&romFilename);
1.331 + //Retry open, and leave on failure
1.332 + ReadStoreContentsL(filename);
1.333 + }
1.334 + }
1.335 + CleanupStack::PopAndDestroy(&filename);
1.336 + ASSERT(iStore);
1.337 + }
1.338 +
1.339 +void CFSCertAppsServer::ReadStoreContentsL(const TDesC& aFilename)
1.340 + {
1.341 + // Make sure the store is not read-only
1.342 + User::LeaveIfError(iFs.SetAtt(aFilename, KEntryAttNormal, KEntryAttReadOnly));
1.343 +
1.344 + RFile file;
1.345 + User::LeaveIfError(file.Open(iFs, aFilename, EFileRead | EFileWrite));
1.346 + CleanupClosePushL(file);
1.347 + CPermanentFileStore* store = CPermanentFileStore::FromL(file);
1.348 + CleanupStack::Pop(&file);
1.349 + CleanupStack::PushL(store);
1.350 +
1.351 + // now read the root stream to get the id of our main stream
1.352 + RStoreReadStream readStream;
1.353 + readStream.OpenLC(*store, store->Root());
1.354 + readStream >> iId; // This can leave
1.355 + CleanupStack::PopAndDestroy(&readStream);
1.356 +
1.357 + // finally, restore the stream which contains the client arrays.
1.358 + // First long is the number of entries, then each entry
1.359 + readStream.OpenLC(*store, iId);
1.360 + TInt count = readStream.ReadInt32L();
1.361 + for (TInt i = 0; i < count; ++i)
1.362 + {
1.363 + TCertificateAppInfo clientInfo;
1.364 + readStream >> clientInfo;
1.365 + User::LeaveIfError(iClients.Append(clientInfo));
1.366 + }
1.367 + CleanupStack::PopAndDestroy(&readStream);
1.368 +
1.369 + ASSERT(!iStore);
1.370 + iStore = store;
1.371 + CleanupStack::Pop(store);
1.372 + }
1.373 +
1.374 +void CFSCertAppsServer::CreateStoreL(const TDesC& aFilename)
1.375 + {
1.376 + // If for some reason we can't complete the creation of the store, we want
1.377 + // to be sure that we don't leave a half-constructed store on the device
1.378 + // as we will then be in trouble when we try to open the store
1.379 + TCleanupItem deleteStoreFile(DeleteStoreFile, this);
1.380 + CleanupStack::PushL(deleteStoreFile);
1.381 +
1.382 + iFs.Delete(aFilename); // ignore errors
1.383 +
1.384 + RFile file;
1.385 + User::LeaveIfError(file.Create(iFs, aFilename, EFileWrite));
1.386 + CleanupClosePushL(file);
1.387 +
1.388 + CPermanentFileStore* store = CPermanentFileStore::NewL(file);
1.389 + CleanupStack::Pop(&file); // now owned by store
1.390 + CleanupStack::PushL(store);
1.391 + store->SetTypeL(KPermanentFileStoreLayoutUid);
1.392 +
1.393 + RStoreWriteStream clientsStream;
1.394 + TStreamId id = clientsStream.CreateLC(*store);
1.395 + WriteClientArrayL(clientsStream);
1.396 + CleanupStack::PopAndDestroy(&clientsStream);
1.397 +
1.398 + RStoreWriteStream rootStream;
1.399 + TStreamId rootId = rootStream.CreateLC(*store);
1.400 + rootStream << id;
1.401 + rootStream.CommitL();
1.402 + CleanupStack::PopAndDestroy(&rootStream);
1.403 +
1.404 + store->SetRootL(rootId);
1.405 + store->CommitL();
1.406 +
1.407 + CleanupStack::PopAndDestroy(store);
1.408 + CleanupStack::Pop(); // deleteStoreFile
1.409 + }
1.410 +
1.411 +void CFSCertAppsServer::RevertStore(TAny* aStore)
1.412 + {
1.413 + // this is a CleanupItem
1.414 + __ASSERT_DEBUG(aStore, PanicServer(EPanicNotInitialised));
1.415 +
1.416 + CPermanentFileStore* store = reinterpret_cast<CPermanentFileStore *>(aStore);
1.417 + store->Revert();
1.418 + }
1.419 +
1.420 +void CFSCertAppsServer::DeleteStoreFile(TAny *aThis)
1.421 + {
1.422 + __ASSERT_DEBUG(aThis, PanicServer(EPanicNotInitialised));
1.423 +
1.424 + // should call non-static member
1.425 +
1.426 + CFSCertAppsServer* self = reinterpret_cast<CFSCertAppsServer*>(aThis);
1.427 +
1.428 + // Something strange has occurred if we can't get the ramStorePath.
1.429 + // Since we can't leave we have to ignore the error
1.430 + TFileName ramStorePath;
1.431 + TRAPD(err, FileUtils::MakePrivateFilenameL(self->iFs, KCertAppsFilename, ramStorePath));
1.432 + if (!err)
1.433 + {
1.434 + self->iFs.Delete(ramStorePath);
1.435 + }
1.436 + }
1.437 +
1.438 +void CFSCertAppsServer::ReplaceAndCommitL(TInt aExcludedIndex)
1.439 + {
1.440 + TCleanupItem cleanupStore(RevertStore, iStore);
1.441 + CleanupStack::PushL(cleanupStore);
1.442 +
1.443 + // compact the store
1.444 + iStore->ReclaimL(); // do we need to reclaim
1.445 + iStore->CompactL();
1.446 +
1.447 + RStoreWriteStream outputStream;
1.448 + outputStream.ReplaceLC(*iStore, iId);
1.449 +
1.450 + WriteClientArrayL(outputStream, aExcludedIndex);
1.451 +
1.452 + CleanupStack::PopAndDestroy(&outputStream);
1.453 + iStore->CommitL();
1.454 + CleanupStack::Pop(); // cleanupStore
1.455 + }
1.456 +
1.457 +void CFSCertAppsServer::WriteClientArrayL(RWriteStream& stream, TInt aExcludedIndex) const
1.458 + {
1.459 + // the count of elements to be written is the arraycount - 1 if we exclude
1.460 + // something, otherwise the arraycount
1.461 + TInt arrayEnd = iClients.Count();
1.462 + TInt count = (aExcludedIndex < 0) ? (arrayEnd) : (arrayEnd - 1);
1.463 +
1.464 + stream.WriteInt32L(count);
1.465 +
1.466 + for (TInt i = 0; i < arrayEnd; ++i)
1.467 + {
1.468 + if (i != aExcludedIndex)
1.469 + {
1.470 + stream << iClients[i]; // This can leave
1.471 + }
1.472 + }
1.473 + stream.CommitL();
1.474 + }