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

/*
* Copyright (c) 2003-2008 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: 
* CPKISupport class implements the PKI interface for Symbian Certificate 
* storage.
*
*/



#include <securitydefs.h>
#include <cctcertinfo.h>
#include <x509cert.h>
#include <ccertattributefilter.h>
#include <asymmetric.h>
#include <unifiedcertstore.h>
#include <mctwritablecertstore.h>

#include "pkiwrapper.h"
#include "PKIMapper.h"
#include "pkisupport.h"
#include "pkisession.h"
#include "log_r6.h"
#include "pkiserviceassert.h"
#include "pkiserviceconstants.h"
#include <vpnlogmessages.rsg>


CPKISupport* CPKISupport::NewLC(CPKIMapper& aMapper, CPKIWrapper& aWrapper)
    {
    CPKISupport* self = new (ELeave)CPKISupport(aMapper, aWrapper);
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
    }

CPKISupport* CPKISupport::NewL(CPKIMapper& aMapper, CPKIWrapper& aWrapper)
    {
    CPKISupport* self = CPKISupport::NewLC(aMapper, aWrapper);
    CleanupStack::Pop(self);
    return self;
    }

void CPKISupport::ConstructL()
	{
	User::LeaveIfError(iEventMediator.Connect());
	}

CPKISupport::~CPKISupport()
    {
    LOG_("CPKISupport::~CPKISupport");
    Cancel();    

    if(iCerts != NULL)
        {
        iCerts->Close();
        delete iCerts;
        }
    delete iCertFilter;
    delete iCertStore;
    iFSession.Close();
    iApplUids.Close();
    delete iImportCertMapping;
    delete iImportCertData;
    iEventMediator.Close();
    delete iCertInfoForLogging; 
    iCertInfoForLogging = NULL;
    }

CPKISupport::CPKISupport(CPKIMapper& aMapper, CPKIWrapper& aWrapper) 
    :CActive(CActive::EPriorityStandard), 
    iMapper(aMapper),
    iWrapper(aWrapper),
    iPending(ENoPendingOperation),
    iImportCertDataPtr(NULL, 0)
    {
    LOG_("-> CPKISupport::CPKISupport()\n");   
    CActiveScheduler::Add(this);
    
    SetCertStoreType(EPkiStoreTypeAny);
    LOG_("<- CPKISupport::CPKISupport()\n");
    } 

// ---------------------------------------------------------------------------
// StartInitializeL
// ---------------------------------------------------------------------------
//
void  CPKISupport::StartInitializeL(const RMessage2& aMessage)
    {
    LOG_("-> CPKISupport::StartInitialize()");
    User::LeaveIfError(iFSession.Connect());
    iCertStore = CUnifiedCertStore::NewL(iFSession, ETrue);
    PKISERVICE_ASSERT(!iCerts);
    iCerts = new (ELeave) RMPointerArray<CCTCertInfo>;
    
    iMessage = aMessage;
    iCallerStatus = NULL;
    iSupportStatus = KErrNone;

    iInitState = EInitInitializeCertStore;
    iCertStore->Initialize(iStatus);
    iPending = EInitializeCertStore;
    SetActive();
    
    LOG_("<- CPKISupport::StartInitialize()");
    }


// ---------------------------------------------------------------------------
// FindInterfacesL
// ---------------------------------------------------------------------------
//
void  CPKISupport::FindInterfacesL()
    {
    TInt i(0);
    
    // Find writable cert interface
    LOG(Log::Printf(_L("Find interfaces")));

    TBool allStoresFound(EFalse);

    MCTWritableCertStore* certStore;

    TInt storeCount = iCertStore->WritableCertStoreCount();
    LOG_1("Found %d cert stores\n", storeCount);


    // Find both user and device cert stores
    for(i = 0; i < storeCount; i++)
        {
        certStore= &(iCertStore->WritableCertStore(i));

        if(certStore->Token().Label().Compare(KUserCertStore) == 0)
            {
            // found the user cert store... See if device cert store 
            // was already found as well
            iWritableCertStore = certStore;

            LOG(Log::Printf(_L("Found writable user certificate store\n")));
            
            if (!allStoresFound) 
                {
                allStoresFound = ETrue;
                }
            else 
                {
                break;
                }
            }
        else if (certStore->Token().Label().Compare(KDeviceCertStore) == 0) 
            {

            // found the device cert store
            iWritableDeviceCertStore = certStore;

            LOG(Log::Printf(_L("Found writable device certificate store\n")));
            
            // See if user cert store was already found as well
            if (!allStoresFound) 
                {
                allStoresFound = ETrue;
                }
            else 
                {
                break;
                }
            }
        }
    
    if (iWritableDeviceCertStore == NULL) 
        {
        LOG(Log::Printf(_L("Note: Device cert store not found\n")));
        }
    }


// ---------------------------------------------------------------------------
// ContinueImportCTFObjectsL
// ---------------------------------------------------------------------------
//
void  CPKISupport::ListAllCertificatesL()
{
    LOG_("-> CPKISupport::ListAllCertificatesL");

    PKISERVICE_ASSERT( !iCertFilter );
    iCertFilter = CCertAttributeFilter::NewL();
    
    iSupportStatus = KErrNone;
    iInitState = EInitRetrieveCertList;
    iImportCounter = 0;
	iToggleSwitch = EFalse;

    // Get list of all known certificates
    GetCertificateStoreListAsync();
    LOG_("<- CPKISupport::ListAllCertificatesL");
}

    
    
// ---------------------------------------------------------------------------
// ImportCTFCertsL
// ---------------------------------------------------------------------------
//
void  CPKISupport::ReadNextCertForImportL()
{
    LOG_("-> CPKISupport::ImportNextCertL()");
    PKISERVICE_ASSERT(iImportCounter < iCerts->Count());
    
    if(iImportCounter == 0)
        {
        LOG_1("Import %d certificates\n", iCerts->Count());
        }
        
    LOG_1("Import certificate:%d", iImportCounter);
    LOG_1("Label: %S", &((*iCerts)[iImportCounter]->Label()));
    
    PKISERVICE_ASSERT((*iCerts)[iImportCounter]->CertificateFormat() == EX509Certificate);

    TSecurityObjectDescriptor descriptor;    
    descriptor.SetSubjectKeyId(
        (*iCerts)[iImportCounter]->SubjectKeyId());
    descriptor.SetOwnerType(
        (TPKICertificateOwnerType)(*iCerts)[iImportCounter]->
        CertificateOwnerType());
	descriptor.SetIsDeletable(
	    (*iCerts)[iImportCounter]->IsDeletable());
      
    delete iImportCertMapping;
    iImportCertMapping = NULL;
    iImportCertMapping = new (ELeave) CMapDescriptor(descriptor);
            
    iImportCertMapping->SetMapObjectName((*iCerts)[iImportCounter]->Label());
    
    delete iImportCertData;
    iImportCertData = NULL;
    iImportCertData = HBufC8::NewL((*iCerts)[iImportCounter]->Size());        
    iImportCertDataPtr.Set(iImportCertData->Des());
    
    LOG_(" Values set OK, retrieving");
    iCertStore->Retrieve(
        *(*iCerts)[iImportCounter], iImportCertDataPtr, iStatus);
    iPending = ECertRetrieve;
    SetActive();
    LOG_("<- CPKISupport::ImportCTFCertsL() SetActive() and ret: EFalse");
}

// ---------------------------------------------------------------------------
// ImportOneCTFCertL
// ---------------------------------------------------------------------------
//
void CPKISupport::SaveCertInfoToCacheL()
    {
    if((iImportCertMapping != NULL) && (iImportCertData != NULL))
        {
        LOG_("Saving cert info to cache");
       
        CX509Certificate* certificate = CX509Certificate::NewLC(iImportCertDataPtr);            
        const CSubjectPublicKeyInfo& publicKeyInfo = certificate->PublicKey();            
        const TPtrC8 keyData = publicKeyInfo.KeyData();

        TX509KeyFactory keyFactory;
        switch(publicKeyInfo.AlgorithmId())
            {
            case ERSA:
                {                        
                iImportCertMapping->iKeyAlgorithm = EPKIRSA;
                const CRSAPublicKey* keyRSA = keyFactory.RSAPublicKeyL( keyData );
                const TInteger&  n = keyRSA->N();
                iImportCertMapping->iKeySize = n.BitCount();
                delete keyRSA;                    
                }
                break;        	
            case EDSA:
                {                        
                iImportCertMapping->iKeyAlgorithm = EPKIDSA;
                TPtrC8 params = publicKeyInfo.EncodedParams();
                const CDSAPublicKey* keyDSA = keyFactory.DSAPublicKeyL( params, keyData );
                const TInteger& y = keyDSA->Y();
                iImportCertMapping->iKeySize = y.BitCount();
                delete keyDSA;
                }
                break;
            default:
                iImportCertMapping->iKeyAlgorithm = EPKIInvalidAlgorithm;
                break;                    
            }                    
        CleanupStack::PopAndDestroy(certificate);                        

        iWrapper.SaveIdentityL(*iImportCertMapping,
                               iImportCertDataPtr,
                               ((*iCerts)[iImportCounter])->CertificateOwnerType());

        TInt storeType = (*iCerts)[iImportCounter]->Token().TokenType().Type().iUid;
        if ( storeType == STORETYPE_DEVICE_CERT_ID )
            {
            iImportCertMapping->SetCertStoreType(EPkiStoreTypeDevice);
            }
        else if ( storeType == STORETYPE_USER_CERT_ID )
            {
            iImportCertMapping->SetCertStoreType(EPkiStoreTypeUser);
            }
        else
            {
            iImportCertMapping->SetCertStoreType(EPkiStoreTypeAny);
            }
            
		for(TInt i=0;i<iApplUids.Count();i++)
			{
			iImportCertMapping->iApplUids.Append(iApplUids[i]);
			}
        User::LeaveIfError( 
            iMapper.AddMapping(*iImportCertMapping) );

        iApplUids.Close();            
            
        iImportCertMapping = NULL;    
        iImportCounter++;
        }    
    }

// ---------------------------------------------------------------------------
// GetApplicationsOfCTFCertL
// ---------------------------------------------------------------------------
//
TBool  CPKISupport::GetApplicationsOfCTFCertL()
{
    LOG_("-> CPKISupport::GetApplicationsOfCTFCertL()");
	if((iImportCertMapping != NULL) && (iImportCertData != NULL))
		{
		if(iToggleSwitch == EFalse)
			{
			if((*iCerts)[iImportCounter]->CertificateOwnerType() == ECACertificate)
				{
				PKISERVICE_ASSERT(iApplUids.Count() == 0);
				
				iToggleSwitch = ETrue;
				// Get applications				
				iCertStore->Applications(*(*iCerts)[iImportCounter], iApplUids, iStatus);
				iPending = EApplications;
                LOG_("<- CPKISupport::GetApplicationsOfCTFCertL() SetActive(), ret: ETrue");
				SetActive();
				return ETrue;
				}
			else
				{
                LOG_("<- CPKISupport::GetApplicationsOfCTFCertL() Not a CA cert, ret: EFalse");
				return EFalse;
				}
			}
		else
			{
            LOG_("<- CPKISupport::GetApplicationsOfCTFCertL() iToggleSwitch == ETrue, ret: EFalse");
			iToggleSwitch = EFalse;
			return EFalse;
			}
		}
	else
		{
		return EFalse;
		}
}


// ---------------------------------------------------------------------------
// CancelCurrentOperation
// ---------------------------------------------------------------------------
//
void CPKISupport::CancelCurrentOperation()
    {
    LOG_1("CPKISupport::CancelCurrentOperation iPending: %d", iPending);    
    MCTWritableCertStore* certStore(NULL);
    switch(iPending)
        {
        case ENoPendingOperation:
            // No pending operation 
            PKISERVICE_ASSERT( iStatus.Int() != KRequestPending);        
            break;
        case EInitializeCertStore:
            // FALLTROUGH
        case EListCerts:
            // FALLTROUGH
        case EListDevCerts:
            // FALLTROUGH
        case ECertRetrieve:
            // FALLTROUGH
        case ECertRemove:
            // FALLTROUGH
        case ESetTrust:
            // FALLTROUGH
        case ETrusted:
            // FALLTROUGH
        case ESetApplicability:
            // FALLTROUGH
        case EApplications:
            // FALLTROUGH
        case EIsApplicable:
            PKISERVICE_ASSERT( iCertStore );
            iCertStore->Cancel();
            break;
        case ECertAdd:
            if (iCertStoreType == EPkiStoreTypeDevice) 
                {
                LOG_("CPKISupport::CancelCurrentOperation cancelling device cert store op");
                certStore = iWritableDeviceCertStore;
                }
            else if (iCertStoreType == EPkiStoreTypeUser)
                {
                LOG_("CPKISupport::CancelCurrentOperation cancelling user cert store op");
                certStore = iWritableCertStore;
                }
            else 
                {
                LOG_("CPKISupport::CancelCurrentOperation cancelling user cert store op (unknown store type was defined)");
                certStore = iWritableCertStore;
                }
            PKISERVICE_ASSERT( certStore );
            certStore->CancelAdd();
            break;
        default:
            LOG_("CPKISupport::CancelCurrentOperation - default");
            break;           
        }
    }       

// ---------------------------------------------------------------------------
// ConvertPKIAlgorithm
// ---------------------------------------------------------------------------
//
CCTKeyInfo::EKeyAlgorithm CPKISupport::ConvertPKIAlgorithm(TPKIKeyAlgorithm aAlg)
{
    CCTKeyInfo::EKeyAlgorithm algorithm = CCTKeyInfo::EInvalidAlgorithm;

    switch(aAlg)
        {
        case EPKIRSA:
            algorithm = CCTKeyInfo::ERSA;
            break;
        case EPKIDSA:
            algorithm = CCTKeyInfo::EDSA;
            break;
        case EPKIDH:
            algorithm = CCTKeyInfo::EDH;
            break;
        default:
            break;
        }
    return algorithm;
}

// ---------------------------------------------------------------------------
// ConvertSymbianAlgorithm
// ---------------------------------------------------------------------------
//
TPKIKeyAlgorithm CPKISupport::ConvertSymbianAlgorithm(CCTKeyInfo::EKeyAlgorithm aAlg)
{
    TPKIKeyAlgorithm algorithm = EPKIInvalidAlgorithm;

    switch(aAlg)
        {
        case ERSA:
            algorithm = EPKIRSA;
            break;
        case EDSA:
            algorithm = EPKIDSA;
            break;
        case EDH:
            algorithm = EPKIDH;
            break;
        default:
            break;
        }
    return algorithm;
}

// ---------------------------------------------------------------------------
// CActive methods
// ---------------------------------------------------------------------------
//
void CPKISupport::RunL()
    {
    LOG_1("CPKISupport::RunL err:%d", iStatus.Int());
    
    iSupportStatus = iStatus.Int();
	if((iSupportStatus == KErrNotSupported) && 
	    iToggleSwitch && (iInitState == EInitCompleteImportCerts))
		{
		// Some implementations of MIDP2 certstore return KErrNotSupported
		// when calling iCertStore->Applications()
		LOG_1("CPKISupport::RunL ignore error :%d", iSupportStatus);
		iSupportStatus = KErrNone;		
		}
		
    iPending = ENoPendingOperation;
    if(iSupportStatus == KErrNone)
        {
        DoRunOperationL();     
        }
    else
        {
        iSubState = ESSCompleteRequest;
        }
    
    if(iSubState == ESSCompleteRequest)
        {
        if(iInitState != EInitDone)
            {
            iMessage.Complete(iSupportStatus);
            }
        else
            {
            CompleteCallerStatus( iSupportStatus );
            }
		}
    }

// ---------------------------------------------------------------------------
// GetRequiredBufferSize
// ---------------------------------------------------------------------------
//    
TInt CPKISupport::GetRequiredBufferSize()
    {
    LOG_1("CPKISupport::GetRequiredBufferSize:%d", iRequiredBufferLength);
    return iRequiredBufferLength;
    }

// ---------------------------------------------------------------------------
// SetCallerStatusPending
// ---------------------------------------------------------------------------
//    
void CPKISupport::SetCallerStatusPending(TRequestStatus& aStatus)
    {
    iCallerStatus = &aStatus;
    aStatus = KRequestPending;    
    }

// ---------------------------------------------------------------------------
// CompleteCallerStatus
// ---------------------------------------------------------------------------
//    
void CPKISupport::CompleteCallerStatus(TInt aError)
    {
    LOG_("-> CPKISupport::CompleteCallerStatus");
    if(iCallerStatus)
        {
        if(iCurrentFunction == PkiService::EStoreCertificate ||
           iCurrentFunction == PkiService::EAttachCertificate)
        	LogCertStoring(aError);
        
        LOG_("Completing caller status");
        User::RequestComplete(iCallerStatus, aError);        
        }
    else
        {
        LOG_("Completing rmessage");
        iMessage.Complete(aError);
        }      
    LOG_("<- CPKISupport::CompleteCallerStatus");        
    }

// ---------------------------------------------------------------------------
// LogCertStoring
// ---------------------------------------------------------------------------
//    
void CPKISupport::LogCertStoring(TInt aError)
    {
    TUid uId(KPkiServiceUid3);
    if(aError == KErrNone)
    	iEventMediator.ReportLogEvent(uId, EInfo, R_VPN_MSG_CERT_INSTALLED, 1, iCertInfoForLogging);
    else 
    	{
    	TPckgBuf<TInt> int1Des(aError);
    	iEventMediator.ReportLogEvent(uId, EError, R_VPN_MSG_CERT_INSTALL_FAILED, 2, &int1Des, iCertInfoForLogging);
    	}
    }

// ---------------------------------------------------------------------------
// DoCancel
// ---------------------------------------------------------------------------
//
void CPKISupport::DoCancel()
    {
    LOG_1("CPKISupport::DoCancel:%d", iStatus.Int());
    CancelCurrentOperation();  
    CompleteCallerStatus( iStatus.Int() );
    }

// ---------------------------------------------------------------------------
// RunError
// ---------------------------------------------------------------------------
//
TInt CPKISupport::RunError(TInt aError)
    {
    LOG_1("RunError status = %d", aError);
    CompleteCallerStatus( aError );
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// SetCurrentFunction
// ---------------------------------------------------------------------------
//
void CPKISupport::SetCurrentFunction(TInt aFunc)
    {
    iCurrentFunction = aFunc;
    iSubState = ESSComplete;
    }


// ---------------------------------------------------------------------------
// StoreCertificateL
// ---------------------------------------------------------------------------
//
void CPKISupport::StoreCertificateL(const TDesC &aLabel, 
                                    TCertificateOwnerType aOwnerType, 
                                    const TDesC8 &aBufferPtr, 
                                    const TBool& aIsDeletable, 
                                    TRequestStatus& aStatus)
{
    LOG_("Store certificate");
    iSupportStatus = KErrNone;
    SetCallerStatusPending( aStatus );
    iKeyId.Zero();

    MCTWritableCertStore* certStore(NULL);

    CX509Certificate* tempCert = CX509Certificate::NewLC(aBufferPtr);
    iKeyId = tempCert->KeyIdentifierL();
    CleanupStack::PopAndDestroy();

    if(aOwnerType == EUserCertificate)
        {
        if (iCertStoreType == EPkiStoreTypeDevice) 
            {
            LOG(Log::Printf(_L(" Using device cert store\n")));
            certStore = iWritableDeviceCertStore;
            }
        else if (iCertStoreType == EPkiStoreTypeUser)
            {
            LOG(Log::Printf(_L(" Using user cert store\n")));
            certStore = iWritableCertStore;
            }
        else if (iCertStoreType == EPkiStoreTypeAny)
            {
            LOG(Log::Printf(_L(" Any cert store type, using user cert store\n")));
            certStore = iWritableCertStore;
            }
        else 
            {
            LOG(Log::Printf(_L(" Error: Unknown cert store type, defaulting to user cert store\n")));
            certStore = iWritableCertStore;
            }
        }
    else 
        {
        certStore = iWritableCertStore;
        }
    
    certStore->Add(aLabel, EX509Certificate, 
                   aOwnerType, NULL, NULL, 
                   aBufferPtr, aIsDeletable, iStatus);
    
    ExtractCertInfoL(aLabel, aOwnerType, aBufferPtr);
        
    iPending = ECertAdd;
    SetActive();
}

// ---------------------------------------------------------------------------
// ExtractCertInfoL
// ---------------------------------------------------------------------------
//
void  CPKISupport::ExtractCertInfoL(const TDesC& aLabel,
								    const TCertificateOwnerType& aOwnerType,
								    const TDesC8& aBufferPtr)
{
	_LIT8(KFormat,"Type: %S, Label: %S, Subject: %S, Issuer: %S");
	
	TBuf8<4> type;
	if(aOwnerType == EPKICACertificate)
		type.Copy(_L8("CA"));
   	else
   		type.Copy(_L8("USER"));
	
	CX509Certificate* tempCert = CX509Certificate::NewLC(aBufferPtr);
	
	HBufC* subject = tempCert->SubjectL();
	CleanupStack::PushL(subject);
	
	HBufC* issuer = tempCert->IssuerL();
	CleanupStack::PushL(issuer);
	
	// Calculates size of 
	// "Type: <type>  Label: <label>  Subject: <subject>  Issuer: <issuer>"
    TInt bufSize(((TDesC8)KFormat).Length() + type.Length() + aLabel.Length() + subject->Length() + issuer->Length());
    delete iCertInfoForLogging; iCertInfoForLogging = NULL;
	iCertInfoForLogging = HBufC8::NewL(bufSize);
   	
	TPtr8 ptrLogMsg = iCertInfoForLogging->Des();        	
   	ptrLogMsg.Format(KFormat, &type, &aLabel, subject, issuer);
	
	CleanupStack::PopAndDestroy(issuer);
	CleanupStack::PopAndDestroy(subject);
    CleanupStack::PopAndDestroy(tempCert);
}


// ---------------------------------------------------------------------------
// ?description_if_needed
// ---------------------------------------------------------------------------
//
void CPKISupport::AttachCertificateL(const TDesC& aLabel, 
    const TPKIKeyIdentifier &aKeyId, const TDesC8 &aBufferPtr, 
    TRequestStatus& aStatus)
{
    TKeyIdentifier tempKeyId;
    CX509Certificate* certificate = CX509Certificate::NewLC(aBufferPtr);

    LOG_("Attach certificate");
    
    iSupportStatus = KErrNone;
    iKeyId = aKeyId;
    
    ExtractCertInfoL(aLabel, EUserCertificate, aBufferPtr);
    
    // fetch the keyId from the certificate
    tempKeyId = certificate->KeyIdentifierL();
    // If given keyId is empty, use the keyId from the certificate
    if(iKeyId.Length() == 0)
        {
        iKeyId = tempKeyId;
        }
        
    SetCallerStatusPending( aStatus );
    CleanupStack::PopAndDestroy(certificate);    // certificate
    
    iSubState = ESSComplete;

    MCTWritableCertStore* certStore(NULL);

    LOG(Log::Printf(_L("-------------------"));

        TBuf<256> buf;
        buf.Format(_L("Attaching certificate '%S'"), &aLabel);
        Log::Printf(buf);
        Log::Printf(_L("Certificate's KEY ID:"));
        Log::HexDump(NULL, NULL, iKeyId.Ptr(), iKeyId.Length());
    );
    if (iCertStoreType == EPkiStoreTypeDevice) 
        {
        LOG(Log::Printf(_L("CPKISupport::ContinueAttachCertificate() Using device cert store\n")));
        certStore = iWritableDeviceCertStore;
        }
    else if (iCertStoreType == EPkiStoreTypeUser)
        {
        LOG(Log::Printf(_L("CPKISupport::ContinueAttachCertificate() Using user cert store\n")));
        certStore = iWritableCertStore;
        }
    else if (iCertStoreType == EPkiStoreTypeAny)
        {
        LOG(Log::Printf(_L("CPKISupport::ContinueAttachCertificate() Any cert store, using user cert store\n")));
        certStore = iWritableCertStore;
        }
    else 
        {
        LOG(Log::Printf(_L("Error: Unknown cert store type, defaulting to user cert store\n")));
        certStore = iWritableCertStore;
        }
    LOG(Log::Printf(_L("-------------------")));

    certStore->Add(aLabel, 
                   EX509Certificate, 
                   EUserCertificate, 
                   &iKeyId, 
                   NULL, 
                   aBufferPtr, 
                   iStatus);
    iPending = ECertAdd;
    SetActive();
}


// ---------------------------------------------------------------------------
// ?description_if_needed
// ---------------------------------------------------------------------------
//
void CPKISupport::RetrieveCertificateL(const TDesC &aLabel, 
    TPtr8 &aBufferPtr, const TPKICertificateOwnerType& aType, 
    TRequestStatus& aStatus)
{
    LOG(Log::Printf(_L("Retrieve certificate\n")));
    iSupportStatus = KErrNone;
    iCerts->Close();
    iSubState = ESSContinue;
    iOutBufferPtr = &aBufferPtr;
    SetCallerStatusPending( aStatus );
    SelectCertificateL(aLabel, aType);
}

// ---------------------------------------------------------------------------
// ?description_if_needed
// ---------------------------------------------------------------------------
//
void CPKISupport::ContinueRetrieveCertificate()
{
    iSubState = ESSComplete;
    iPending = ECertRetrieve;
    
    TUint certificateSize = (*iCerts)[0]->Size();
    iRequiredBufferLength = certificateSize;
    if (certificateSize <= iOutBufferPtr->MaxLength())
        {        
        iCertStore->Retrieve(*(*iCerts)[0], *iOutBufferPtr, iStatus);
        SetActive();
        }
    else
        {
        iStatus = KRequestPending;
        SetActive();
        
        TRequestStatus* ownStatus = &iStatus;
        User::RequestComplete(ownStatus, KPKIErrBufferTooShort);
        }
}


/**
    Removes all unnecessary certificates from the certificate
    list before generating the local mapping data.
    More specifically, all MIDP2 and non X509 certificates are removed.
    (MIDP2 certificates can never have a "VPN" trust setting.)
    
    iListCleaned instance variable is used to limit the frequency
    of this cleanup - it's only necessary once, during PKI startup.
*/
void CPKISupport::CleanupCertListL() 
    {
    LOG_("Removing invalid certs (MIDP2 certs)");
    if (iCerts) 
        {
        TInt certcount = iCerts->Count();
        _LIT(KMidp2Label, "MIDP2");
        LOG_1("Total cert count, before cleanup: %d", iCerts->Count());
        RMPointerArray<CCTCertInfo> removedInfos;
        CleanupClosePushL(removedInfos);
        for (TInt i = certcount - 1; i >= 0; i--) 
            {
            CCTCertInfo* info = (*iCerts)[i];
            if (info->Label().Compare(KMidp2Label) == 0 ||
                info->CertificateFormat() != EX509Certificate) 
                {
                // CCTCertInfo has private destructor
                removedInfos.AppendL( info );
                iCerts->Remove(i);
                continue;
                }
            }
        CleanupStack::PopAndDestroy(); // removedInfos
        iCerts->Compress();
        LOG_1("Total cert count, after cleanup: %d", iCerts->Count());
        }
    else 
        {
        LOG_("Certs list empty!");
        }
    }

// ---------------------------------------------------------------------------
// DoRunOperationL
// ---------------------------------------------------------------------------
//
void CPKISupport::DoRunOperationL()
    {
    LOG_1("CPKISupport::DoRunOperationL iInitState:%d", iInitState);
    LOG_1("CPKISupport::DoRunOperationL iCurrentFunction:%d", 
        iCurrentFunction);
    LOG_1("CPKISupport::DoRunOperationL iSubState:%d", iSubState);
    
    switch(iInitState)
        {
        case EInitDone:
            DoRunLoggedInOperationL();
            break;

        case EInitInitializeCertStore:            
            if(iMapper.CacheCreated())
                {
                FindInterfacesL();
                iInitState = EInitDone;
                iMessage.Complete(KErrNone);
                return;
                }
            else
                {
				iMapper.SetCacheCreated();
                FindInterfacesL();
                ListAllCertificatesL();
                }
            break;
        case EInitRetrieveCertList:
            LOG_("CPKISupport::DoRunOperationL() EInitRetrieveCertList");
            // Cert list might be new. Remove all MIDP2 certificates first,
            // if it hasn't been already done
            CleanupCertListL();
            iInitState = EInitCompleteImportCerts;
            
            //Falls through
        case EInitCompleteImportCerts:
            LOG_("CPKISupport::DoRunOperationL() EInitCompleteImportCerts");            
			if(GetApplicationsOfCTFCertL())
				{
                LOG_(" Getting cert's applications returned with FALSE, breaking");
				break;
				}
            SaveCertInfoToCacheL();    // Handles one certificate, if found
            if(iImportCounter < iCerts->Count())
                {
                ReadNextCertForImportL();
                }
            else
                {
                LOG_(" All certificates imported, doing clean ups");
                // Cleanup

                delete iImportCertMapping;
                iImportCertMapping = NULL;

                delete iImportCertData;
                iImportCertData = NULL;

                iCerts->Close();

                delete iCertFilter;
                iCertFilter = NULL;
                iInitState = EInitDone;
                iMessage.Complete(KErrNone);
                }
            break;  // repeat            
        default:
            PKISERVICE_INVARIANT();
            iSupportStatus = KPKIErrUnexpectedState;
            iSubState = ESSCompleteRequest;
            break;
        } // End switch(iInitState)
    
    }

// ---------------------------------------------------------------------------
// DoRunLoggedInOperationL
// ---------------------------------------------------------------------------
//
void CPKISupport::DoRunLoggedInOperationL()
    {
    LOG_1("CPKISupport::DoRunLoggedInOperationL iCurrentFunction:%d", 
        iCurrentFunction);
    LOG_1("CPKISupport::DoRunLoggedInOperationL iSubState:%d", iSubState);
     
    switch(iCurrentFunction)
        {
        case PkiService::EAttachCertificate:
            switch(iSubState)
                {
                case ESSComplete:
                    iSubState = ESSCompleteRequest;
                    break;
                default:
                    iSupportStatus = KPKIErrUnexpectedState;
                    iSubState = ESSCompleteRequest;
                    break;
                }
            break;
            
        case PkiService::EReadCertificate:
            switch(iSubState)
                {
                case ESSContinue:
                    {
                    if(iCerts->Count() > 1)
                        {
                        LOG(Log::Printf(_L("Duplicate Certificate\n")));
                        iSubState = ESSCompleteRequest;
                        iSupportStatus = KErrNotFound;
                        }
                    else if (iCerts->Count() < 1)
                        {
                        LOG(Log::Printf(_L("No matching certificates found\n")));
                        iSubState = ESSCompleteRequest;
                        iSupportStatus = KErrNotFound;
                        }
					else if ((((*iCerts)[0])->CertificateOwnerType() == EUserCertificate) &&
							(((iCertStoreType == EPkiStoreTypeDevice) && (((*iCerts)[0])->Token().Label().Compare(KDeviceCertStore)!=0)) ||
                    	  	((iCertStoreType == EPkiStoreTypeUser) && (((*iCerts)[0])->Token().Label().Compare(KUserCertStore)!=0))))
						{
						LOG_1("User certificate's certificate info does not match certificate store type. Store type is: %d", iCertStoreType);
						iSubState = ESSCompleteRequest;
						iSupportStatus = KErrNotFound;                    	
						}
                    else
                        {
                        ContinueRetrieveCertificate();
                        }
                    break;
                    }
                case ESSComplete:
                    iSubState = ESSCompleteRequest;
                    break;
                default:
                    iSupportStatus = KPKIErrUnexpectedState;
                    iSubState = ESSCompleteRequest;
                    break;
                }
            break;
            
        case PkiService::ESetTrust:
        case PkiService::ETrusted:
            switch(iSubState)
                {
                case ESSContinue:
                    {
                    if(iCerts->Count() != 1)
                        {
                        iSubState = ESSCompleteRequest;
                        iSupportStatus = KErrNotFound;
                        }
                    else
                        {
                        if(iCurrentFunction == PkiService::ESetTrust)
                            {
                            ContinueSetTrust();
                            }
                        else
                            {
                            ContinueTrusted();
                            }
                        }
                    break;
                    }
                case ESSComplete:
                    if(iCurrentFunction == PkiService::ETrusted)
                        {
                        iWrapper.SetTrusted(iTrusted);
                        }
                    iSubState = ESSCompleteRequest;
                    break;
                default:
                    iSupportStatus = KPKIErrUnexpectedState;
                    iSubState = ESSCompleteRequest;
                    break;
                }
            break;

        case PkiService::ESetApplicability:
        case PkiService::EApplications:
            switch(iSubState)
                {
                case ESSContinue:
                    {
                    if(iCerts->Count() != 1)
                        {
                        iSubState = ESSCompleteRequest;
                        iSupportStatus = KErrNotFound;
                        }
                    else
                        {
                        if(iCurrentFunction == PkiService::ESetApplicability)
                            {
                            ContinueSetApplicability();
                            }
                        else if(iCurrentFunction == PkiService::EApplications)
                            {
                            ContinueApplications();
                            }
                        else
                            {
                            PKISERVICE_INVARIANT();
                            }
                        }
                    break;
                    }
                case ESSComplete:
                    if(iCurrentFunction == PkiService::EApplications)
                        {
                        iWrapper.SetApplications(iApplUids);
                        }
                            
                    iSubState = ESSCompleteRequest;
                    break;
                default:
                    iSupportStatus = KPKIErrUnexpectedState;
                    iSubState = ESSCompleteRequest;
                    break;
                }
            break;

        case PkiService::ERemoveCertificate:
            switch(iSubState)
                {
                case ESSContinue:
                    if(iCerts->Count() != 1)
                        {
                        iSupportStatus = KPKIErrNotFound;
                        iSubState = ESSCompleteRequest;
                        }
                    else
                        {
                        ContinueRemoveCertificate();
                        }
                    break;
                case ESSComplete:
                    iSubState = ESSCompleteRequest;
                    break;
                default:
                    iSupportStatus = KPKIErrUnexpectedState;
                    iSubState = ESSCompleteRequest;
                    break;
                }
            break;            
        default:
            iSubState = ESSCompleteRequest;
            break;
        }
    }    






// ---------------------------------------------------------------------------
// ?description_if_needed
// ---------------------------------------------------------------------------
//
void CPKISupport::RemoveCertificateL(const TDesC &aLabel, 
    TRequestStatus& aStatus)
{
    LOG(Log::Printf(_L("Remove certificate\n")));
    iSupportStatus = KErrNone;
    iCerts->Close();
    iSubState = ESSContinue;
    SetCallerStatusPending( aStatus );
    SelectCertificateL(aLabel);
}

// ---------------------------------------------------------------------------
// ?description_if_needed
// ---------------------------------------------------------------------------
//
void CPKISupport::ContinueRemoveCertificate()
{
    iCertStore->Remove(*(*iCerts)[0], iStatus);
    iPending = ECertRemove;
    iSubState = ESSComplete;
    SetActive();
}


// ---------------------------------------------------------------------------
// ?description_if_needed
// ---------------------------------------------------------------------------
//
void CPKISupport::SetTrustL(const TDesC &aLabel, 
    TBool aTrusted, TRequestStatus& aStatus)
{
    LOG(Log::Printf(_L("SetTrust\n")));
    iSupportStatus = KErrNone;
    iCerts->Close();
    iSubState = ESSContinue;
    iTrusted = aTrusted;
    SetCallerStatusPending( aStatus );
    SelectCertificateL(aLabel);
}

// ---------------------------------------------------------------------------
// ?description_if_needed
// ---------------------------------------------------------------------------
//
void CPKISupport::ContinueSetTrust()
{
    iSubState = ESSComplete;    
    iCertStore->SetTrust(*(*iCerts)[0], iTrusted, iStatus);
    iPending = ESetTrust;
    SetActive();
}

// ---------------------------------------------------------------------------
// ?description_if_needed
// ---------------------------------------------------------------------------
//
void CPKISupport::TrustedL(const TDesC &aLabel, TRequestStatus& aStatus)
{
    LOG(Log::Printf(_L("Trusted\n")));
    iSupportStatus = KErrNone;
    iCerts->Close();
    iSubState = ESSContinue;
    SetCallerStatusPending( aStatus );
    SelectCertificateL(aLabel);
}

// ---------------------------------------------------------------------------
// ?description_if_needed
// ---------------------------------------------------------------------------
//
void CPKISupport::ContinueTrusted()
{
    iSubState = ESSComplete;
    iCertStore->Trusted(*(*iCerts)[0], iTrusted, iStatus);
    iPending = ETrusted;
    SetActive();
}

// ---------------------------------------------------------------------------
// ?description_if_needed
// ---------------------------------------------------------------------------
//
void CPKISupport::SetApplicabilityL(const TDesC &aLabel, const RArray<TUid>& aApplUids, TRequestStatus& aStatus)
{
    LOG(Log::Printf(_L("SetApplicability\n")));
    iSupportStatus = KErrNone;
    iCerts->Close();
    iSubState = ESSContinue;
	iApplUids.Close();
	for(TInt i = 0;i<aApplUids.Count();i++)
		{
		iApplUids.Append(aApplUids[i]);
		}
    SetCallerStatusPending( aStatus );
    SelectCertificateL(aLabel);
}

// ---------------------------------------------------------------------------
// ContinueSetApplicability
// ---------------------------------------------------------------------------
//
void CPKISupport::ContinueSetApplicability()
    {
    PKISERVICE_ASSERT(iCerts && iCerts->Count());
    iSubState = ESSComplete;
    iCertStore->SetApplicability(*(*iCerts)[0], iApplUids, iStatus);
    iPending = ESetApplicability;
    SetActive();
    }

// ---------------------------------------------------------------------------
// ?description_if_needed
// ---------------------------------------------------------------------------
//
void CPKISupport::ApplicationsL(const TDesC &aLabel, TRequestStatus& aStatus)
{
    LOG(Log::Printf(_L("Applications\n")));
    iSupportStatus = KErrNone;
    iCerts->Close();
    iSubState = ESSContinue;
    SetCallerStatusPending( aStatus );
    SelectCertificateL(aLabel);
}

// ---------------------------------------------------------------------------
// ContinueApplications
// ---------------------------------------------------------------------------
//
void CPKISupport::ContinueApplications()
{
    iSubState = ESSComplete;
	iApplUids.Close();
    iCertStore->Applications(*(*iCerts)[0], iApplUids, iStatus);
    iPending = EApplications;
    SetActive();
}


// ---------------------------------------------------------------------------
// SelectCertificateL
// ---------------------------------------------------------------------------
//
void CPKISupport::SelectCertificateL(const TDesC &aLabel, 
                                     const TPKICertificateOwnerType& aType )
{
    delete iCertFilter;
    iCertFilter = NULL;
    iCertFilter = CCertAttributeFilter::NewL();

    LOG(Log::Printf(_L(" Select by label: %S\n"), &aLabel));
    iCertFilter->SetLabel(aLabel);
    if (aType != 0) 
        {
        LOG_1(" Select by owner type: %d", aType);
        iCertFilter->SetOwnerType(TCertificateOwnerType(aType));
        }
    GetCertificateStoreListAsync();
}



// ---------------------------------------------------------------------------
// GetCertificateStoreListAsync()
// ---------------------------------------------------------------------------
//
void CPKISupport::GetCertificateStoreListAsync()
    {
    LOG_1("-> CPKISupport::GetCertificateStoreListAsync() iSubState:%d",
            iSubState );
    // preconditions
    PKISERVICE_ASSERT( iCerts && iCertFilter && iStatus != KRequestPending );
    LOG_1("CPKISupport::GetSertificateStoreListAsync iSubState:%d", 
        iSubState );

    // Get list of all known certificates
    iCertStore->List(*iCerts, *iCertFilter, iStatus);
    iPending = EListCerts;
    SetActive();
    LOG_("<- CPKISupport::GetCertificateStoreListAsync()");
    }