cryptoservices/filebasedcertificateandkeystores/source/keystore/Server/Cfskeystoreserver.cpp
changeset 0 2c201484c85f
child 8 35751d3474b7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cryptoservices/filebasedcertificateandkeystores/source/keystore/Server/Cfskeystoreserver.cpp	Wed Jul 08 11:25:26 2009 +0100
@@ -0,0 +1,1305 @@
+/*
+* Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "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: 
+*
+*/
+
+
+#include "cfskeystoreserver.h"
+#include "CKeyDataManager.h"
+#include "CKeyStoreConduit.h"
+#include "CKeyStoreSession.h"
+#include "fstokencliserv.h"
+#include "CCreateKey.h"
+#include "OpenedKeys.h"
+#include "keystorepassphrase.h"
+#include "fsdatatypes.h"
+#include "keystreamutils.h"
+#include <fstokenutil.h>
+#include <asnpkcs.h>
+#include <pbedata.h>
+#include <securityerr.h>
+#include <pbe.h>
+#include <asnpkcs.h>
+#include <asn1enc.h>
+#include <x509keys.h>
+#include <keyidentifierutil.h>
+#include <mctauthobject.h>
+#include <utf.h>
+
+// We don't currently allow any keys larger than 2048 bits.  It may be necessary to
+// increase this limit in the future. 
+const TUint KTheMinKeySize = 512;
+const TUint KTheMaxKeySize = 2048;
+
+// Security policies
+_LIT_SECURITY_POLICY_C1(KSetTimeoutSecurityPolicy, ECapabilityWriteDeviceData);
+_LIT_SECURITY_POLICY_C1(KCreateSecurityPolicy, ECapabilityWriteUserData);
+_LIT_SECURITY_POLICY_C1(KListSecurityPolicy, ECapabilityReadUserData);
+
+CFSKeyStoreServer* CFSKeyStoreServer::NewL()
+	{
+	CFSKeyStoreServer* me = new (ELeave) CFSKeyStoreServer();
+	CleanupStack::PushL(me);
+	me->ConstructL();
+	CleanupStack::Pop(me);
+	return (me);
+	}
+
+CFSKeyStoreServer::CFSKeyStoreServer() :
+	CActive(EPriorityStandard),
+	iAction(EIdle),
+	iExportBuf(NULL, 0)
+	{
+	}
+
+void CFSKeyStoreServer::ConstructL()
+	{
+	iKeyDataManager = CFileKeyDataManager::NewL();
+	iConduit = CKeyStoreConduit::NewL(*this);
+	CActiveScheduler::Add(this);
+	}
+
+CFSKeyStoreServer::~CFSKeyStoreServer()
+	{
+	Cancel();
+
+	delete iKeyDataManager;
+	delete iConduit;
+	delete iKeyCreator;
+	iSessions.Close();
+	}
+
+CKeyStoreSession* CFSKeyStoreServer::CreateSessionL()
+	{
+	CPassphraseManager* passMan = iKeyDataManager->CreatePassphraseManagerLC();
+	CKeyStoreSession* session = CKeyStoreSession::NewL(*this, passMan);
+	CleanupStack::Pop(passMan);
+	CleanupStack::PushL(session);
+	User::LeaveIfError(iSessions.Append(session));
+	CleanupStack::Pop(session);
+	return session;
+	}
+
+void CFSKeyStoreServer::RemoveSession(CKeyStoreSession& aSession)
+	{
+	if (iSession == &aSession) // just in case
+		{
+		iSession = NULL; 
+		}
+	
+	for (TInt index = 0 ; index < iSessions.Count() ; ++index)
+		{
+		if (iSessions[index] == &aSession)
+			{
+			iSessions.Remove(index);
+			return;
+			}
+		}
+	User::Invariant();
+	}
+
+void CFSKeyStoreServer::ServiceRequestL(const RMessage2& aMessage, CKeyStoreSession& aSession)
+	{
+	iMessage = &aMessage;
+	iSession = &aSession;
+	iConduit->ServiceRequestL(aMessage, aSession);
+	}
+
+//	*********************************************************************************
+//	From MCTKeyStore
+//	*********************************************************************************
+void CFSKeyStoreServer::ListL(const TCTKeyAttributeFilter& aFilter,
+							  RPointerArray<CKeyInfo>& aKeys)
+	{
+	ASSERT(iMessage);
+	
+	// Check the calling process has ReadUserData capability
+	if (!KListSecurityPolicy.CheckPolicy(*iMessage))
+		{
+		User::Leave(KErrPermissionDenied);
+		}
+	
+	TInt count = iKeyDataManager->Count();
+
+	for (TInt i = 0; i < count; ++i)
+		{
+		const CFileKeyData* data = (*iKeyDataManager)[i];
+		CKeyInfo* info = iKeyDataManager->ReadKeyInfoLC(*data);
+		if (KeyMatchesFilterL(*info, aFilter))
+			{
+			User::LeaveIfError(aKeys.Append(info));
+			CleanupStack::Pop(info);
+			}
+		else
+			{
+			CleanupStack::PopAndDestroy(info);
+			}
+		}
+	}
+
+TBool CFSKeyStoreServer::KeyMatchesFilterL(const CKeyInfo& aInfo,
+										   const TCTKeyAttributeFilter& aFilter)
+	{
+	ASSERT(iMessage);
+	
+	if (aFilter.iKeyId.Length() && aFilter.iKeyId != aInfo.ID())
+		{
+		return EFalse;
+		}
+
+	if (aFilter.iUsage != EPKCS15UsageAll)
+		{
+		if ((aInfo.Usage() & aFilter.iUsage) == 0)
+			return EFalse;
+		}
+
+	if (aFilter.iKeyAlgorithm != CCTKeyInfo::EInvalidAlgorithm && 
+		aFilter.iKeyAlgorithm != aInfo.Algorithm())
+		{
+		return EFalse;
+		}
+
+	switch (aFilter.iPolicyFilter)
+		{
+		case TCTKeyAttributeFilter::EAllKeys:
+			// All keys pass
+			break;
+			   
+		case TCTKeyAttributeFilter::EUsableKeys:
+			if (!aInfo.UsePolicy().CheckPolicy(*iMessage))
+				{
+				return EFalse;
+				}
+			break;
+			
+		case TCTKeyAttributeFilter::EManageableKeys:
+			if (!aInfo.ManagementPolicy().CheckPolicy(*iMessage))
+				{
+				return EFalse;
+				}
+			break;
+
+		case TCTKeyAttributeFilter::EUsableOrManageableKeys:
+			if (!aInfo.UsePolicy().CheckPolicy(*iMessage) &&
+				!aInfo.ManagementPolicy().CheckPolicy(*iMessage))
+				{
+				return EFalse;
+				}
+			break;
+						
+		default:
+			User::Leave(KErrArgument);
+		}
+
+	return ETrue;
+	}
+
+void CFSKeyStoreServer::GetKeyInfoL(TInt aObjectId, CKeyInfo*& aInfo)
+	{
+	const CFileKeyData* keyData = iKeyDataManager->Lookup(aObjectId);
+	if (!keyData)
+		{
+		User::Leave(KErrNotFound);
+		}
+
+	CKeyInfo* result = iKeyDataManager->ReadKeyInfoLC(*keyData);
+	if (!result->UsePolicy().CheckPolicy(*iMessage))
+		{
+		User::Leave(KErrPermissionDenied);
+		}
+
+	aInfo = result;
+	CleanupStack::Pop(aInfo);
+	}
+
+TInt CFSKeyStoreServer::GetKeyLengthL(TInt aObjectId)
+	{
+	const CFileKeyData* keyData = iKeyDataManager->Lookup(aObjectId);
+	if (!keyData)
+		{
+		User::Leave(KErrNotFound);
+		}
+
+	// this could be cached in memory (would break file format though)
+	CKeyInfo* keyInfo = iKeyDataManager->ReadKeyInfoLC(*keyData);
+	TInt result = keyInfo->Size();
+	CleanupStack::PopAndDestroy(keyInfo);
+
+	return result;
+	}
+
+COpenedKey* CFSKeyStoreServer::OpenKeyL(TInt aHandle, TUid aOpenedKeyType)
+	{
+	ASSERT(iMessage);
+	
+	const CFileKeyData *keyData = iKeyDataManager->Lookup(aHandle);
+	if (!keyData)
+		{
+		User::Leave(KErrNotFound);
+		}
+
+	return COpenedKey::NewL(*keyData, aOpenedKeyType, *iMessage,
+							*iKeyDataManager, iSession->PassphraseManager());
+	}
+
+void CFSKeyStoreServer::ExportPublicL(TInt aObjectId,
+									  TDes8& aOut)
+	{
+	const CFileKeyData* keyData = iKeyDataManager->Lookup(aObjectId);
+	if (!keyData)
+		{
+		User::Leave(KErrNotFound);
+		}
+
+	CKeyInfo* keyInfo = iKeyDataManager->ReadKeyInfoLC(*keyData);
+
+	RStoreReadStream stream;
+	iKeyDataManager->OpenPublicDataStreamLC(*keyData, stream);
+
+	CKeyInfo::EKeyAlgorithm keyAlgorithm = keyInfo->Algorithm();
+	
+	switch(keyAlgorithm)
+		{
+		case (CKeyInfo::ERSA):
+			{
+			CRSAPublicKey* publicKey = NULL;
+
+			CreateL(stream, publicKey);
+			ASSERT(publicKey);
+			CleanupStack::PushL(publicKey);
+
+			TX509RSAKeyEncoder encoder(*publicKey, ESHA1);
+			CASN1EncBase* encoded = encoder.EncodeKeyLC();
+
+			if (encoded->LengthDER() > static_cast<TUint>(aOut.MaxLength()))
+				{
+				User::Leave(KErrOverflow);
+				}
+			
+			//	Get the Public key DER encoding
+			TUint pos=0;
+			encoded->WriteDERL(aOut, pos);
+			
+			// WriteDERL does not set the length of the buffer, we do it ourselves			
+			aOut.SetLength(encoded->LengthDER());			
+			
+			CleanupStack::PopAndDestroy(2, publicKey);
+			}
+		break;
+
+		case (CKeyInfo::EDSA):
+			{
+			CDSAPublicKey* publicKey = NULL;
+
+			CreateL(stream, publicKey);
+			ASSERT(publicKey);
+			CleanupStack::PushL(publicKey);
+
+			TX509DSAKeyEncoder encoder(*publicKey, ESHA1);
+			CASN1EncBase* encoded = encoder.EncodeKeyLC();
+
+			if (encoded->LengthDER() > static_cast<TUint>(aOut.MaxLength()))
+				{
+				User::Leave(KErrOverflow);
+				}
+
+			//	Get the Public key DER encoding
+			TUint pos=0;
+			encoded->WriteDERL(aOut, pos);
+			
+			// WriteDERL does not set the length of the buffer, we do it ourselves			
+			aOut.SetLength(encoded->LengthDER());						
+			
+			CleanupStack::PopAndDestroy(2, publicKey);
+			}
+		break;
+
+		case (CKeyInfo::EDH):
+		default:
+			User::Leave(KErrKeyAlgorithm);
+			break;
+	}
+
+	CleanupStack::PopAndDestroy(2, keyInfo); //stream, keyinfo
+	}
+
+//	*********************************************************************************
+//	From MCTKeyStoreManager
+//	*********************************************************************************
+
+TInt CFSKeyStoreServer::CheckKeyAttributes(CKeyInfo& aKey, TNewKeyOperation aOp)
+	{
+	ASSERT(iMessage);
+	
+	// Sort out the access rights
+	TInt access = aKey.AccessType(); 
+	
+	// Only allow sensitive and extractable to be sepcified
+	if (access & ~(CKeyInfo::ESensitive | CKeyInfo::EExtractable))
+		{
+		return KErrKeyAccess;
+		}	
+		
+	// If it's sensitive and either created internally 
+	// or imported from an encrypted source then it's always been sensitive
+	if ((access & CKeyInfo::ESensitive) &&
+		(aOp == ENewKeyCreate || aOp == ENewKeyImportEncrypted))
+		{
+		access |= CKeyInfo::EAlwaysSensitive;		
+		}
+		
+	// If it's not extractable and it's created internally
+	// then it's never been extractable
+	if ((!(access & CKeyInfo::EExtractable)) && aOp == ENewKeyCreate)
+		{
+		access |= CKeyInfo::ENeverExtractable;		
+		}
+		
+	aKey.SetAccessType(access);
+	
+	// check management policy allows the calling process to manage the key
+	if (!aKey.ManagementPolicy().CheckPolicy(*iMessage))
+		{
+		return KErrArgument;
+		}
+
+	// check end date is not in the past
+	TTime timeNow;
+	timeNow.UniversalTime();
+	if (aKey.EndDate().Int64() != 0 && aKey.EndDate() <= timeNow)
+		{
+		return KErrKeyValidity;
+		}
+
+	// We don't support non-repudiation, however we currently allow keys
+	// to be created with this usage
+
+	return KErrNone;
+	}
+
+TInt CFSKeyStoreServer::CheckKeyAlgorithmAndSize(CKeyInfo& aKey)
+	{
+	CKeyInfo::EKeyAlgorithm keyAlgorithm = aKey.Algorithm();
+	if ( ((keyAlgorithm!=CKeyInfo::ERSA) && (keyAlgorithm!=CKeyInfo::EDSA) && (keyAlgorithm!=CKeyInfo::EDH) ))
+		{
+		return KErrKeyAlgorithm;
+		}
+	
+	if (aKey.Size() < KTheMinKeySize || aKey.Size() > KTheMaxKeySize)
+		{
+		return KErrKeySize;
+		}
+
+	return KErrNone;
+	}
+
+void CFSKeyStoreServer::CreateKey(CKeyInfo& aReturnedKey, TRequestStatus& aStatus)
+	{
+	ASSERT(iSession);
+	ASSERT(iMessage);
+
+	TInt err = KErrNone;
+	
+	// Check the calling process has WriteUserData capability
+	if (!KCreateSecurityPolicy.CheckPolicy(*iMessage))
+		{
+		err = KErrPermissionDenied;
+		}
+	
+	// Check the incoming information has been initialised correctly
+	if (err == KErrNone)
+		{
+		err = CheckKeyAttributes(aReturnedKey, ENewKeyCreate);
+		}
+	
+	if (err == KErrNone)
+		{
+		err = CheckKeyAlgorithmAndSize(aReturnedKey);
+		}
+	
+	if (err != KErrNone)
+		{
+		TRequestStatus* status = &aStatus;
+		User::RequestComplete(status, err);
+		return;
+		}
+
+	// DEF042306: Make it local only if it's created in the keystore
+	aReturnedKey.SetAccessType(aReturnedKey.AccessType() | CKeyInfo::ELocal);
+
+	if (iKeyDataManager->IsKeyAlreadyInStore(aReturnedKey.Label()))
+		{
+		TRequestStatus* status = &aStatus;
+		User::RequestComplete(status, KErrAlreadyExists);
+		return;
+		}
+	
+	iCallerRequest = &aStatus;
+	iKeyInfo = &aReturnedKey;
+
+	GetKeystorePassphrase(ECreateKeyCreate);	
+	}
+
+void CFSKeyStoreServer::CancelCreateKey()
+	{
+	if (iAction == ECreateKeyCreate ||
+		iAction == ECreateKeyFinal)
+		{
+		Cancel();
+		}
+	}
+
+void CFSKeyStoreServer::DoCreateKeyL()
+{
+	__ASSERT_DEBUG(iAction==ECreateKeyCreate, PanicServer(EPanicECreateKeyNotReady));
+	__ASSERT_DEBUG(iKeyInfo, PanicServer(EPanicNoClientData));
+	
+	if (iKeyCreator)
+	{
+		delete iKeyCreator;
+		iKeyCreator = NULL;
+	}
+
+	iKeyCreator = new (ELeave) CKeyCreator();
+	iStatus = KRequestPending;
+	iAction = EKeyCreated;
+	iKeyCreator->DoCreateKeyAsyncL(iKeyInfo->Algorithm(), iKeyInfo->Size(), iStatus);
+	SetActive(); 
+}
+												  
+/**
+ * Get the default passphrase for the store, or create one if it hasn't been set
+ * yet.  This is used for key creation, import and export.
+ *
+ * Calls SetActive(), and sets the next state.
+ */
+void CFSKeyStoreServer::GetKeystorePassphrase(ECurrentAction aNextState)
+	{
+	ASSERT(iSession);
+	TStreamId passphraseId = iKeyDataManager->DefaultPassphraseId();
+	TInt timeout = iKeyDataManager->GetPassphraseTimeout();
+	if (passphraseId == KNullStreamId)
+		{
+		iSession->PassphraseManager().CreatePassphrase(timeout, iPassphrase, iStatus);
+		}
+	else
+		{
+		iSession->PassphraseManager().GetPassphrase(passphraseId, timeout, iPassphrase, iStatus);
+		}
+	iAction = aNextState;
+	SetActive();
+	}
+
+/**
+ * Store a key.
+ *
+ * 
+ *
+ * This method is not transaction-safe, as if a leave occurs after key data has
+ * been written to the store, it is not cleaned up.  Also, it shares most of its
+ * code with PKCS8ToKeyL (and the same problem applied).  This should be
+ * corrected by creating an interface for generic key data, including write
+ * private key / write public key / get key identifier operations, which can be
+ * passed to a single method in the key data manager to do the job of these two
+ * methods.
+ *
+ * I'm not fixing this now because it's not a big problem for real-world use,
+ * and I don't have the time to spend on it.
+ *
+ * - jc
+ */
+void CFSKeyStoreServer::DoStoreKeyL()
+	{
+	__ASSERT_DEBUG(iAction==ECreateKeyFinal, PanicServer(EPanicECreateKeyNotReady));
+	__ASSERT_DEBUG(iKeyInfo, PanicServer(EPanicNoClientData));
+	__ASSERT_DEBUG(iKeyCreator, PanicServer(ENoCreatedKeyData));
+	ASSERT(iPassphrase);
+
+	const CFileKeyData* keyData = iKeyDataManager->CreateKeyDataLC(iKeyInfo->Label(), iPassphrase->StreamId());	   
+
+	RStoreWriteStream privateStream;
+	iKeyDataManager->OpenPrivateDataStreamLC(*keyData, *iPassphrase, privateStream);
+	
+	CKeyInfo::EKeyAlgorithm keyAlgorithm = iKeyInfo->Algorithm();
+
+// 	Get key identifier and externalize private key 
+	TKeyIdentifier theKeyId;
+	switch (keyAlgorithm)
+		{
+		case (CKeyInfo::ERSA):
+			{
+			CRSAKeyPair* newKey = iKeyCreator->GetCreatedRSAKey();
+			KeyIdentifierUtil::RSAKeyIdentifierL(newKey->PublicKey(), theKeyId);			
+			privateStream << newKey->PrivateKey();
+			break;
+			}
+			
+		case (CKeyInfo::EDSA):
+			{
+			CDSAKeyPair* newKey = iKeyCreator->GetCreatedDSAKey();			
+			KeyIdentifierUtil::DSAKeyIdentifierL(newKey->PublicKey(), theKeyId);
+			privateStream << newKey->PrivateKey();
+			break;
+			}
+
+		case (CKeyInfo::EDH):
+			{
+			RInteger newKey; 
+			iKeyCreator->GetCreatedDHKey(newKey);			
+			KeyIdentifierUtil::DHKeyIdentifierL(newKey, theKeyId);
+
+			if (newKey.IsZero())
+				User::Leave(KErrArgument);
+
+			privateStream << newKey;
+			privateStream.CommitL();
+			break;
+			}
+		
+		default:
+			__ASSERT_DEBUG(EFalse, PanicServer(EPanicInvalidKeyCreateReq));
+			break;
+		}
+
+	privateStream.CommitL();
+	CleanupStack::PopAndDestroy(); // privateStream
+	
+//	Fill in the CCTKeyInfo data currently missing (TKeyIdentifier and handle)
+	iKeyInfo->SetHandle(keyData->Handle());
+	iKeyInfo->SetIdentifier(theKeyId);	
+
+// 	Externalize public key
+
+	RStoreWriteStream publicStream;
+	iKeyDataManager->OpenPublicDataStreamLC(*keyData, publicStream);
+
+	switch (keyAlgorithm)
+		{
+		case (CKeyInfo::ERSA):
+			publicStream << iKeyCreator->GetCreatedRSAKey()->PublicKey();			
+			break;
+			
+		case (CKeyInfo::EDSA):
+			publicStream << iKeyCreator->GetCreatedDSAKey()->PublicKey();
+			break;
+
+		case (CKeyInfo::EDH):
+			// Nothing to do for DH
+			break;
+		
+		default:
+			__ASSERT_DEBUG(EFalse, PanicServer(EPanicInvalidKeyCreateReq));
+			break;
+		}
+	
+	publicStream.CommitL();
+	CleanupStack::PopAndDestroy(); // publicStream
+
+//	Finished with the key creator
+	if (iKeyCreator)
+	{
+		delete iKeyCreator;
+		iKeyCreator = NULL;
+	}
+
+//	Externalize the CKeyInfo data associated with the key,
+	iKeyDataManager->WriteKeyInfoL(*keyData, *iKeyInfo);
+
+//	Now add the new key to the data manager (which adds it to the store)
+	iKeyDataManager->AddL(keyData);
+	CleanupStack::Pop(); // keydata
+}
+
+void CFSKeyStoreServer::ImportKey(const TDesC8& aKey, CKeyInfo& aReturnedKey, TBool aIsEncrypted, TRequestStatus& aStatus)
+	{
+	ASSERT(iMessage);
+ 
+	TInt err = KErrNone;
+
+	// Check the calling process has WriteUserData capability
+	if (!KCreateSecurityPolicy.CheckPolicy(*iMessage))
+		{
+		err = KErrPermissionDenied;
+		}
+
+	if (err == KErrNone)
+		{
+		err = CheckKeyAttributes(aReturnedKey,
+								 aIsEncrypted ? ENewKeyImportEncrypted : ENewKeyImportPlaintext);
+		}
+
+	if (err == KErrNone && iKeyDataManager->IsKeyAlreadyInStore(aReturnedKey.Label()))
+		{
+		err = KErrAlreadyExists;
+		}
+
+	if (err != KErrNone)
+		{
+		TRequestStatus* status = &aStatus;
+		User::RequestComplete(status, err);
+		return;
+		}
+
+	iPKCS8Data.Set(aKey);
+	
+	iImportingEncryptedKey = aIsEncrypted;
+	iCallerRequest = &aStatus;
+	iKeyInfo = &aReturnedKey;
+
+	iAction = EImportOpenPrivateStream;
+	SetActive();
+
+	if (aIsEncrypted)
+		{
+		TPasswordManager::ImportPassword(iPassword, iStatus);
+		}
+	else
+		{
+		TRequestStatus* status = &iStatus;
+		User::RequestComplete(status, KErrNone);
+		}
+	}
+
+void CFSKeyStoreServer::CancelImportKey()
+	{
+	if (iAction == EImportOpenPrivateStream ||
+		iAction == EImportKey)
+		{
+		Cancel();
+		}
+	}
+
+void CFSKeyStoreServer::DoImportKeyL()
+	{
+	// Generate a decode PKCS8 data object from the incoming descriptor of PKCS8
+	// data Creation of this will parse the DER stream and generate the
+	// appropriate key representation based on the algorithm
+
+	ASSERT(iPKCS8Data.Ptr());
+
+	CDecPKCS8Data* pkcs8Data = NULL;
+
+	if (iImportingEncryptedKey)
+		{
+		// Convert import passphrase to 8 bit representation
+		TBuf8<32> password;
+		
+		CnvUtfConverter::ConvertFromUnicodeToUtf8(password, iPassword);
+		pkcs8Data = TASN1DecPKCS8::DecodeEncryptedDERL(iPKCS8Data, password);
+		}
+	else
+		{
+		pkcs8Data = TASN1DecPKCS8::DecodeDERL(iPKCS8Data);
+		}
+	
+	CleanupStack::PushL(pkcs8Data);	
+	PKCS8ToKeyL(pkcs8Data);
+	CleanupStack::PopAndDestroy(pkcs8Data);
+}
+
+void CFSKeyStoreServer::PKCS8ToKeyL(CDecPKCS8Data* aPKCS8Data)
+{ 
+	ASSERT(iPassphrase);
+	ASSERT(aPKCS8Data);
+	
+	MPKCS8DecodedKeyPairData* keyPairData = aPKCS8Data->KeyPairData();
+
+	// Set algorithm and size from pkcs8 data, and sanity check them
+	if (aPKCS8Data->Algorithm() != ERSA && aPKCS8Data->Algorithm() != EDSA)
+		{
+		User::Leave(KErrKeyAlgorithm);
+		}
+	iKeyInfo->SetAlgorithm((aPKCS8Data->Algorithm() == ERSA) ? CKeyInfoBase::ERSA : CKeyInfoBase::EDSA);
+	iKeyInfo->SetSize(keyPairData->KeySize());
+	User::LeaveIfError(CheckKeyAlgorithmAndSize(*iKeyInfo));
+
+	// Retrieve and store any PKCS8 attributes (in DER encoded descriptor)
+	// These will form part of CKeyInfo & available for callers to decode	
+	TPtrC8 theAttributes(aPKCS8Data->PKCS8Attributes());
+	if (theAttributes != KNullDesC8)
+		{
+		iKeyInfo->SetPKCS8AttributeSet(theAttributes.AllocL());
+		}
+		
+	const CFileKeyData* keyData = iKeyDataManager->CreateKeyDataLC(iKeyInfo->Label(), iPassphrase->StreamId());
+	RStoreWriteStream privateStream;
+	iKeyDataManager->OpenPrivateDataStreamLC(*keyData, *iPassphrase, privateStream);
+
+	// Generate the key identifier
+	TKeyIdentifier theKeyId;
+	keyPairData->GetKeyIdentifierL(theKeyId);
+	
+	// Fill in the CKeyInfo data currently missing (TKeyIdentifier and handle)
+	iKeyInfo->SetHandle(keyData->Handle());
+	iKeyInfo->SetIdentifier(theKeyId);	
+
+	CKeyInfo::EKeyAlgorithm keyAlgorithm = iKeyInfo->Algorithm();
+
+	// Externalize private key data
+	switch (keyAlgorithm)
+		{
+		case (CKeyInfo::ERSA):
+			privateStream << static_cast<CPKCS8KeyPairRSA*>(keyPairData)->PrivateKey();
+			break;
+			
+		case (CKeyInfo::EDSA):
+			privateStream << static_cast<CPKCS8KeyPairDSA*>(keyPairData)->PrivateKey();
+			break;
+			
+		default:
+			__ASSERT_DEBUG(EFalse, PanicServer(EPanicInvalidKeyCreateReq));
+			break;
+		}
+
+	privateStream.CommitL();
+	CleanupStack::PopAndDestroy(&privateStream);
+
+	// Externalize public key data
+	RStoreWriteStream publicStream;
+	iKeyDataManager->OpenPublicDataStreamLC(*keyData, publicStream);
+
+	switch (keyAlgorithm)
+		{
+		case (CKeyInfo::ERSA):
+			publicStream << static_cast<CPKCS8KeyPairRSA*>(keyPairData)->PublicKey();
+			break;
+			
+		case (CKeyInfo::EDSA):
+			publicStream << static_cast<CPKCS8KeyPairDSA*>(keyPairData)->PublicKey();
+			break;
+			
+		default:
+			__ASSERT_DEBUG(EFalse, PanicServer(EPanicInvalidKeyCreateReq));
+			break;
+		}
+
+	publicStream.CommitL();
+	CleanupStack::PopAndDestroy(&publicStream);
+
+	// Externalize the CKeyInfo data associated with the key,
+	iKeyDataManager->WriteKeyInfoL(*keyData, *iKeyInfo);
+
+	// Now add the new key to the data manager (which adds it to the store)
+	iKeyDataManager->AddL(keyData);
+	CleanupStack::Pop(const_cast<CFileKeyData*>(keyData));
+}
+
+void CFSKeyStoreServer::ExportKey(TInt aObjectId, const TPtr8& aKey, TRequestStatus& aStatus)
+	{
+	iExportingKeyEncrypted = EFalse;				
+	TRAPD(err, DoExportKeyL(aObjectId, aKey, aStatus));
+	if (err != KErrNone)
+		{
+		TRequestStatus* status = &aStatus;
+		User::RequestComplete(status, err);
+		}
+	}
+
+void CFSKeyStoreServer::CancelExportKey()
+	{
+
+	if (iAction == EExportKey ||
+		iAction == EExportKeyGetPassphrase)
+		{
+		Cancel();
+		}
+	}	
+
+void CFSKeyStoreServer::ExportEncryptedKey(TInt aObjectId, const TPtr8& aKey, CPBEncryptParms& aParams, TRequestStatus& aStatus)
+	{
+	iExportingKeyEncrypted	= ETrue;	
+	iPbeParams = &aParams;		
+	TRAPD(err, DoExportKeyL(aObjectId, aKey, aStatus));
+	if (err != KErrNone)
+		{
+		TRequestStatus* status = &aStatus;
+		User::RequestComplete(status, err);
+		}
+	}
+
+
+void CFSKeyStoreServer::CancelExportEncryptedKey()
+	{
+	if (iAction == EExportKeyGetPassphrase ||
+		iAction == EExportKey)
+		{
+		Cancel();
+		}
+	}	
+
+void CFSKeyStoreServer::DoExportKeyL(TInt aObjectId, const TPtr8& aKey, TRequestStatus& aStatus)
+	{
+	ASSERT(iMessage);
+	ASSERT(!iKeyData);
+	ASSERT(!iKeyInfo);
+	
+	const CFileKeyData* keyData = iKeyDataManager->Lookup(aObjectId);
+	if (!keyData)
+		{
+		User::Leave(KErrNotFound);
+		}
+
+	CKeyInfo* keyInfo = iKeyDataManager->ReadKeyInfoLC(*keyData);
+
+	// Check access flags allow key to be exported
+	if (!(keyInfo->AccessType() & CCTKeyInfo::EExtractable) ||
+		((keyInfo->AccessType() & CCTKeyInfo::ESensitive) && !iExportingKeyEncrypted))
+		{
+		User::Leave(KErrKeyAccess);
+		}
+
+	// Check this isn't a DH key
+	if (keyInfo->Algorithm() != CKeyInfo::ERSA &&
+		keyInfo->Algorithm() != CKeyInfo::EDSA)
+		{
+		User::Leave(KErrNotSupported);
+		}
+
+	// Check the caller is allowed by the management policy
+	if (!keyInfo->ManagementPolicy().CheckPolicy(*iMessage))
+		{
+		User::Leave(KErrPermissionDenied);
+		}
+
+	iKeyData = keyData;
+	iKeyInfo = keyInfo;
+	CleanupStack::Pop(keyInfo);
+	iExportBuf.Set(aKey);		
+	iCallerRequest = &aStatus;
+		
+	if (iExportingKeyEncrypted)
+		{
+		iAction = EExportEncryptedKeyGetPassphrase;			
+		}
+	else
+		{
+		iAction = EExportKeyGetPassphrase;
+		}
+	SetActive();				
+	TRequestStatus* status = &iStatus;
+	User::RequestComplete(status, KErrNone);		
+	}
+	
+void CFSKeyStoreServer::CompleteKeyExportL(TBool encrypted /*=EFalse*/)
+	{
+	ASSERT(iPassphrase);
+	ASSERT(iKeyData);
+	ASSERT(iExportBuf.Ptr());
+	
+	CKeyInfo::EKeyAlgorithm keyAlgorithm = iKeyInfo->Algorithm();
+	RStoreReadStream privStream;		
+	iKeyDataManager->OpenPrivateDataStreamLC(*iKeyData, *iPassphrase, privStream);
+
+	CASN1EncSequence* encoded = NULL;
+			
+	switch(keyAlgorithm)
+		{
+		case (CKeyInfo::ERSA):
+			{
+			RStoreReadStream pubStream;
+			iKeyDataManager->OpenPublicDataStreamLC(*iKeyData, pubStream);
+			CRSAPublicKey* publicKey = NULL;
+			CreateL(pubStream, publicKey);
+			ASSERT(publicKey);
+			CleanupStack::PushL(publicKey);
+					
+			CRSAPrivateKey* privateKey = NULL;
+			CreateL(privStream, privateKey);
+			ASSERT(privateKey);
+			CleanupStack::PushL(privateKey);			
+
+			if (encrypted)
+				{
+				TBuf8<32> password;
+				CnvUtfConverter::ConvertFromUnicodeToUtf8(password, iPassword);
+
+				CPBEncryptElement* encryptElement = CPBEncryptElement::NewLC(password, *iPbeParams);
+				CPBEncryptor* encryptor = encryptElement->NewEncryptLC();
+				encoded = TASN1EncPKCS8::EncodeEncryptedL(*(static_cast<CRSAPrivateKeyCRT*>(privateKey)), *publicKey, *encryptor, *iPbeParams, iKeyInfo->PKCS8AttributeSet());
+				CleanupStack::PopAndDestroy(2, encryptElement); 	// encryptor, encryptElement 
+				}
+			else
+				{
+				encoded = TASN1EncPKCS8::EncodeL(*(static_cast<CRSAPrivateKeyCRT*>(privateKey)), *publicKey, iKeyInfo->PKCS8AttributeSet());					
+				}
+			CleanupStack::PopAndDestroy(3, &pubStream);          // privateKey,  publicKey, pubStream
+			}
+			break;
+
+		case (CKeyInfo::EDSA):
+			{
+			CDSAPrivateKey* privateKey = NULL;
+
+			CreateL(privStream, privateKey);
+			ASSERT(privateKey);
+			CleanupStack::PushL(privateKey);
+
+			if (encrypted)
+				{			
+				TBuf8<32> password;
+				CnvUtfConverter::ConvertFromUnicodeToUtf8(password, iPassword);
+										
+				CPBEncryptElement* encryptElement = CPBEncryptElement::NewLC(password, *iPbeParams);         				
+				CPBEncryptor* encryptor = encryptElement->NewEncryptLC(); 								
+				encoded = TASN1EncPKCS8::EncodeEncryptedL(*privateKey, *encryptor, *iPbeParams, iKeyInfo->PKCS8AttributeSet());					
+				CleanupStack::PopAndDestroy(2, encryptElement);	// encryptor, encryptElement	
+				}
+			else
+				{
+				encoded = TASN1EncPKCS8::EncodeL(*privateKey, iKeyInfo->PKCS8AttributeSet());					
+				}					
+			CleanupStack::PopAndDestroy(privateKey);
+			}
+			break;
+
+		case (CKeyInfo::EInvalidAlgorithm):
+		default:
+			User::Leave(KErrKeyAlgorithm);		
+			break;
+		}
+			
+	// common to all algorithms			
+	ASSERT(encoded);
+	CleanupStack::PushL(encoded);
+	if (encoded->LengthDER() > static_cast<TUint>(iExportBuf.MaxLength()))
+		{
+		User::Leave(KErrOverflow);
+		}
+	TUint pos=0;
+	encoded->WriteDERL(iExportBuf, pos);
+
+	// WriteDERL does not set the length of the buffer, we do it ourselves			
+	iExportBuf.SetLength(encoded->LengthDER());
+			
+	CleanupStack::PopAndDestroy(encoded); 
+	CleanupStack::PopAndDestroy(&privStream); 
+	RunError(KErrNone);
+	}
+
+void CFSKeyStoreServer::DeleteKeyL(TInt aObjectId)
+	{
+	ASSERT(iMessage);
+	
+	const CFileKeyData* keyData = iKeyDataManager->Lookup(aObjectId);
+	if (!keyData)
+		{
+		User::Leave(KErrNotFound);
+		}
+
+	CKeyInfo* keyInfo = iKeyDataManager->ReadKeyInfoLC(*keyData);
+
+	// Check the caller is allowed by the management policy
+	if (!keyInfo->ManagementPolicy().CheckPolicy(*iMessage))
+		{
+		User::Leave(KErrPermissionDenied);
+		}
+
+	CleanupStack::PopAndDestroy(keyInfo);
+
+	// Check if any session has this key open
+	for (TInt i = 0 ; i < iSessions.Count() ; ++i)
+		{
+		CKeyStoreSession& session = *iSessions[i];
+		if (session.HasOpenKey(aObjectId))
+			{
+			User::Leave(KErrInUse);
+			}	
+		}
+
+	iKeyDataManager->RemoveL(aObjectId);
+}
+
+void CFSKeyStoreServer::SetUsePolicyL(TInt aObjectId, const TSecurityPolicy& aPolicy)
+	{
+	ASSERT(iMessage);
+	
+	const CFileKeyData* keyData = iKeyDataManager->Lookup(aObjectId);
+	if (!keyData)
+		{
+		User::Leave(KErrNotFound);
+		}
+
+	CKeyInfo* keyInfo = iKeyDataManager->ReadKeyInfoLC(*keyData);
+
+	// Check the caller is allowed by the management policy
+	if (!keyInfo->ManagementPolicy().CheckPolicy(*iMessage))
+		{
+		User::Leave(KErrPermissionDenied);
+		}
+
+	// should revert change if write fails
+	keyInfo->SetUsePolicy(aPolicy); 
+	iKeyDataManager->SafeWriteKeyInfoL(*keyData, *keyInfo);	
+
+	CleanupStack::PopAndDestroy(keyInfo);
+	}
+	
+void CFSKeyStoreServer::SetManagementPolicyL(TInt aObjectId, const TSecurityPolicy& aPolicy)
+	{
+	ASSERT(iMessage);
+	
+	const CFileKeyData* keyData = iKeyDataManager->Lookup(aObjectId);
+	if (!keyData)
+		{
+		User::Leave(KErrNotFound);
+		}
+
+	CKeyInfo* keyInfo = iKeyDataManager->ReadKeyInfoLC(*keyData);
+
+	// Check the caller is allowed by current management policy
+	if (!keyInfo->ManagementPolicy().CheckPolicy(*iMessage))
+		{
+		User::Leave(KErrPermissionDenied);
+		}
+
+	// Check the caller is allowed by new management policy
+	if (!aPolicy.CheckPolicy(*iMessage))
+		{
+		User::Leave(KErrArgument);
+		}
+
+	// should revert change if write fails
+	keyInfo->SetManagementPolicy(aPolicy);
+	iKeyDataManager->SafeWriteKeyInfoL(*keyData, *keyInfo);	
+
+	CleanupStack::PopAndDestroy(keyInfo);
+	}
+
+// For MCTAuthenticationObject
+
+void CFSKeyStoreServer::ChangePassphrase(TRequestStatus& aStatus)
+	{
+	if (iKeyDataManager->DefaultPassphraseId() == KNullStreamId)
+		{
+		// No passphrase set, can't change it
+		TRequestStatus* status = &aStatus;
+		User::RequestComplete(status, KErrNotFound);		
+		}
+	
+	iCallerRequest = &aStatus;
+	iAction = EChangePassphrase;
+	SetActive();
+	TRequestStatus* status = &iStatus;
+	User::RequestComplete(status, KErrNone);
+	}
+
+void CFSKeyStoreServer::DoChangePassphrase()
+	{
+	ASSERT(iSession);
+	ASSERT(iKeyDataManager->DefaultPassphraseId() != KNullStreamId);
+	iSession->PassphraseManager().ChangePassphrase(iKeyDataManager->DefaultPassphraseId(), iStatus);
+	iAction = EChangePassphraseClearCached;
+	SetActive();
+	}
+
+void CFSKeyStoreServer::CancelChangePassphrase()
+	{
+	if (iAction == EChangePassphrase ||
+		iAction == EChangePassphraseClearCached)
+		{
+		Cancel();
+		}
+	}
+
+void CFSKeyStoreServer::AuthOpen(TRequestStatus& aStatus)
+	{
+	iCallerRequest = &aStatus;
+	GetKeystorePassphrase(EAuthOpen);
+	}
+
+void CFSKeyStoreServer::CancelAuthOpen()
+	{
+	if (iAction == EAuthOpen)
+		{
+		Cancel();
+		}
+	}
+
+void CFSKeyStoreServer::AuthClose()
+	{
+	ASSERT(iSession);
+	iSession->PassphraseManager().RemoveCachedPassphrases(iKeyDataManager->DefaultPassphraseId());
+	}
+
+TInt CFSKeyStoreServer::GetTimeRemainingL()
+	{
+	ASSERT(iSession);
+	TStreamId passStreamId = iKeyDataManager->DefaultPassphraseId();
+	return iSession->PassphraseManager().TimeRemainingL(passStreamId);
+	}
+
+void CFSKeyStoreServer::SetTimeoutL(TInt aTimeout)
+	{
+	ASSERT(iMessage);
+
+	if (!KSetTimeoutSecurityPolicy.CheckPolicy(*iMessage))
+		{
+		User::Leave(KErrPermissionDenied);
+		}
+	
+	if (aTimeout < KTimeoutNever)
+		{
+		User::Leave(KErrArgument);
+		}
+
+	iKeyDataManager->SetPassphraseTimeoutL(aTimeout);
+	RemoveCachedPassphrases(KNullStreamId);
+	}
+
+TInt CFSKeyStoreServer::GetTimeoutL()
+	{
+	return iKeyDataManager->GetPassphraseTimeout();
+	}
+
+void CFSKeyStoreServer::Relock()
+	{
+	RemoveCachedPassphrases(KNullStreamId);
+	}
+
+void CFSKeyStoreServer::RemoveCachedPassphrases(TStreamId aStreamId)
+	{
+	for (TInt index = 0 ; index < iSessions.Count() ; ++index)
+		{
+		CKeyStoreSession& session = *iSessions[index];					
+		session.PassphraseManager().RemoveCachedPassphrases(aStreamId);
+		}			
+	}
+
+//	*********************************************************************************
+//	From CActive
+//	*********************************************************************************
+TInt CFSKeyStoreServer::RunError(TInt aError)
+	{ 
+	// Delete anything we might have created
+	delete iKeyCreator; iKeyCreator = NULL;
+
+	if (iAction == EExportKeyGetPassphrase ||
+		iAction == EExportEncryptedKeyGetPassphrase ||
+		iAction == EExportKey ||
+		iAction == EExportEncryptedKey)
+		{
+		// we only own iKeyInfo for export operations
+		delete iKeyInfo;
+		iKeyInfo = NULL;
+		}
+	
+	// Zero pointers to things we don't own
+	iPassphrase = NULL;
+	iKeyInfo = NULL;
+	iKeyData = NULL;
+	iExportBuf.Set(NULL, 0, 0);
+	iPKCS8Data.Set(NULL, 0);
+	iSession = NULL;
+	iMessage = NULL;
+
+	if (iCallerRequest)
+		User::RequestComplete(iCallerRequest, aError);
+
+	iAction = EIdle;		//	Reset action
+	return (KErrNone);		//	Handled
+	}
+
+void CFSKeyStoreServer::DoCancel()
+	{
+	switch (iAction)
+		{
+		case EImportKey:
+		case ECreateKeyCreate:
+		case EExportKey:
+		case EExportEncryptedKey:
+		case EChangePassphraseClearCached:
+			ASSERT(iSession);
+			iSession->PassphraseManager().Cancel();
+			break;
+
+		case ECreateKeyFinal:
+			ASSERT(iKeyCreator);
+			iKeyCreator->Cancel();
+			break;
+
+		default:
+			// Nothing to do
+			break;
+		}
+	
+	RunError(KErrCancel);
+	}
+
+void CFSKeyStoreServer::RunL()
+	{
+	User::LeaveIfError(iStatus.Int()); 
+
+	switch (iAction)
+		{
+		case EImportOpenPrivateStream:
+			ASSERT(iKeyInfo);
+			GetKeystorePassphrase(EImportKey);
+			break;
+		case ECreateKeyCreate:
+			DoCreateKeyL();	
+			iAction = ECreateKeyFinal;
+			break;
+		case ECreateKeyFinal:
+			DoStoreKeyL();			 
+			//	Check iKeyInfo was initialised for the caller
+			ASSERT(iKeyInfo->HandleID() != 0);						
+			RunError(KErrNone);
+			break;
+		case EImportKey:
+			{
+			TRAPD(err, DoImportKeyL());
+			if (err == KErrTooBig)
+				{
+				// Returned by ASN library if data is unexpected probably as a result of
+				// bad import data
+				err = KErrArgument;
+				}
+			User::LeaveIfError(err);
+			RunError(KErrNone);
+			break;
+			}
+		case EExportKeyGetPassphrase:
+			GetKeystorePassphrase(EExportKey);
+			break;
+		case EExportEncryptedKeyGetPassphrase:
+			GetKeystorePassphrase(EExportEncryptedKey);
+			break;
+		case EExportEncryptedKey:
+			{
+			TPasswordManager::ExportPassword(iPassword, iStatus); 
+			iAction = EExportKey;
+			SetActive();
+			}	
+			break;
+		case EExportKey:
+			{
+			CompleteKeyExportL(iExportingKeyEncrypted);
+			}
+			break;				
+		case EChangePassphrase:
+			DoChangePassphrase();
+			break;
+		case EChangePassphraseClearCached:
+			// Make sure the passphrase we just changed is not cached anywhere
+			RemoveCachedPassphrases(iKeyDataManager->DefaultPassphraseId());
+			RunError(KErrNone);
+			break;
+		case EAuthOpen:
+			RunError(KErrNone);
+			break;
+		default:
+			ASSERT(EFalse);
+		}
+	}