vpnengine/pkiservice/src/keymanager.cpp
changeset 0 33413c0669b9
child 4 29b591713d44
--- /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;
+    }