vpnengine/ikecert/src/ikev2pkiservice.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 09:14:51 +0200
changeset 0 33413c0669b9
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* Copyright (c) 2008-2009 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:   IKEv2 specifig certificate reading related stuff
*
*/

#include <x500dn.h>
#include <x509cert.h>
#include <asn1dec.h>

#include "ikev2pkiservice.h"
#include "utlcrypto.h"
#include "ikecert.h"
#include "ikecaelem.h"
#include "ikecalist.h"
#include "ikedebug.h"
#include "ikepolparser.h"
#include "ikev2const.h"
#include "ikecertconst.h"
//
// CIkePkiService Class
//
_LIT8(KEmptyString, "");


const TInt KDefaultCertificateBufferSize = 2048;

//
//  Certificate field indicators for GetCertificateFieldDERL()
//

#ifdef _DEBUG

#define SET_ACTIVE DEBUG_LOG2(_L("CIkeV2PkiService::SetActive (0x%x) %d\n"), this, __LINE__);\
                   SetActive()

#else

#define SET_ACTIVE SetActive()

#endif 


EXPORT_C CIkeV2PkiService* CIkeV2PkiService::NewL(MIkeV2PkiServiceObserver& aObserver, MIkeDebug& aDebug)
    {     
    CIkeV2PkiService* self = new (ELeave) CIkeV2PkiService(aObserver, aDebug);
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
    }


CIkeV2PkiService::CIkeV2PkiService(MIkeV2PkiServiceObserver& aObserver, MIkeDebug& aDebug)
    :CActive(EPriorityStandard),  
    iObserver(aObserver),
    iDebug(aDebug),
    iState(EPkiServiceIdle),     
    iCertPtr(NULL, 0)
    {
    CActiveScheduler::Add(this);
    }


void CIkeV2PkiService::ConstructL()
    {    
    User::LeaveIfError(iPkiService.Connect());

    iTrustedCAList   = new (ELeave) CIkeCaList(2);
    iReadCertificate = HBufC8::NewL(KDefaultCertificateBufferSize);
    iCertPtr.Set(iReadCertificate->Des());

    //The code assumes that these are not NULL.
    //Reallocated, when needed
    iSubjName = HBufC8::NewL(2);      
    iRfc822Name = HBufC8::NewL(2);              
    }


EXPORT_C CIkeV2PkiService::~CIkeV2PkiService()
    {
	Cancel();

    delete iUserCertificate;
    delete i1Certificate;
    delete i2Certificate;
    delete i2CertificateName;
	delete iTrustedCAList;

    iCasTrustedByPeer.Reset();
    iCasTrustedByPeer.Close();

	delete iCaName;
	delete iReadCertificate;
	delete iSubjName;
	delete iRfc822Name;
	
	iPkiService.Close();	
    }


void CIkeV2PkiService::DoCancel()
    {
    
    iPkiService.CancelPendingOperation();    
    iState = EPkiServiceIdle;
    
    delete iCaName;
    iCaName = NULL;

    __ASSERT_DEBUG(iReadCertificate != NULL, User::Invariant());
    iReadCertificate->Des().Zero();
    
        
    __ASSERT_DEBUG(iSubjName != NULL, User::Invariant());
    iSubjName->Des().Zero();
    
    __ASSERT_DEBUG(iRfc822Name != NULL, User::Invariant());
    iRfc822Name->Des().Zero();

			
    iCasTrustedByPeer.Reset();    
    
    delete iIkeDataCAList;		
    iIkeDataCAList = NULL;
    
    iTrustedCAList->ResetAndDestroy();
    }


TInt CIkeV2PkiService::RunError(TInt /*aError*/)
    {    
    //Currently RunL may leave.
    //But we seem to ignore the possible leave.
    
	return KErrNone; 
    }


