// Copyright (c) 2003-2010 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "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:
// CTlsProviderImpl.CPP
// 
//

#include <ecom/ecom.h>
#include <securitydefsconst.h>
#include <x520ava.h>
#include <asn1dec.h>

#include "tlsprovider.h"
#include "cryptostrength.h"


//
//  CTlsProviderImpl
//

/**
This method creates a new CTlsProviderImpl object
@return Pointer to a new CTlsProviderImpl object is returned

*/
CTlsProviderImpl* CTlsProviderImpl::ConnectL()
	{
	
	CTlsProviderImpl* tPtr = new (ELeave)CTlsProviderImpl;
	CleanupStack::PushL(tPtr);
	tPtr->ConstructL();
	tPtr->iTlsCryptoAttributes = CTlsCryptoAttributes::NewL();
	CleanupStack::Pop();
	return tPtr;	
	}


CTlsProviderImpl::CTlsProviderImpl()
	:CActive(0), iValidationStatus(EValidatedOK, 0), iTlsProviderPolicy(NULL)
	{
	  if(CActiveScheduler::Current()) //Allready installed?
		{
		CActiveScheduler::Add( this );
		}
	}

TInt CipherSuiteOrder(
		const TTLSCipherSuite& aLeft,
		const TTLSCipherSuite& aRight)
	{	
	if((aLeft.iHiByte == aRight.iHiByte) && (aLeft.iLoByte == aRight.iLoByte))
		return 1;
	else
		return 0;
	}

static TInt CompareCipherIdentities(
	const TTLSCipherSuite& aLeft, const TTLSCipherSuite& aRight)
/**
	This ordering relation is used by CTlsProviderImpl::ReturnCipherListL
	to ensure that cipher appears in a list at most once.  (It will
	also order the ciphers by identity, but that is incidental.)
	
	It is used with a TLinearOrder template and an RArray.
	It orders the ciphers by identity, which means iHiByte is the most
	significant byte, and iLoByte is the least significant byte.
	
	@param	aLeft			Left cipher suite to compare.
	@param	aRight			Right cipher suite to compare.
	@return					<0 if the left cipher's identity is less
							than the right cipher's; 0 if they are
							the same; >0 otherwise.
	@see CTlsProviderImpl::ReturnCipherListL
 */
	{
	TInt leftHi = aLeft.iHiByte;
	TInt leftLo = aLeft.iLoByte;
	TInt leftIdentity = (leftHi << 8) | leftLo;

	TInt rightHi = aRight.iHiByte;
	TInt rightLo = aRight.iLoByte;
	TInt rightIdentity = (rightHi << 8) | rightLo;

	return leftIdentity - rightIdentity;
	}


static TInt CompareCipherPriorities(	
	const TTLSCipherSuite& aLeft, const TTLSCipherSuite& aRight)
/**
	This ordering relation is used by CTlsProviderImpl::ReturnCipherListL
	to put the ciphers in priority order, highest priority first.
	A higher priority means the numerically lower value of iPriority.
	E.g. priority 1 is before priority 2.
	
	It is wrapped in a TLinearOrder object and used to sort an RArray.
	
	@param	aLeft			Left cipher suite to compare.
	@param	aRight			Right cipher suite to compare.
	@return					<0 if the left cipher's priority is gt
							the right cipher; 0 if they are the same;
							>0 otherwise.
	
	@see CTlsProviderImpl::ReturnCipherListL
 */
	{
	const TTLSCipherSuiteMapping* cipherDetail = aLeft.CipherDetails();
	TInt leftPri = (cipherDetail == NULL)? pri_unsupp:  cipherDetail->iPriority;
	cipherDetail = aRight.CipherDetails();
	TInt rightPri = (cipherDetail == NULL)? pri_unsupp:  cipherDetail->iPriority;
	
	return leftPri - rightPri;
	}


/**
The first call to CTlsProviderImpl takes place before ClientHello is sent,then as the handshake progresses, 
the information relevant for Provider and token will be gradually filled in a structure. This 
structure CTlsCryptoAttributes will be returned in this API, If the structure already exists,
then the pointer to the same structure is returned.
@param None
@return Pointer to a CTlsCryptoAttributes structure 
@see CTlsCryptoAttributes
*/
CTlsCryptoAttributes* CTlsCryptoAttributes::NewL()
	{
	CTlsCryptoAttributes* tPtr = new (ELeave)CTlsCryptoAttributes;
	CleanupStack::PushL(tPtr);
	tPtr->iPublicKeyParams = new (ELeave)CTLSPublicKeyParams;
	CleanupStack::Pop();
	return tPtr;
	}

CTlsCryptoAttributes::CTlsCryptoAttributes()
	{
	}

CTlsCryptoAttributes::~CTlsCryptoAttributes()
	{
	delete iPskIdentityHint;
	iReqCertTypes.Close();
	if(iPublicKeyParams)
		delete iPublicKeyParams;
    for ( TInt n = 0; n < iDistinguishedCANames.Count(); n++ )
      	{
      	HBufC8* buf = (HBufC8*)(iDistinguishedCANames[n]);
      	delete buf;
      	}
	iDistinguishedCANames.Close();
	
	delete iServerNames;
	if(iServerDNFromCertSubject)
		delete iServerDNFromCertSubject;
	if(iServerDNFromCertIssuer)
		delete iServerDNFromCertIssuer;
	}

CTlsCryptoAttributes* CTlsProviderImpl::Attributes() 
	{
	return iTlsCryptoAttributes;
	}


CTlsSessionImpl* CTlsProviderImpl::TlsSessionPtr() 
	{
	return iTlsSessionImpl;
	}


