os/security/cryptoservices/filebasedcertificateandkeystores/test/tcryptotokenhai/tcryptotokenhai.cpp
First public contribution.
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
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".
9 * Initial Contributors:
10 * Nokia Corporation - initial contribution.
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.
25 #include "tcryptotokenhai.h"
26 #include "tkeydetails.h"
27 #include "cryptosignatureapi.h"
30 #include <cryptospi/cryptoparams.h>
31 #include <cryptospi/cryptospidef.h>
33 EXPORT_C CCryptoTokenHai* CCryptoTokenHai::NewLC(MCTToken* aToken)
35 CCryptoTokenHai* instance = new(ELeave) CCryptoTokenHai(*aToken);
36 CleanupStack::PushL(instance);
37 instance->ConstructL();
41 EXPORT_C CCryptoTokenHai* CCryptoTokenHai::NewL(MCTToken* aToken)
43 CCryptoTokenHai* instance = CCryptoTokenHai::NewLC(aToken);
44 CleanupStack::Pop(instance);
48 void CCryptoTokenHai::ConstructL()
50 User::LeaveIfError(iFs.Connect());
54 CCryptoTokenHai::CCryptoTokenHai(MCTToken& aToken)
58 EXPORT_C CCryptoTokenHai::~CCryptoTokenHai()
67 iKeys.ResetAndDestroy();
72 * Performs the decryption operation.
74 * This API gets called when the decryption is supposed to be done in
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.
83 * @leave This function can leave with following error codes:-
84 * - KErrNotFound - If the key corresponding to given handle is not
86 * - Any other error code returned by AllocL().
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.
95 EXPORT_C void CCryptoTokenHai::DecryptL( TInt aHandle,
96 const TDesC8& /* aCiphertext */,
99 TInt keyIndex = KeyPresent(aHandle);
100 if(keyIndex == KErrNotFound)
102 User::Leave(KErrNotFound);
105 ExportPrivateKeyL(aHandle, aPlainText);
109 * Performs the signing operation.
111 * This API gets called when the signing is supposed to be done inside
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.
121 * @leave This function can leave with following error codes:-
122 * - KErrNotFound - If the key corresponding to given handle is not
124 * - Any other error code returned by AllocL().
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.
133 EXPORT_C void CCryptoTokenHai::SignL( TInt aHandle,
134 const TDesC8& /* aPlaintext */,
135 HBufC8*& aSignature )
137 TInt keyIndex = KeyPresent(aHandle);
138 if(keyIndex == KErrNotFound)
140 User::Leave(KErrNotFound);
143 ExportPrivateKeyL(aHandle, aSignature);
147 * Returns the index of the key whose handle is given.
149 * @param aHandle Handle of the key. This is used to search the key.
151 * @return index of the key if search is successful, KErrNotFound
154 EXPORT_C TInt CCryptoTokenHai::KeyPresent( TInt aHandle )
156 int keysCount = iKeys.Count();
157 for(TInt i=0; i < keysCount; ++i)
159 if(iKeys[i]->Handle() == aHandle)
168 * Extracts the private key.
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.
174 * @leave Following leave codes possible:-
175 * - Any leave code returned by AllocL().
176 * - KErrNotFound - If key corresponding to the given handle is not
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.
185 EXPORT_C void CCryptoTokenHai::ExportPrivateKeyL( TInt aHandle, HBufC8*& aKey )
187 int keysCount = iKeys.Count();
188 for(int i = 0; i < keysCount; ++i)
190 if(iKeys[i]->Handle() == aHandle)
192 aKey = iKeys[i]->PrivateKey()->AllocL();
196 User::Leave(KErrNotFound);
200 * Extracts the public key.
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.
206 * @leave Following leave codes possible:-
207 * - Any leave code returned by AllocL().
208 * - KErrNotFound - If key corresponding to the given handle is not
211 EXPORT_C void CCryptoTokenHai::ExportPublicKeyL( TInt aHandle, HBufC8*& aKey )
213 int keysCount = iKeys.Count();
214 for(int i = 0; i < keysCount; ++i)
216 if(iKeys[i]->Handle() == aHandle)
218 aKey = iKeys[i]->PublicKey()->AllocL();
222 User::Leave(KErrNotFound);
226 * Stores the key with given details.
228 * @param aLabel Label of the key.
229 * @param aPrivateKey Private component of the key.
230 * @param aPublicKey Public component of the key.
232 * @leave Following leave codes possible:-
233 * - KErrAlreadyExists If there is already a key with the inputted
235 * - Any other leave code returned by NewL() or AppendL().
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.
242 EXPORT_C void CCryptoTokenHai::ImportKeyL(const TDesC& aLabel,
243 const TDesC8& aPrivateKey, const TDesC8& aPublicKey)
245 int keysCount = iKeys.Count();
246 for(int i = 0; i < keysCount; ++i)
248 if(iKeys[i]->Label() == aLabel)
250 User::Leave(KErrAlreadyExists);
253 CKeyDetails* keyDetails = CKeyDetails::NewL(keysCount+1,aLabel,aPrivateKey,aPublicKey);
254 iKeys.AppendL(keyDetails);
258 * Populates the string containing full RAM path of file containing
261 void CCryptoTokenHai::MakePrivateFilenameL(RFs& aFs, const TDesC& aLeafName, TDes& aNameOut)
263 aNameOut.SetLength(0);
264 aNameOut.Append(RFs::GetSystemDriveChar());
266 aNameOut.Append(':');
269 TBuf<20> privatePath;
270 User::LeaveIfError(aFs.PrivatePath(privatePath));
271 aNameOut.Append(privatePath);
273 aNameOut.Append(aLeafName);
277 * Creates the corresponding directory, if it does not exist.
279 void CCryptoTokenHai::EnsurePathL(RFs& aFs, const TDesC& aFile)
281 TInt err = aFs.MkDirAll(aFile);
282 if (err != KErrNone && err != KErrAlreadyExists)
289 * Populates the string containing full ROM path of the keys file.
291 void CCryptoTokenHai::MakePrivateROMFilenameL(RFs& aFs, const TDesC& aLeafName, TDes& aNameOut)
293 _LIT(KFileStoreROMDrive, "Z:");
295 aNameOut.Copy(KFileStoreROMDrive);
298 TBuf<20> privatePath;
299 User::LeaveIfError(aFs.PrivatePath(privatePath));
300 aNameOut.Append(privatePath);
301 aNameOut.Append(aLeafName);
305 * Copies the contents of source file to destination file.
307 * This is typically used to copy the keys file from ROM to RAM.
309 void CCryptoTokenHai::CopyL(RFs& aFs, const TDesC& aSouce, const TDesC& aDest)
312 User::LeaveIfError(in.Open(aFs, aSouce, EFileRead | EFileShareReadersOnly));
313 CleanupClosePushL(in);
315 RFileWriteStream out;
316 User::LeaveIfError(out.Replace(aFs, aDest, EFileWrite | EFileShareExclusive));
317 CleanupClosePushL(out);
320 CleanupStack::PopAndDestroy(2, &in);
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.
328 _LIT(KKeyStoreFilename,"hwkeys.dat");
331 * Opens a store containing hardware keys.
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.
338 void CCryptoTokenHai::OpenStoreL()
341 MakePrivateFilenameL(iFs, KKeyStoreFilename, fullPath);
343 EnsurePathL(iFs, fullPath);
344 TRAPD(result, OpenStoreInFileL(fullPath));
346 if (result == KErrInUse )
348 // Cannot access the file now. Abort rather than wiping the keystore.
352 if (result != KErrNone )
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
359 TRAPD(result2, CopyStoreFromROML(fullPath, result));
361 if (KErrNone != result2)
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
368 CreateStoreInFileL(fullPath);
375 * Copies the key store file from ROM to RAM.
377 void CCryptoTokenHai::CopyStoreFromROML(const TDesC& fullPath, TInt result)
379 if (result != KErrNotFound)
381 // Wipe the keystore if we can't open it (it's corrupt anyway)
382 User::LeaveIfError(iFs.Delete(fullPath));
386 MakePrivateROMFilenameL(iFs, KKeyStoreFilename, romPath);
388 // Copy data from rom and open it
389 CopyL(iFs, romPath, fullPath);
390 OpenStoreInFileL(fullPath);
394 * Opens a store from the given file.
396 void CCryptoTokenHai::OpenStoreInFileL(const TDesC& aFile)
399 User::LeaveIfError(file.Open(iFs, aFile, EFileRead | EFileWrite | EFileShareAny));
400 CleanupClosePushL(file);
404 iFileStore = CPermanentFileStore::FromL(file);
405 // iFileStore takes ownership of file now
406 CleanupStack::Pop(&file);
408 // Get the salt, root and manager TStreamIds
409 iRootStreamId = iFileStore->Root();
410 if (iRootStreamId == KNullStreamId)
412 User::Leave(KErrCorrupt);
414 RStoreReadStream rootStream;
415 rootStream.OpenLC(*iFileStore, iRootStreamId);
416 ReadKeysFromStoreL();
417 CleanupStack::PopAndDestroy(&rootStream);
421 * Creates a keys store in RAM from scratch.
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.
428 void CCryptoTokenHai::CreateStoreInFileL(const TDesC& aFile)
430 TInt r = iFs.MkDirAll(aFile);
431 if ( (r!=KErrNone) && (r!=KErrAlreadyExists) )
436 iFileStore = CPermanentFileStore::ReplaceL(iFs, aFile, EFileRead | EFileWrite | EFileShareExclusive);
437 iFileStore->SetTypeL(KPermanentFileStoreLayoutUid);
439 TCleanupItem cleanupStore(RevertStore, iFileStore);
440 CleanupStack::PushL(cleanupStore);
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
453 * Copies the keys stored in the instance to inputted write stream.
455 * This invokes the CKeyDetails::ExternalizeL() function.
457 void CCryptoTokenHai::WriteKeysToStoreL(RStoreWriteStream& aRootStream)
459 TInt keyCount = iKeys.Count();
460 aRootStream.WriteInt32L(keyCount);
462 for (TInt index = 0; index < keyCount; index++)
464 aRootStream << *iKeys[index];
466 aRootStream.CommitL();
470 * Copies the keys present in the read store to instance of class.
472 * This eventually invokes the CKeyDetails::InternalizeL() function.
474 void CCryptoTokenHai::ReadKeysFromStoreL()
476 RStoreReadStream rootStream;
478 rootStream.OpenLC(*iFileStore, iRootStreamId);
479 TInt keyCount = rootStream.ReadInt32L();
481 for (TInt index = 0; index < keyCount; index++)
483 CKeyDetails* keyDetails = CKeyDetails::NewL(rootStream);
484 iKeys.Append(keyDetails);
486 CleanupStack::PopAndDestroy(&rootStream);
490 * This is a cleanup item that reverts the store.
492 void CCryptoTokenHai::RevertStore(TAny* aStore)
494 CPermanentFileStore* store = reinterpret_cast<CPermanentFileStore*>(aStore);
495 TRAP_IGNORE(store->RevertL());
499 * Compacts the store.
501 void CCryptoTokenHai::CompactStore()
504 TRAP_IGNORE(iFileStore->ReclaimL(); iFileStore->CompactL());
508 * Populates the list of keys based on the input filter.
510 * @param aFilter Set of conditions to be used to decide which keys
512 * @param aKeys Output param. Contains the array of keys which fulfil
513 * criteria mentioned in filter. Caller should take responsibility of
516 * @leave Any of the system wide error codes.
518 * @note Though Crypto Token HAI internally operates in CKeyDetails,
519 * this function returns CCTKeyInfo array.
521 EXPORT_C void CCryptoTokenHai::ListL(const TCTKeyAttributeFilter& aFilter ,
522 RPointerArray<CCTKeyInfo>& aKeys) const
524 TInt count = iKeys.Count();
525 for(TInt index = 0 ;index < count; ++ index)
527 const CKeyDetails* keyDetails = iKeys[index];
529 if(KeyMatchesFilterL(*keyDetails,aFilter))
531 MCTAuthenticationObject* authObject = NULL;
532 HBufC8* attribute = keyDetails->PKCS8AttributeSet().AllocLC();
533 HBufC* label = keyDetails->Label().AllocLC();
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);
541 CleanupStack::Pop(2, attribute); // label
542 CleanupReleasePushL(*keyInfo);
544 User::LeaveIfError(aKeys.Append(keyInfo));
545 CleanupStack::Pop(keyInfo);
553 * Takes in a filter and key details and decides if key fulfils the
556 * @param aInfo The Key Details
557 * @param aFilter Filter specifying the conditions to be satisfied for
560 * @retval ETrue if key satisfies the conditions specified in filter
561 * @retval EFalse otherwise.
563 * @leave KErrArgument If there is an issue in policy filter.
565 TBool CCryptoTokenHai::KeyMatchesFilterL(const CKeyDetails& aInfo,
566 const TCTKeyAttributeFilter& aFilter) const
569 if (aFilter.iKeyId.Length() && aFilter.iKeyId != aInfo.ID())
574 if (aFilter.iUsage != EPKCS15UsageAll)
576 if ((aInfo.Usage() & aFilter.iUsage) == 0)
580 if (aFilter.iKeyAlgorithm != CCTKeyInfo::EInvalidAlgorithm &&
581 aFilter.iKeyAlgorithm != aInfo.Algorithm())
586 switch (aFilter.iPolicyFilter)
588 case TCTKeyAttributeFilter::EAllKeys:
592 case TCTKeyAttributeFilter::EUsableKeys:
593 if (!aInfo.UsePolicy().CheckPolicy(RThread()))
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.
603 case TCTKeyAttributeFilter::EUsableOrManageableKeys:
604 if (!aInfo.UsePolicy().CheckPolicy(RThread()) &&
605 !aInfo.ManagementPolicy().CheckPolicy(RThread()))
612 User::Leave(KErrArgument);