--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/vpnengine/pkiservice/src/keymanager.cpp Thu Dec 17 09:14:51 2009 +0200
@@ -0,0 +1,539 @@
+/*
+* Copyright (c) 2008 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: Class, which provides operation for deleting, saving and creating keypairs.
+*
+*/
+
+
+
+#include <mctauthobject.h>
+
+#include "keymanager.h"
+#include "logonservices.h"
+#include "utlcrypto.h"
+#include "base64.h"
+#include "pkiserviceassert.h"
+#include "pkiserviceconstants.h"
+
+const TTimeIntervalYears KValidityPeriod(20);
+_LIT_SECURITY_POLICY_C1(KSymbianKeyStoreMgmtPolicy, ECapabilityWriteDeviceData);
+_LIT_SECURITY_POLICY_C1(KSymbianKeyStoreUsePolicy, ECapabilityReadDeviceData);
+
+CKeyManager* CKeyManager::NewL(CLogonServices& aLogonServices)
+ {
+ CKeyManager* self = new (ELeave) CKeyManager(aLogonServices);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+
+CKeyManager::CKeyManager(CLogonServices& aLogonServices)
+:CActive(EPriorityNormal), iLogonServices(aLogonServices)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+
+void CKeyManager::ConstructL()
+ {
+ }
+
+
+CKeyManager::~CKeyManager()
+ {
+ Cleanup();
+ }
+
+
+void CKeyManager::RemoveKeyPair(const TPKIKeyIdentifier& aKeyId,
+ CUnifiedKeyStore& aUnifiedKeyStore,
+ TInt aUsedKeyStore,
+ TRequestStatus& aClientStatus)
+ {
+ PKISERVICE_ASSERT(iState == EKeyManagerIdle);
+ PKISERVICE_ASSERT(iClientStatus == NULL);
+ PKISERVICE_ASSERT(aUsedKeyStore == STORETYPE_USER_KEY_ID ||
+ aUsedKeyStore == STORETYPE_DEVICE_KEY_ID ||
+ aUsedKeyStore == STORETYPE_ANY_KEY_ID);
+
+
+ iState = ERetrievingKeyPairForRemove;
+
+ iClientStatus = &aClientStatus;
+ *iClientStatus = KRequestPending;
+
+ iUsedKeyStore = aUsedKeyStore;
+ iUnifiedKeyStore = &aUnifiedKeyStore;
+
+ TCTKeyAttributeFilter filter;
+ filter.iKeyId = aKeyId;
+
+ iUnifiedKeyStore->List(iKeysList, filter, iStatus);
+ SetActive();
+ }
+
+
+void CKeyManager::GenerateKeyPair(CUnifiedKeyStore& aUnifiedKeyStore,
+ TInt aUsedKeyStore,
+ const TUint aKeySize,
+ TPKIKeyAlgorithm aKeyAlgorithm,
+ TPKIKeyIdentifier& aKeyId,
+ TRequestStatus& aClientStatus)
+ {
+ PKISERVICE_ASSERT(iState == EKeyManagerIdle);
+ PKISERVICE_ASSERT(iObjectName == NULL);
+ PKISERVICE_ASSERT(iClientStatus == NULL);
+ PKISERVICE_ASSERT(aUsedKeyStore == STORETYPE_USER_KEY_ID ||
+ aUsedKeyStore == STORETYPE_DEVICE_KEY_ID ||
+ aUsedKeyStore == STORETYPE_ANY_KEY_ID);
+
+ iState = EGeneratingKeyPair;
+
+ iKeyId = &aKeyId;
+ iClientStatus = &aClientStatus;
+ *iClientStatus = KRequestPending;
+
+ iUnifiedKeyStore = &aUnifiedKeyStore;
+
+ if (aUsedKeyStore == STORETYPE_ANY_KEY_ID)
+ {
+ //If any type is used the key is greated in
+ //user store.
+ aUsedKeyStore = STORETYPE_USER_KEY_ID;
+ }
+
+ TRAPD(err, iObjectName = GetUniqueNameL());
+ if (err == KErrNone)
+ {
+ TTime startDate;
+ TTime endDate;
+ startDate.UniversalTime();
+ endDate.UniversalTime();
+ endDate += KValidityPeriod;
+
+ TInt keyStoreCount = iUnifiedKeyStore->KeyStoreManagerCount();
+ TInt i = 0;
+ for (i = 0; i < keyStoreCount; ++i)
+ {
+ MCTKeyStoreManager& keyStore = iUnifiedKeyStore->KeyStoreManager(i);
+ if (keyStore.Token().TokenType().Type().iUid == aUsedKeyStore)
+ {
+ break;
+ }
+ }
+ PKISERVICE_ASSERT(i < keyStoreCount);
+
+
+ iUnifiedKeyStore->CreateKey(i, EPKCS15UsageSignDecrypt,
+ aKeySize,
+ *iObjectName,
+ ConvertPKIAlgorithm(aKeyAlgorithm),
+ CKeyInfoBase::EExtractable,
+ startDate,
+ endDate,
+ iKeyInfo,
+ iStatus);
+ SetActive();
+
+ }
+ else
+ {
+ TRequestStatus* ownStatus = &iStatus;
+ *ownStatus = KRequestPending;
+ SetActive();
+
+ User::RequestComplete(ownStatus, err);
+ }
+ }
+
+
+void CKeyManager::ImportKeyPair(CUnifiedKeyStore& aUnifiedKeyStore,
+ TInt aUsedKeyStore,
+ const TDesC8& aKeyData,
+ TPKIKeyIdentifier& aKeyId,
+ TRequestStatus& aClientStatus)
+ {
+ PKISERVICE_ASSERT(iState == EKeyManagerIdle);
+ PKISERVICE_ASSERT(iObjectName == NULL);
+ PKISERVICE_ASSERT(iClientStatus == NULL);
+ PKISERVICE_ASSERT(aUsedKeyStore == STORETYPE_USER_KEY_ID ||
+ aUsedKeyStore == STORETYPE_DEVICE_KEY_ID ||
+ aUsedKeyStore == STORETYPE_ANY_KEY_ID);
+
+
+ iState = EImportingKeyPair;
+
+ iKeyId = &aKeyId;
+ iClientStatus = &aClientStatus;
+ *iClientStatus = KRequestPending;
+
+ iUnifiedKeyStore = &aUnifiedKeyStore;
+
+ if (aUsedKeyStore == STORETYPE_ANY_KEY_ID)
+ {
+ //If any type is used the key is greated in
+ //user store.
+ aUsedKeyStore = STORETYPE_USER_KEY_ID;
+ }
+
+
+ TRAPD(err, iObjectName = GetUniqueNameL());
+ if (err == KErrNone)
+ {
+ TTime startDate;
+ TTime endDate;
+ startDate.UniversalTime();
+ endDate.UniversalTime();
+ endDate += KValidityPeriod;
+
+ TInt keyStoreCount = iUnifiedKeyStore->KeyStoreManagerCount();
+ TInt i = 0;
+ for (i = 0; i < keyStoreCount; ++i)
+ {
+ MCTKeyStoreManager& keyStore = iUnifiedKeyStore->KeyStoreManager(i);
+ if (keyStore.Token().TokenType().Type().iUid == aUsedKeyStore)
+ {
+ break;
+ }
+ }
+ PKISERVICE_ASSERT(i < keyStoreCount);
+
+
+ iUnifiedKeyStore->ImportKey(i, aKeyData,
+ EPKCS15UsageSignDecrypt,
+ *iObjectName,
+ CKeyInfoBase::EExtractable,
+ startDate,
+ endDate,
+ iKeyInfo,
+ iStatus);
+ SetActive();
+ }
+ else
+ {
+ TRequestStatus* ownStatus = &iStatus;
+ *ownStatus = KRequestPending;
+ SetActive();
+
+ User::RequestComplete(ownStatus, err);
+ }
+ }
+
+
+void CKeyManager::ExportPublicKey(CUnifiedKeyStore& aUnifiedKeyStore,
+ TInt aUsedKeyStore,
+ const TPKIKeyIdentifier& aKeyId,
+ HBufC8*& aPublicKeyData,
+ TRequestStatus& aClientStatus)
+ {
+ PKISERVICE_ASSERT(iState == EKeyManagerIdle);
+ PKISERVICE_ASSERT(iPublicKeyData == NULL);
+ PKISERVICE_ASSERT(iClientStatus == NULL);
+ PKISERVICE_ASSERT(aUsedKeyStore == STORETYPE_USER_KEY_ID ||
+ aUsedKeyStore == STORETYPE_DEVICE_KEY_ID ||
+ aUsedKeyStore == STORETYPE_ANY_KEY_ID);
+
+ iState = ERetrievingKeyListForExport;
+ iPublicKeyData = &aPublicKeyData;
+ iUsedKeyStore = aUsedKeyStore;
+
+ iClientStatus = &aClientStatus;
+ *iClientStatus = KRequestPending;
+
+ iUnifiedKeyStore = &aUnifiedKeyStore;
+
+
+ TCTKeyAttributeFilter filter;
+ filter.iKeyId = aKeyId;
+
+ iUnifiedKeyStore->List(iKeysList, filter, iStatus);
+ SetActive();
+ }
+
+
+
+void CKeyManager::RunL()
+ {
+ if (iStatus.Int() == KErrNone)
+ {
+ switch(iState)
+ {
+ case ERetrievingKeyPairForRemove:
+ {
+ TInt keyIndex = GetKeyIndex(iUsedKeyStore, iKeysList);
+ if ( keyIndex >= 0)
+ {
+ iState = ERemovingKeyPair;
+ iUnifiedKeyStore->DeleteKey(iKeysList[keyIndex]->Handle(), iStatus);
+ SetActive();
+ }
+ else
+ {
+ Cleanup();
+ User::RequestComplete(iClientStatus, KPKIErrNotFound);
+ }
+ }
+ break;
+ case ERemovingKeyPair:
+ Cleanup();
+ User::RequestComplete(iClientStatus, iStatus.Int());
+ break;
+ case EImportingKeyPair: //falls through
+ case EGeneratingKeyPair:
+ {
+ iState = ESettingManagementPolicy;
+
+ MCTAuthenticationObject* authObject = iKeyInfo->Protector();
+ if (authObject != NULL)
+ {
+ //authObject is NULL for device store
+ iLogonServices.SetAuthenticationObject(authObject);
+ }
+
+ iUnifiedKeyStore->SetManagementPolicy(iKeyInfo->Handle(),
+ KSymbianKeyStoreMgmtPolicy,
+ iStatus);
+ SetActive();
+ }
+ break;
+ case ESettingManagementPolicy:
+ iState = ESettingUsePolicy;
+ iUnifiedKeyStore->SetUsePolicy(iKeyInfo->Handle(),
+ KSymbianKeyStoreUsePolicy,
+ iStatus);
+ SetActive();
+ break;
+ case ESettingUsePolicy:
+ *iKeyId = iKeyInfo->ID();
+ Cleanup();
+ User::RequestComplete(iClientStatus, KErrNone);
+ break;
+ case ERetrievingKeyListForExport:
+ {
+ TInt keyIndex = GetKeyIndex(iUsedKeyStore, iKeysList);
+ if ( keyIndex >= 0)
+ {
+ iState = EExportingPublicKey;
+ TCTTokenObjectHandle tokenHandle = iKeysList[keyIndex]->Handle();
+ iUnifiedKeyStore->ExportPublic(tokenHandle, *iPublicKeyData, iStatus);
+ SetActive();
+
+ }
+ else
+ {
+ Cleanup();
+ User::RequestComplete(iClientStatus, KPKIErrNotFound);
+ }
+ }
+ break;
+ case EExportingPublicKey:
+ {
+ iState = EKeyManagerIdle;
+
+ if (iStatus.Int() == KErrNone)
+ {
+ TPtr8 publicKeyPtr = (*iPublicKeyData)->Des();
+
+ // Fix length and strip header (not a
+ // perfect solution!), but certificate
+ // enrollment request wants to have
+ // only PKCS#1 key data.
+ TInt tempLength = 0;
+ TInt skip = 0;
+ if(publicKeyPtr[1] == 0x82)
+ {
+ tempLength = (publicKeyPtr[2] << 8) + publicKeyPtr[3] + 4 - 0x18;
+ skip = 0x18;
+ }
+ else
+ {
+ tempLength = publicKeyPtr[2] + 3 - 0x16;
+ skip = 0x16;
+ }
+
+ PKISERVICE_ASSERT(tempLength <= publicKeyPtr.MaxLength());
+ publicKeyPtr.Copy(publicKeyPtr.Ptr() + skip, tempLength);
+ }
+ Cleanup();
+ User::RequestComplete(iClientStatus, iStatus.Int());
+ }
+ break;
+ default:
+ PKISERVICE_INVARIANT();
+ }
+ }
+ else
+ {
+ Cleanup();
+ User::RequestComplete(iClientStatus, iStatus.Int());
+ }
+ }
+
+
+void CKeyManager::DoCancel()
+ {
+ switch(iState)
+ {
+ case ERetrievingKeyListForExport: //falls through
+ case ERetrievingKeyPairForRemove:
+ iUnifiedKeyStore->CancelList();
+ break;
+ case ERemovingKeyPair:
+ iUnifiedKeyStore->CancelDeleteKey();
+ break;
+ case EGeneratingKeyPair:
+ iUnifiedKeyStore->CancelCreateKey();
+ break;
+ case EImportingKeyPair:
+ iUnifiedKeyStore->CancelImportKey();
+ break;
+ case ESettingManagementPolicy:
+ iUnifiedKeyStore->CancelSetManagementPolicy();
+ break;
+ case ESettingUsePolicy:
+ iUnifiedKeyStore->CancelSetUsePolicy();
+ break;
+ case EExportingPublicKey:
+ iUnifiedKeyStore->CancelExportPublic();
+ delete *iPublicKeyData;
+ *iPublicKeyData = NULL;
+ break;
+ default:
+ PKISERVICE_INVARIANT();
+ }
+ Cleanup();
+ User::RequestComplete(iClientStatus, KErrCancel);
+ }
+
+
+void CKeyManager::RunError()
+ {
+ //RunL doesn't leave
+ PKISERVICE_INVARIANT();
+ }
+
+void CKeyManager::Cleanup()
+ {
+ iState = EKeyManagerIdle;
+
+ iPublicKeyData = NULL;
+
+ if (iKeyInfo != NULL)
+ {
+ iKeyInfo->Release();
+ iKeyInfo = NULL;
+ }
+ iKeysList.Close();
+
+ delete iObjectName;
+ iObjectName = NULL;
+
+ iUnifiedKeyStore = NULL;
+
+ iUsedKeyStore = 0;
+ }
+
+
+HBufC* CKeyManager::GetUniqueNameL() const
+ {
+ TBuf<MAX_FILENAME_LENGTH> date;
+ TTime time;
+ TDateTime dateTime;
+
+ time.HomeTime();
+ dateTime = time.DateTime();
+
+ TBuf8<16> dateString;
+
+ _LIT8(KFormatTxt,"%4d%02d%02d%02d%02d%02d%02d");
+ dateString.Format(KFormatTxt,
+ dateTime.Year(),
+ dateTime.Month()+1,
+ // Format the month as a TInt to preserve locale independence
+ dateTime.Day()+1,
+ // Day and month ranges begin at zero (0-30 and 0-11),
+ // so add one when formatting
+ dateTime.Hour(), dateTime.Minute(), dateTime.Second(), dateTime.MicroSecond()
+ );
+
+ TPKISHA1Hash hash;
+ CUtlMessageDigest* digester = TUtlCrypto::MakeMessageDigesterL(TUtlCrypto::EUtlMessageDigestSha1);
+ CleanupStack::PushL(digester);
+ TPtrC8 hashValue = digester->Final(dateString);
+
+ TBase64Codec base64Codec;
+ HBufC8* uniqueName8 = base64Codec.Base64EncodeLC(hashValue);
+ TPtr8 uniqueName8Ptr = uniqueName8->Des();
+
+ // Replace /
+ for(TInt i = 0; i < uniqueName8->Length(); i++)
+ {
+ if(uniqueName8Ptr[i] == '/')
+ {
+ uniqueName8Ptr[i] = '_';
+ }
+ }
+
+ HBufC* uniqueName = HBufC::NewL(uniqueName8->Length());
+ uniqueName->Des().Copy(*uniqueName8);
+
+ CleanupStack::PopAndDestroy(uniqueName8);
+ CleanupStack::PopAndDestroy(digester);
+
+ return uniqueName;
+ }
+
+
+CCTKeyInfo::EKeyAlgorithm CKeyManager::ConvertPKIAlgorithm(TPKIKeyAlgorithm aAlg) const
+ {
+ CCTKeyInfo::EKeyAlgorithm algorithm = CCTKeyInfo::EInvalidAlgorithm;
+
+ switch(aAlg)
+ {
+ case EPKIRSA:
+ algorithm = CCTKeyInfo::ERSA;
+ break;
+ case EPKIDSA:
+ algorithm = CCTKeyInfo::EDSA;
+ break;
+ case EPKIDH:
+ algorithm = CCTKeyInfo::EDH;
+ break;
+ default:
+ break;
+ }
+ return algorithm;
+ }
+
+
+TInt CKeyManager::GetKeyIndex(TInt aUsedKeyStore, const RMPointerArray<CCTKeyInfo>& aKeysList) const
+ {
+ TInt i;
+ for (i = 0; i < aKeysList.Count(); ++i)
+ {
+ if (aUsedKeyStore == STORETYPE_ANY_KEY_ID ||
+ aUsedKeyStore == aKeysList[i]->Token().TokenType().Type().iUid)
+ {
+ break;
+ }
+ }
+ if ( i >= aKeysList.Count())
+ {
+ i = KErrNotFound;
+ }
+
+ return i;
+ }