sl@0: /* sl@0: * Copyright (c) 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: * This class implements the reference Crypto Token Hardware Abstraction sl@0: * Interface (HAI). It is just intended to show how operations using sl@0: * device keys can be performed using crypto token framework. In the sl@0: * real world scenario, this HAI should be replaced by device drivers sl@0: * by the licensees. In such a case, all the operations performed by sl@0: * the replacing class would be performed in Kernel Space. sl@0: * sl@0: */ sl@0: sl@0: sl@0: #include "tcryptotokenhai.h" sl@0: #include "tkeydetails.h" sl@0: #include "cryptosignatureapi.h" sl@0: #include "keys.h" sl@0: sl@0: #include sl@0: #include sl@0: sl@0: EXPORT_C CCryptoTokenHai* CCryptoTokenHai::NewLC(MCTToken* aToken) sl@0: { sl@0: CCryptoTokenHai* instance = new(ELeave) CCryptoTokenHai(*aToken); sl@0: CleanupStack::PushL(instance); sl@0: instance->ConstructL(); sl@0: return instance; sl@0: } sl@0: sl@0: EXPORT_C CCryptoTokenHai* CCryptoTokenHai::NewL(MCTToken* aToken) sl@0: { sl@0: CCryptoTokenHai* instance = CCryptoTokenHai::NewLC(aToken); sl@0: CleanupStack::Pop(instance); sl@0: return instance; sl@0: } sl@0: sl@0: void CCryptoTokenHai::ConstructL() sl@0: { sl@0: User::LeaveIfError(iFs.Connect()); sl@0: OpenStoreL(); sl@0: } sl@0: sl@0: CCryptoTokenHai::CCryptoTokenHai(MCTToken& aToken) sl@0: :iToken(aToken) sl@0: {} sl@0: sl@0: EXPORT_C CCryptoTokenHai::~CCryptoTokenHai() sl@0: { sl@0: if(iFileStore) sl@0: { sl@0: CompactStore(); sl@0: delete iFileStore; sl@0: } sl@0: sl@0: iFs.Close(); sl@0: iKeys.ResetAndDestroy(); sl@0: iKeys.Close(); sl@0: } sl@0: sl@0: /** sl@0: * Performs the decryption operation. sl@0: * sl@0: * This API gets called when the decryption is supposed to be done in sl@0: * the hardware. sl@0: * sl@0: * @param aHandle The key handle sl@0: * @param aCiphertext The cipher text. This is not being used presently sl@0: * due to decryption logic used in this function. sl@0: * @param aPlainText Output param. The decrypted plain text. Ownership sl@0: * of the pointer lies with the caller. sl@0: * sl@0: * @leave This function can leave with following error codes:- sl@0: * - KErrNotFound - If the key corresponding to given handle is not sl@0: * found. sl@0: * - Any other error code returned by AllocL(). sl@0: * sl@0: * @note This function does not actually implement ECC decryption. It sl@0: * just intends to show that the key is with this class and it can sl@0: * do actual ECC decryption here. This function just returns the sl@0: * private key as decrypted text. The caller can verify the decryption sl@0: * by ensuring that test case has same public and private keys and then sl@0: * comparing the decrypted text with public key. sl@0: */ sl@0: EXPORT_C void CCryptoTokenHai::DecryptL( TInt aHandle, sl@0: const TDesC8& /* aCiphertext */, sl@0: HBufC8*& aPlainText ) sl@0: { sl@0: TInt keyIndex = KeyPresent(aHandle); sl@0: if(keyIndex == KErrNotFound) sl@0: { sl@0: User::Leave(KErrNotFound); sl@0: } sl@0: sl@0: ExportPrivateKeyL(aHandle, aPlainText); sl@0: } sl@0: sl@0: /** sl@0: * Performs the signing operation. sl@0: * sl@0: * This API gets called when the signing is supposed to be done inside sl@0: * the hardware. sl@0: * sl@0: * @param aHandle The key handle sl@0: * @param aPlaintext The text which has to be signed. This is not being sl@0: * used due to signing logic used in this function. sl@0: * @param aSignature Output param. The signature in HBufC8 format. sl@0: * Ownership of the pointer lies with the caller. This should be sl@0: * converted to CCryptoParams by the crypto token reference plugin. sl@0: * sl@0: * @leave This function can leave with following error codes:- sl@0: * - KErrNotFound - If the key corresponding to given handle is not sl@0: * found. sl@0: * - Any other error code returned by AllocL(). sl@0: * sl@0: * @note This function does not actually implement ECC signing. It sl@0: * just intends to show that the key is with this class and it can sl@0: * do actual ECC signing here. Currently this function just returns sl@0: * the private key as output signature. The caller can verify the sl@0: * signature by ensuring that test case has same public and private sl@0: * keys and then comparing the signature with public key. sl@0: */ sl@0: EXPORT_C void CCryptoTokenHai::SignL( TInt aHandle, sl@0: const TDesC8& /* aPlaintext */, sl@0: HBufC8*& aSignature ) sl@0: { sl@0: TInt keyIndex = KeyPresent(aHandle); sl@0: if(keyIndex == KErrNotFound) sl@0: { sl@0: User::Leave(KErrNotFound); sl@0: } sl@0: sl@0: ExportPrivateKeyL(aHandle, aSignature); sl@0: } sl@0: sl@0: /** sl@0: * Returns the index of the key whose handle is given. sl@0: * sl@0: * @param aHandle Handle of the key. This is used to search the key. sl@0: * sl@0: * @return index of the key if search is successful, KErrNotFound sl@0: * otherwise. sl@0: */ sl@0: EXPORT_C TInt CCryptoTokenHai::KeyPresent( TInt aHandle ) sl@0: { sl@0: int keysCount = iKeys.Count(); sl@0: for(TInt i=0; i < keysCount; ++i) sl@0: { sl@0: if(iKeys[i]->Handle() == aHandle) sl@0: { sl@0: return i; sl@0: } sl@0: } sl@0: return KErrNotFound; sl@0: } sl@0: sl@0: /** sl@0: * Extracts the private key. sl@0: * sl@0: * @param aHandle Handle of the private key to be extracted. sl@0: * @param aKey Output Parameter. Stores the private key on success. sl@0: * Ownership of pointer is with the caller. sl@0: * sl@0: * @leave Following leave codes possible:- sl@0: * - Any leave code returned by AllocL(). sl@0: * - KErrNotFound - If key corresponding to the given handle is not sl@0: * found. sl@0: * sl@0: * @note In the actual implementation, licensees should ensure that sl@0: * this function can be called only in Kernel space. In the reference sl@0: * implementation, this function gets called only by CCryptoSpiHai, sl@0: * which is assumed to operate in kernel space. This would ensure that sl@0: * the private key always stays inside the hardware. sl@0: */ sl@0: EXPORT_C void CCryptoTokenHai::ExportPrivateKeyL( TInt aHandle, HBufC8*& aKey ) sl@0: { sl@0: int keysCount = iKeys.Count(); sl@0: for(int i = 0; i < keysCount; ++i) sl@0: { sl@0: if(iKeys[i]->Handle() == aHandle) sl@0: { sl@0: aKey = iKeys[i]->PrivateKey()->AllocL(); sl@0: return; sl@0: } sl@0: } sl@0: User::Leave(KErrNotFound); sl@0: } sl@0: sl@0: /** sl@0: * Extracts the public key. sl@0: * sl@0: * @param aHandle Handle of the public key to be extracted. sl@0: * @param aKey Output Parameter. Stores the public key on success. sl@0: * Ownership of pointer is with the caller. sl@0: * sl@0: * @leave Following leave codes possible:- sl@0: * - Any leave code returned by AllocL(). sl@0: * - KErrNotFound - If key corresponding to the given handle is not sl@0: * found. sl@0: */ sl@0: EXPORT_C void CCryptoTokenHai::ExportPublicKeyL( TInt aHandle, HBufC8*& aKey ) sl@0: { sl@0: int keysCount = iKeys.Count(); sl@0: for(int i = 0; i < keysCount; ++i) sl@0: { sl@0: if(iKeys[i]->Handle() == aHandle) sl@0: { sl@0: aKey = iKeys[i]->PublicKey()->AllocL(); sl@0: return; sl@0: } sl@0: } sl@0: User::Leave(KErrNotFound); sl@0: } sl@0: sl@0: /** sl@0: * Stores the key with given details. sl@0: * sl@0: * @param aLabel Label of the key. sl@0: * @param aPrivateKey Private component of the key. sl@0: * @param aPublicKey Public component of the key. sl@0: * sl@0: * @leave Following leave codes possible:- sl@0: * - KErrAlreadyExists If there is already a key with the inputted sl@0: * label. sl@0: * - Any other leave code returned by NewL() or AppendL(). sl@0: * sl@0: * @note In the present reference implementation this function is not sl@0: * being used, since device keys are pre-provisioned by the licensees. sl@0: * Hence licensees may decide not to implement this function in their sl@0: * real implementation. sl@0: */ sl@0: EXPORT_C void CCryptoTokenHai::ImportKeyL(const TDesC& aLabel, sl@0: const TDesC8& aPrivateKey, const TDesC8& aPublicKey) sl@0: { sl@0: int keysCount = iKeys.Count(); sl@0: for(int i = 0; i < keysCount; ++i) sl@0: { sl@0: if(iKeys[i]->Label() == aLabel) sl@0: { sl@0: User::Leave(KErrAlreadyExists); sl@0: } sl@0: } sl@0: CKeyDetails* keyDetails = CKeyDetails::NewL(keysCount+1,aLabel,aPrivateKey,aPublicKey); sl@0: iKeys.AppendL(keyDetails); sl@0: } sl@0: sl@0: /** sl@0: * Populates the string containing full RAM path of file containing sl@0: * keys. sl@0: */ sl@0: void CCryptoTokenHai::MakePrivateFilenameL(RFs& aFs, const TDesC& aLeafName, TDes& aNameOut) sl@0: { sl@0: aNameOut.SetLength(0); sl@0: aNameOut.Append(RFs::GetSystemDriveChar()); sl@0: sl@0: aNameOut.Append(':'); sl@0: sl@0: // Get private path sl@0: TBuf<20> privatePath; sl@0: User::LeaveIfError(aFs.PrivatePath(privatePath)); sl@0: aNameOut.Append(privatePath); sl@0: sl@0: aNameOut.Append(aLeafName); sl@0: } sl@0: sl@0: /** sl@0: * Creates the corresponding directory, if it does not exist. sl@0: */ sl@0: void CCryptoTokenHai::EnsurePathL(RFs& aFs, const TDesC& aFile) sl@0: { sl@0: TInt err = aFs.MkDirAll(aFile); sl@0: if (err != KErrNone && err != KErrAlreadyExists) sl@0: { sl@0: User::Leave(err); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: * Populates the string containing full ROM path of the keys file. sl@0: */ sl@0: void CCryptoTokenHai::MakePrivateROMFilenameL(RFs& aFs, const TDesC& aLeafName, TDes& aNameOut) sl@0: { sl@0: _LIT(KFileStoreROMDrive, "Z:"); sl@0: sl@0: aNameOut.Copy(KFileStoreROMDrive); sl@0: sl@0: // Get private path sl@0: TBuf<20> privatePath; sl@0: User::LeaveIfError(aFs.PrivatePath(privatePath)); sl@0: aNameOut.Append(privatePath); sl@0: aNameOut.Append(aLeafName); sl@0: } sl@0: sl@0: /** sl@0: * Copies the contents of source file to destination file. sl@0: * sl@0: * This is typically used to copy the keys file from ROM to RAM. sl@0: */ sl@0: void CCryptoTokenHai::CopyL(RFs& aFs, const TDesC& aSouce, const TDesC& aDest) sl@0: { sl@0: RFileReadStream in; sl@0: User::LeaveIfError(in.Open(aFs, aSouce, EFileRead | EFileShareReadersOnly)); sl@0: CleanupClosePushL(in); sl@0: sl@0: RFileWriteStream out; sl@0: User::LeaveIfError(out.Replace(aFs, aDest, EFileWrite | EFileShareExclusive)); sl@0: CleanupClosePushL(out); sl@0: sl@0: in.ReadL(out); sl@0: CleanupStack::PopAndDestroy(2, &in); sl@0: } sl@0: sl@0: /** sl@0: * Keys corresponding to this store are present in hwkeys.dat. sl@0: * In the production code written by licensees, this would be the path sl@0: * where device keys are stored. sl@0: */ sl@0: _LIT(KKeyStoreFilename,"hwkeys.dat"); sl@0: sl@0: /** sl@0: * Opens a store containing hardware keys. sl@0: * sl@0: * This function uses the following logic to open the store:- sl@0: * -# Try to open the store from the private directory. sl@0: * -# If this fails copy the file from ROM to RAM. sl@0: * -# If both fail, create your own keys store from scratch. sl@0: */ sl@0: void CCryptoTokenHai::OpenStoreL() sl@0: { sl@0: TFileName fullPath; sl@0: MakePrivateFilenameL(iFs, KKeyStoreFilename, fullPath); sl@0: sl@0: EnsurePathL(iFs, fullPath); sl@0: TRAPD(result, OpenStoreInFileL(fullPath)); sl@0: sl@0: if (result == KErrInUse ) sl@0: { sl@0: // Cannot access the file now. Abort rather than wiping the keystore. sl@0: User::Leave(result); sl@0: } sl@0: sl@0: if (result != KErrNone ) sl@0: { sl@0: /* sl@0: * Not yet opened a valid store, either no file to be found, or sl@0: * no valid store in it. Copy the original one stored in the sl@0: * ROM. sl@0: */ sl@0: TRAPD(result2, CopyStoreFromROML(fullPath, result)); sl@0: sl@0: if (KErrNone != result2) sl@0: { sl@0: /* sl@0: * We tried to copy the keystore from ROM. For some reason this sl@0: * failed and we still cannot open the file. Create a new one from sl@0: * scratch. sl@0: */ sl@0: CreateStoreInFileL(fullPath); sl@0: } sl@0: } sl@0: sl@0: } sl@0: sl@0: /** sl@0: * Copies the key store file from ROM to RAM. sl@0: */ sl@0: void CCryptoTokenHai::CopyStoreFromROML(const TDesC& fullPath, TInt result) sl@0: { sl@0: if (result != KErrNotFound) sl@0: { sl@0: // Wipe the keystore if we can't open it (it's corrupt anyway) sl@0: User::LeaveIfError(iFs.Delete(fullPath)); sl@0: } sl@0: sl@0: TFileName romPath; sl@0: MakePrivateROMFilenameL(iFs, KKeyStoreFilename, romPath); sl@0: sl@0: // Copy data from rom and open it sl@0: CopyL(iFs, romPath, fullPath); sl@0: OpenStoreInFileL(fullPath); sl@0: } sl@0: sl@0: /** sl@0: * Opens a store from the given file. sl@0: */ sl@0: void CCryptoTokenHai::OpenStoreInFileL(const TDesC& aFile) sl@0: { sl@0: RFile file; sl@0: User::LeaveIfError(file.Open(iFs, aFile, EFileRead | EFileWrite | EFileShareAny)); sl@0: CleanupClosePushL(file); sl@0: delete iFileStore; sl@0: iFileStore = NULL; sl@0: sl@0: iFileStore = CPermanentFileStore::FromL(file); sl@0: // iFileStore takes ownership of file now sl@0: CleanupStack::Pop(&file); sl@0: sl@0: // Get the salt, root and manager TStreamIds sl@0: iRootStreamId = iFileStore->Root(); sl@0: if (iRootStreamId == KNullStreamId) sl@0: { sl@0: User::Leave(KErrCorrupt); sl@0: } sl@0: RStoreReadStream rootStream; sl@0: rootStream.OpenLC(*iFileStore, iRootStreamId); sl@0: ReadKeysFromStoreL(); sl@0: CleanupStack::PopAndDestroy(&rootStream); sl@0: } sl@0: sl@0: /** sl@0: * Creates a keys store in RAM from scratch. sl@0: * sl@0: * @note This function should never get called as hwkeys.dat should be sl@0: * always present in ROM. If this function somehow gets called, it sl@0: * will create a hwkeys.dat file from scratch. However, this file would sl@0: * not contain any keys and tests would not pass. sl@0: */ sl@0: void CCryptoTokenHai::CreateStoreInFileL(const TDesC& aFile) sl@0: { sl@0: TInt r = iFs.MkDirAll(aFile); sl@0: if ( (r!=KErrNone) && (r!=KErrAlreadyExists) ) sl@0: User::Leave(r); sl@0: sl@0: delete iFileStore; sl@0: iFileStore = NULL; sl@0: iFileStore = CPermanentFileStore::ReplaceL(iFs, aFile, EFileRead | EFileWrite | EFileShareExclusive); sl@0: iFileStore->SetTypeL(KPermanentFileStoreLayoutUid); sl@0: sl@0: TCleanupItem cleanupStore(RevertStore, iFileStore); sl@0: CleanupStack::PushL(cleanupStore); sl@0: sl@0: // Create root stream - just contains id of info stream sl@0: RStoreWriteStream rootStream; sl@0: iRootStreamId = rootStream.CreateLC(*iFileStore); sl@0: iFileStore->SetRootL(iRootStreamId); sl@0: WriteKeysToStoreL(rootStream); sl@0: iFileStore->CommitL(); sl@0: CleanupStack::PopAndDestroy(&rootStream); sl@0: CleanupStack::Pop(); // cleanupStore sl@0: } sl@0: sl@0: /** sl@0: * Copies the keys stored in the instance to inputted write stream. sl@0: * sl@0: * This invokes the CKeyDetails::ExternalizeL() function. sl@0: */ sl@0: void CCryptoTokenHai::WriteKeysToStoreL(RStoreWriteStream& aRootStream) sl@0: { sl@0: TInt keyCount = iKeys.Count(); sl@0: aRootStream.WriteInt32L(keyCount); sl@0: sl@0: for (TInt index = 0; index < keyCount; index++) sl@0: { sl@0: aRootStream << *iKeys[index]; sl@0: } sl@0: aRootStream.CommitL(); sl@0: } sl@0: sl@0: /** sl@0: * Copies the keys present in the read store to instance of class. sl@0: * sl@0: * This eventually invokes the CKeyDetails::InternalizeL() function. sl@0: */ sl@0: void CCryptoTokenHai::ReadKeysFromStoreL() sl@0: { sl@0: RStoreReadStream rootStream; sl@0: sl@0: rootStream.OpenLC(*iFileStore, iRootStreamId); sl@0: TInt keyCount = rootStream.ReadInt32L(); sl@0: sl@0: for (TInt index = 0; index < keyCount; index++) sl@0: { sl@0: CKeyDetails* keyDetails = CKeyDetails::NewL(rootStream); sl@0: iKeys.Append(keyDetails); sl@0: } sl@0: CleanupStack::PopAndDestroy(&rootStream); sl@0: } sl@0: sl@0: /** sl@0: * This is a cleanup item that reverts the store. sl@0: */ sl@0: void CCryptoTokenHai::RevertStore(TAny* aStore) sl@0: { sl@0: CPermanentFileStore* store = reinterpret_cast(aStore); sl@0: TRAP_IGNORE(store->RevertL()); sl@0: } sl@0: sl@0: /** sl@0: * Compacts the store. sl@0: */ sl@0: void CCryptoTokenHai::CompactStore() sl@0: { sl@0: ASSERT(iFileStore); sl@0: TRAP_IGNORE(iFileStore->ReclaimL(); iFileStore->CompactL()); sl@0: } sl@0: sl@0: /** sl@0: * Populates the list of keys based on the input filter. sl@0: * sl@0: * @param aFilter Set of conditions to be used to decide which keys sl@0: * should be listed sl@0: * @param aKeys Output param. Contains the array of keys which fulfil sl@0: * criteria mentioned in filter. Caller should take responsibility of sl@0: * this array. sl@0: * sl@0: * @leave Any of the system wide error codes. sl@0: * sl@0: * @note Though Crypto Token HAI internally operates in CKeyDetails, sl@0: * this function returns CCTKeyInfo array. sl@0: */ sl@0: EXPORT_C void CCryptoTokenHai::ListL(const TCTKeyAttributeFilter& aFilter , sl@0: RPointerArray& aKeys) const sl@0: { sl@0: TInt count = iKeys.Count(); sl@0: for(TInt index = 0 ;index < count; ++ index) sl@0: { sl@0: const CKeyDetails* keyDetails = iKeys[index]; sl@0: sl@0: if(KeyMatchesFilterL(*keyDetails,aFilter)) sl@0: { sl@0: MCTAuthenticationObject* authObject = NULL; sl@0: HBufC8* attribute = keyDetails->PKCS8AttributeSet().AllocLC(); sl@0: HBufC* label = keyDetails->Label().AllocLC(); sl@0: sl@0: CCTKeyInfo* keyInfo = CCTKeyInfo::NewL( sl@0: keyDetails->ID(),keyDetails->Usage(),keyDetails->Size(), sl@0: authObject,label,iToken,keyDetails->Handle(),keyDetails->UsePolicy(), sl@0: keyDetails->ManagementPolicy(),keyDetails->Algorithm(),keyDetails->AccessType(), sl@0: keyDetails->Native(),keyDetails->StartDate(),keyDetails->EndDate(),attribute); sl@0: sl@0: CleanupStack::Pop(2, attribute); // label sl@0: CleanupReleasePushL(*keyInfo); sl@0: sl@0: User::LeaveIfError(aKeys.Append(keyInfo)); sl@0: CleanupStack::Pop(keyInfo); sl@0: sl@0: } sl@0: } sl@0: sl@0: } sl@0: sl@0: /** sl@0: * Takes in a filter and key details and decides if key fulfils the sl@0: * filter criteria. sl@0: * sl@0: * @param aInfo The Key Details sl@0: * @param aFilter Filter specifying the conditions to be satisfied for sl@0: * listing the keys. sl@0: * sl@0: * @retval ETrue if key satisfies the conditions specified in filter sl@0: * @retval EFalse otherwise. sl@0: * sl@0: * @leave KErrArgument If there is an issue in policy filter. sl@0: */ sl@0: TBool CCryptoTokenHai::KeyMatchesFilterL(const CKeyDetails& aInfo, sl@0: const TCTKeyAttributeFilter& aFilter) const sl@0: { sl@0: sl@0: if (aFilter.iKeyId.Length() && aFilter.iKeyId != aInfo.ID()) sl@0: { sl@0: return EFalse; sl@0: } sl@0: sl@0: if (aFilter.iUsage != EPKCS15UsageAll) sl@0: { sl@0: if ((aInfo.Usage() & aFilter.iUsage) == 0) sl@0: return EFalse; sl@0: } sl@0: sl@0: if (aFilter.iKeyAlgorithm != CCTKeyInfo::EInvalidAlgorithm && sl@0: aFilter.iKeyAlgorithm != aInfo.Algorithm()) sl@0: { sl@0: return EFalse; sl@0: } sl@0: sl@0: switch (aFilter.iPolicyFilter) sl@0: { sl@0: case TCTKeyAttributeFilter::EAllKeys: sl@0: // All keys pass sl@0: break; sl@0: sl@0: case TCTKeyAttributeFilter::EUsableKeys: sl@0: if (!aInfo.UsePolicy().CheckPolicy(RThread())) sl@0: { sl@0: return EFalse; sl@0: } sl@0: break; sl@0: case TCTKeyAttributeFilter::EManageableKeys: sl@0: // As this key store implementation is a hardware simulation, sl@0: // the support for managing through software interface has been diabled. sl@0: return EFalse; sl@0: sl@0: case TCTKeyAttributeFilter::EUsableOrManageableKeys: sl@0: if (!aInfo.UsePolicy().CheckPolicy(RThread()) && sl@0: !aInfo.ManagementPolicy().CheckPolicy(RThread())) sl@0: { sl@0: return EFalse; sl@0: } sl@0: break; sl@0: sl@0: default: sl@0: User::Leave(KErrArgument); sl@0: } sl@0: sl@0: return ETrue; sl@0: } sl@0: sl@0: sl@0: