vpnengine/ikecert/src/ikev1pkiservice.cpp
changeset 0 33413c0669b9
child 25 735de8341ce4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vpnengine/ikecert/src/ikev1pkiservice.cpp	Thu Dec 17 09:14:51 2009 +0200
@@ -0,0 +1,1067 @@
+/*
+* Copyright (c) 2005-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:   PKI store and Certificate verification interface class
+*                implementation for IKEv1 plug-in
+*
+*/
+
+#include <x500dn.h>
+#include <x509cert.h>
+#include <asn1dec.h>
+#include <utf.h>
+
+#include "ikedebug.h"
+#include "ikev1pkiservice.h"
+#include "utlcrypto.h"
+#include "ikecert.h"
+#include "ikecaelem.h"
+#include "ikepublickey.h"
+#include "ikecalist.h"
+#include "ikepkiutils.h"
+#include "pkcs10.h"
+#include "vpnapidefs.h"
+#include "pkiutil.h"
+#include "ikecertconst.h"
+
+//
+// CIkeV1PkiService Class
+//
+_LIT8(KEmptyString, "");
+
+
+EXPORT_C CIkeV1PkiService* CIkeV1PkiService::NewL(
+    CIkeData*             aIkeData,
+    MIkeDebug&            aDebug
+)
+{
+    CIkeV1PkiService* self =
+        new (ELeave) CIkeV1PkiService(aIkeData, aDebug);
+
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self;
+}
+
+
+CIkeV1PkiService::CIkeV1PkiService(
+    CIkeData*            aIkeData,
+    MIkeDebug&           aDebug
+) :
+    iOperation(KNoOperation),
+    iIkeData(aIkeData),
+    iCertPtr(NULL, 0),
+    iCertBfrSize(2048),
+    iDebug(aDebug)
+{
+}
+
+
+void CIkeV1PkiService::ConstructL()
+{
+    User::LeaveIfError(iPkiService.Connect());
+    
+    // Set certificate store type to device certificate store,
+    // if Own_cert_type is defined as "DEVICE"
+    if ( iIkeData->iClientCertType != NULL )
+    {
+        TPtrC16 certStoreType = iIkeData->iClientCertType->GetData();
+        if ( certStoreType.CompareF(_L("DEVICE")) == 0 )
+        {
+			User::LeaveIfError(iPkiService.SetStoreType(EPkiStoreTypeDevice));            
+        }
+        else
+        {
+			User::LeaveIfError(iPkiService.SetStoreType(EPkiStoreTypeUser));                    
+        }
+    }
+
+    iTrustedCAList   = new (ELeave) CIkeCaList(2);
+    iReadCertificate = HBufC8::NewL(iCertBfrSize);
+    
+
+    //The code assumes that these are not NULL.
+    //Reallocated, when needed
+    iSubjName = HBufC8::NewL(2);
+    iRfc822Name = HBufC8::NewL(2);
+}
+
+
+EXPORT_C CIkeV1PkiService::~CIkeV1PkiService()
+{
+    if ( iApplUidList )
+    {
+        iApplUidList->Reset();
+        delete iApplUidList;
+    }
+    
+    if ( iCaCertList )
+    {
+        iCaCertList->Reset();
+        delete iCaCertList;
+    }
+
+    delete iTrustedCAList;
+
+    iCasTrustedByPeer.Reset();
+    iCasTrustedByPeer.Close();
+
+    delete iCaName;
+    delete iCa1Name;
+    delete iCa2Name;
+   
+    delete iReadCertificate;
+    delete iSubjName;
+    delete iRfc822Name;
+
+    
+    iPkiService.Close();
+}
+
+
+EXPORT_C TBool CIkeV1PkiService::ImportCACertsL(
+    CArrayFixFlat<TCertInfo*> *aCAList
+)
+{
+    DEBUG_LOG(_L("-> CIkeV1PkiService::ImportCACertsL"));
+
+    //
+    // Build trusted CA certificate list into CIkeV1PkiService object
+    // aCAList call parameter array contains the list of trusted CA:s
+    // (names in ASCII format).
+    // Read corresponding certificate from PKI store and if found,
+    // add a new element (=CIkeCaElem) into CIkeCaList
+    //
+    TBool Status = EFalse;
+
+    if ( aCAList && aCAList->Count() )
+    {
+        delete iCaName;
+
+        iCaName     = NULL;
+        iCaName     = HBufC8::NewL(256);
+        iCaNameList = aCAList;
+        iCurrIndex  = 0;
+        iOperation  = KBuildingCaList;
+
+        Status = GetNextCaElemL();
+    }
+
+    return Status;
+}
+
+
+//
+// CIkeV1PkiService::ReadCertWithNameL
+// This method is used to read a certificate from the PKI store.
+// Input parameters:
+// -- const TDesC8& Trusted CA name
+// -- TBool  aGetCACert
+//    ETrue = Read a CA certificate; EFalse read an user certificate
+// Output parameters:
+// -- X509 certificate into iReadCertificate buffer
+//
+EXPORT_C TInt CIkeV1PkiService::ReadUserCertWithNameL(
+    const TDesC8& aTrustedCaName, CIkeData* aIkeData, TBool aDnType)
+
+{
+    iIkeData = aIkeData;
+    
+    delete iCaName;
+    iCaName = NULL;
+    iCaName = HBufC8::NewL(aTrustedCaName.Length());
+    iCaName->Des().Copy(aTrustedCaName);
+    
+    delete iReadCertificate;
+    iReadCertificate=NULL;
+    
+    TInt Status = ReadCertificateL(*iCaName, EFalse);
+
+    iUserCertDerType=aDnType;
+    return Status;
+}
+EXPORT_C TInt CIkeV1PkiService::ReadChainL(CIkeData* aIkeData, const HBufC8* aCAName)
+{
+    iIkeData = aIkeData;
+    delete iReadCertificate;
+    iReadCertificate=NULL;
+    //read own certificate
+    TInt Status = ReadCertificateL(KEmptyString, EFalse);
+    TInt StatusICA1 = KErrNotFound;
+    TInt StatusICA2 = KErrNotFound;
+    TInt StatusICA = KErrNotFound;
+       
+    if ( Status == KErrNone )
+        {
+        iReadCertificateOrig = HBufC8::NewL(iReadCertificate->Length());
+        TPtr8 iReadCertCopy(iReadCertificateOrig->Des());
+        iReadCertCopy.Copy(iReadCertificate->Des());
+        delete iCaName;
+        iCaName = NULL;
+        iCaName =  IkeCert::GetCertificateFieldDERL(iReadCertificate, KIssuerName);
+        
+        //Read ICA2
+        StatusICA2 = ReadCertificateL(KEmptyString, ETrue);
+       
+        if ( StatusICA2 != KErrNone)
+            {
+            delete iReadCertificateOrig;
+            iReadCertificateOrig=NULL;
+            return KErrNotFound;
+            }
+        }
+    if ( Status == KErrNone && StatusICA2 == KErrNone)
+        {
+        
+        delete iCaName;
+        iCaName = NULL;
+        iCaName =  IkeCert::GetCertificateFieldDERL(iReadCertificate, KIssuerName);
+        delete iCa2Name;
+        iCa2Name=NULL;
+        iCa2Name = GetCertificate();
+        
+        CX500DistinguishedName* dn=NULL;
+        CX500DistinguishedName* asn1DnNameofICaName = NULL;
+        dn = CX500DistinguishedName::NewLC(*aCAName);
+        asn1DnNameofICaName = CX500DistinguishedName::NewLC(*iCaName);
+               
+        if (  asn1DnNameofICaName->ExactMatchL(*dn)  )
+            
+            {
+             StatusICA=KErrNone;
+             //read ICA1
+             StatusICA1 = ReadCertificateL(KEmptyString, ETrue);
+             if ( StatusICA1 != KErrNone)
+                 {
+                 delete iReadCertificateOrig;
+                 iReadCertificateOrig=NULL;
+                 
+                 CleanupStack::PopAndDestroy(asn1DnNameofICaName);
+                 asn1DnNameofICaName=NULL;
+                 
+                 CleanupStack::PopAndDestroy(dn);
+                 dn=NULL;
+                 
+                 return KErrNotFound;
+                 }
+            }
+        else
+            {
+            StatusICA1 = ReadCertificateL(KEmptyString, ETrue);
+            if ( StatusICA1 == KErrNotFound)
+                {
+                delete iReadCertificateOrig;
+                iReadCertificateOrig=NULL;
+                             
+                CleanupStack::PopAndDestroy(asn1DnNameofICaName);
+                asn1DnNameofICaName=NULL;
+
+                CleanupStack::PopAndDestroy(dn);
+                dn=NULL;
+            
+                return KVpnErrInvalidCaCertFile;
+                }
+            else
+	            StatusICA1=KErrNone;
+            }
+        CleanupStack::PopAndDestroy(asn1DnNameofICaName);
+        asn1DnNameofICaName=NULL;
+        
+        CleanupStack::PopAndDestroy(dn);
+        dn=NULL;
+       
+        }
+ 
+    if ( Status == KErrNone && StatusICA1 == KErrNone && StatusICA2 == KErrNone)
+        {
+        if ( StatusICA == KErrNotFound )
+           {
+           delete iCaName;
+           iCaName = NULL;
+           iCaName =  IkeCert::GetCertificateFieldDERL(iReadCertificate, KIssuerName);
+           }
+        delete iCa1Name;
+        iCa1Name=NULL;
+        iCa1Name = GetCertificate();
+        
+        CX500DistinguishedName* dn=NULL;
+        CX500DistinguishedName* asn1DnNameofICaName = NULL;
+        
+        dn = CX500DistinguishedName::NewLC(*aCAName);
+        
+        asn1DnNameofICaName = CX500DistinguishedName::NewLC(*iCaName);
+        
+        if ( asn1DnNameofICaName->ExactMatchL(*dn) )
+           {
+           delete iCaName;
+           iCaName=NULL;
+           iCaName=HBufC8::NewL(aCAName->Length());
+           iCaName->Des().Copy(*aCAName);
+           
+           TInt Status = ReadCertificateL(KEmptyString, ETrue);
+           
+           delete iCaName;
+           iCaName = NULL;
+           iCaName =  IkeCert::GetCertificateFieldDERL(iCa2Name, KSubjectName);
+           
+           delete iReadCertificate;
+           iReadCertificate=iReadCertificateOrig;
+           iReadCertificateOrig=NULL;
+           
+           CleanupStack::PopAndDestroy(asn1DnNameofICaName);
+           asn1DnNameofICaName=NULL;
+           
+           CleanupStack::PopAndDestroy(dn);
+           dn=NULL;
+          
+           if ( Status!=KErrNone )
+               return KVpnErrInvalidCaCertFile;
+           else    
+	           return KErrNone;
+           }
+        else
+           {
+           delete iReadCertificate;
+           
+           iReadCertificate=iReadCertificateOrig;
+           iReadCertificateOrig=NULL;
+           delete iReadCertificateOrig; 
+           
+           delete iReadCertificate;
+           iReadCertificate=NULL;
+           
+           CleanupStack::PopAndDestroy(asn1DnNameofICaName);
+           asn1DnNameofICaName=NULL;
+           
+           CleanupStack::PopAndDestroy(dn);
+           dn=NULL;
+           
+           return KErrNotFound;
+           }
+        }
+     return KErrNotFound;
+}
+
+//
+// CIkeV1PkiService::Ikev1SignatureL
+// This method is used to compute IKEv1 signature with a specified private key.
+// Actually a signature computed happens by referring the related certificate
+// when the PKI store produces the signature with corresponding private key.
+// Parameters:
+// -- const TDesC8& aTrustedAuthority
+//    Trusted CA name coded either in ASN1 (DN) format or ASCII format
+// -- CIkeData* aHostData
+//    Related IKE configuration section. Used to get IdentitySubjectName or
+//    Identity Rfc822 Name information for actual PKI service ReadCertificateL
+//    method call
+// -- const TDesC8& aHashIn
+//    Hash data signed (in matter of fact the hash data is simply
+//    encrypted with private key)
+// Return:
+// -- TInt, sign length
+//
+EXPORT_C TInt CIkeV1PkiService::Ikev1SignatureL(
+    const TDesC8&  aTrustedCaName,
+    CIkeData*      aIkeData,
+    const TDesC8&  aHashIn,
+    TDes8&         aSignature
+)
+{
+    iIkeData = aIkeData;
+    return ComputeSignatureL(aTrustedCaName, aHashIn, aSignature, EFalse);
+}
+
+
+EXPORT_C CIkeCaList* CIkeV1PkiService::CaList()
+{
+    return iTrustedCAList;
+}
+
+
+EXPORT_C HBufC8* CIkeV1PkiService::GetCertificate()
+{
+    HBufC8* Cert = iReadCertificate;
+    iReadCertificate = NULL;
+    return Cert;
+}
+
+
+EXPORT_C HBufC8* CIkeV1PkiService::GetTrustedCA()
+{
+    HBufC8* Cert = iCaName;
+    iCaName = NULL;
+    return Cert;
+}
+
+
+EXPORT_C HBufC8* CIkeV1PkiService::GetTrustedICA1()
+{
+    HBufC8* Cert = iCa1Name;
+    iCa1Name = NULL;
+    return Cert;
+}
+
+EXPORT_C HBufC8* CIkeV1PkiService::GetTrustedICA2()
+{
+    HBufC8* Cert = iCa2Name;
+    iCa2Name = NULL;
+    return Cert;
+}
+
+TInt CIkeV1PkiService::ComputeSignatureL(
+    const TDesC8&  aTrustedAuthority,
+    const TDesC8&  aHashIn,
+    TDes8&         aSignature,
+    TBool          aRsaSignature
+)
+{
+    DEBUG_LOG(_L("-> CIkeV1PkiService::ComputeSignatureL"));
+
+    TPKIKeyAlgorithm keyAlgorithm = EPKIRSA;
+    TUint keySize = InitUserCertIdentDataL();
+    HBufC8* Asn1EncodedHash = NULL;
+    TPtrC8 hashIn(aHashIn);
+
+    if ( aRsaSignature )
+    {
+        //
+        // Build PKCS1v15 format signature (ASN1 encoded)
+        //
+        Asn1EncodedHash = IkeCert::BuildPkcs1v15HashL(aHashIn);
+        
+        ASSERT( Asn1EncodedHash != NULL );        
+        hashIn.Set(Asn1EncodedHash->Des());
+    }
+
+    TInt SignLth = 0;
+    TInt err = iPkiService.Sign(aTrustedAuthority, *iSubjName, *iRfc822Name,
+                                EX509DigitalSignature, keySize,
+                                keyAlgorithm, hashIn, aSignature);
+
+    if (err == KErrNone)
+    {
+        SignLth = aSignature.Length();
+    }
+
+    DEBUG_LOG2(_L("Sign returned %d, length=%d"), err, SignLth);
+    User::LeaveIfError(err);
+
+    delete Asn1EncodedHash;
+    return SignLth;
+}
+
+
+TInt CIkeV1PkiService::ReadCertificateL(
+    const TDesC8& aTrustedAuthority, TBool aGetCACert
+)
+{
+    //
+    // Read certificate from PKI store using pkiserviceapi
+    //
+    DEBUG_LOG(
+        _L("-> ReadCertificateL(aTrustedAuthority, aGetCACert)")
+    );
+
+    TInt Status = KErrNone;
+    TPKIKeyAlgorithm keyAlgorithm = EPKIRSA;
+    TPKICertificateOwnerType ownerType;
+    TUint keySize = 0;
+
+    if (aGetCACert)
+    {
+        DEBUG_LOG(_L("Reading CA certificate"));
+
+        ownerType = EPKICACertificate;
+
+        //Init CA cert ident data.
+        //aTrustedAuthority (issuer) checking for CA certs is not supported.
+        if ( aTrustedAuthority.Length() == 0 )
+            {
+            delete iSubjName;
+            iSubjName = NULL;
+            iSubjName = iCaName->AllocL();
+            iRfc822Name->Des().Zero();
+            } 
+      }
+    else
+    {
+        DEBUG_LOG(_L("Reading User certificate"));
+        ownerType = EPKIUserCertificate;
+        keySize = InitUserCertIdentDataL();
+    }
+
+    for (;;)    // Only for easy exits...
+    {
+        if ( iReallocated )
+        {
+            //
+            // Allocate a new buffer for ASN1 coded certificate read from
+            // PKI store. Buffer size is now asked from pkiserviceapi
+            //
+            delete iReadCertificate;
+            iReadCertificate = NULL;
+            TInt RealCertSize;
+            
+            if ( iPkiService.GetRequiredBufferSize(RealCertSize) == KErrNone )
+                iCertBfrSize = (RealCertSize | 0x3) + 1;
+            // Try double size in error case
+            else iCertBfrSize = (iCertBfrSize << 1);
+        }
+        
+        if ( !iReadCertificate )
+        {
+            iReadCertificate=NULL;
+            iReadCertificate = HBufC8::NewL(iCertBfrSize);
+        }
+        
+        iCertPtr.Set(iReadCertificate->Des());
+        iCertPtr.Zero();
+
+        TRequestStatus status;
+        iPkiService.ReadCertificateL(aTrustedAuthority,
+                                     *iSubjName, *iRfc822Name,
+                                     ownerType, keySize,
+                                     keyAlgorithm, iCertPtr,
+                                     &iResArray, status);
+
+
+        User::WaitForRequest(status);
+        Status = status.Int();
+        iPkiService.Finalize(iResArray);
+        iResArray = NULL;
+        
+        if ( (Status == KPKIErrBufferTooShort) && !iReallocated )
+        {
+            //
+            // Certificate buffer was too small try to read once more if
+            // not already tried
+            //
+            iReallocated = ETrue;
+        }
+        else
+        {
+            if ( Status == KErrNone )
+            {
+                //iReadCertificate->Des().SetLength(iCertPtr.Length());
+                iReallocated = EFalse;
+            }
+            break;
+        }
+        
+    }
+
+    DEBUG_LOG(
+        _L("<- ReadCertificateL(aTrustedAuthority, aGetCACert)")
+    );
+
+    return Status;
+}
+
+
+TUint CIkeV1PkiService::InitUserCertIdentDataL()
+{
+    DEBUG_LOG(_L("-> CIkeV1PkiService::InitUserCertIdentDataL"));
+    __ASSERT_ALWAYS(iIkeData != NULL, User::Invariant());
+
+    TUint keySize = 0;        // Default: Length is undefined
+
+    if ( !iReallocated )
+    {
+        //
+        //  Get possible user identity information from current IKE policy
+        //  section and convert it from 16-bit Unicode into UTF-8 format
+        //
+        TInt Lth = 3*( iIkeData->iOwnCert.iSubjectDnSuffix.Length() );
+
+        if ( Lth )
+        {
+            delete iSubjName;
+            iSubjName = NULL;
+            iSubjName = HBufC8::NewL(Lth);
+
+            TPtr8   dn8 = iSubjName->Des();
+            TPtrC16 dn16( iIkeData->iOwnCert.iSubjectDnSuffix );
+
+            if ( 0 != CnvUtfConverter::ConvertFromUnicodeToUtf8(
+                dn8, dn16 ) )
+            {
+                User::Leave(KErrCorrupt);
+            }
+        }
+        else
+        {
+            iSubjName->Des().Zero();
+        }
+
+        Lth = iIkeData->iOwnCert.iRfc822NameFqdn.Length();
+
+        if ( Lth )
+        {
+            delete iRfc822Name;
+            iRfc822Name = NULL;
+            iRfc822Name = HBufC8::NewL(Lth);
+            iRfc822Name->Des().Copy(iIkeData->iOwnCert.iRfc822NameFqdn);
+        }
+        else
+        {
+            iRfc822Name->Des().Zero();
+        }
+
+        if ( iIkeData->iOwnCert.iPrivateKeyLength )
+        {
+            keySize = iIkeData->iOwnCert.iPrivateKeyLength;
+        }
+    }
+
+    DEBUG_LOG(_L("<- CIkeV1PkiService::InitUserCertIdentDataL"));
+    return keySize;
+}
+
+
+TBool CIkeV1PkiService::GetNextCaElemL()
+{
+    //
+    // Get next CA certificate from PKI store using current CA name in
+    // iCaNameList.
+    //
+    DEBUG_LOG(_L("-> CIkeV1PkiService::GetNextCaElemL"));
+
+    TCertInfo* CertInfo;
+    TBool Ret;
+
+    Ret = EFalse;
+    TInt Status;
+
+    while ( iCurrIndex < iCaNameList->Count() )
+    {
+        CertInfo = iCaNameList->At(iCurrIndex);
+        
+        if ( CertInfo->iFormat == CA_NAME )
+        {
+            TPtr8   dn8 = iCaName->Des();
+            TPtrC16 dn16( CertInfo->iData );
+
+            if ( 0 != CnvUtfConverter::ConvertFromUnicodeToUtf8(
+                dn8, dn16
+            ) )
+            {
+                User::Leave(KErrCorrupt);
+            }
+
+            Status = ReadCertificateL(KEmptyString, ETrue);
+            Ret |= AddNextCaElemL(Status);
+        }
+        else if ( CertInfo->iFormat == KEY_ID )
+        {
+            Status = GetCertificateWithKeyIdL(CertInfo->iData);
+            Ret |= AddNextCaElemL(Status);
+        }
+        else if ( CertInfo->iFormat == APPL_UID )
+        {
+            Ret |= GetApplUidListL(CertInfo->iData);
+        }
+        else
+        {
+            Ret |= EFalse;
+            iCurrIndex ++;
+            DEBUG_LOG1(
+                _L("Unsupported CA certificate element format = %d"),
+                CertInfo->iFormat
+            );
+        }
+
+    }
+
+    iCaNameList = NULL;
+
+    DEBUG_LOG(_L("<- CIkeV1PkiService::GetNextCaElemL"));
+    return Ret;
+}
+
+
+TBool CIkeV1PkiService::AddNextCaElemL(TInt& aStatus)
+{
+    DEBUG_LOG(_L("-> CIkeV1PkiService::AddNextCaElemL()"));
+    
+    //
+    // CA has been read PKI store. Build and add a new CIkeCaElem to CIkeCaList
+    //
+#ifdef _DEBUG    
+    CertReadCompleted(ETrue, aStatus, __LINE__);
+#endif // _DEBUG    
+
+    if (aStatus == KErrNotFound)
+    {
+        DEBUG_LOG(_L(" Leave: status == KErrNotFound"));
+        User::Leave(KVpnErrInvalidCaCertFile);
+    }
+
+    TBool Ret;
+    
+    if ( aStatus == KErrNone )
+    {
+        ASSERT(iReadCertificate);
+        HBufC8* CaCert = iReadCertificate; // Link CA buffer to CIkeCaElem
+        CaCert->Des().SetLength(iCertPtr.Length());
+        iReadCertificate = NULL;
+        CleanupStack::PushL(CaCert);
+        CIkeCaElem* CaElem = CIkeCaElem::NewL(CaCert);
+        CleanupStack::Pop(CaCert);
+        CleanupStack::PushL(CaElem);
+        iTrustedCAList->AppendL(CaElem);
+        CleanupStack::Pop(CaElem);
+
+        if ( iOperation == KProcessingApplUidList )
+            iListIndex ++;
+        else iCurrIndex ++;
+
+        Ret = ETrue;
+    }
+    else
+    {
+        if ( iOperation == KProcessingApplUidList )
+            iListIndex ++;
+        else iCurrIndex ++;
+
+        Ret = EFalse;
+    }
+
+    DEBUG_LOG(_L("<- CIkeV1PkiService::AddNextCaElemL()"));
+    
+    return Ret;
+}
+
+TInt CIkeV1PkiService::GetNextCertificateL()
+{
+    DEBUG_LOG(_L("-> CIkeV1PkiService::GetNextCertificateL"));
+    //
+    // Get next user certificate from PKI store using either Key
+    // identifier or CA name as read argument
+    //
+    TInt Status = KErrNotFound;
+    if ( iCasTrustedByPeer.Count() > 0 )
+    {
+        CIkeCaElem* CaElem = iCasTrustedByPeer[0];
+        iCasTrustedByPeer.Remove(0);
+        iOperation = KReadingCertificate;
+        
+        HBufC8* CaName = IkeCert::GetCertificateFieldDERL(
+            CaElem->Certificate(), KSubjectName
+        );
+        
+        if ( CaName )
+        {
+            delete iCaName;
+            iCaName = CaName;
+            ReadCertificateL(*iCaName, EFalse);
+            Status = KErrNone;
+        }
+
+    }
+
+    DEBUG_LOG(_L("<- CIkeV1PkiService::GetNextCertificateL"));
+    return Status;
+}
+
+
+TBool CIkeV1PkiService::CertificateReadL(TInt& aStatus)
+{
+    //
+    // A Certificate has been read PKI store.
+    // Build X509 certificate object from certificate data
+    //
+#ifdef _DEBUG
+    CertReadCompleted(EFalse, aStatus, __LINE__);
+#endif // _DEBUG    
+    TBool Status = ETrue;
+    
+    if ( aStatus == KErrNone )
+    {
+        iReallocated = EFalse;
+        iReadCertificate->Des().SetLength(iCertPtr.Length());
+    }
+    else
+    {
+        if ( (aStatus == KPKIErrBufferTooShort) && !iReallocated )
+        {
+            //
+            // Certificate buffer was too small try to read once more if
+            // not already tried
+            //
+            Status  = EFalse;
+            aStatus = KErrNone;
+            iReallocated = ETrue;
+            ReadCertificateL(*iCaName, EFalse);
+        }
+
+        if ( (aStatus != KErrNone) && ( aStatus != KPKIErrBufferTooShort) )
+        {
+            //
+            // User certificate not found from PKI store, try to read next
+            //
+            iReallocated = EFalse;
+            aStatus = GetNextCertificateL();
+            
+            if ( aStatus == KErrNone )
+            {
+                Status = EFalse;
+            }
+        }
+    }
+
+    return Status;
+}
+
+
+TInt CIkeV1PkiService::ReadCertificateL(const TPKIKeyIdentifier& aKeyIdentifier)
+{
+    //
+    // Read certificate from PKI store using pkiserviceapi
+    //    
+    TRequestStatus status;
+
+    for (;;)    // Only for easy exits...
+    {
+        if ( iReallocated )
+        {
+            //
+            // Allocate a new buffer for ASN1 coded certificate read from
+            // PKI store. Buffer size is now asked from pkiserviceapi
+            //
+            delete iReadCertificate;
+            iReadCertificate = NULL;
+            TInt RealCertSize;
+            
+            if ( iPkiService.GetRequiredBufferSize(RealCertSize) == KErrNone )
+                iCertBfrSize = (RealCertSize | 0x3) + 1;
+            // Try double size in error case
+            else iCertBfrSize = (iCertBfrSize << 1);
+        }
+
+        if ( !iReadCertificate )
+            iReadCertificate = HBufC8::NewL(iCertBfrSize);
+            
+        iCertPtr.Set((TUint8*)iReadCertificate->Ptr(), 0, iCertBfrSize);
+
+        iPkiService.ReadCertificateL(aKeyIdentifier, iCertPtr,
+                                     &iResArray, status);
+                    
+        User::WaitForRequest(status);
+        iPkiService.Finalize(iResArray);
+        iResArray = NULL;
+  
+        if ( (status.Int() == KPKIErrBufferTooShort) && !iReallocated )
+        {
+            //
+            // Certificate buffer was too small try to read once more if
+            // not already tried
+            //
+            iReallocated = ETrue;
+        }
+        else
+        {
+            if ( status.Int() == KErrNone )
+            {
+                iReadCertificate->Des().SetLength(iCertPtr.Length());
+                iReallocated = EFalse;
+            }
+            break;
+        }
+        
+    }
+
+    return status.Int();
+}
+
+
+TInt CIkeV1PkiService::ReadCertificateListL()
+{
+    //
+    // Read certificate list with Application UID:s
+    //
+    if ( iCaCertList )
+    {
+        iCaCertList->Reset();
+        delete iCaCertList;
+        iCaCertList = NULL;
+    }
+    
+    iOperation  = KBuildingApplUidList;
+
+    iPkiService.ListApplicableCertificatesL(
+        (const RArray<TUid>&)(*iApplUidList), iCaCertList
+    );
+
+    return KErrNone;
+}
+
+
+TInt CIkeV1PkiService::GetCertificateWithKeyIdL(const TDesC16& aKeyIdString)
+{
+    TInt Status;
+    
+    if ( IkeParser::TextToHexOctets(aKeyIdString, iCertKeyId) )
+        Status = ReadCertificateL(iCertKeyId);
+    else Status = KErrArgument;
+
+    return Status;
+}
+
+
+TBool CIkeV1PkiService::GetApplUidListL(const TDesC16& aApplUidString)
+{
+    //
+    // Build application UID array to get trusted CA certificate list
+    // from PKI service.
+    //
+    if ( iApplUidList )
+    {
+        iApplUidList->Reset();
+        delete iApplUidList;
+        iApplUidList = NULL;
+    }
+
+    iApplUidList = IkeParser::GetApplUidListL(aApplUidString);
+
+    TBool Status = (iApplUidList->Count() != 0);
+    
+    if ( Status )
+    {
+        TInt Ret = ReadCertificateListL();
+        Status = ( Ret == KErrNone);
+        iListIndex = 0;
+        
+        Status = ApplUidCertListCompletedL(Ret);
+    }
+
+    return Status;
+}
+
+
+TBool CIkeV1PkiService::ApplUidCertListCompletedL(TInt aStatus)
+{
+    DEBUG_LOG2(
+        _L("Certificate list read completed, status= %d, list elem count= %d"),
+        aStatus, iCaCertList->Count()
+    );
+    DEBUG_LOG1(
+        _L(" APPL UID(s) = %S\n"), &iCaNameList->At(iCurrIndex)->iData
+    );
+  
+    TBool Ret;
+  
+    if ( (aStatus == KErrNone) && iCaCertList->Count() )
+    {
+        //
+        // Start to read in trusted CA certificates provided in list
+        //
+        iOperation = KProcessingApplUidList;
+        Ret = ReadNextInListL();
+    }
+    else
+    {
+        //
+        // No trusted CA certificates found with current application
+        // UID:s. Continue processing CA elements
+        //
+        Ret = EFalse;
+        iOperation = KBuildingCaList;
+        iCurrIndex ++;
+        
+    }
+
+    return Ret;
+}
+
+
+TBool CIkeV1PkiService::ReadNextInListL()
+{
+    TBool Status = EFalse;
+    
+    TInt Ret;
+    
+    while ( iListIndex < iCaCertList->Count() )
+    {
+        Ret = ReadCertificateL(iCaCertList->At(iListIndex).iSubjectKeyId);
+        if ( AddNextCaElemL(Ret) )
+            Status = ETrue;
+    }
+    
+    iCurrIndex ++;
+
+    return Status;
+}
+
+
+#ifdef _DEBUG
+
+void CIkeV1PkiService::CertReadCompleted(TBool aCaCert, TInt aStatus, TInt aLine )
+{
+  TBuf<320>DebugMsg;
+  if ( aCaCert )
+  {
+        ASSERT( iCurrIndex < iCaNameList->Count() );
+     DebugMsg.Format(_L("Trusted CA certificate read completed with status = %d (line = %d)"),
+                     aStatus, aLine);
+     DebugMsg.AppendFormat(_L(" ; Search criteria: "));
+     TCertInfo* CertInfo = iCaNameList->At(iCurrIndex);
+     switch ( CertInfo->iFormat )
+     {
+       case CA_NAME:
+         DebugMsg.AppendFormat(_L("CA_NAME = %S\n"), &CertInfo->iData);
+         break;
+       case KEY_ID:
+         DebugMsg.AppendFormat(_L("KEY_ID = %S\n"), &CertInfo->iData);
+         break;
+       default:
+         TBuf<48> KeyIdString;
+                ASSERT( iListIndex < iCaCertList->Count() );
+         HexToString(iCaCertList->At(iListIndex).iSubjectKeyId, KeyIdString);
+         DebugMsg.AppendFormat(_L("APPL_UID/<KEY_ID> = %S\n"), &KeyIdString);
+         break;
+     }
+  }
+  else
+  {
+     DEBUG_LOG2(_L("End user certificate read completed with status = %d (line = %d)\n"),
+                     aStatus, aLine);
+  }
+    DEBUG_LOG(DebugMsg);
+}
+
+void CIkeV1PkiService::HexToString(const TDesC8& aKeyId, TDes16& aKeyIdString)
+{
+  TInt i = 0;
+  TUint x;
+  TUint y;
+
+  while (i < aKeyId.Length())
+  {
+    x = (TUint)aKeyId[i];
+    for ( TInt j = 4; j >= 0; j -= 4 )
+    {
+          y  = (x >> j) & 0xf;
+        TChar ch(y);
+            if ( y < 0xa )
+           ch += 0x30;
+        else if ( (y > 9) && (y < 0x10) )
+             ch += (0x61 - 0xa);
+        else ch += (0x30 - ch);
+        aKeyIdString.Append(ch);
+    }
+    i ++;
+  }
+}
+
+#endif //_DEBUG