void CTlsProviderImpl::CreateL(
		CTLSSession*& aTlsSession,		
		TRequestStatus& aStatus) 
		{
		TInt Err = 0;
		aStatus = KRequestPending;
		iOriginalRequestStatus = &aStatus;
		aTlsSession = 0;
		iTlsSessionHldr = 0;
		if(IsActive())
			{
			Err = KErrInUse;			
			}

	
		if(iTlsCryptoAttributes)
 			{
			if((iTlsCryptoAttributes->iSessionNameAndID.iSessionId.Length()) && 
				(iTlsCryptoAttributes->iSessionNameAndID.iSessionId == iSessionData.iSessionId)
			  )
				{
				iSelectedTypeIndex = 0;
				iAbbreviatedHandshake = ETrue;
				}
			else
				{
				iAbbreviatedHandshake = EFalse;

 				TIdentityRelation<TTLSCipherSuite> CipherOrder(CipherSuiteOrder);
				if((iTlsCryptoAttributes->iNegotiatedProtocol != KTLS1_0) || (iTlsCryptoAttributes->iNegotiatedProtocol != KSSL3_0) )
 					Err = KErrSSLAlertIllegalParameter;
 				if(iSupportedCipherSuiteList.Count() &&
 					(iSupportedCipherSuiteList.Find((iTlsCryptoAttributes->iCurrentCipherSuite),CipherOrder) ==KErrNotFound))
 						Err = KErrSSLAlertIllegalParameter;
 				if(iTlsCryptoAttributes->iMasterSecretInput.iServerRandom.Size() != 32)
 					Err = KErrSSLAlertIllegalParameter;	
				if(!(
					(iTlsCryptoAttributes->iMasterSecretInput.iServerRandom).Compare(iTlsCryptoAttributes->iMasterSecretInput.iClientRandom)
					)
				  )
					Err = KErrSSLAlertIllegalParameter;	
				if(!iTotalTokenTypeCount)
					Err = KErrSSLAlertIllegalParameter;	
				}

			}

		if(Err != KErrNone || !iTlsCryptoAttributes)
			{	
   			User::RequestComplete(iOriginalRequestStatus, Err);
  			return; 
   			}

		iOriginalState =  ECreate;			
		iTlsSessionHldr = &aTlsSession;
		iSelectedTypeIndex = -1;	
		
		TBool TokenFound = EFalse;
		if(!iAbbreviatedHandshake) //Full handshake
			{
			TokenFound = SelectToken();

			if(!TokenFound) //No tokens supporting the selected cipher
				{
				User::RequestComplete(iOriginalRequestStatus, KErrCipherNotSupported);
				}
			else
				{
				if(iTlsCryptoAttributes->iClientAuthenticate)
					{
					//Before we initilize client authenticate, let's check if server
					//provides us it's DN name
					if(!iTlsCryptoAttributes->iDistinguishedCANames.Count())
						{
							//seems we need to use the server DN obtained from server cert as a backup
							iTlsCryptoAttributes->iDistinguishedCANames.AppendL(iTlsCryptoAttributes->iServerDNFromCertSubject);
							iTlsCryptoAttributes->iDistinguishedCANames.AppendL(iTlsCryptoAttributes->iServerDNFromCertIssuer);
							iTlsCryptoAttributes->iServerDNFromCertSubject = NULL; //ownership handover 
							iTlsCryptoAttributes->iServerDNFromCertIssuer = NULL; //ownership handover 
						}
					
					iClntAuthenticate = CTlsClntAuthenticate::NewL(*iTlsCryptoAttributes,
																	 iEncodedServerCerts);
					iCurrentState = EClientAuthenticate;
					
					iStoredIntermediatesCACertificates.Reset();
					iClntAuthenticate->DoClientAuthenticate(iSelectedCertInfo,
															iSelectedKeyInfo,
															&iStoredIntermediatesCACertificates,
															iStatus);
					SetActive();
					}
				else
					{
					// Get the session interface and create CtlsSession object
					TLSPROV_LOG2(_L("Using (newly selected) token %d's provider interface"), iSelectedTypeIndex)
					iPtrTokenSearch->GetSessionInterface(iListAllTokensAndTypes[iSelectedTypeIndex].iProviderInterface,
								iSessionInterface,iStatus);
					iCurrentState = EGetSessionInterface;
					iStatus = KRequestPending;
					SetActive();
					}
				}
			}
		else //Abbrevated handshake
			{
			iCurrentState = EGetSessionInterface;
			iNextState =  EConstructResumed;
			iStatus = KRequestPending;
			iPtrTokenSearch->GetSessionInterface(iSessionData.iProviderInterface,
			iSessionInterface,iStatus);
			SetActive();
			}
		return;
		}

void CTlsProviderImpl::GetSessionL(	
		TTLSServerAddr& aServerName,
		TTLSSessionId& aSessionId,
		TRequestStatus& aStatus) 
	{ 
	aStatus = KRequestPending;
	iOriginalRequestStatus = &aStatus;
	if(IsActive())
		{
		User::RequestComplete(iOriginalRequestStatus, KErrInUse);
		return;
		}

	iPServerName =  &aServerName;
	iOutputSessionData.iSessionId.Zero();
	iPSessionId= &aSessionId;

	if(iPtrTokenSearch)
		iTotalTokenTypeCount = iPtrTokenSearch->TotalTypeCount();

	iCurrentTokentype = 0;
	iCurrentToken = 0;
	iOriginalState = EGetSession;


	if(!iTotalTokenTypeCount)
		{	
		iCurrentState =  EBrowseTokens;
		iPtrTokenSearch = CTlsBrowseToken::NewL();		
		iStatus = KRequestPending;
		iPtrTokenSearch->StartBrowsingL(iListAllTokensAndTypes,iStatus);
		SetActive();
		return;
		}
	else
		RetrieveSession();
	
	return;	
	}

void CTlsProviderImpl::RetrieveSession()
	{

	while((iCurrentTokentype + 1) <= iListAllTokensAndTypes.Count())
		{
		iCurrentState = EGetSession;		
		iReqProtList.Reset();			
		if(iTlsCryptoAttributes)
			{		
			if((iTlsCryptoAttributes->iProposedProtocol.iMajor !=0)
				&& (iTlsCryptoAttributes->iProposedProtocol.iMajor != 0))
				{				
				iReqProtList.Append(iTlsCryptoAttributes->iProposedProtocol);
				}		
			}
		iStatus = KRequestPending;
		iListAllTokensAndTypes[iCurrentTokentype].iProviderInterface->GetSession(
				( (iOriginalState !=  EClearSessionCache)?(*iPServerName):(iServerNameAndId.iServerName)),
				iReqProtList,
				iOutputSessionData,iStatus);
		SetActive();	
		return;	
		}
	ReturnResult();
	}



void CTlsProviderImpl::CipherSuitesL(RArray<TTLSCipherSuite>& aUserCipherSuiteList,TRequestStatus& aStatus)
	{

	aStatus = KRequestPending;
	iOriginalState =  EGetCiphers;
	iOriginalRequestStatus = &aStatus;
	if(IsActive())
		{
		User::RequestComplete(iOriginalRequestStatus, KErrInUse);
		return;
		}
		
	TLSPROV_LOG2(_L("Obtaining the list of ciphersuites %d"), iTotalTokenTypeCount)

	iUserCipherSuiteList = &aUserCipherSuiteList;
	aUserCipherSuiteList.Reset();

	if(iPtrTokenSearch)
		iTotalTokenTypeCount = iListAllTokensAndTypes.Count();

	if(!iTotalTokenTypeCount)
		{	

		iCurrentState =  EBrowseTokens;
		iStatus = KRequestPending;
		iPtrTokenSearch = CTlsBrowseToken::NewL();		
		iPtrTokenSearch->StartBrowsingL(iListAllTokensAndTypes,iStatus);
		SetActive();
		return;		
		}
	else 
		{
		//we have the Token details already...so lets return the cipher list
		TRAPD(err,ReturnCipherListL());
		User::RequestComplete(iOriginalRequestStatus, err);
		}
	return;
	}

void CTlsProviderImpl::OnEBrowseTokens()
	{
   if ( iStatus == KErrNone )
      {
	   if(iPtrTokenSearch)
		   iTotalTokenTypeCount = iListAllTokensAndTypes.Count();

	   switch(iOriginalState)
	      {
	      case EGetCiphers:
		      ReturnResult();
		      break;
	      case EGetSession:
	      case EClearSessionCache:
		      {
		      RetrieveSession();		
		      }
		      break;
	      default:
		      break;
	      }
      }
   else
      {
		User::RequestComplete(iOriginalRequestStatus, iStatus.Int());
      }
	return;
	}	

void CTlsProviderImpl::VerifyServerCertificate(
		const TDesC8& aEncodedServerCerts, 
		CX509Certificate*& aServerCert,		  			
		TRequestStatus& aStatus)
	{
	aStatus = KRequestPending;
	iOriginalRequestStatus = &aStatus;
	if(IsActive())
		{
		User::RequestComplete(iOriginalRequestStatus, KErrInUse);
		return;
		}

	TTime ValidationTime;	
	ValidationTime.UniversalTime();
	iStatus = KRequestPending;
	iX509ServerCert= &aServerCert;

	iOriginalState =  EValidateCertificate;

	TRAPD(leaveValue, 		
		iEncodedServerCerts=aEncodedServerCerts.AllocL();		
		(iCertVerificationResult= CPKIXValidationResult::NewL()); 
		iServerCertsChain = CPKIXCertChain::NewL(iFs,  aEncodedServerCerts,
												  TUid::Uid(KUidUnicodeSSLProtocolModule));
      
		if ( iTlsProviderPolicy->PKICriticalExtensions() != 0 )
		    {
            TLSPROV_LOG2(_L("Adding %d additionally Supported Critical Extensions"), iTlsProviderPolicy->PKICriticalExtensions())
            iServerCertsChain->AddSupportedCriticalExtensionsL(iTlsProviderPolicy->GetPKICriticalExtensions());
		    }

		iServerCertsChain->ValidateL(*iCertVerificationResult,ValidationTime,iStatus) );
	
	if (leaveValue!=KErrNone)
		{
		delete iServerCertsChain;
		iServerCertsChain = 0;
		delete iEncodedServerCerts;
		iEncodedServerCerts = 0;
		iStatus = KErrNone;
		User::RequestComplete(iOriginalRequestStatus, leaveValue);
		}
	else
		{
		iCurrentState = EValidateCertificate;
		SetActive();
		}
	
	return;
	}

// This patch is to fix-up the Common Name component of the Subject field. 
// This is due to a bug in TASN1DecBMPString::DecodeContentsL which is incorrectly decoding the BMP String contents. 
// Since fixing TASN1DecBMPString would cause a major break in public API, this fix-up is being done here locally.
// This patch is active only if the encoding is in BMP String. If TASN1DecBMPString::DecodeContentsL is ever fixed (which 
// means CX500DistinguishedName::DisplayNameL is also automatically fixed) then this patch MUST to be removed.

HBufC* CTlsProviderImpl::ExtractCertFieldL(const TDesC& aFieldName, const CX500DistinguishedName& aDistinguishedName)
    {
    TInt count = aDistinguishedName.Count();
    for (TInt i = 0; i < count; i++)
        {
        const CX520AttributeTypeAndValue& ava = aDistinguishedName.Element(i);
        if (ava.Type() == aFieldName)
            {
            HBufC* res = ava.ValueL();
            CleanupStack::PushL(res);
            TPtr pRes = res->Des();
            TUint8* data = const_cast<TUint8 *>(reinterpret_cast<const TUint8 *>(res->Ptr())); 
            TUint len = pRes.Length()*2;
            TASN1DecGeneric gen(ava.EncodedValue());
            gen.InitL();
            if (gen.Tag() == EASN1BMPString)
                {
                // Bmp String internally store them as little endian, as a string we want it big
                // endian interchange least and most significent byte
                for(TUint i=0; i<len; i+=2)
                     {
                     TUint8 temp = data[i];
                     data[i] = data[i+1];
                     data[i+1] = temp;       
                     }
                }
            CleanupStack::Pop();
            return res;
            }
        }
    return NULL;
    }


TBool CTlsProviderImpl::VerifySignatureL(
		const CSubjectPublicKeyInfo& aServerPublicKey, 
		const TDesC8& aDigest,const TDesC8& aSignature)
	{
	TBool tempResult;
	tempResult = EFalse;
	switch(iTlsCryptoAttributes->isignatureAlgorithm)
	{
	case ERsaSigAlg:
		{
	
		//create an RSA public key object from the server certificate
		CRSAPublicKey* rsaPublicKey = CX509RSAPublicKey::NewLC(aServerPublicKey.KeyData());

		//create an RSA signature object from the signature buffer
		RInteger sigInt = RInteger::NewL(aSignature);
		CleanupStack::PushL(sigInt);
		CRSASignature* rsaSignature = CRSASignature::NewL(sigInt);
		CleanupStack::Pop(&sigInt);	//	Owned by rsaSignature
		CleanupStack::PushL(rsaSignature);

		//create a verifier with the server public key
		CRSAPKCS1v15Verifier*  Verifier = CRSAPKCS1v15Verifier::NewLC(*rsaPublicKey);
		
		//verify the signature
		tempResult = Verifier->VerifyL(aDigest, *rsaSignature);	
		CleanupStack::PopAndDestroy(3, rsaPublicKey);		
		}
		break;
	case EDsa:
		{
		//digest and signature are 8-bit descriptors
		//create a DSA public key object from the server certificate
		CDSAPublicKey* dsaPublicKey = CX509DSAPublicKey::NewL(aServerPublicKey.EncodedParams(),
															  aServerPublicKey.KeyData());

		CleanupStack::PushL(dsaPublicKey);

		//create verifier, verify sig
		CDSAVerifier* verifier = CDSAVerifier::NewL(*dsaPublicKey);
		CleanupStack::PushL(verifier);
		
		//create DSA signature object from signature buffer
		CDSASignature* dsaSignature = CX509DSASignature::NewLC(aSignature);
		
		tempResult = verifier->VerifyL(aDigest, *dsaSignature);	
		CleanupStack::PopAndDestroy(3, dsaPublicKey);  
		}
		break;
	default:
		break;
	}
		
	return tempResult;
	}



void CTlsProviderImpl::GenerateRandom(TDes8& aBuffer)
	{
	// Fill the buffer with zero bytes
	aBuffer.SetLength(KTLSServerClientRandomLen);
	aBuffer.Fill(0);
	
	// The last 28 bytes should be filled with random data
	TPtr8 random = aBuffer.MidTPtr(4);
	TRAPD(errRandom,TRandom::RandomL(random));
	if (errRandom)
		{
		aBuffer.SetLength(0);
		return;
		}
	
	// The first 4 bytes should a unix timestamp.
	TTime now;
	now.UniversalTime();
	
	_LIT(KEpoch,"19700000:");
	TTime epoch(KEpoch);
	
	TTimeIntervalSeconds timestamp;
	TInt err = now.SecondsFrom(epoch, timestamp);
	
	if (err == KErrNone)
		{
		TInt timestampInt = timestamp.Int();
		aBuffer[0] = timestampInt >> 24;
		aBuffer[1] = timestampInt >> 16;
		aBuffer[2] = timestampInt >> 8;
		aBuffer[3] = timestampInt;
		}
		
	}