EXPORT_C void CIkeV2PkiService::ReadTrustedUserCertificateL()
    {    
    __ASSERT_ALWAYS(!IsActive(), User::Invariant());
    __ASSERT_ALWAYS(iTrustedCAList != NULL, User::Invariant());    
    __ASSERT_ALWAYS(iIkeData->iOwnCert.iOwnCertExists, User::Invariant());

    iCasTrustedByPeer.Reset();
		
	for (TInt i = 0; i < iTrustedCAList->Count(); ++i)
	    {		    
        CIkeCaElem* caElem = (*iTrustedCAList)[i];
        User::LeaveIfError(iCasTrustedByPeer.Append(caElem));
	    }


    iState = EReadingCertificate;

    if (iTrustedCAList->Count() > 0)
        {
        CIkeCaElem* CaElem = iCasTrustedByPeer[0];	                   
        HBufC8* caName = IkeCert::GetCertificateFieldDERL(CaElem->Certificate(), KSubjectName);
        if (caName == NULL)
            {
            User::Leave(KErrArgument);
            }
        delete iCaName;
        iCaName = caName;
        
        ReadUserCertificateL(*iCaName, EFalse);
        }
    else
        {
        //No CA's found.
        //We can't read anything
        User::Leave(KErrNotFound);
        }
    }


EXPORT_C TInt CIkeV2PkiService::Ikev2SignatureL(const TDesC8& aTrustedAuthority, 
                                                const TOwnCertInfo& aOwnCertInfo, 
                                                const TDesC8& aMsgOctets, 
                                                TDes8& aSignature, TUint8 aAuthMeth)
    {
    __ASSERT_ALWAYS(!IsActive(), User::Invariant());	

	TPKIKeyAlgorithm keyAlgorithm = EPKIRSA;	
    TInt length = aOwnCertInfo.iSubjectDnSuffix.Length();
    if ( length )
        {
        delete iSubjName;
        iSubjName = NULL;
        iSubjName = HBufC8::NewL(length);  	   			 
        iSubjName->Des().Copy(aOwnCertInfo.iSubjectDnSuffix);		
        }
    else 
        {
        iSubjName->Des().Zero();
        } 

    length = aOwnCertInfo.iRfc822NameFqdn.Length();
    if ( length )
        {
        delete iRfc822Name;
        iRfc822Name = NULL;
        iRfc822Name = HBufC8::NewL(length);  	   			 
        iRfc822Name->Des().Copy(aOwnCertInfo.iRfc822NameFqdn);        	 
        }
    else
        {
        iRfc822Name->Des().Zero();
        }

	//
	// Build PKCS1v15 format signature (ASN1 encoded) for RSA and SHA1 for DSA
	//
	CUtlMessageDigest* digest = TUtlCrypto::MakeMessageDigesterL(TUtlCrypto::EUtlMessageDigestSha1);
	CleanupStack::PushL(digest);
	HBufC8* asn1EncodedHash =NULL;
	HBufC8* DSSHash = NULL;
			
	switch( aAuthMeth )
		{
			case RSA_DIGITAL_SIGN:
				asn1EncodedHash = IkeCert::BuildPkcs1v15HashL(digest->Final(aMsgOctets));
				User::LeaveIfNull(asn1EncodedHash);
	    		CleanupStack::PopAndDestroy(digest);
    			CleanupStack::PushL(asn1EncodedHash);
    			User::LeaveIfError(iPkiService.Sign(aTrustedAuthority, *iSubjName, *iRfc822Name, 
		                                    		EX509DigitalSignature, aOwnCertInfo.iPrivateKeyLength, 
	                                    			keyAlgorithm, *asn1EncodedHash, aSignature));
   				CleanupStack::PopAndDestroy(asn1EncodedHash);
   				DEBUG_LOG(_L("Signing Auth data using RSA key."));
   				break;
			case DSS_DIGITAL_SIGN:
				DSSHash = HBufC8::New(20);
				DSSHash->Des().Append(digest->Final(aMsgOctets));
				CleanupStack::PopAndDestroy(digest);
    			CleanupStack::PushL(DSSHash);
				User::LeaveIfError(iPkiService.Sign(aTrustedAuthority, *iSubjName, *iRfc822Name, 
		                                    EX509DigitalSignature, aOwnCertInfo.iPrivateKeyLength, 
	                                    	keyAlgorithm, *DSSHash, aSignature));
   				CleanupStack::PopAndDestroy(DSSHash);
   				DEBUG_LOG(_L("Signing Auth data using DSA key."));
   				break;
   			default:
   				DEBUG_LOG1(_L("Authentication method %d not supported when using digital signatures."), aAuthMeth);
   				User::Leave(KErrNotSupported);
   				break;			
		}

	return aSignature.Length();
    }	 


EXPORT_C const CIkeCaList& CIkeV2PkiService::CaList() const
    {
    return *iTrustedCAList;
    }
            
    
EXPORT_C const TDesC8& CIkeV2PkiService::UserCertificateData() const 
    {    
    if (iUserCertificate != NULL)
        {
        return *iUserCertificate;
        }
    else
        {
        return KEmptyString;
        }
    }

EXPORT_C const TDesC8& CIkeV2PkiService::I2CertificateData() const 
    {    
    if (i2Certificate != NULL)
        {
        return *i2Certificate;
        }
    else
        {
        return KEmptyString;
        }
    }

EXPORT_C const TDesC8& CIkeV2PkiService::I1CertificateData() const 
    {    
    if (i1Certificate != NULL)
        {
        return *i1Certificate;
        }
    else
        {
        return KEmptyString;
        }
    }
    
    
EXPORT_C const TDesC8& CIkeV2PkiService::TrustedCaName() const
    {
    if ( i2CertificateName != NULL )
        {
        return *i2CertificateName;
        }
    if (iCaName != NULL)
        {
        return *iCaName;
        }
    else
        {
        return KEmptyString;
        }
    }               				


void CIkeV2PkiService::ReadUserCertificateL(const TDesC8& aTrustedAuthority, TBool aGetCACert)
    {
    __ASSERT_DEBUG(iReadCertificate != NULL, User::Invariant());
   //
   // Read certificate from PKI store using pkiserviceapi
   //  
	TPKIKeyAlgorithm keyAlgorithm = EPKIRSA; 
	TPKICertificateOwnerType ownerType; 	
	TUint keySize = 0;
	
	 if ( aGetCACert )
	    {
	        ownerType = EPKICACertificate;

	        //Init CA cert ident data.
	        //aTrustedAuthority (issuer) checking for CA certs is not supported.
	        //__ASSERT_ALWAYS(aTrustedAuthority.Length() == 0, User::Invariant());
	        if ( aTrustedAuthority.Length() == 0 )
	            {
	            delete iSubjName;
	            iSubjName = NULL;
	            iSubjName = iCaName->AllocL();
	            iRfc822Name->Des().Zero();
	            } 
	     }
	 else
	     {
	     ownerType = EPKIUserCertificate;	    
	     TInt length = iIkeData->iOwnCert.iSubjectDnSuffix.Length();
	     if ( length )
	         {
	         delete iSubjName;
	         iSubjName = NULL;
	         iSubjName = HBufC8::NewL(length);  	   			 
	         iSubjName->Des().Copy(iIkeData->iOwnCert.iSubjectDnSuffix);		
	         }
	     else 
	         {
	         iSubjName->Des().Zero();
	         } 

	     length = iIkeData->iOwnCert.iRfc822NameFqdn.Length();
	     if ( length )
	         {
	         delete iRfc822Name;
	         iRfc822Name = NULL;
	         iRfc822Name = HBufC8::NewL(length);  	   			 
	         iRfc822Name->Des().Copy(iIkeData->iOwnCert.iRfc822NameFqdn);        	 
	         }
	     else
	         {
	         iRfc822Name->Des().Zero();
	         }
	     keySize = iIkeData->iOwnCert.iPrivateKeyLength;
	     }
	iPkiService.ReadCertificateL(aTrustedAuthority,
	                              *iSubjName, *iRfc822Name,
			                      ownerType, keySize,
			                      keyAlgorithm, iCertPtr,
			                      &iResArray, iStatus);
    SET_ACTIVE;
    }	 


void CIkeV2PkiService::CIkeV2PkiServiceApplUidArrayCleanup(TAny* any)
    {
    RArray<TUid>* applUidList = reinterpret_cast<RArray<TUid>*>(any);
    applUidList->Reset();
    applUidList->Close();
    delete applUidList;    
    }


