diff -r 000000000000 -r 164170e6151a pkiutilities/DeviceToken/Src/KeyStore/Server/DevCertKeyDataManager.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkiutilities/DeviceToken/Src/KeyStore/Server/DevCertKeyDataManager.cpp Tue Jan 26 15:20:08 2010 +0200 @@ -0,0 +1,693 @@ +/* +* Copyright (c) 2006 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 DevCertKeyDataManager +* +*/ + + + +#include "DevCertKeyDataManager.h" +#include "DevTokenDataTypes.h" +#include "DevTokenCliServ.h" +#include "DevTokenUtil.h" + +_LIT(KDevCertKeyStoreFilename,"DevCertKeys.dat"); + + +// ======== MEMBER FUNCTIONS ======== + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager::NewL() +// Key store data manager - maintains array of objects representing keys +// --------------------------------------------------------------------------- +// +CDevCertKeyDataManager* CDevCertKeyDataManager::NewL() + { + CDevCertKeyDataManager* self = new (ELeave) CDevCertKeyDataManager(); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager::~CDevCertKeyDataManager() +// --------------------------------------------------------------------------- +// +CDevCertKeyDataManager::~CDevCertKeyDataManager() + { + if (iFileStore) + { + CompactStore(); + delete iFileStore; + } + + iFile.Close(); // May already have been closed by store + iFs.Close(); + + iKeys.ResetAndDestroy(); + iKeys.Close(); + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager::CDevCertKeyDataManager() +// --------------------------------------------------------------------------- +// +CDevCertKeyDataManager::CDevCertKeyDataManager() : + iRootStreamId(KNullStreamId), + iInfoStreamId(KNullStreamId) + { + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager::ConstructL() +// --------------------------------------------------------------------------- +// +void CDevCertKeyDataManager::ConstructL() + { + User::LeaveIfError(iFs.Connect()); + OpenStoreL(); + + RStoreReadStream lookupStream; + lookupStream.OpenLC(*iFileStore, iInfoStreamId); + + TInt count = lookupStream.ReadInt32L(); + for (TInt index = 0; index < count; index++) + { + const CDevCertKeyData* keyData = CDevCertKeyData::NewL(lookupStream); + + if (keyData->Handle() > iKeyIdentifier) + iKeyIdentifier = keyData->Handle(); + + iKeys.Append(keyData); + } + + CleanupStack::PopAndDestroy(&lookupStream); + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager::OpenStoreL() +// --------------------------------------------------------------------------- +// +void CDevCertKeyDataManager::OpenStoreL() + { + // Tries to locate a key store file on the default drive and then from ROM + // If it cannot find one, tries to create a file with permanent file store + // inside it In all cases, should initialise iFileStore unless it cannot + // create the file/store/streams + + __ASSERT_DEBUG(!iFileStore, PanicServer(EPanicStoreInitialised)); + + TFileName fullPath; + FileUtils::MakePrivateFilenameL(iFs, KDevCertKeyStoreFilename, fullPath); + + FileUtils::EnsurePathL(iFs, fullPath); + TRAPD(result, OpenStoreInFileL(fullPath)); + + if (result == KErrInUse) + { + // Cannot access the file now. Abort server startup rather than wiping the keystore. + User::Leave(result); + } + + if (result != KErrNone) + { + // Not yet opened a valid store, either no file to be found, or no valid + // store in it. Copy the original one stored in the ROM. + delete iFileStore; + iFileStore = NULL; + + TFileName romPath; + FileUtils::MakePrivateROMFilenameL(iFs, KDevCertKeyStoreFilename, romPath); + + if (result != KErrNotFound) + { + // Wipe the keystore if we can't open it (it's corrupt anyway) + User::LeaveIfError(iFs.Delete(fullPath)); + } + + // Copy data from rom and open it + TRAPD(err, + FileUtils::CopyL(iFs, romPath, fullPath); + OpenStoreInFileL(fullPath) + ); + + if (KErrNone != err) + { + // We tried to copy the keystore from ROM. For some reason this + // failed and we still cannot open the file. Create a new one from + // scratch. + CreateStoreInFileL(fullPath); + } + } + + __ASSERT_DEBUG(iFileStore, PanicServer(EPanicStoreInitialised)); + __ASSERT_DEBUG((KNullStreamId!=iRootStreamId), PanicServer(EPanicRootStreamNotReady)); + __ASSERT_DEBUG((KNullStreamId!=iInfoStreamId), PanicServer(EPanicManagerStreamNotReady)); + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager::CreateStoreInFileL() +// --------------------------------------------------------------------------- +// +void CDevCertKeyDataManager::CreateStoreInFileL(const TDesC& aFile) + { + TInt r = iFs.MkDirAll(aFile); + if ( (r!=KErrNone) && (r!=KErrAlreadyExists) ) + User::Leave(r); + + iFileStore = CPermanentFileStore::ReplaceL(iFs, aFile, EFileRead | EFileWrite | EFileShareExclusive); + iFileStore->SetTypeL(KPermanentFileStoreLayoutUid); + + TCleanupItem cleanupStore(RevertStore, iFileStore); + CleanupStack::PushL(cleanupStore); + + // Create info stream - Currently no passphrase created, and no keys + RStoreWriteStream managerStream; + iInfoStreamId = managerStream.CreateLC(*iFileStore); + managerStream.WriteUint32L(0); // Write key count of zero + managerStream.CommitL(); + CleanupStack::PopAndDestroy(&managerStream); + + // Create root stream - just contains id of info stream + RStoreWriteStream rootStream; + iRootStreamId = rootStream.CreateLC(*iFileStore); + iFileStore->SetRootL(iRootStreamId); + rootStream.WriteUint32L(iInfoStreamId.Value()); + rootStream.CommitL(); + CleanupStack::PopAndDestroy(&rootStream); + + WriteKeysToStoreL(); + + iFileStore->CommitL(); + CleanupStack::Pop(); // cleanupStore + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager::OpenStoreInFileL() +// --------------------------------------------------------------------------- +// +void CDevCertKeyDataManager::OpenStoreInFileL(const TDesC& aFile) + { + // Make sure the file isn't write protected + User::LeaveIfError(iFs.SetAtt(aFile, 0, KEntryAttReadOnly)); + + User::LeaveIfError(iFile.Open(iFs, aFile, EFileRead | EFileWrite | EFileShareExclusive)); + + iFileStore = CPermanentFileStore::FromL(iFile); + + // Get the salt, root and manager TStreamIds + iRootStreamId = iFileStore->Root(); + if (iRootStreamId == KNullStreamId) + { + User::Leave(KErrCorrupt); + } + + RStoreReadStream rootStream; + rootStream.OpenLC(*iFileStore, iRootStreamId); + iInfoStreamId = (TStreamId)(rootStream.ReadUint32L()); + CleanupStack::PopAndDestroy(&rootStream); + } + + +// Methods dealing with atomic updates to key data file + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager::RevertStore() +// This is a cleanup item that reverts the store +// --------------------------------------------------------------------------- +// +void CDevCertKeyDataManager::RevertStore(TAny* aStore) + { + CPermanentFileStore* store = reinterpret_cast(aStore); + TRAP_IGNORE(store->RevertL()); + // We're ignoring the leave code from this becuase there's no way we can + // handle this sensibly. This shouldn't be a problem in practice - this + // will leave if for example the file store is on removable which is + // unexpectedly remove, and this is never the case for us. + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager::RevertStore() +// Rewrites the info stream (ie the array of key data info) to the store +// --------------------------------------------------------------------------- +// +void CDevCertKeyDataManager::WriteKeysToStoreL() + { + RStoreWriteStream lookupStream; + lookupStream.ReplaceLC(*iFileStore, iInfoStreamId); + + TInt keyCount = iKeys.Count(); + lookupStream.WriteInt32L(keyCount); + + for (TInt index = 0; index < keyCount; index++) + { + const CDevCertKeyData* key = iKeys[index]; + key->ExternalizeL(lookupStream); + } + + lookupStream.CommitL(); + CleanupStack::PopAndDestroy(&lookupStream); + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager::AddL() +// Add a key to the store. Assumes that the key data streams (info, public key +// and private key) have already been written. +// --------------------------------------------------------------------------- +// +void CDevCertKeyDataManager::AddL(const CDevCertKeyData* aKeyData) + { + ASSERT(aKeyData); + + // Add the key to to the array, rewrite the infostream and + // ONLY THEN commit the store + User::LeaveIfError(iKeys.Append(aKeyData)); + + TRAPD(err, WriteKeysToStoreL()); + + // Release ownership of key data and reset default passphrase id if store + // can't be written + TCleanupItem cleanupStore(RevertStore, iFileStore); + CleanupStack::PushL(cleanupStore); + + if (err != KErrNone) + { + iKeys.Remove(iKeys.Count() - 1); + User::Leave(err); + } + + iFileStore->CommitL(); + + CleanupStack::Pop(); // cleanupStore + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager::RemoveL() +// "Transaction safe" key removal - only removes the key in memory and file if +// all operations are successful. +// --------------------------------------------------------------------------- +// +void CDevCertKeyDataManager::RemoveL(TInt aObjectId) + { + TInt index; + const CDevCertKeyData* key = NULL; + for (index = 0 ; index < iKeys.Count() ; ++index) + { + if (iKeys[index]->Handle() == aObjectId) + { + key = iKeys[index]; + break; + } + } + + if (!key) + { + User::Leave(KErrNotFound); + } + + TCleanupItem cleanupStore(RevertStore, iFileStore); + CleanupStack::PushL(cleanupStore); + + iFileStore->DeleteL(key->PrivateDataStreamId()); + iFileStore->DeleteL(key->PublicDataStreamId()); + iFileStore->DeleteL(key->InfoDataStreamId()); + + // Remove the key + iKeys.Remove(index); + + TRAPD(res, WriteKeysToStoreL()); + if (res != KErrNone) + { + User::LeaveIfError(iKeys.Append(key)); // Put it back, shouldn't leave + User::Leave(res); + } + else + { + delete key; // Cannot leave from the point it's removed to here, so no cleanup stack! + } + iFileStore->CommitL(); + + CleanupStack::Pop(); // cleanupStore + CompactStore(); + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager::IsKeyAlreadyInStore(). +// --------------------------------------------------------------------------- +// +TBool CDevCertKeyDataManager::IsKeyAlreadyInStore(const TDesC& aKeyLabel) const + {// Check each key in the store to determine if aKeyLabel already exists + TInt keyCount = iKeys.Count(); + TBool isInStore = EFalse; + for (TInt index = 0; index < keyCount; index++) + { + const TDesC& keyLabel = iKeys[index]->Label(); + if (keyLabel.Compare(aKeyLabel)==0) + { + isInStore = ETrue; + break; + } + } + + return (isInStore); + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager::Count(). +// --------------------------------------------------------------------------- +// +TInt CDevCertKeyDataManager::Count() const + { + return iKeys.Count(); + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager:::operator[](TInt aIndex) const +// --------------------------------------------------------------------------- +// +const CDevCertKeyData* CDevCertKeyDataManager::operator[](TInt aIndex) const + { + return iKeys[aIndex]; + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager:::Lookup() +// --------------------------------------------------------------------------- +// +const CDevCertKeyData* CDevCertKeyDataManager::Lookup(TInt aObjectId) const + { + TInt count = Count(); + for (TInt i = 0; i < count; ++i) + { + if ((*this)[i]->Handle() == aObjectId) + { + return (*this)[i]; + } + } + return NULL; + } + + +// Management of file and store therein + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager:::CreateKeyDataLC() +// --------------------------------------------------------------------------- +// +const CDevCertKeyData* CDevCertKeyDataManager::CreateKeyDataLC( const TDesC& aLabel ) + { + TInt objectId = ++iKeyIdentifier; + TStreamId infoData = CreateWriteStreamL(); + TStreamId publicKeyData = CreateWriteStreamL(); + TStreamId privateKeyData = CreateWriteStreamL(); + return CDevCertKeyData::NewLC(objectId, aLabel, infoData, publicKeyData, privateKeyData); + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager:::CreateWriteStreamL() +// Creates a new write stream in the store (which it then closes) +// Returns the TStreamId associated with it +// --------------------------------------------------------------------------- +// +TStreamId CDevCertKeyDataManager::CreateWriteStreamL() + { + __ASSERT_DEBUG(iFileStore, PanicServer(EPanicStoreInitialised)); + if (!iFileStore) + User::Leave(KErrNotReady); + + RStoreWriteStream newStream; + TStreamId result = newStream.CreateLC(*iFileStore); + if (KNullStreamId == result) + User::Leave(KErrBadHandle); + + newStream.CommitL(); + CleanupStack::PopAndDestroy(&newStream); + + return result; + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager:::ReadKeyInfoLC() +// --------------------------------------------------------------------------- +// +CDevTokenKeyInfo* CDevCertKeyDataManager::ReadKeyInfoLC(const CDevCertKeyData& aKeyData) const + { + __ASSERT_ALWAYS(iFileStore, PanicServer(EPanicStoreInitialised)); + RStoreReadStream stream; + stream.OpenLC(*iFileStore, aKeyData.InfoDataStreamId()); + CDevTokenKeyInfo* info = CDevTokenKeyInfo::NewL(stream); + CleanupStack::PopAndDestroy(&stream); + info->CleanupPushL(); + if (info->Handle() != aKeyData.Handle()) + { + User::Leave(KErrCorrupt); // is this appropriate? + } + return info; + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager:::WriteKeyInfoL() +// --------------------------------------------------------------------------- +// +void CDevCertKeyDataManager::WriteKeyInfoL(const CDevCertKeyData& aKeyData, const CDevTokenKeyInfo& aKeyInfo) + { + RStoreWriteStream infoStream; + OpenInfoDataStreamLC(aKeyData, infoStream); + infoStream << aKeyInfo; + infoStream.CommitL(); + CleanupStack::PopAndDestroy(&infoStream); + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager:::SafeWriteKeyInfoL() +// --------------------------------------------------------------------------- +// +void CDevCertKeyDataManager::SafeWriteKeyInfoL(const CDevCertKeyData& aKeyData, const CDevTokenKeyInfo& aKeyInfo) + { + TCleanupItem cleanupStore(RevertStore, iFileStore); + CleanupStack::PushL(cleanupStore); + + WriteKeyInfoL(aKeyData, aKeyInfo); + iFileStore->CommitL(); + + CleanupStack::Pop(); // cleanupStore + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager:::OpenInfoDataStreamLC() +// --------------------------------------------------------------------------- +// +void CDevCertKeyDataManager::OpenInfoDataStreamLC(const CDevCertKeyData& aKeyData, RStoreWriteStream& aStream) + { + __ASSERT_ALWAYS(iFileStore, PanicServer(EPanicStoreInitialised)); + aStream.ReplaceLC(*iFileStore, aKeyData.InfoDataStreamId()); + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager:::OpenPublicDataStreamLC() +// --------------------------------------------------------------------------- +// +void CDevCertKeyDataManager::OpenPublicDataStreamLC(const CDevCertKeyData& aKeyData, RStoreWriteStream& aStream) + { + __ASSERT_ALWAYS(iFileStore, PanicServer(EPanicStoreInitialised)); + aStream.ReplaceLC(*iFileStore, aKeyData.PublicDataStreamId()); + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager:::OpenPublicDataStreamLC() +// --------------------------------------------------------------------------- +// +void CDevCertKeyDataManager::OpenPublicDataStreamLC(const CDevCertKeyData& aKeyData, RStoreReadStream& aStream) const + { + __ASSERT_ALWAYS(iFileStore, PanicServer(EPanicStoreInitialised)); + aStream.OpenLC(*iFileStore, aKeyData.PublicDataStreamId()); + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager:::OpenPrivateDataStreamLC() +// --------------------------------------------------------------------------- +// +void CDevCertKeyDataManager::OpenPrivateDataStreamLC(const CDevCertKeyData& aKeyData, + RStoreWriteStream& aStream) + { + __ASSERT_DEBUG(iFileStore, PanicServer(EPanicStoreInitialised)); + aStream.ReplaceLC(*iFileStore, aKeyData.PrivateDataStreamId()); + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager:::OpenPrivateDataStreamLC() +// --------------------------------------------------------------------------- +// +void CDevCertKeyDataManager::OpenPrivateDataStreamLC(const CDevCertKeyData& aKeyData, + RStoreReadStream& aStream) + { + __ASSERT_DEBUG(iFileStore, PanicServer(EPanicStoreInitialised)); + aStream.OpenLC(*iFileStore, aKeyData.PrivateDataStreamId()); + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyDataManager:::CompactStore() +// Attempt to compact the store - it doesn't matter if these calls leave, it +// will only mean that the store takes up more space than necessary. +// --------------------------------------------------------------------------- +// +void CDevCertKeyDataManager::CompactStore() + { + ASSERT(iFileStore); + TRAP_IGNORE(iFileStore->ReclaimL(); iFileStore->CompactL()); + } + + +// CDevCertKeyData + +// --------------------------------------------------------------------------- +// CDevCertKeyData::NewLC() +// --------------------------------------------------------------------------- +// +CDevCertKeyData* CDevCertKeyData::NewLC(TInt aObjectId, const TDesC& aLabel, TStreamId aInfoData, + TStreamId aPublicData, TStreamId aPrivateData) + { + CDevCertKeyData* self = new (ELeave) CDevCertKeyData(aObjectId, aInfoData, aPublicData, aPrivateData); + CleanupStack::PushL(self); + self->ConstructL(aLabel); + return self; + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyData::NewL() +// --------------------------------------------------------------------------- +// +CDevCertKeyData* CDevCertKeyData::NewL(RStoreReadStream& aReadStream) + { + CDevCertKeyData* self = new (ELeave) CDevCertKeyData(); + CleanupStack::PushL(self); + self->InternalizeL(aReadStream); + CleanupStack::Pop(self); + return (self); + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyData::~CDevCertKeyData() +// --------------------------------------------------------------------------- +// +CDevCertKeyData::~CDevCertKeyData() + { + delete iLabel; + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyData::CDevCertKeyData() +// --------------------------------------------------------------------------- +// +CDevCertKeyData::CDevCertKeyData(TInt aObjectId, TStreamId aInfoData, + TStreamId aPublicData, TStreamId aPrivateData) : + iObjectId(aObjectId), iInfoData(aInfoData), + iPublicKeyData(aPublicData), iPrivateKeyData(aPrivateData) + { + ASSERT(iObjectId); + ASSERT(iInfoData != KNullStreamId); + ASSERT(iPublicKeyData != KNullStreamId); + ASSERT(iPrivateKeyData != KNullStreamId); + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyData::CDevCertKeyData() +// --------------------------------------------------------------------------- +// +CDevCertKeyData::CDevCertKeyData() + { + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyData::ConstructL() +// --------------------------------------------------------------------------- +// +void CDevCertKeyData::ConstructL(const TDesC& aLabel) + { + TInt labelLen = aLabel.Length(); + iLabel = HBufC::NewMaxL(labelLen); + TPtr theLabel(iLabel->Des()); + theLabel.FillZ(); + theLabel.Copy(aLabel); + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyData::InternalizeL() +// --------------------------------------------------------------------------- +// +void CDevCertKeyData::InternalizeL(RReadStream& aReadStream) + { + iObjectId = aReadStream.ReadInt32L(); + iInfoData.InternalizeL(aReadStream); + iPublicKeyData.InternalizeL(aReadStream); + iPrivateKeyData.InternalizeL(aReadStream); + + TInt labelLen = aReadStream.ReadInt32L(); + iLabel = HBufC::NewMaxL(labelLen); + TPtr theLabel((TUint16*)iLabel->Ptr(), labelLen, labelLen); + theLabel.FillZ(labelLen); + aReadStream.ReadL(theLabel); + } + + +// --------------------------------------------------------------------------- +// CDevCertKeyData::ExternalizeL() +// --------------------------------------------------------------------------- +// +void CDevCertKeyData::ExternalizeL(RWriteStream& aWriteStream) const + { + aWriteStream.WriteInt32L(iObjectId); + iInfoData.ExternalizeL(aWriteStream); + iPublicKeyData.ExternalizeL(aWriteStream); + iPrivateKeyData.ExternalizeL(aWriteStream); + + TInt labelLen = iLabel->Length(); + aWriteStream.WriteInt32L(labelLen); + TPtr theLabel(iLabel->Des()); + theLabel.SetLength(labelLen); + aWriteStream.WriteL(theLabel); + } + +//EOF +