void CTlsProviderImpl::ClearSessionCacheL(
		TTLSSessionNameAndID& aServerNameAndId, 		
		TRequestStatus& aStatus) 
{
	aStatus = KRequestPending;
	iOriginalRequestStatus = &aStatus;
	if(IsActive())
		{
		User::RequestComplete(iOriginalRequestStatus, KErrInUse);
		return;
		}

	iServerNameAndId = aServerNameAndId;	
	iOriginalState =  EClearSessionCache;
	iOutputSessionData.iSessionId.Zero();


	if(iPtrTokenSearch)
		iTotalTokenTypeCount = iPtrTokenSearch->TotalTypeCount();

	if(!iTotalTokenTypeCount)
		{				
		iPtrTokenSearch = CTlsBrowseToken::NewL();	
		iCurrentState =  EBrowseTokens;	
		iStatus = KRequestPending;
		iPtrTokenSearch->StartBrowsingL(iListAllTokensAndTypes,iStatus);
		SetActive();
		return;
		}
	else
		RetrieveSession();	

	return;
}

#ifdef _DEBUG

void CTlsProviderImpl::Panic(CTlsProviderImpl::TPanic aPanic)
/**
	Halt the current thread with the panic category "TlsProvImpl"
	and the supplied panic reason.
	
	@param	aPanic			Panic reason.
 */
	{
	_LIT(KPanicCat, "TlsProvImpl");
	User::Panic(KPanicCat, aPanic);
	}
	
static TBool AreSuitesInPriorityOrder(const RArray<TTLSCipherSuite>& aSuites)
/**
	Predicate function determines whether the supplied array contains
	cipher suites in priority order, highest-priority first.
	(Higher priority suites have numerically lower iPriority fields.)
	
	@param	aSuites			Array of cipher suites.
	@return					ETrue if the suites are in priority
							order, EFalse otherwise.
 */
	{
	TInt curSuite = aSuites.Count();
	if (curSuite == 0)
		return ETrue;

	const TTLSCipherSuiteMapping* cipherDetail = aSuites[--curSuite].CipherDetails();
	TInt nextPri = (cipherDetail == NULL)? pri_unsupp: cipherDetail->iPriority;
	while (--curSuite >= 0)
		{
		cipherDetail = aSuites[curSuite].CipherDetails();
		TInt curPri = (cipherDetail == NULL)? pri_unsupp: cipherDetail->iPriority;
		if (nextPri < curPri)
			return EFalse;
		nextPri = curPri;
		}
	
	return ETrue;
	}

#endif	// #ifdef _DEBUG

TBool CTlsProviderImpl::IsCipherAvailable( const TTLSCipherSuiteMapping& aCipherSuiteMapping ) const
{
//this is a simplification that is allowable as DES_CBS & 3DES_CBS cipher ignore one & three bytes
//respectively from the key material so the key length is in fact shorter than the computed one
//but this still allows us to distinguish between strong & weak cipher suites...
   TInt nKeyBits = aCipherSuiteMapping.iKeyMaterial * 8;
   return aCipherSuiteMapping.iSupported && (TCrypto::Strength() == TCrypto::EStrong || nKeyBits <= 64);
}


void CTlsProviderImpl::ReturnCipherListL()
	{
	
	TInt aTotalTokenTypes = iListAllTokensAndTypes.Count();

	iUserCipherSuiteList->Reset();
	TLinearOrder<TTLSCipherSuite> CipherOrder(CompareCipherIdentities);

	TLSPROV_LOG2(_L("CTlsProviderImpl::ReturnCipherListL %d"), aTotalTokenTypes)
	TBool thisCipherSupportedByAToken = EFalse;
	
	for (TInt CipherIndex = 0; CipherIndex < TLS_CIPHER_SUITES_NUMBER; ++CipherIndex)
		{
		const TTLSCipherSuiteMapping& mapping = KSetOfTLSCipherSuites[CipherIndex];
		thisCipherSupportedByAToken = EFalse;   // reset
		
		if(! IsCipherAvailable(mapping))
			continue;

		// NULL encryption based ciphersuites are disallowed unless explicitly enabled
		if( (! iTlsCryptoAttributes->iAllowNullCipherSuites) && (mapping.iBulkCiphAlg == ENullSymCiph))
			{
			continue;
			}
		
		// PSK key exchange ciphersuites are not usable unless PSK has been configured.
		if((! iTlsCryptoAttributes->iPskConfigured) &&
			((mapping.iKeyExAlg==EPsk) || (mapping.iKeyExAlg==EDhePsk) || (mapping.iKeyExAlg==ERsaPsk)))
			{
			continue;
			}
		
		TLSPROV_LOG3(_L("cipher 0x%02x.0x%02x available"), mapping.iCipherSuite.iHiByte, mapping.iCipherSuite.iLoByte)
		
		//offer just these matching the current crypto strength.
		for (TInt i = 0; i < aTotalTokenTypes; i++) //For every Token type
			{
			CTokenInfo* tokenInfo = iListAllTokensAndTypes[i].iTokenInfo;
			
			// check if this token contains the required key exchange and
			// signature algorithms
			
			TBool reqAlgs = 
					tokenInfo->aKeyExchAlgs.Find(mapping.iKeyExAlg) != KErrNotFound
				&&	tokenInfo->aSignatureExchAlgs.Find(mapping.iSigAlg) != KErrNotFound;
			
			if (! reqAlgs)
				continue;
			
			TLSPROV_LOG2(_L("token %d supports this cipher"), i)
			thisCipherSupportedByAToken = ETrue;
			
			// Add this cipher to the token's list of suites supported
			if(tokenInfo->iCipherSuitesSupported.InsertInOrder(mapping.iCipherSuite,CipherOrder) == KErrNoMemory)
				User::Leave(KErrNoMemory); 
			}
		
		if (thisCipherSupportedByAToken)
			{
			// don't need to order the ciphers as they are sorted below
			TLSPROV_LOG(_L("adding this cipher to iUserCipherSuiteList"))
			iUserCipherSuiteList->AppendL(mapping.iCipherSuite);
			}
		}

	// order the cipher suites by priority, highest-priority first.
	const TLinearOrder<TTLSCipherSuite> priOrder(CompareCipherPriorities);
	iUserCipherSuiteList->Sort(priOrder);

	// also order the cipher suites stored with each token type
	for (TInt j = aTotalTokenTypes - 1; j >= 0 ; --j)
		{
		CTokenInfo* tokenInfo = iListAllTokensAndTypes[j].iTokenInfo;
		tokenInfo->iCipherSuitesSupported.Sort(priOrder);
		}
	
#ifdef _DEBUG
	// Ensure suites are in priority order, as required for
	// DEF063433 - TLS is sending CipherSuites in the wrong order 
	
	if (! AreSuitesInPriorityOrder(*iUserCipherSuiteList))
		Panic(ERCLBadUserOrder);
	
	for (TInt k = aTotalTokenTypes - 1; k >= 0 ; --k)
		{
		const CTokenInfo* tokenInfo = iListAllTokensAndTypes[k].iTokenInfo;
		const RArray<TTLSCipherSuite>& suites = tokenInfo->iCipherSuitesSupported;
		if (! AreSuitesInPriorityOrder(suites))
			Panic(ERCLBadTokenOrder);
		}
#endif

	TLSPROV_LOG(_L("Returning the list of ciphersuites"))
	}
	
