/*
* Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "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: 
* UNIFIEDKEYSTORE.H
* The unified key store implementation
*
*/


/**
 @file 
 @publishedPartner
 @released
*/
 
#ifndef __UNIFIEDKEYSTORE_H__
#define __UNIFIEDKEYSTORE_H__

#include <f32file.h>
#include <e32base.h>

#include <mctkeystoremanager.h>


/**
 * Unified KeyStore panics 
 *
 * @publishedPartner
 * @released
 */
enum TUnifiedKeyStorePanic
	{
	EUnexpectedInitialise		= 1,	///< Unexpected initialise
	EArrayAccessOutOfBounds		= 2,	///< Array access out of bounds
	ETokensArrayAlreadyInUse	= 3,	///< Tokens array already in use
	EUnrecognisedState			= 4,	///< Unrecognised state
	};

/**
 * The unified key store.
 * 
 * This class provides a key store whose contents are the sum of the contents of
 * all key store implementations on the device.  It is intended a single point
 * of access for clients wishing to access key stores.
 *
 * Since this class is intended for widespread use, capability checks relating
 * to key access are documented here even though the checks are actually made in
 * the individual key store implementations.
 * 
 * @publishedPartner
 * @released
 */
NONSHARABLE_CLASS(CUnifiedKeyStore) : public CActive, public MKeyStore
	{
 public:	
	/**
	 * Creates a new CUnifiedKeyStore object.
	 * 
	 * @param aFs	A file server session. It must already be open.
	 * @return		A pointer to an instance of the CUnifiedKeyStore class.
	 */
	IMPORT_C static CUnifiedKeyStore* NewL(RFs& aFs);
	
	/**
	 * Creates a new CUnifiedKeyStore object and and puts a pointer to the new object 
	 * onto the cleanup stack.
	 * 
	 * @param aFs	A file server session. It must already be open.
	 * @return		A pointer to an instance of the CUnifiedKeyStore class.
	 */
	IMPORT_C static CUnifiedKeyStore* NewLC(RFs& aFs);

	/**
	 * The destructor destroys all the resources owned by this object.
	 */
	IMPORT_C ~CUnifiedKeyStore();

	/**
	 * Initialises the manager.
	 * 
	 * It must be called after the manager has been constructed and before any call 
	 * to the manager functions.
	 * 
	 * This is an asynchronous request.
	 * 
	 * @param aStatus	The request status object; contains the result of the Initialize() 
	 * 					request when complete. Set to KErrCancel if any outstanding request is cancelled.
	 */
	IMPORT_C void Initialize(TRequestStatus& aStatus);

	/** 
	 * Cancels an ongoing Initialize() operation.
	 *
	 * The operation completes with KErrCancel.
	 */
	IMPORT_C void CancelInitialize();
	
public:  // Implementation of MKeyStore interface
	virtual void List(RMPointerArray<CCTKeyInfo>& aKeys, const TCTKeyAttributeFilter& aFilter, TRequestStatus& aStatus);
	virtual void CancelList();
	virtual void GetKeyInfo(TCTTokenObjectHandle aHandle, CCTKeyInfo*& aInfo,TRequestStatus& aStatus);
	virtual void CancelGetKeyInfo();
	virtual void Open(const TCTTokenObjectHandle& aHandle, 
					  MRSASigner*& aSigner,
					  TRequestStatus& aStatus);
	virtual void Open(const TCTTokenObjectHandle& aHandle, 
					  MDSASigner*& aSigner, 
					  TRequestStatus& aStatus);
	virtual void Open(const TCTTokenObjectHandle& aHandle, 
					  MCTDecryptor*& aDecryptor,
					  TRequestStatus& aStatus);
	virtual void Open(const TCTTokenObjectHandle& aHandle, 
					  MCTDH*& aDH, TRequestStatus& aStatus);
	virtual void CancelOpen();
	virtual void ExportPublic(const TCTTokenObjectHandle& aHandle,
							  HBufC8*& aPublicKey,
							  TRequestStatus& aStatus);
	virtual void CancelExportPublic();


public:		//	For MCTKeyStoreManager except those (CreateKey, ImportKey, ImportEncryptedKey)
			//	that require a caller-specified store
	
	/**
	 * Exports a key pair in the clear.
	 *
	 * The key is exported as DER-encoded PKCS#8 data.
	 *
	 * @param aHandle	The handle of the key to export
	 * @param aKey		A reference to a HBufC8 pointer.  The pointer will be set to
	 *					a newly allocated buffer containing the key data.  It is the caller's
	 *					responsibility to delete this buffer.
	 * @param aStatus	The request status object; contains the result of the ExportKey() request 
	 *					when complete. Set to KErrCancel if any outstanding request is cancelled.
	 *				
	 * @capability ReadUserData		Requires the caller to have ReadUserData capability
	 * @leave KErrPermissionDenied	If the caller does not have ReadUserData capability, 
	 *								or is not the owner of the key.
	 * @leave KErrNotFound			If the key the handle referes to does not exist.
	 * @leave KErrKeyAccess			If the sensitive flag is set for the key, or the
	 *								exportable flag is not set.
	 * @leave KErrKeyAlgorithm		If this type of key cannot be exported.
	 */
	IMPORT_C void ExportKey(TCTTokenObjectHandle aHandle, HBufC8*& aKey, TRequestStatus& aStatus);

	/** 
	 * Cancels an ongoing ExportKey() operation.
	 *
	 * The operation completes with KErrCancel.
	 */
	IMPORT_C void CancelExportKey();

	/**
	 * Exports an encrypted key pair.
	 *
	 * The key is exported as DER-encoded PKCS#5/PKCS#8 data.
	 *
	 * @param aHandle	The handle of the key to export
	 * @param aKey		A reference to a HBufC8 pointer.  The pointer will be set to
	 *					a newly allocated buffer containing the key data.
	 * @param aParams	The PBE encryption parameters to use when encrypting the key.
	 * @param aStatus	The request status object; contains the result of the ExportEncryptedKey() request 
	 *					when complete. Set to KErrCancel if any outstanding request is cancelled.
	 * 
	 * @capability ReadUserData		Requires the caller to have ReadUserData capability
	 * @leave KErrPermissionDenied	If the caller does not have ReadUserData capability,
	 *								or is not the owner of the key.
	 * @leave KErrNotFound			If the key the handle referes to does not exist. 
	 * @leave KErrKeyAccess			If the exportable flag is not set for the key.
	 * @leave KErrKeyAlgorithm		If this type of key cannot be exported.
	 */
	IMPORT_C void ExportEncryptedKey(TCTTokenObjectHandle aHandle, const CPBEncryptParms& aEncryptParams, 
									 HBufC8*& aKey, TRequestStatus& aStatus);

	/** 
	 * Cancels an ongoing ExportEncryptedKey() operation.
	 *
	 * The operation completes with KErrCancel.
	 */
	IMPORT_C void CancelExportEncryptedKey();

	/**
	 * Deletes a key.
	 * 
	 * @param aHandle	The handle of the key to delete
	 * @param aStatus	The request status object; contains the result of the DeleteKey() request 
	 *					when complete. Set to KErrCancel if any outstanding request is cancelled.
	 *	
	 * @capability WriteUserData	Requires the caller to have WriteUserData capability
	 * @leave KErrPermissionDenied	If the caller does not have WriteUserData capability,
	 *								or is not the owner of the key.
	 * @leave KErrNotFound			If the key the handle referes to does not exist. 
	 * @leave KErrAccessDenied		If the calling process is not allowed to delete the key.
	 * @leave KErrInUse				If another client is currently using the key.
	 */
	IMPORT_C void DeleteKey(TCTTokenObjectHandle aHandle, TRequestStatus& aStatus);

	/** 
	 * Cancels an ongoing DeleteKey() operation.
	 *
	 * The operation completes with KErrCancel.
	 */
	IMPORT_C void CancelDeleteKey();

	/**
	 * Sets the security policy for key use.
	 *
	 * Specifies which processes are allowed to use the key for cryptographic
	 * operations.
	 *
	 * @param aHandle	The handle of the key
	 * @param aPolicy	The new security policy.
	 * @param aStatus	The request status object; contains the result of the SetUsePolicy() request 
	 *					when complete. Set to KErrCancel if any outstanding request is cancelled.
	 *	
	 * @capability WriteUserData	Requires the caller to have WriteUserData capability
	 * @leave KErrPermissionDenied	If the caller does not have WriteUserData capability,
	 *								or is not the owner of the key.
	 * @leave KErrNotFound			If the key the handle referes to does not exist.
	 */
	IMPORT_C void SetUsePolicy(TCTTokenObjectHandle aHandle,
							  const TSecurityPolicy& aPolicy,
							  TRequestStatus& aStatus);

	/** 
	 * Cancels an ongoing SetUsePolicy() operation.
	 *
	 * The operation completes with KErrCancel.
	 */
	IMPORT_C void CancelSetUsePolicy();

	/**
	 * Sets the security policy for key management.
	 *
	 * Specifies which processes are allowed to perform management operations on
	 * the key.
	 *
	 * @param aHandle	The handle of the key
	 * @param aPolicy	The new security policy.
	 * @param aStatus	The request status object; contains the result of the SetManagementPolicy() request 
	 *					when complete. Set to KErrCancel if any outstanding request is cancelled.
	 *	
	 * @capability WriteUserData	Requires the caller to have WriteUserData capability
	 * @leave KErrPermissionDenied	If the caller does not have WriteUserData capability,
	 *								or is not the owner of the key.
	 * @leave KErrNotFound			If the key the handle referes to does not exist.
	 */
	IMPORT_C void SetManagementPolicy(TCTTokenObjectHandle aHandle,
									  const TSecurityPolicy& aPolicy,
									  TRequestStatus& aStatus);

	/** 
	 * Cancels an ongoing SetManagementPolicy() operation.
	 *
	 * The operation completes with KErrCancel.
	 */
	IMPORT_C void CancelSetManagementPolicy();

	/**
	 * Sets the passphrase timeout for all keys owned by this process.
	 * 
	 * @param aTimeout	The timeout in seconds. 0 means that the passphrase is
	 *     				always asked for, and -1 means that it is never expired
	 * @param aStatus	The request status object; contains the result of the SetPassphraseTimeout() request 
	 *					when complete. Set to KErrCancel if any outstanding request is cancelled.
	 *	
	 * @capability WriteUserData	Requires the caller to have WriteUserData capability
	 * @leave KErrPermissionDenied	If the caller does not have WriteUserData capability,
	 *								or is not the owner of the key
	 * @leave KErrArgument			If the timeout specified is invalid.
	 */
	IMPORT_C void SetPassphraseTimeout(TInt aTimeout, TRequestStatus& aStatus);

	/** 
	 * Cancels an ongoing SetPassphraseTimeout() operation. 
	 *
	 * The operation completes with KErrCancel.
	 */
	IMPORT_C void CancelSetPassphraseTimeout();

	/** 
	 * Re-locks the entire store (i.e., forget the passphrase).
	 *
	 * @param aStatus	The request status object; contains the result of the Relock() request 
	 *					when complete. Set to KErrCancel if any outstanding request is cancelled.
	 */
	IMPORT_C void Relock(TRequestStatus& aStatus);
	
	/** 
	 * Cancels an ongoing Relock() operation.
	 *
	 * The operation completes with KErrCancel.
	 */
	IMPORT_C void CancelRelock();
	
public:
	/**
	 * Generates a new key pair.
	 *
	 * For the software key store, the owner of the new key is set to the
	 * calling process.  Users can subsequently be added by calling SetUsers().
	 *	
	 * @param aKeyStoreIndex  The index of the key store manager in which to
	 *                        create the key.  Must be between zero and
	 *	                      KeyStoreMangerCount() exclusive.		
	 * @param aUsage		  The key usage flags in the PKCS#15 format.
	 * @param aSize		      The size of the key in bits.
	 * @param aLabel		  A textual label for the key.
	 * @param aAlgorithm	  The type of key.
	 * @param aAccessType     The key access type - a bitfield specifying key
	 *	                      access requirements.  Allowed values are zero, or
	 *	                      a comination of CCTKeyInfo::EKeyAccess::ESenstive
	 *	                      and CCTKeyInfo::EKeyAccess::EExtractable
	 * @param aStartDate	  The start of the validity period.
	 * @param aEndDate		  The end of the validity period.	
	 * @param aKeyInfoOut     A pointer that is set to a newly created key info
	 *	                      object on successful completion.
	 * @param aStatus		  The request status object; contains the result of
	 *						  the CreateKey() request when complete. Set to 
	 *						  KErrCancel if any outstanding request is cancelled.
	 *   
	 * @capability WriteUserData	Requires the caller to have WriteUserData capability
	 * @leave KErrPermissionDenied	If the caller does not have WriteUserData capability
	 * @leave KErrKeyUsage			If the key usage flags are not valid or not
	 *								consistent with the key algorithm.
	 * @leave KErrKeyValidity		If the validity start and end dates are specified
	 *								but do not form a valid time period.
	 * @panic						If aKeyStoreIndex does not specify a valid keystore manager.
	 */
	IMPORT_C void CreateKey(TInt aKeyStoreIndex, TKeyUsagePKCS15 aUsage,TUint aSize, 
							const TDesC& aLabel, CCTKeyInfo::EKeyAlgorithm aAlgorithm, 
							TInt aAccessType, TTime aStartDate, TTime aEndDate, 
							CCTKeyInfo*& aKeyInfoOut, TRequestStatus& aStatus);
	
	/** 
	 * Cancels an ongoing CreateKey() operation. 
	 *
	 * The operation completes with KErrCancel.
	 */
	IMPORT_C void CancelCreateKey();

	/**
	 * Imports a key pair.
	 *
	 * For the software key store, the owner of the new key is set to the
	 * calling process.  Users can subsequently be added by calling SetUsers().
	 *
	 * The key data should be in PKCS#8 format.  Both encrypted and cleartext
	 * versions are allowed.
	 *
	 * @param aKeyStoreIndex  The index of the key store manager in which to
	 *	                      create the key.  Must be between zero and
	 *	                      KeyStoreMangerCount() exclusive.			
	 * @param aKeyData		  The key data to import, ASN.1 DER encoded PKCS#8.
	 * @param aUsage		  The key usage flags in the PKCS#15 format.
	 * @param aLabel		  A textual label for the key.
	 * @param aAccessType     The key access type - a bitfield specifying key
	 *	                      access requirements.  Allowed values are zero, or
	 *	                      a comination of CCTKeyInfo::EKeyAccess::ESenstive
	 *	                      and CCTKeyInfo::EKeyAccess::EExtractable
	 * @param aStartDate	  The start of the validity period.
	 * @param aEndDate		  The end of the validity period.	
	 * @param aKeyInfoOut     A pointer that is set to a newly created key info
	 *	                      object on successful completion.
	 * @param aStatus		  The request status object; contains the result of
	 *						  the ImportKey() request when complete. Set to 
	 *						  KErrCancel if any outstanding request is cancelled.
	 *	                      
	 * @capability WriteUserData	Requires the caller to have WriteUserData capability
	 * @leave KErrPermissionDenied	If the caller does not have WriteUserData capability
	 * @leave KErrKeyUsage			If the key usage flags are not valid or not
	 *								consistent with the key algorithm.
	 * @leave KErrKeyValidity		If the validity start and end dates are specified
	 *								but do not form a valid time period.
	 * @leave KErrArgument			If the key data cannot be parsed.
	 * @panic						If aKeyStoreIndex does not specify a valid keystore manager.
	 */
	IMPORT_C void ImportKey(TInt aKeyStoreIndex, const TDesC8& aKeyData,
							TKeyUsagePKCS15 aUsage, const TDesC& aLabel, 
							TInt aAccessType, TTime aStartDate, TTime aEndDate, 
							CCTKeyInfo*& aKeyInfoOut, TRequestStatus& aStatus);
	
	/** 
	 * Cancels an ongoing ImportKey() operation. 
	 *
	 * The operation completes with KErrCancel.
	 */
	IMPORT_C void CancelImportKey();
	
public:
	
	/**
	 * Gets the number of available read-only key stores.
	 * 
	 * @return	The number of available read-only key stores.
	 */
	IMPORT_C TInt KeyStoreCount() const;
	
	/**
	 * Gets a read-only interface to a key store.
	 * 
	 * @param aIndex				An ordinal number that identifies the key store.
	 * @return						A read-only interface to the key store specified by aIndex.
	 * 
	 * @panic CUnifiedKeyStore 2    If aIndex is out of range, ie it is greater
	 * 								than or equal to the value returned by KeyStoreCount().
	 */
	IMPORT_C MCTKeyStore& KeyStore(TInt aIndex);
	
	/**
	 * Gets the number of available read-write key stores.
	 * 
	 * @return	The number of key stores that are open for read-write access.
	 */
	IMPORT_C TInt KeyStoreManagerCount() const;
	
	/**
	 * Gets a read-write interface to the store specified by aIndex.
	 * 
	 * @param aIndex				An ordinal number that identifies the key store.
	 * @return						A read-write interface to the key store specified by aIndex.
	 * 
	 * @panic CUnifiedKeyStore 2    If aIndex s out of range, ie it is greater than
	 * 								or equal to the value returned by KeyStoreManagerCount().
	 */
	IMPORT_C MCTKeyStoreManager& KeyStoreManager(TInt aIndex);
	
private:
	CUnifiedKeyStore(RFs& aFs);
	void ConstructL();
private:	//	From CActive
	void RunL();
	TInt RunError(TInt aError);
	void DoCancel();
private:
	enum TState
		{
		EIdle,
		EInitializeGetTokenList,
		EInitializeGetToken,
		EInitialiseGetKeyManagerInterface,
		EInitializeGetKeyUserInterface,
		EInitializeGetKeyUserInterfaceFinished,
		EInitializeFinished,
	//	----------------------------------------------
		EList,
		EGetKeyInfo,
		EOpen,
	//	----------------------------------------------
		ECreateKey,
		EImportKey,
		EImportKeyEncrypted,
		EExportKey,
		EExportEncryptedKey,
		EExportPublic,
		EDeleteKey,
		ESetUsePolicy,
		ESetManagementPolicy,
		ESetPassphraseTimeout,
		ERelock,
		ESetAuthenticationPolicy,
		EGetAuthenticationPolicy
		};
private:
	void StartAsyncOperation(TState aState, TRequestStatus& aStatus);
	void DoInitializeL();
	TBool DoOpen(const TCTTokenObjectHandle& aHandle, 
				 TRequestStatus& aStatus);
	void PrepareToCreateKeyL(TInt aKeyStoreIndex,
							TKeyUsagePKCS15 aUsage, TUint aSize, 
							const TDesC& aLabel,
							CCTKeyInfo::EKeyAlgorithm aAlgorithm,
							TInt aAccessType,
							TTime aStartDate, TTime aEndDate,  
							TRequestStatus& aStatus);
	/**
	 * A synchronous method to find the key store given a token object handle.
	 * Returns NULL if none found.
	 */
	MCTKeyStore* FindKeyStore(const TCTTokenObjectHandle& aHandle);
	/**
	 * A synchronous method to find the key store manager given a token object
	 * handle.  Returns NULL if none found.
	 */
	MCTKeyStoreManager* FindKeyStoreManager(const TCTTokenObjectHandle& aHandle);
	/** Complete the user's request and clean up state. */
	void Complete(TInt aError);
	/** Clean up state. */
	void Cleanup();
	/** Cancel the outstanding request. */
	void CancelOutstandingRequest();
private:
	/**
	 * A wrapper around a keystore interface that remebers whether it is a
	 * readonly or manager interface.
	 */
	class CKeyStoreIF
	{
	public:
		CKeyStoreIF(MCTTokenInterface*, TBool);
		~CKeyStoreIF();
	public:
		inline MCTTokenInterface* KeyStore() const {return (iKeyStore);};
		inline TBool IsKeyManager() const {return (iIsKeyManager);};
	private:
		CKeyStoreIF(){};
	private:
		MCTTokenInterface* iKeyStore;
		TBool iIsKeyManager;
	};
private:
	RFs& iFs;
	TState iState;
	TRequestStatus* iOriginalRequestStatus;
	RPointerArray<CKeyStoreIF> iKeyStoresHolder;

	RCPointerArray<CCTTokenTypeInfo> iTokenTypes;
	TInt iIndexTokenTypes;
	MCTTokenType* iTokenType;	
	MCTToken* iToken;
	MCTTokenInterface* iTokenInterface;
	TUid iRequestUid;	
	RCPointerArray<HBufC> iTokens;
	TInt iIndexTokens;
	
	MCTKeyStore* iKeyStore;               ///< The key store in use by the current operation or NULL
	MCTKeyStoreManager* iKeyStoreManager; ///< The key store manager in use by the current operation or NULL
	
	RMPointerArray<CCTKeyInfo>* iKeyInfos;
	TCTKeyAttributeFilter* iFilter;
	CCTKeyInfo* iKeyInfo;
	HBufC8* iKeyData;
	CCTKeyInfo** iKeyInfoOut; 			 ///< Pointer to client's key info pointer
	CPBEncryptParms* iPbeParams;     // PBE parameters for encrypted key export

	TInt iIndex;
	TInt iNewTimeout;
};

#endif