void CIkeV2PkiService::RunL()
    {   
    DEBUG_LOG1(_L("CIkeV2PkiService::RunL: Status %d"), iStatus.Int());
    
	//
	// A PKI service operation completed. Take actions according to
	// iOperation code
	//

    TInt err = KErrNone;
			
	TInt status = iStatus.Int();				

    iPkiService.Finalize(iResArray);
    iResArray = NULL;

	
	switch ( iState )
	    {
		case EBuildingCaList:
            TRAP(err, BuildingCaListRunL());
            break;				
		case EReadingCertificate:
		    TRAP(err, ReadUserCertificateRunL());
			break;
		case EReadingCertificateChain:
		    TRAP(err, ReadCertificateChainRunL());
		    break;
		default:
		    DEBUG_LOG(_L("RunL called in unknown state"));
		    User::Invariant();
			break;
	    }	

	if ( err != KErrNone )
	    {	
	    DEBUG_LOG(_L("Operation completed. Signalling observer."));

        SignalObserverL(err);
	    }   
    }


void CIkeV2PkiService::ReadUserCertificateRunL()
    {        
	//
	// A Certificate has been read PKI store.
	// Build X509 certificate object from certificate data
	//
	switch(iStatus.Int())
	    {
	    case KErrNone:	        
	        iUserCertificate = iReadCertificate->AllocL();
	        iReadCertificate->Des().Zero();
	        SignalObserverL(KErrNone);            
	        break;
	    case KPKIErrBufferTooShort:
		    {	
            //
            // Allocate a new buffer for ASN1 coded certificate read from PKI store
            // Buffer size is now asked from pkiserviceapi 
            //            
            TInt realCertSize;        
            User::LeaveIfError(iPkiService.GetRequiredBufferSize(realCertSize));

            delete iReadCertificate;
            iReadCertificate = NULL;

            iReadCertificate = HBufC8::NewL(realCertSize);
            iCertPtr.Set(iReadCertificate->Des());
            		   		   
            ReadUserCertificateL(*iCaName, EFalse);
		    }
	        break;
	    case KPKIErrNotFound:
	        {	            
            //
            // Get next user certificate from PKI store using either Key
            // identifier or CA name as read argument
            //                                    
            iCasTrustedByPeer.Remove(0);
            if ( iCasTrustedByPeer.Count() > 0 )
                {
                
                CIkeCaElem* CaElem = iCasTrustedByPeer[0];	                                   
                HBufC8* caName = IkeCert::GetCertificateFieldDERL(CaElem->Certificate(), KSubjectName);
                if (caName == NULL)
                    {
                    User::Leave(KErrArgument);
                    }
                delete iCaName;
                iCaName = caName;
                caName=NULL;
                delete caName;
                ReadUserCertificateL(*iCaName, EFalse);
                }	   
            else
                {
                User::Leave(KErrNotFound);
                }
	        }
            break;
	    case KErrNotFound:
	        ReadCertificateChainL();
	        break;
        default:
            User::Leave(iStatus.Int());
            break;            
	    }
    }    


void CIkeV2PkiService::BuildingCaListRunL()
    {       
    
    switch(iStatus.Int())
        {
        case KErrNone:
            {                        
            iIkeDataCAList->Delete(0);     
            
    	    ASSERT(iReadCertificate);
    		HBufC8* caCert = iReadCertificate; // Link CA buffer to CIkeCaElem
    		CleanupStack::PushL(caCert);		
    		
    		iReadCertificate = NULL;    		
    		iReadCertificate = HBufC8::NewL(KDefaultCertificateBufferSize);
    		iCertPtr.Set(iReadCertificate->Des());
    		
    		
     		CIkeCaElem* caElem = CIkeCaElem::NewL(caCert);
    		CleanupStack::Pop(caCert);		
    		CleanupStack::PushL(caElem);
    		
    		//Append ca cert to list, if not already present.
    		if (iTrustedCAList->FindCaElem(caElem->KeyHash()) == NULL)
    		    {    		    
    		    iTrustedCAList->AppendL(caElem);
    		    CleanupStack::Pop(caElem);
    		    }
            else
                {
                CleanupStack::PopAndDestroy(caElem);
                }
            
            if (iIkeDataCAList->Count() > 0)
                {
                ImportNextCaElemFromIkeDataListL();
                }
            else
                {
                
                if (iIkeData->iOwnCert.iOwnCertExists)
                    {
                    ReadTrustedUserCertificateL();
                    }
                else
                    {
                    SignalObserverL(KErrNone);
                    }
                }
            }
            break;
        case KPKIErrBufferTooShort:
            {
                
            DEBUG_LOG(_L("Buffer too short"));
            
            TInt certSize = 0;            
		    User::LeaveIfError(iPkiService.GetRequiredBufferSize(certSize));
            
            __ASSERT_DEBUG(iCertPtr.MaxLength() < certSize, User::Invariant());
            
            delete iReadCertificate;
            iReadCertificate = NULL;            
            iReadCertificate = HBufC8::NewL(certSize);
            iCertPtr.Set(iReadCertificate->Des());
            
            //Tries to reimport the certificate.
            ImportNextCaElemFromIkeDataListL();            
            }
            break;
        default:        
            DEBUG_LOG1(_L("Error code %d"), iStatus.Int());
            User::Leave(iStatus.Int());
            break;
        }
    }


EXPORT_C void CIkeV2PkiService::InitIkeV2PkiService(const CIkeData* aIkeData)
    {          
    __ASSERT_DEBUG(iState == EPkiServiceIdle, User::Invariant());
    __ASSERT_DEBUG(iIkeDataCAList == NULL, User::Invariant());
    __ASSERT_DEBUG(aIkeData->iCAList != NULL, User::Invariant());
    __ASSERT_DEBUG(aIkeData->iCAList->Count() > 0, User::Invariant());
    __ASSERT_DEBUG(iIkeData == NULL, User::Invariant());
    
    iIkeData = aIkeData;
    
    iState = EBuildingCaList;
    TRAPD(err, InitIkeV2PkiServiceL());
    if (err != KErrNone)
        {
        iStatus = KRequestPending;
        SET_ACTIVE;
        
        TRequestStatus* status = &iStatus;
        User::RequestComplete(status, err);
        }     
    }
    

void CIkeV2PkiService::InitIkeV2PkiServiceL()
    {               
    if (iIkeData->iClientCertType != NULL)
        {
        if (iIkeData->iClientCertType->GetData().Compare(_L("DEVICE")) == 0)
            {
            User::LeaveIfError(iPkiService.SetStoreType(EPkiStoreTypeDevice));
            }
        else
            {
            User::LeaveIfError(iPkiService.SetStoreType(EPkiStoreTypeUser));
            }
        }
    
    iIkeDataCAList = new (ELeave) CArrayFixFlat<TCertInfo>(2);
    for (TInt i = 0; i < iIkeData->iCAList->Count(); ++i)
        {
        const TCertInfo* info = (*iIkeData->iCAList)[i];
        iIkeDataCAList->AppendL(*info);
        }       
         
    ImportNextCaElemFromIkeDataListL();         
    }
    
    
void CIkeV2PkiService::ImportNextCaElemFromIkeDataListL()
    {        
    __ASSERT_DEBUG(iIkeDataCAList != NULL, User::Invariant());
    __ASSERT_DEBUG(iIkeDataCAList->Count() > 0, User::Invariant());
    
    const TCertInfo certInfo = (*iIkeDataCAList)[0];        
    switch(certInfo.iFormat)
        {            
        case CA_NAME:    
            delete iSubjName;
            iSubjName = NULL;
            iSubjName = HBufC8::NewL(certInfo.iData.Length());
            iSubjName->Des().Copy(certInfo.iData);                    
        	iPkiService.ReadCertificateL(KEmptyString,
                                         *iSubjName, KEmptyString,
		                                 EPKICACertificate, 0,
		                                 EPKIRSA, iCertPtr,
		                                 &iResArray, iStatus);
            SET_ACTIVE;  
            break;                  
        case KEY_ID:
            if (!IkeParser::TextToHexOctets(certInfo.iData, iCertKeyId))
                {
                User::Leave(KErrArgument);
                }
            iPkiService.ReadCertificateL(iCertKeyId, iCertPtr,
            			                 &iResArray, iStatus);
            SET_ACTIVE;                     
            break;
       case APPL_UID:           
            {            
            //Get the list of applicable CA certs and appends it
            //to the original list, which was defined in the policy.
            //After this removes the currently handled node and
            //calls the method recursively.
            RArray<TUid>*  applUidList = IkeParser::GetApplUidListL(certInfo.iData);	
            CleanupStack::PushL(TCleanupItem(CIkeV2PkiServiceApplUidArrayCleanup,
                                 applUidList));

            CArrayFix<TCertificateListEntry>* applicableCaCertList;
            iPkiService.ListApplicableCertificatesL(*applUidList, applicableCaCertList);                                
            
            CleanupStack::PopAndDestroy(); //applUidList
                        
            if (applicableCaCertList->Count() > 0)
                {                                            
                CleanupStack::PushL(applicableCaCertList);
                TCertInfo* info = new (ELeave) TCertInfo;
                CleanupDeletePushL(info);
                for (TInt i = 0; i < applicableCaCertList->Count(); i++)
                    {
                    const TCertificateListEntry& entry = (*applicableCaCertList)[i];
                    info->iFormat = CA_NAME;
                    info->iData.Zero();
                    info->iData.Copy(entry.iIdentitySubjectName);

                    iIkeDataCAList->AppendL(*info);
                    DEBUG_LOG1(_L("Appending Applicable cert to the list (%S)"), &(info->iData));
                                                
                    }
                
                CleanupStack::PopAndDestroy(info);
                CleanupStack::PopAndDestroy(applicableCaCertList);
                
                iIkeDataCAList->Delete(0);                
                ImportNextCaElemFromIkeDataListL();
                }
            else
                {
                delete applicableCaCertList;
                applicableCaCertList = NULL;
                
                iStatus = KRequestPending;
                SET_ACTIVE;
                
                TRequestStatus* status = &iStatus;
                User::RequestComplete(status, KErrNotFound);                
                }                                                                
            }
            break;
        default:
            User::Leave(KErrArgument);                
            break;
        }
    }

void CIkeV2PkiService::ReadCertificateChainL()
    {
    delete iCaName;
    iCaName = NULL;
    iCaName = IkeCert::GetCertificateFieldDERL(iCasTrustedByPeer[0]->Certificate(), KSubjectName);;
    iState = EReadingCertificateChain;
    ReadUserCertificateL(KEmptyString, EFalse);
    }

void CIkeV2PkiService::ReadCertificateChainRunL()
    {
    TInt err;
    HBufC8* issuerName=NULL;
    TRAP(err, issuerName =  IkeCert::GetCertificateFieldDERL(iReadCertificate, KIssuerName));
    if (err!=KErrNone)
        {
        err=KKmdIkeNoCertFoundErr;
        User::Leave(err);
        }
    if ( issuerName->Compare(iCaName->Des())==0)
        {
        iReadCertificate->Des().Zero();
        delete issuerName;
        issuerName = NULL;
        SignalObserverL(KErrNone);    
        }
    else
        {
         delete issuerName;
         issuerName = NULL;
         delete iCaName;
         iCaName = NULL;
         iCaName =  IkeCert::GetCertificateFieldDERL(iReadCertificate, KIssuerName);
         delete iSubjName;
         iSubjName = NULL;
         iSubjName = iCaName->AllocL();
         if ( !iUserCertificate)
             iUserCertificate = iReadCertificate->AllocL();
         else if ( !i2Certificate )
             {
             i2Certificate = iReadCertificate->AllocL();
             i2CertificateName= IkeCert::GetCertificateFieldDERL(i2Certificate, KSubjectName);
             }
         else if ( !i1Certificate)
             i1Certificate = iReadCertificate->AllocL();
                            
         iPkiService.ReadCertificateL(KEmptyString,
                                      *iSubjName, KEmptyString,
                                      EPKICACertificate, 0,
                                      EPKIRSA, iCertPtr,
                                      &iResArray, iStatus);
         SET_ACTIVE;
        }
        
    }
    
void CIkeV2PkiService::SignalObserverL(TInt aStatus)
{    
    DEBUG_LOG1(_L("CIkeV2PkiService::SignalObserverL: Signalling with %d"), aStatus);
    
    if (aStatus != KErrNone)
        {
        delete iUserCertificate;
        iUserCertificate = NULL;
        
		delete iCaName;
		iCaName = NULL;
				
		iCertPtr.Zero();
        
        iTrustedCAList->ResetAndDestroy(); // Trusted CA certificate list 
               
        }

    iIkeData = NULL;

    iSubjName->Des().Zero();
    iRfc822Name->Des().Zero();

    iCertKeyId.Zero();
    iResArray = NULL;
    
    iCasTrustedByPeer.Reset();
    	    	    	    
    delete iIkeDataCAList;
    iIkeDataCAList = NULL;
    	    	       
    iState = EPkiServiceIdle;
    iObserver.IkeV2PkiInitCompleteL(aStatus);		
}