void CTlsProviderImpl::ReturnSession()
	{
	if((iOutputSessionData.iSessionId).Length())
		{
		*iPSessionId = iOutputSessionData.iSessionId;
		iPSessionId = 0;
		}
		User::RequestComplete(iOriginalRequestStatus, KErrNone);				
	}

void CTlsProviderImpl::OnEGetSessionInterfaceL()
	{
	
	if(!iStatus.Int()) //Successfull, Session interface obtained
		{
		TLSPROV_LOG(_L("Session interface from token obtained successfully"))

		iCurrentState = EStartSession;
		
		//we can delete the token search object here
		if(iPtrTokenSearch)
			{
			delete iPtrTokenSearch;
			iPtrTokenSearch = 0;
			}

		iTlsSessionImpl = 0;
		CTlsSessionImpl *newImpl = 0;
		TRAPD(Kerr, ( newImpl = CTlsSessionImpl::NewL(
			iSessionInterface,		
			iSelectedCertInfo,
			iSelectedKeyInfo,
			&iStoredIntermediatesCACertificates)
			) );
		
		if(Kerr != KErrNone)
			{			
			User::RequestComplete(iOriginalRequestStatus,Kerr);
			return;
			}		

		CleanupStack::PushL(newImpl);
		
		if(iNextState == EConstructResumed)
			{			
			iStatus = KRequestPending;
			iCurrentState = iNextState;
			newImpl->ConstructResumedL(iTlsCryptoAttributes,iStatus);			
			SetActive();
			CleanupStack::Pop(newImpl);
			iTlsSessionImpl = newImpl;
			return;

			}
		else
			{	
			iCurrentState =  EConstruct;
			iStatus = KRequestPending;
			newImpl->ConstructL(iTlsCryptoAttributes,iEncodedServerCerts,iStatus);	
			SetActive();
			CleanupStack::Pop(newImpl);
			iTlsSessionImpl = newImpl;
			return;
			}
		}
	else	//session interface not obtained..Dodgy token..release it
		{
		User::RequestComplete(iOriginalRequestStatus, iStatus.Int());	
		}
	}


void CTlsProviderImpl::OnEGetSession()
	{
	if( (!iStatus.Int())  && 
		( (iOutputSessionData.iSessionId).Size()) 
	  )
		{

		TLSPROV_LOG(_L(" GetSession  obtained successfully"))

		if(iOriginalState ==  EClearSessionCache)
			{
			TBool result;
			iStatus = KRequestPending;
			iCurrentState = EClearSessionCache;
			iListAllTokensAndTypes[iCurrentTokentype].iProviderInterface->ClearSessionCache(iServerNameAndId.iServerName,
				iServerNameAndId.iSessionId,result,iStatus);
			SetActive();
			return;
			}
				
		iSessionData.iSessionId = iOutputSessionData.iSessionId;
		iSessionData.iProviderInterface = iListAllTokensAndTypes[iCurrentTokentype].iProviderInterface;
			
		if(iOriginalState == EGetSession ) 
			{
			//return the result here
			ReturnSession();
			return;
			}
		}
	iCurrentTokentype++;
	RetrieveSession();	
	return;	
	}


void CTlsProviderImpl::RunL()
{
	
	switch(iCurrentState)
	{
	
	//Obtain Session Interface
	case EGetSessionInterface:
		{
		OnEGetSessionInterfaceL();
		}
		break;
	
	//Retrieving and clearing of Sesion cache
	case EGetSession:
		{
		OnEGetSession();
		}
		break;

	case EClearSessionCache:
		{	
		if(!iStatus.Int()) 
			{	
			if((iSessionData.iSessionId).Compare(iOutputSessionData.iSessionId) ==0)
				{
				(iSessionData.iSessionId).Zero();
				}
			}
		User::RequestComplete(iOriginalRequestStatus,iStatus.Int());						
		}
		break;	
	
	//Abbreviated handshake	
	case EConstructResumed:
		{
		if(iStatus.Int() != KErrNone)
			{
			delete iTlsSessionImpl;
			iTlsSessionImpl = NULL;
			}
		*iTlsSessionHldr = CTLSSession::NewL(iTlsSessionImpl);		
		iTlsSessionOwnershipPassedToCaller = ETrue;
		User::RequestComplete(iOriginalRequestStatus,iStatus.Int());
		return;
		}

	//Full handshake
	case EConstruct:
		{
		iEncodedServerCerts = 0; //Owned by CTLSSession 
		if(iStatus.Int() != KErrNone)
			{
			delete iTlsSessionImpl;
			iTlsSessionImpl = NULL;
			}
		*iTlsSessionHldr = CTLSSession::NewL(iTlsSessionImpl);
		iTlsSessionOwnershipPassedToCaller = ETrue;
		User::RequestComplete(iOriginalRequestStatus,iStatus.Int());
		return;
		}

	//To obtain client certificate
	case EClientAuthenticate:
		{
		delete iClntAuthenticate;
		iClntAuthenticate = 0;
		
		iCurrentState = EGetSessionInterface;
		iNextState = EStartSession;	
		iStatus = KRequestPending;
				
		// Iterate through tokens, GetSessionInterface() for this token if pointers match
		for(TInt i=0; i< iListAllTokensAndTypes.Count(); i++)
			{
			MCTToken* tempPtr = &(iListAllTokensAndTypes[i].iProviderInterface->Token());
			if(iSelectedKeyInfo && (tempPtr == &(iSelectedKeyInfo->Token())))
				{
				TLSPROV_LOG(_L("EClientAuthenticate: iSelectedKeyInfo->Token() valid; reusing this token interface"))
				// Keep existing selected token
				iPtrTokenSearch->GetSessionInterface(iListAllTokensAndTypes[i].iProviderInterface, iSessionInterface,iStatus);
				SetActive();
				return;
				}
			}
			
		// Otherwise, have already selected (potentially new) token in call to SelectToken()
		// in previous state. Use iSelectedTypeIndex in call to GetSessionInterface()
		TLSPROV_LOG2(_L("EClientAuthenticate: Using (newly selected) token %d's provider interface"), iSelectedTypeIndex)
		iPtrTokenSearch->GetSessionInterface(iListAllTokensAndTypes[iSelectedTypeIndex].iProviderInterface,
				iSessionInterface,iStatus);
		SetActive();
		}
		break;
	
	case EQueryCache:
		{
		OnQueryCacheL();
		}
		break;
	
	case EUserDialog:
		{
		OnEUserDialogL();
		}
		break;

	case EValidateCertificate:
		{
		User::LeaveIfError(iStatus.Int());
		
		//We set iServerDNFromCert in case server doesn't
		//give us DistingshedName in CertificateRequest Message. 
		if(iValidationStatus.iReason == EValidatedOK)
		{
			TInt serverCertChainLength = iServerCertsChain->Count();
			TLSPROV_LOG2(_L("EValidateCertificate iServerCertsChain length = %d"), serverCertChainLength);
			CX509Certificate* cert = CX509Certificate::NewL(iServerCertsChain->Cert(serverCertChainLength-1));
			CleanupStack::PushL(cert);
			iTlsCryptoAttributes->iServerDNFromCertIssuer = cert->DataElementEncoding(CX509Certificate::EIssuerName)->AllocL();
			iTlsCryptoAttributes->iServerDNFromCertSubject = cert->DataElementEncoding(CX509Certificate::ESubjectName)->AllocL();
			CleanupStack::PopAndDestroy(cert);					

		}
		delete iServerCertsChain;
		iServerCertsChain = 0;
		iValidationStatus = iCertVerificationResult->Error();
		delete iCertVerificationResult;
		iCertVerificationResult = 0;
		TBool acceptCert = EFalse;
		GetX509CertL(iEncodedServerCerts,*iX509ServerCert);
		
		if (iValidationStatus.iReason == EValidatedOK)
			{
 			
			// If the certificate is fine, check whether the server name matches
			// the site the certificate was issued to.
		
			if (iTlsCryptoAttributes->idomainName.Length() != 0) // skip the check if domain name is unset.
				{
				acceptCert = ValidateDNSNameL(**iX509ServerCert);
				}
			else
				{
				acceptCert = ETrue;
				}
			
			if(acceptCert)
				{				
				acceptCert = CheckExtendedKeyUsageL(**iX509ServerCert);
				if(!acceptCert)
					{
					iValidationStatus.iReason = ECriticalExtendedKeyUsage;
					}
				}
			}
		
		if(acceptCert)
			{
			TLSPROV_LOG(_L("Server Certificate verified successfully"))			
			iCurrentState = iOriginalState = ENullState;
			User::RequestComplete(iOriginalRequestStatus,KErrNone); 
			}
		else
			{
			if(iTlsCryptoAttributes && iTlsCryptoAttributes->iDialogNonAttendedMode)
				{	
				TLSPROV_LOG(_L("Server Certificate validation failed but in DialogNonAttended mode"))	
				TInt err(0);
				
				switch(iValidationStatus.iReason)
					{
				case EChainHasNoRoot:
					err = KErrSSLAlertUnknownCA;
					break;
				case EDateOutOfRange:
					err = KErrSSLAlertCertificateExpired;
					break;
				case ECertificateRevoked:
					err = KErrSSLAlertCertificateRevoked;
					break;
				case ECriticalExtendedKeyUsage:
					err = KErrSSLAlertUnsupportedCertificate;
					break;
				default:
					err = KErrSSLAlertIllegalParameter;
					break;
					}
					
				iCurrentState = iOriginalState = ENullState;
				User::RequestComplete(iOriginalRequestStatus,err); 				
				}
			else
				{			
				
				User::LeaveIfError(iCacheClient.Open(**iX509ServerCert));
				HandleBadCertificateL(iValidationStatus);
				
				}		
			}

		}
		break;
	//Obtain interface form all tokens supproted
	case EBrowseTokens:
		OnEBrowseTokens();
		break;
	BULLSEYE_OFF
	default:
		{
		TLSPROV_LOG(_L("PANIC: in Default state of the state machine..cant happen"))	
		}
		break;
	BULLSEYE_RESTORE
	}

}	
		
TBool CTlsProviderImpl::CheckExtendedKeyUsageL(const CX509Certificate& aCert)
	{
	TBool result(ETrue);
		
	const CX509CertExtension* ext = aCert.Extension(KExtendedKeyUsage);
	if (ext)
			{
			result = EFalse;
			CX509ExtendedKeyUsageExt* extendedKeyUsage = CX509ExtendedKeyUsageExt::NewLC(ext->Data());
			const CArrayPtrFlat<HBufC>& usages = extendedKeyUsage->KeyUsages();
			
			for (TInt k = 0; k < usages.Count(); k++)
            {
            if (usages[k]->Compare(KServerAuthOID) == 0)
                    {
                    result = ETrue;
                    break;
                    }
            }
        	CleanupStack::PopAndDestroy(); // Cannot leave before we get here
			}
				
	return result;
	}

void CTlsProviderImpl::HandleBadCertificateL(const TValidationStatus aResult)
	{
	TCacheEntryState entryState = iCacheClient.GetStateL();
				
	switch (entryState)
		{
	case ENewEntry:
		// Show dialog
		ShowUntrustedDialogL(aResult);
		break;
					
	case EEntryAwaitingApproval:
		// Request notification on status change
		iCurrentState = EQueryCache;
		iCacheClient.RequestNotify(iStatus);
		SetActive();
		break;
					
	case EEntryDenied:
		iCurrentState = iOriginalState = ENullState;
		User::RequestComplete(iOriginalRequestStatus,KErrAbort); 
		break;
					
	case EEntryApproved:
		iCurrentState = iOriginalState = ENullState;
		User::RequestComplete(iOriginalRequestStatus,KErrNone); 
		break;
					
		}
	}

void CTlsProviderImpl::ShowUntrustedDialogL(const TValidationStatus aResult)
	{
	iCurrentState = EUserDialog;
#ifdef _USESECDLGSV_
	TLSPROV_LOG(_L("Server Certificate validation failed old dialog"))	
	User::LeaveIfError( iDialogServ.Connect() );
    iDialogServ.DisplayCertNotTrustedDlg(iProceed, **iX509ServerCert, iStatus);
#else
	TLSPROV_LOG(_L("Server Authentication Failure New dialog"))	
	iSecurityDialog = SecurityDialogFactory::CreateL();
	iStatus = KRequestPending;			
	TPtrC8 encodedCert(iEncodedServerCerts->Des());
	// Calls Server authentication failure dialog box
	iSecurityDialog->ServerAuthenticationFailure(iTlsCryptoAttributes->idomainName,aResult.iReason,encodedCert,iStatus );
#endif
	SetActive();
	}

CTlsProviderImpl::~CTlsProviderImpl()
	{
	Cancel();
	
	if ( iTlsProviderPolicy )
	    {
	    delete iTlsProviderPolicy;
	    iTlsProviderPolicy = NULL;
	    }
	
#if !defined(_USESECDLGSV_)
	if(iSecurityDialog)
		{
		iSecurityDialog->Release();
		}
#endif
	iReqProtList.Close();

	if((!iTlsSessionOwnershipPassedToCaller) && (iTlsSessionImpl))
		{
		// We have created a CTlsSessionImpl (which now owns iSelectedCertInfo etc)
		// BUT the CTLSSession create failed so we still own the CTlsSessionImpl and 
		// are still responsible for deleting it.
		delete iTlsSessionImpl;
		iTlsSessionImpl = 0;
		}
	else
		{
		if(iTlsSessionImpl == NULL) //Session object not created
			{
			if(iSelectedCertInfo)
				iSelectedCertInfo->Release();	

			if(iSelectedKeyInfo)
				iSelectedKeyInfo->Release();
			
			if(iSessionInterface)		
				iSessionInterface->Release();	

			if(iTlsCryptoAttributes)
				delete iTlsCryptoAttributes;
			
			if(iEncodedServerCerts)
				delete iEncodedServerCerts;
			}
		}
	
	if(iServerCertsChain)
		{
		delete iServerCertsChain;	
		iServerCertsChain = NULL;
		}
	
	delete iCertVerificationResult;
	iCertVerificationResult = NULL;

	if(iPtrTokenSearch)
		{
		delete iPtrTokenSearch;	
		iPtrTokenSearch = NULL;
		}
	
	TInt count = iListAllTokensAndTypes.Count();
	TInt i(0);
	
	while(i<count)
		{
		iListAllTokensAndTypes[i].Release();
		i++;
		}
	
	// clear the intermediate certificates
	TInt certCount = iStoredIntermediatesCACertificates.Count();
	for (TInt i = 0; i < certCount; i++)
		{
		CX509Certificate *x509Cert = (CX509Certificate*)(iStoredIntermediatesCACertificates[i]);
		delete x509Cert;
		}				
	iStoredIntermediatesCACertificates.Reset();   				

	iListAllTokensAndTypes.Close();
	if(iClntAuthenticate)
		delete iClntAuthenticate;
   
   	iCacheClient.Close();

	iFs.Close();
	REComSession::FinalClose();
	}



void CTlsProviderImpl::CancelRequest()
	{
	if(IsActive())
		Cancel();
	}

void CTlsProviderImpl::DoCancel()
	{
	switch(iCurrentState)
	{			
	
	case EGetSessionInterface:
		{
		iPtrTokenSearch->CancelRequest();
		break;
		}
	case EGetCiphers:
		{
		if(iListAllTokensAndTypes[iCurrentTokentype].iProviderInterface)
			iListAllTokensAndTypes[iCurrentTokentype].iProviderInterface->CancelCryptoCapabilities();
		}
		break;
	case EGetSession:
		{
		if(iListAllTokensAndTypes[iCurrentTokentype].iProviderInterface)
			iListAllTokensAndTypes[iCurrentTokentype].iProviderInterface->CancelGetSession();
		}
		break;
	case EClearSessionCache:
		{
		if(iListAllTokensAndTypes[iCurrentTokentype].iProviderInterface)
			iListAllTokensAndTypes[iCurrentTokentype].iProviderInterface->CancelClearSessionCache();
		}
		break;
	case EConstruct:
	case EConstructResumed:
		{
		if(iTlsSessionImpl)
			iTlsSessionImpl->CancelRequest();
		}
		break;			
	
	case EValidateCertificate:
		{
		if(iServerCertsChain)
			iServerCertsChain->CancelValidate();

		}
		break;
	case EBrowseTokens:
		{
		if(iPtrTokenSearch)
			iPtrTokenSearch->CancelRequest();
		}
		break;
		
	case EQueryCache:
		{
		iCacheClient.Cancel();
		}
		break;
	
	case EUserDialog:
		{
#ifdef _USESECDLGSV_
		iDialogServ.Cancel();
#else
		iSecurityDialog->Cancel();
#endif
		}
		break;
			
	default:
		break;
	}
	iCurrentState = ENullState;
	
	User::RequestComplete(iOriginalRequestStatus, KErrCancel);
	
	return;
	}	


void CTlsProviderImpl::ReturnResult()
	{
	switch(iOriginalState)
		{
		case EGetCiphers:
			{
			iCurrentTokentype= 0;
			TRAPD(err,ReturnCipherListL());
			if(err != KErrNone)
				{
				iUserCipherSuiteList->Reset();
				}
			User::RequestComplete(iOriginalRequestStatus, err);
			}
			break;
		case EGetSession:
			{
			iCurrentTokentype= 0;
			ReturnSession();
			}
			break;
		case EClearSessionCache:
			{
			User::RequestComplete(iOriginalRequestStatus, iStatus.Int());
			}
			break;
		BULLSEYE_OFF
		default:
			{
			//Not possible......Log him anyway
			}
			break;
		BULLSEYE_RESTORE
		}
	iCurrentState = ENullState;
	}


void CTlsProviderImpl::OnQueryCacheL()
	{
	HandleBadCertificateL(iValidationStatus);
	}

void CTlsProviderImpl::OnEUserDialogL()
	{
	TCacheEntryState entryStatus;
#ifdef _USESECDLGSV_	
  	entryStatus = iProceed ? EEntryApproved : EEntryDenied;
#else
	entryStatus = iStatus.Int() == KErrNone ? EEntryApproved : EEntryDenied;
#endif
	
	iCacheClient.SetStateL(entryStatus);
	User::RequestComplete(iOriginalRequestStatus, entryStatus == EEntryApproved ? KErrNone : KErrAbort);
	iCurrentState = iOriginalState = ENullState;
	}

TBool CTlsProviderImpl::SelectToken()
	{
	TLSPROV_LOG(_L("In CTlsProviderImpl::SelectToken()"))
	if(iSelectedTypeIndex == -1)
		{
		TIdentityRelation<TTLSCipherSuite> CipherOrder(CipherSuiteOrder);
		TInt selectedSoftwareToken = -1;
		TInt selectedHardwareToken = -1;
		TBool foundToken = EFalse;
		
		// Iterate through all tokens; pick a supported token
		TInt total = iListAllTokensAndTypes.Count();
		for(TInt i = 0; i < total; i++)
			{
			TLSPROV_LOG3(_L("token %d supports %d total ciphers"),
				  i, iListAllTokensAndTypes[i].iTokenInfo->iCipherSuitesSupported.Count())
			if ((iListAllTokensAndTypes[i].iTokenInfo)->iCipherSuitesSupported.Find(
					iTlsCryptoAttributes->iCurrentCipherSuite, CipherOrder) != KErrNotFound)
				{
				// Select the first valid token found (from zero upwards)
				foundToken = ETrue;
				if (iListAllTokensAndTypes[i].iSoftwareToken && selectedSoftwareToken == -1)
					selectedSoftwareToken = i;
				
				if (! iListAllTokensAndTypes[i].iSoftwareToken && selectedHardwareToken == -1)
					selectedHardwareToken = i;
				}
			
			// No need to continue if we've found a hardware token, otherwise keep
			// searching, since there might be a hardware token later in the search
			// and this should always be used in preference to a software token
			if (selectedHardwareToken != -1)
				break;
			}
			
		if (foundToken == EFalse)
			{
			TLSPROV_LOG(_L("Didn't find a suitable token for this cipher"))
			return EFalse;
			}
		
		// Prefer a hardware token
		if (selectedHardwareToken != -1)
			{
			iSelectedTypeIndex = selectedHardwareToken;
			TLSPROV_LOG2(_L("Hardware Token %d selected"), iSelectedTypeIndex)
			}
		else
			{
			iSelectedTypeIndex = selectedSoftwareToken;
			TLSPROV_LOG2(_L("Software Token %d selected"), iSelectedTypeIndex)
			}
		}

	return ETrue;
	}


