sl@0: /* sl@0: * Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: * All rights reserved. sl@0: * This component and the accompanying materials are made available sl@0: * under the terms of the License "Eclipse Public License v1.0" sl@0: * which accompanies this distribution, and is available sl@0: * at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: * sl@0: * Initial Contributors: sl@0: * Nokia Corporation - initial contribution. sl@0: * sl@0: * Contributors: sl@0: * sl@0: * Description: sl@0: * sl@0: */ sl@0: sl@0: sl@0: #include "CCreateKey.h" sl@0: #include "tokenserverdebug.h" sl@0: #include sl@0: #include sl@0: sl@0: // Wrapper class because we differ from crypto on what a DH key is sl@0: class CSimpleDHKey : public CBase sl@0: { sl@0: public: sl@0: static CSimpleDHKey* NewL(TInt aSize); sl@0: ~CSimpleDHKey(); sl@0: public: sl@0: inline RInteger& DHKey() {return (iKey);}; sl@0: private: sl@0: CSimpleDHKey() {}; sl@0: void ConstructL(TInt aSize); sl@0: private: sl@0: RInteger iKey; sl@0: }; sl@0: sl@0: CSimpleDHKey* CSimpleDHKey::NewL(TInt aSize) sl@0: { sl@0: CSimpleDHKey* me = new (ELeave) CSimpleDHKey(); sl@0: CleanupStack::PushL(me); sl@0: me->ConstructL(aSize); sl@0: CleanupStack::Pop(me); sl@0: return (me); sl@0: } sl@0: sl@0: void CSimpleDHKey::ConstructL(TInt aSize) sl@0: { sl@0: iKey = RInteger::NewRandomL(aSize - 1); sl@0: } sl@0: sl@0: CSimpleDHKey::~CSimpleDHKey() sl@0: { sl@0: iKey.Close(); sl@0: } sl@0: sl@0: CKeyCreator::CKeyCreator() sl@0: : CActive(EPriorityStandard), sl@0: iAction(EIdle) sl@0: { sl@0: CActiveScheduler::Add(this); sl@0: } sl@0: sl@0: CKeyCreator::~CKeyCreator() sl@0: { sl@0: Cancel(); sl@0: sl@0: iCreatorThread.LogonCancel(iStatus); sl@0: iCreatorThread.Close(); sl@0: sl@0: delete iCreateData; sl@0: } sl@0: sl@0: // Spin a thread to create an appropriate key, if successful, left on CleanupStack sl@0: void CKeyCreator::DoCreateKeyAsync(CKeyInfo::EKeyAlgorithm aAlgorithm, TInt aSize, TRequestStatus& aStatus) sl@0: { sl@0: iClientStatus = &aStatus; sl@0: *iClientStatus = KRequestPending; sl@0: iStatus = KRequestPending; sl@0: sl@0: TInt err = KErrNone; sl@0: sl@0: if ( (aSize <= 0) || sl@0: (aAlgorithm==CKeyInfo::EInvalidAlgorithm) || sl@0: ((aAlgorithm!=CKeyInfo::ERSA) && (aAlgorithm!=CKeyInfo::EDSA) && (aAlgorithm!=CKeyInfo::EDH)) ) sl@0: { sl@0: err = KErrKeyAlgorithm; sl@0: } sl@0: if(err == KErrNone) sl@0: { sl@0: iCreateData = new CKeyCreatorData(aAlgorithm, aSize); sl@0: if(iCreateData == NULL) sl@0: { sl@0: err = KErrNoMemory; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: User::RequestComplete(iClientStatus, err); sl@0: return; sl@0: } sl@0: sl@0: // OK, ready to start the async operation...do it in RunL sl@0: iAction = EReadyToCreateKey; sl@0: sl@0: SetActive(); sl@0: TRequestStatus* stat = &iStatus; sl@0: User::RequestComplete(stat, err); sl@0: } sl@0: sl@0: // HERE'S THE THREAD TO CREATE THE KEY sl@0: // Code cannot leave in here, but not as many traps as it looks sl@0: /*static*/ TInt CKeyCreator::CreatorThreadEntryPoint(TAny* aParameters) sl@0: { sl@0: CTrapCleanup* cleanup = CTrapCleanup::New(); sl@0: if (!cleanup) sl@0: User::Exit(KErrNoMemory); sl@0: sl@0: #ifdef _DEBUG sl@0: TokenServerDebug::PauseOOMTest(); sl@0: #endif sl@0: sl@0: ASSERT(aParameters); sl@0: TInt result = KErrNone; sl@0: CKeyCreatorData* createData = static_cast(aParameters); sl@0: switch (createData->iKeyAlgorithm) sl@0: { sl@0: case(CKeyInfo::ERSA): sl@0: {// Currently, CRT signing is not supported, in case the key is to be used sl@0: // for such, create a standard (private) key as part of the pair sl@0: TRAP(result, createData->iKey.iRSAKey = CRSAKeyPair::NewL(createData->iSize)); sl@0: } sl@0: break; sl@0: case (CKeyInfo::EDSA): sl@0: { sl@0: TRAP(result, createData->iKey.iDSAKey = CDSAKeyPair::NewL(createData->iSize)); sl@0: } sl@0: break; sl@0: case (CKeyInfo::EDH): sl@0: {// Generate a number that's less than N. The snag is that sl@0: // we don't know what N is. We do know that it'll be of a sl@0: // particular size, so we can safely generate any number sl@0: // with less than iSize digits sl@0: TRAP(result, createData->iKey.iDHKey = CSimpleDHKey::NewL(createData->iSize)); sl@0: } sl@0: break; sl@0: default: sl@0: ASSERT(EFalse); sl@0: result = KErrArgument; sl@0: } sl@0: sl@0: #ifdef _DEBUG sl@0: TokenServerDebug::ResumeOOMTest(); sl@0: #endif sl@0: delete cleanup; sl@0: User::Exit(result); sl@0: return (KErrNone); sl@0: } sl@0: sl@0: CRSAKeyPair* CKeyCreator::GetCreatedRSAKey() sl@0: { sl@0: // Check algorithm is as expected, return NULL if no key or wrong type sl@0: if ( (!iCreateData) || (CKeyInfo::ERSA!=iCreateData->iKeyAlgorithm) ) sl@0: return (NULL); sl@0: else sl@0: return (iCreateData->iKey.iRSAKey); sl@0: } sl@0: sl@0: CDSAKeyPair* CKeyCreator::GetCreatedDSAKey() sl@0: { sl@0: // Check algorithm is as expected, return NULL if no key or wrong type sl@0: if ( (!iCreateData) || (CKeyInfo::EDSA!=iCreateData->iKeyAlgorithm) ) sl@0: return (NULL); sl@0: else sl@0: return (iCreateData->iKey.iDSAKey); sl@0: } sl@0: sl@0: void CKeyCreator::GetCreatedDHKey(RInteger& aDHKey) sl@0: { sl@0: ASSERT(iCreateData); sl@0: ASSERT(CKeyInfo::EDH==iCreateData->iKeyAlgorithm); sl@0: aDHKey = iCreateData->iKey.iDHKey->DHKey(); sl@0: } sl@0: sl@0: void CKeyCreator::DoCancel() sl@0: { sl@0: // Only do the cancel if in the middle of creating a key. Kill the thread. sl@0: if (iAction!=EIdle) sl@0: { sl@0: TExitType exitType = iCreatorThread.ExitType(); sl@0: if (EExitPending==exitType) // Still alive, so kill it sl@0: { sl@0: iCreatorThread.Kill(KErrCancel); sl@0: } sl@0: iAction = EIdle; sl@0: } sl@0: sl@0: ASSERT(iClientStatus); sl@0: User::RequestComplete(iClientStatus, KErrCancel); sl@0: } sl@0: sl@0: void CKeyCreator::RunL() sl@0: { sl@0: ASSERT(iClientStatus); sl@0: User::LeaveIfError(iStatus.Int()); sl@0: sl@0: switch (iAction) sl@0: { sl@0: case (EReadyToCreateKey): sl@0: { sl@0: // Spin off the thread and pass it the parameter data, then stand by sl@0: // INC118634 sl@0: // To be safe, we should use anonymous threads because naming a thread means anybody could have opened a handle on the thread, sl@0: // most likely system applications which want to know about panicing threads. So next thread creation will fail with KErrAlreadyExist(-11). sl@0: User::LeaveIfError(iCreatorThread.Create(KNullDesC, CreatorThreadEntryPoint, KDefaultStackSize, NULL, (TAny*)iCreateData)); sl@0: iStatus = KRequestPending; sl@0: iCreatorThread.Logon(iStatus); sl@0: iAction = ECreatedKey; sl@0: SetActive(); sl@0: iCreatorThread.Resume(); sl@0: } sl@0: break; sl@0: sl@0: case (ECreatedKey): sl@0: {// Notify the caller sl@0: ASSERT(iClientStatus); sl@0: // May be OOM creating logon, in which case we should kill thread sl@0: if (iStatus.Int() == KErrNoMemory) sl@0: { sl@0: TExitType exitType = iCreatorThread.ExitType(); sl@0: if (EExitPending==exitType) // Still alive, so kill it sl@0: iCreatorThread.Kill(KErrNone); sl@0: } sl@0: sl@0: User::RequestComplete(iClientStatus, iStatus.Int()); sl@0: iAction = EIdle; sl@0: } sl@0: break; sl@0: default: sl@0: ASSERT(EFalse); sl@0: } sl@0: } sl@0: sl@0: TInt CKeyCreator::RunError(TInt anError) sl@0: { sl@0: if (iClientStatus) sl@0: User::RequestComplete(iClientStatus, anError); sl@0: sl@0: return (KErrNone); sl@0: } sl@0: sl@0: sl@0: sl@0: CKeyCreator::CKeyCreatorData::CKeyCreatorData(CKeyInfo::EKeyAlgorithm aAlgorithm, TInt aSize) sl@0: :iSize(aSize), sl@0: iKeyAlgorithm(aAlgorithm) sl@0: {} sl@0: sl@0: CKeyCreator::CKeyCreatorData::~CKeyCreatorData() sl@0: { sl@0: if (iKeyAlgorithm==CKeyInfo::ERSA) sl@0: delete iKey.iRSAKey; sl@0: else if (iKeyAlgorithm==CKeyInfo::EDSA) sl@0: delete iKey.iDSAKey; sl@0: else if (iKeyAlgorithm==CKeyInfo::EDH) sl@0: delete iKey.iDHKey; sl@0: } sl@0: