os/security/cryptoservices/filebasedcertificateandkeystores/test/tcryptotokenhai/tcryptotokenhai.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /*
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
     3 * All rights reserved.
     4 * This component and the accompanying materials are made available
     5 * under the terms of the License "Eclipse Public License v1.0"
     6 * which accompanies this distribution, and is available
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
     8 *
     9 * Initial Contributors:
    10 * Nokia Corporation - initial contribution.
    11 *
    12 * Contributors:
    13 *
    14 * Description: 
    15 * This class implements the reference Crypto Token Hardware Abstraction 
    16 * Interface (HAI). It is just intended to show how operations using 
    17 * device keys can be performed using crypto token framework. In the 
    18 * real world scenario, this HAI should be replaced by device drivers 
    19 * by the licensees. In such a case, all the operations performed by 
    20 * the replacing class would be performed in Kernel Space.
    21 *
    22 */
    23 
    24 
    25 #include "tcryptotokenhai.h"
    26 #include "tkeydetails.h"
    27 #include "cryptosignatureapi.h"
    28 #include "keys.h"
    29 
    30 #include <cryptospi/cryptoparams.h>
    31 #include <cryptospi/cryptospidef.h>
    32 
    33 EXPORT_C CCryptoTokenHai* CCryptoTokenHai::NewLC(MCTToken* aToken)
    34 	{
    35 	CCryptoTokenHai* instance = new(ELeave) CCryptoTokenHai(*aToken);
    36 	CleanupStack::PushL(instance);
    37 	instance->ConstructL();
    38 	return instance;
    39 	}
    40 
    41 EXPORT_C CCryptoTokenHai* CCryptoTokenHai::NewL(MCTToken* aToken)
    42 	{
    43 	CCryptoTokenHai* instance = CCryptoTokenHai::NewLC(aToken);
    44 	CleanupStack::Pop(instance);
    45 	return instance;
    46 	}
    47 
    48 void CCryptoTokenHai::ConstructL()
    49 	{
    50 	User::LeaveIfError(iFs.Connect());
    51 	OpenStoreL();
    52 	}
    53 
    54 CCryptoTokenHai::CCryptoTokenHai(MCTToken& aToken)
    55 	:iToken(aToken)
    56 	{}
    57 
    58 EXPORT_C CCryptoTokenHai::~CCryptoTokenHai()
    59 	{
    60 	if(iFileStore)
    61         {
    62         CompactStore();
    63         delete iFileStore;
    64         }
    65 	
    66 	iFs.Close();
    67 	iKeys.ResetAndDestroy();
    68     iKeys.Close();
    69 	}
    70 
    71 /**
    72  * Performs the decryption operation.
    73  * 
    74  * This API gets called when the decryption is supposed to be done in  
    75  * the hardware.
    76  * 
    77  * @param aHandle The key handle
    78  * @param aCiphertext The cipher text. This is not being used presently 
    79  * due to decryption logic used in this function.
    80  * @param aPlainText Output param. The decrypted plain text. Ownership 
    81  * of the pointer lies with the caller.
    82  * 
    83  * @leave This function can leave with following error codes:-
    84  * - KErrNotFound - If the key corresponding to given handle is not 
    85  * found.
    86  * - Any other error code returned by AllocL().
    87  *
    88  * @note This function does not actually implement ECC decryption. It 
    89  * just intends to show that the key is with this class and it can 
    90  * do actual ECC decryption here. This function just returns the 
    91  * private key as decrypted text. The caller can verify the decryption 
    92  * by ensuring that test case has same public and private keys and then 
    93  * comparing the decrypted text with public key. 
    94  */
    95 EXPORT_C void CCryptoTokenHai::DecryptL(	TInt aHandle,	
    96 											const TDesC8& /* aCiphertext */,
    97 											HBufC8*& aPlainText )
    98 	{
    99     TInt keyIndex = KeyPresent(aHandle);
   100     if(keyIndex == KErrNotFound)
   101         {
   102         User::Leave(KErrNotFound);
   103         }
   104     
   105     ExportPrivateKeyL(aHandle, aPlainText);
   106 	}
   107 
   108 /**
   109  * Performs the signing operation.
   110  * 
   111  * This API gets called when the signing is supposed to be done inside 
   112  * the hardware.
   113  * 
   114  * @param aHandle The key handle
   115  * @param aPlaintext The text which has to be signed. This is not being 
   116  * used due to signing logic used in this function.
   117  * @param aSignature Output param. The signature in HBufC8 format.  
   118  * Ownership of the pointer lies with the caller. This should be 
   119  * converted to CCryptoParams by the crypto token reference plugin. 
   120  * 
   121  * @leave This function can leave with following error codes:-
   122  * - KErrNotFound - If the key corresponding to given handle is not 
   123  * found.
   124  * - Any other error code returned by AllocL().
   125  * 
   126  * @note This function does not actually implement ECC signing. It 
   127  * just intends to show that the key is with this class and it can 
   128  * do actual ECC signing here. Currently this function just returns 
   129  * the private key as output signature. The caller can verify the 
   130  * signature by ensuring that test case has same public and private 
   131  * keys and then comparing the signature with public key.
   132  */
   133 EXPORT_C void CCryptoTokenHai::SignL( 	TInt aHandle,
   134 										const TDesC8& /* aPlaintext */,
   135 										HBufC8*& aSignature )
   136 	{
   137 	TInt keyIndex = KeyPresent(aHandle);
   138 	if(keyIndex == KErrNotFound)
   139 	    {
   140 	    User::Leave(KErrNotFound);
   141 	    }
   142 	
   143 	ExportPrivateKeyL(aHandle, aSignature);
   144 	}
   145 
   146 /**
   147  * Returns the index of the key whose handle is given.
   148  * 
   149  * @param aHandle Handle of the key. This is used to search the key.
   150  * 
   151  * @return index of the key if search is successful, KErrNotFound 
   152  * otherwise.
   153  */
   154 EXPORT_C TInt CCryptoTokenHai::KeyPresent( TInt aHandle )
   155 	{
   156 	int keysCount = iKeys.Count();
   157 	for(TInt i=0; i < keysCount; ++i)
   158 		{
   159 		if(iKeys[i]->Handle() == aHandle)
   160 			{
   161 			return i;
   162 			}
   163 		}
   164 	return KErrNotFound;
   165 	}
   166 
   167 /**
   168  * Extracts the private key.
   169  * 
   170  * @param aHandle Handle of the private key to be extracted.
   171  * @param aKey Output Parameter. Stores the private key on success. 
   172  * Ownership of pointer is with the caller.
   173  * 
   174  * @leave Following leave codes possible:-
   175  * - Any leave code returned by AllocL().
   176  * - KErrNotFound - If key corresponding to the given handle is not 
   177  * found.
   178  * 
   179  * @note In the actual implementation, licensees should ensure that 
   180  * this function can be called only in Kernel space. In the reference 
   181  * implementation, this function gets called only by CCryptoSpiHai, 
   182  * which is assumed to operate in kernel space. This would ensure that 
   183  * the private key always stays inside the hardware.
   184  */
   185 EXPORT_C void CCryptoTokenHai::ExportPrivateKeyL( TInt aHandle, HBufC8*& aKey )
   186 	{
   187 	int keysCount = iKeys.Count();
   188 	for(int i = 0; i < keysCount; ++i)
   189 		{
   190 		if(iKeys[i]->Handle() == aHandle)
   191 			{
   192 			aKey = iKeys[i]->PrivateKey()->AllocL();
   193 			return;
   194 			}
   195 		}
   196 	User::Leave(KErrNotFound);
   197 	}
   198 
   199 /**
   200  * Extracts the public key.
   201  * 
   202  * @param aHandle Handle of the public key to be extracted.
   203  * @param aKey Output Parameter. Stores the public key on success.
   204  * Ownership of pointer is with the caller.
   205  * 
   206  * @leave Following leave codes possible:-
   207  * - Any leave code returned by AllocL().
   208  * - KErrNotFound - If key corresponding to the given handle is not 
   209  * found.
   210  */
   211 EXPORT_C void CCryptoTokenHai::ExportPublicKeyL( TInt aHandle, HBufC8*& aKey )
   212     {
   213     int keysCount = iKeys.Count();
   214     for(int i = 0; i < keysCount; ++i)
   215         {
   216         if(iKeys[i]->Handle() == aHandle)
   217             {
   218             aKey = iKeys[i]->PublicKey()->AllocL();
   219             return;
   220             }
   221         }
   222     User::Leave(KErrNotFound);
   223     }
   224 
   225 /**
   226  * Stores the key with given details.
   227  * 
   228  * @param aLabel Label of the key.
   229  * @param aPrivateKey Private component of the key.
   230  * @param aPublicKey Public component of the key.
   231  * 
   232  * @leave Following leave codes possible:-
   233  * - KErrAlreadyExists If there is already a key with the inputted
   234  * label.
   235  * - Any other leave code returned by NewL() or AppendL().
   236  *  
   237  * @note In the present reference implementation this function is not 
   238  * being used, since device keys are pre-provisioned by the licensees. 
   239  * Hence licensees may decide not to implement this function in their 
   240  * real implementation. 
   241  */
   242 EXPORT_C void CCryptoTokenHai::ImportKeyL(const TDesC& aLabel, 
   243         const TDesC8& aPrivateKey, const TDesC8& aPublicKey)
   244 	{
   245 	int keysCount = iKeys.Count();
   246 	for(int i = 0; i < keysCount; ++i)
   247 		{
   248 		if(iKeys[i]->Label() == aLabel)
   249 			{
   250 			User::Leave(KErrAlreadyExists);
   251 			}
   252 		}
   253 	CKeyDetails* keyDetails = CKeyDetails::NewL(keysCount+1,aLabel,aPrivateKey,aPublicKey);
   254 	iKeys.AppendL(keyDetails);
   255 	}
   256 
   257 /**
   258  * Populates the string containing full RAM path of file containing 
   259  * keys.
   260  */
   261 void CCryptoTokenHai::MakePrivateFilenameL(RFs& aFs, const TDesC& aLeafName, TDes& aNameOut)
   262     {
   263     aNameOut.SetLength(0);  
   264     aNameOut.Append(RFs::GetSystemDriveChar());
   265 
   266     aNameOut.Append(':');
   267 
   268     // Get private path
   269     TBuf<20> privatePath;
   270     User::LeaveIfError(aFs.PrivatePath(privatePath));
   271     aNameOut.Append(privatePath);
   272     
   273     aNameOut.Append(aLeafName);
   274     }
   275 
   276 /**
   277  * Creates the corresponding directory, if it does not exist.
   278  */
   279 void CCryptoTokenHai::EnsurePathL(RFs& aFs, const TDesC& aFile)
   280     {
   281     TInt err = aFs.MkDirAll(aFile);
   282     if (err != KErrNone && err != KErrAlreadyExists)
   283         {
   284         User::Leave(err);
   285         }
   286     }
   287 
   288 /**
   289  * Populates the string containing full ROM path of the keys file.
   290  */
   291 void CCryptoTokenHai::MakePrivateROMFilenameL(RFs& aFs, const TDesC& aLeafName, TDes& aNameOut)
   292     {
   293     _LIT(KFileStoreROMDrive, "Z:");
   294     
   295     aNameOut.Copy(KFileStoreROMDrive);
   296 
   297     // Get private path
   298     TBuf<20> privatePath;
   299     User::LeaveIfError(aFs.PrivatePath(privatePath)); 
   300     aNameOut.Append(privatePath);
   301     aNameOut.Append(aLeafName);
   302     }
   303 
   304 /**
   305  * Copies the contents of source file to destination file.
   306  * 
   307  * This is typically used to copy the keys file from ROM to RAM.
   308  */
   309 void CCryptoTokenHai::CopyL(RFs& aFs, const TDesC& aSouce, const TDesC& aDest)
   310     {
   311     RFileReadStream in;
   312     User::LeaveIfError(in.Open(aFs, aSouce, EFileRead | EFileShareReadersOnly));
   313     CleanupClosePushL(in);
   314 
   315     RFileWriteStream out;
   316     User::LeaveIfError(out.Replace(aFs, aDest, EFileWrite | EFileShareExclusive));
   317     CleanupClosePushL(out);
   318 
   319     in.ReadL(out);  
   320     CleanupStack::PopAndDestroy(2, &in);
   321     }
   322 
   323 /**
   324  * Keys corresponding to this store are present in hwkeys.dat. 
   325  * In the production code written by licensees, this would be the path 
   326  * where device keys are stored.
   327  */
   328 _LIT(KKeyStoreFilename,"hwkeys.dat");
   329 
   330 /**
   331  * Opens a store containing hardware keys.
   332  * 
   333  * This function uses the following logic to open the store:-
   334  * -# Try to open the store from the private directory.
   335  * -# If this fails copy the file from ROM to RAM.
   336  * -# If both fail, create your own keys store from scratch.
   337  */
   338 void CCryptoTokenHai::OpenStoreL()
   339 	{
   340 	TFileName fullPath;
   341 	MakePrivateFilenameL(iFs, KKeyStoreFilename, fullPath);
   342 
   343 	EnsurePathL(iFs, fullPath);
   344 	TRAPD(result, OpenStoreInFileL(fullPath));
   345 
   346 	if (result == KErrInUse  ) 
   347 		{		
   348 		// Cannot access the file now. Abort rather than wiping the keystore.
   349 		User::Leave(result); 
   350 		}
   351 	
   352 	if (result != KErrNone )
   353 		{		
   354 		/*
   355 		 * Not yet opened a valid store, either no file to be found, or 
   356 		 * no valid store in it. Copy the original one stored in the 
   357 		 * ROM.
   358 		 */
   359 		TRAPD(result2, CopyStoreFromROML(fullPath, result));
   360 				
   361 		if (KErrNone != result2)
   362 			{
   363 			/*
   364 			 * We tried to copy the keystore from ROM. For some reason this
   365 			 * failed and we still cannot open the file. Create a new one from
   366 			 * scratch.
   367 			 */ 
   368 			CreateStoreInFileL(fullPath);
   369 			}
   370 		}
   371 
   372 	}
   373 
   374 /**
   375  * Copies the key store file from ROM to RAM.
   376  */
   377 void CCryptoTokenHai::CopyStoreFromROML(const TDesC& fullPath, TInt result)
   378     {
   379     if (result != KErrNotFound)
   380         {
   381         // Wipe the keystore if we can't open it (it's corrupt anyway)
   382         User::LeaveIfError(iFs.Delete(fullPath));
   383         }
   384 
   385     TFileName romPath;
   386     MakePrivateROMFilenameL(iFs, KKeyStoreFilename, romPath);
   387 
   388     // Copy data from rom and open it   
   389     CopyL(iFs, romPath, fullPath);
   390     OpenStoreInFileL(fullPath);
   391     }
   392 
   393 /**
   394  * Opens a store from the given file.
   395  */
   396 void CCryptoTokenHai::OpenStoreInFileL(const TDesC& aFile)
   397 	{
   398 	RFile file;
   399 	User::LeaveIfError(file.Open(iFs, aFile, EFileRead | EFileWrite | EFileShareAny));
   400 	CleanupClosePushL(file);
   401     delete iFileStore;
   402     iFileStore = NULL;
   403 
   404 	iFileStore = CPermanentFileStore::FromL(file);
   405     // iFileStore takes ownership of file now
   406 	CleanupStack::Pop(&file);
   407 	
   408     // Get the salt, root and manager TStreamIds
   409     iRootStreamId = iFileStore->Root();
   410     if (iRootStreamId == KNullStreamId)
   411         {
   412         User::Leave(KErrCorrupt);
   413         }
   414     RStoreReadStream rootStream;
   415     rootStream.OpenLC(*iFileStore, iRootStreamId);
   416     ReadKeysFromStoreL();
   417     CleanupStack::PopAndDestroy(&rootStream);
   418     }
   419 
   420 /**
   421  * Creates a keys store in RAM from scratch.
   422  * 
   423  * @note This function should never get called as hwkeys.dat should be 
   424  * always present in ROM. If this function somehow gets called, it 
   425  * will create a hwkeys.dat file from scratch. However, this file would 
   426  * not contain any keys and tests would not pass.
   427  */
   428 void CCryptoTokenHai::CreateStoreInFileL(const TDesC& aFile)
   429 	{
   430 	TInt r = iFs.MkDirAll(aFile);
   431 	if ( (r!=KErrNone) && (r!=KErrAlreadyExists) )
   432 		User::Leave(r);
   433 
   434     delete iFileStore;
   435     iFileStore = NULL;
   436 	iFileStore = CPermanentFileStore::ReplaceL(iFs, aFile, EFileRead | EFileWrite | EFileShareExclusive);
   437 	iFileStore->SetTypeL(KPermanentFileStoreLayoutUid);
   438 
   439 	TCleanupItem cleanupStore(RevertStore, iFileStore);
   440 	CleanupStack::PushL(cleanupStore);
   441 	
   442 	// Create root stream - just contains id of info stream
   443 	RStoreWriteStream rootStream;
   444 	iRootStreamId = rootStream.CreateLC(*iFileStore);
   445 	iFileStore->SetRootL(iRootStreamId);
   446 	WriteKeysToStoreL(rootStream);
   447 	iFileStore->CommitL();
   448 	CleanupStack::PopAndDestroy(&rootStream);
   449 	CleanupStack::Pop(); // cleanupStore
   450 	}
   451 
   452 /**
   453  * Copies the keys stored in the instance to inputted write stream.
   454  * 
   455  * This invokes the CKeyDetails::ExternalizeL() function.
   456  */
   457 void CCryptoTokenHai::WriteKeysToStoreL(RStoreWriteStream& aRootStream)
   458 	{
   459 	TInt keyCount = iKeys.Count();
   460 	aRootStream.WriteInt32L(keyCount);
   461 
   462 	for (TInt index = 0; index < keyCount; index++)
   463 		{
   464 		aRootStream << *iKeys[index];
   465 		}
   466 	aRootStream.CommitL();
   467 	}
   468 
   469 /**
   470  * Copies the keys present in the read store to instance of class.
   471  * 
   472  * This eventually invokes the CKeyDetails::InternalizeL() function.
   473  */
   474 void CCryptoTokenHai::ReadKeysFromStoreL()
   475 	{
   476 	RStoreReadStream rootStream;
   477 	
   478 	rootStream.OpenLC(*iFileStore, iRootStreamId);
   479 	TInt keyCount = rootStream.ReadInt32L();
   480 
   481 	for (TInt index = 0; index < keyCount; index++)
   482 		{
   483 		CKeyDetails* keyDetails = CKeyDetails::NewL(rootStream);
   484 		iKeys.Append(keyDetails);
   485 		}
   486 	CleanupStack::PopAndDestroy(&rootStream);
   487 	}
   488 
   489 /**
   490  * This is a cleanup item that reverts the store.
   491  */
   492 void CCryptoTokenHai::RevertStore(TAny* aStore)
   493 	{
   494 	CPermanentFileStore* store = reinterpret_cast<CPermanentFileStore*>(aStore);
   495 	TRAP_IGNORE(store->RevertL());
   496 	}
   497 
   498 /**
   499  * Compacts the store.
   500  */
   501 void CCryptoTokenHai::CompactStore()
   502     {
   503     ASSERT(iFileStore);
   504     TRAP_IGNORE(iFileStore->ReclaimL(); iFileStore->CompactL());
   505     }
   506 
   507 /**
   508  * Populates the list of keys based on the input filter.
   509  * 
   510  * @param aFilter Set of conditions to be used to decide which keys 
   511  * should be listed
   512  * @param aKeys Output param. Contains the array of keys which fulfil 
   513  * criteria mentioned in filter. Caller should take responsibility of 
   514  * this array.
   515  * 
   516  * @leave Any of the system wide error codes.
   517  * 
   518  * @note Though Crypto Token HAI internally operates in CKeyDetails, 
   519  * this function returns CCTKeyInfo array.
   520  */
   521 EXPORT_C void CCryptoTokenHai::ListL(const TCTKeyAttributeFilter&  aFilter , 
   522                 RPointerArray<CCTKeyInfo>& aKeys) const
   523     {
   524     TInt count = iKeys.Count();
   525     for(TInt index = 0 ;index < count; ++ index)
   526     	{
   527     	const CKeyDetails* keyDetails = iKeys[index];
   528     	
   529     	if(KeyMatchesFilterL(*keyDetails,aFilter))
   530     		{
   531 			MCTAuthenticationObject* authObject = NULL;
   532 			HBufC8* attribute = keyDetails->PKCS8AttributeSet().AllocLC();
   533 			HBufC* label = keyDetails->Label().AllocLC();
   534 			
   535 			CCTKeyInfo* keyInfo = CCTKeyInfo::NewL(
   536 					keyDetails->ID(),keyDetails->Usage(),keyDetails->Size(),
   537 					authObject,label,iToken,keyDetails->Handle(),keyDetails->UsePolicy(),
   538 					keyDetails->ManagementPolicy(),keyDetails->Algorithm(),keyDetails->AccessType(),
   539 					keyDetails->Native(),keyDetails->StartDate(),keyDetails->EndDate(),attribute);
   540 			
   541 			CleanupStack::Pop(2, attribute); // label
   542 			CleanupReleasePushL(*keyInfo);
   543 						
   544 			User::LeaveIfError(aKeys.Append(keyInfo));
   545 			CleanupStack::Pop(keyInfo); 
   546 			
   547 			}
   548     	}
   549     	
   550     }
   551 
   552 /**
   553  * Takes in a filter and key details and decides if key fulfils the 
   554  * filter criteria.
   555  * 
   556  * @param aInfo The Key Details
   557  * @param aFilter Filter specifying the conditions to be satisfied for 
   558  * listing the keys.
   559  * 
   560  * @retval ETrue if key satisfies the conditions specified in filter
   561  * @retval EFalse otherwise.
   562  * 
   563  * @leave KErrArgument If there is an issue in policy filter.
   564  */
   565 TBool CCryptoTokenHai::KeyMatchesFilterL(const CKeyDetails& aInfo,
   566 										   const TCTKeyAttributeFilter& aFilter) const
   567 	{
   568 		
   569 	if (aFilter.iKeyId.Length() && aFilter.iKeyId != aInfo.ID())
   570 		{
   571 		return EFalse;
   572 		}
   573 
   574 	if (aFilter.iUsage != EPKCS15UsageAll)
   575 		{
   576 		if ((aInfo.Usage() & aFilter.iUsage) == 0)
   577 			return EFalse;
   578 		}
   579 
   580 	if (aFilter.iKeyAlgorithm != CCTKeyInfo::EInvalidAlgorithm && 
   581 		aFilter.iKeyAlgorithm != aInfo.Algorithm())
   582 		{
   583 		return EFalse;
   584 		}
   585 	
   586 	switch (aFilter.iPolicyFilter)
   587 		{
   588 		case TCTKeyAttributeFilter::EAllKeys:
   589 			// All keys pass
   590 			break;
   591 			   
   592 		case TCTKeyAttributeFilter::EUsableKeys:
   593 			if (!aInfo.UsePolicy().CheckPolicy(RThread()))
   594 				{
   595 				return EFalse;
   596 				}
   597 			break;
   598 		case TCTKeyAttributeFilter::EManageableKeys:
   599 			// As this key store implementation is a hardware simulation,
   600 			// the support for managing through software interface has been diabled.
   601 			return EFalse;
   602 
   603 		case TCTKeyAttributeFilter::EUsableOrManageableKeys:
   604 			if (!aInfo.UsePolicy().CheckPolicy(RThread()) &&
   605 				!aInfo.ManagementPolicy().CheckPolicy(RThread()))
   606 				{
   607 				return EFalse;
   608 				}
   609 			break;
   610 						
   611 		default:
   612 			User::Leave(KErrArgument);
   613 		}
   614 
   615 	return ETrue;
   616 	}
   617 
   618 
   619