/*The following function gets the encoded certificate and converts it into
an x509 object..Only called from a direct secure socket API call	
*/
void CTlsProviderImpl::GetX509CertL(HBufC8*& aEncodedCert,CX509Certificate*& aOutputX509)
	{
	if(aEncodedCert)
		{
		TLSPROV_LOG(_L("CTlsProviderImpl::GetX509CertL"))	
		CPKIXCertChain* CertsChain = CPKIXCertChain::NewLC(iFs,aEncodedCert->Des(),
												  TUid::Uid(KUidUnicodeSSLProtocolModule));
		if(CertsChain->Count())
			{
   		TLSPROV_LOG(_L("CX509Certificate::NewL"))	
			aOutputX509 = CX509Certificate::NewL(CertsChain->Cert(0));		
			}
		CleanupStack::PopAndDestroy(CertsChain);	
		}
	}

TBool CTlsProviderImpl::ValidateDNSNameL(const CX509Certificate& aSource)
	{
	TBool ret = EFalse;
	TBool hasAltNameExt = EFalse;
	
	// Get a unicode descriptor with the server DNS name
	HBufC* server = HBufC::NewLC(iTlsCryptoAttributes->idomainName.Length());
	TPtr des = server->Des();
	des.Copy(iTlsCryptoAttributes->idomainName);
	
	// and contruct a domain name from it
	CX509DNSName* serverDns = CX509DNSName::NewLC(*server);
	CX509DNSName* dNS = NULL;
	
	// try fetch Alt Name first (see RFC 2595)
	const CX509CertExtension* ext = aSource.Extension(KSubjectAltName); 
	if (ext)
		{
		CX509AltNameExt* subjectAltName = CX509AltNameExt::NewLC(ext->Data()); 
		const CArrayPtrFlat<CX509GeneralName>& gNs = subjectAltName->AltName();
		TInt count = gNs.Count(); 

		for (TInt i = 0; i < count; i++)
			{ 
			const CX509GeneralName* gN = gNs.At(i); 
			if (gN->Tag() == EX509DNSName) 
				{
				hasAltNameExt = ETrue;
				
				// wildcards are allowed at every part of DNS name
				// e.g. "foo.example.com" would be validated
				// against cert "foo.*.com", even though RFC 2595 states:
				// "A '*' wildcard character MAY be used as the left-most name 
				// component in the certificate"
				TBool wildcard = (gN->Data().Locate('*') > KErrNotFound);
				dNS = CX509DNSName::NewL(gN->Data()); 
	
				// Check if the server matches this cert name
				if (NameIsInSubtree(*serverDns, *dNS, wildcard))
					{
					ret = ETrue;
					}
					
				delete dNS;
				if ( ret )
					break;
				} 
			} 
			CleanupStack::PopAndDestroy(subjectAltName); 
		}
		
	// if the certificate has an alternative name extension, with DNS entries, ignore the common name	
	if(!hasAltNameExt)
		{
		// no name yet lets try common name from Subject
		//HBufC* commonName = aSource.SubjectName().ExtractFieldL(KX520CommonName);
		HBufC* commonName  = ExtractCertFieldL(KX520CommonName, aSource.SubjectName());
		if(commonName)
			{
			CleanupStack::PushL(commonName);
			TPtr name = commonName->Des();
			// check for wildcard, we consider it only if left-most name component (see RFC 2595)
			TBool wildcard = EFalse;
			if(0 == name.Locate('*'))
				{
				// wildcard as the left-most part,
				// lets return the name without it...
				// Do NOT remove the '.' otherwise DNS name "example.com" would validate
				// against cert "*.example.com" and that's not correct
				name = name.Mid(1);
				wildcard = ETrue;
				}
			dNS = CX509DNSName::NewL(name);
			ret = NameIsInSubtree(*serverDns, *dNS, wildcard);
			delete dNS;
			CleanupStack::PopAndDestroy(commonName);
			}
		}
		
	CleanupStack::PopAndDestroy(2, server);
	return ret;
	}

TBool CTlsProviderImpl::NameIsInSubtree(CX509DNSName& aServerName, CX509DNSName& aCertName, TBool aIsWildcard)
	{
	return (aServerName.IsWithinSubtree(aCertName) && 
  		(aIsWildcard || (aCertName.Name().Length() == aServerName.Name().Length())));
	}

TInt CTlsProviderImpl::RunError(TInt aError)
	{
	
	if (iCurrentState == EUserDialog)
		{
		// Treat this as denied
		// ignore any problems writing this entry to disk
		TRAP_IGNORE(iCacheClient.SetStateL(EEntryDenied));
		}
	
	User::RequestComplete(iOriginalRequestStatus, aError);
	return KErrNone;
	}


MCTToken* CTlsProviderImpl::GetTokenHandle()
	{
	
	if(iListAllTokensAndTypes.Count() > iSelectedTypeIndex && iSelectedTypeIndex >=0 )
		{
      CTokenTypesAndTokens& Tokens = iListAllTokensAndTypes[iSelectedTypeIndex];
      if ( Tokens.iProviderInterface )
         {
   		MCTToken& tempPtr = Tokens.iProviderInterface->Token();
		   iListAllTokensAndTypes[iSelectedTypeIndex].iProviderInterface->Release();
		   iListAllTokensAndTypes[iSelectedTypeIndex].iProviderInterface = 0;
   		return  &tempPtr;	
         }
		}
	return NULL;
	}

void CTokenTypesAndTokens::Release()
	{
	if(iProviderInterface)
		{
		MCTToken& tempPtr = iProviderInterface->Token();
		iProviderInterface->Release();	//Release provider interface
		tempPtr.Release();	//Release token
		iProviderInterface = 0;
		}
	if(iTokenInfo)
		{
		iTokenInfo->Close();
		delete iTokenInfo;
		}
		
	}

CTokenTypesAndTokens::~CTokenTypesAndTokens()
	{
	Release();	
	}

void CTokenInfo::Close()
	{
	aKeyExchAlgs.Close();
	aSignatureExchAlgs.Close();
	iCipherSuitesSupported.Close();
	iSupportedProtocols.Close();
	}

CTokenInfo::~CTokenInfo()
	{
	Close();
	}

void CTlsProviderImpl::ConstructL()
	{
	User::LeaveIfError(iFs.Connect());
	
    TLSPROV_LOG(_L("Creating a newer instance of TlsProviderPolicy"))
    iTlsProviderPolicy = CTlsProviderPolicy::NewL();
	}

CTLSPublicKeyParams::~CTLSPublicKeyParams()
	{
	delete iValue1;
	delete iValue2;
	delete iValue3;	
	delete iValue4;
	delete iValue5;
	}
