vpnengine/vpnmanager/src/pkiutil.cpp
changeset 0 33413c0669b9
child 25 735de8341ce4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vpnengine/vpnmanager/src/pkiutil.cpp	Thu Dec 17 09:14:51 2009 +0200
@@ -0,0 +1,961 @@
+/*
+* Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "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: 
+* Provides static PKI-related helper functions 
+* (such as building Distinguished Names)
+*
+*/
+
+#include <x500dn.h>
+#include <x509cert.h>
+#include <x520ava.h>
+#include <utf.h>
+#include <x509keys.h>
+
+#include "pkiutil.h"
+#include "pkiserviceapi.h"
+#include "pkcs10.h"
+#include "ikepolparser.h"
+
+
+HBufC* PkiUtil::CertSubjectNameL(const TDesC8& aCertData)
+    {
+    CX509Certificate* certificate = CX509Certificate::NewL(aCertData);
+    CleanupStack::PushL(certificate);
+
+    CX500DistinguishedName* subjectDn;
+    subjectDn = CX500DistinguishedName::NewL(certificate->SubjectName());
+    CleanupStack::PushL(subjectDn);
+
+    HBufC* certDn = CertDnL(*subjectDn);
+
+    CleanupStack::PopAndDestroy(2); // subjectDn, certificate
+
+    return certDn;
+    }
+
+HBufC* PkiUtil::CertIssuerNameL(const TDesC8& aCertData)
+    {
+    CX509Certificate* certificate = CX509Certificate::NewL(aCertData);
+    CleanupStack::PushL(certificate);
+
+    CX500DistinguishedName* issuerDn;
+    issuerDn = CX500DistinguishedName::NewL(certificate->IssuerName());
+    CleanupStack::PushL(issuerDn);
+
+    HBufC* certDn = CertDnL(*issuerDn);
+
+    CleanupStack::PopAndDestroy(2); // issuerDn, certificate
+
+    return certDn;
+    }
+
+HBufC* PkiUtil::CertDnL(const CX500DistinguishedName& aName)
+    {
+    TInt count = aName.Count();
+    HBufC* certDn = HBufC::NewL(KCertDnSizeIncrement);
+    CleanupStack::PushL(certDn);
+
+    for (TInt i = 0; i < count; i++)
+        {
+        const CX520AttributeTypeAndValue& attribute = aName.Element(i);
+
+        // Unsupported attribute is not appended (KErrNotSupported error)
+        TRAPD( err, AppendAttributeL(certDn, attribute) );
+        if ( err != KErrNotSupported )
+            {
+            User::LeaveIfError( err );
+            }
+        }
+
+    CleanupStack::Pop(); // certDn
+
+    return certDn;
+    }
+
+TInt PkiUtil::CertKeySizeL(const TDesC8& aCertData)
+    {
+    TInt keySize = 0;
+
+    CX509Certificate* certificate = CX509Certificate::NewLC(aCertData);
+    const CSubjectPublicKeyInfo& publicKeyInfo = certificate->PublicKey();
+    const TPtrC8 keyData = publicKeyInfo.KeyData();
+
+    TX509KeyFactory keyFactory;
+
+    switch(publicKeyInfo.AlgorithmId())
+        {
+        case ERSA:
+            {
+            const CRSAPublicKey* keyRSA = keyFactory.RSAPublicKeyL(keyData);
+            const TInteger&  n = keyRSA->N();
+            keySize = n.BitCount();
+            delete keyRSA;
+            }
+            break;
+        case EDSA:
+            {
+            TPtrC8 params = publicKeyInfo.EncodedParams();
+
+            const CDSAPublicKey* keyDSA =
+                keyFactory.DSAPublicKeyL(params, keyData);
+
+            const TInteger& y = keyDSA->Y();
+            keySize = y.BitCount();
+            delete keyDSA;
+            }
+            break;
+        default:
+            User::Leave(KErrNotSupported);
+            break;
+        }
+
+    CleanupStack::PopAndDestroy(certificate);
+
+    return keySize;
+    }
+
+
+void PkiUtil::AppendAttributeL(HBufC*& aBuf, const CX520AttributeTypeAndValue& aAttribute)
+    {
+    HBufC* attrName = AttributeTypeToNameL(aAttribute.Type());
+    CleanupStack::PushL(attrName);
+
+    HBufC* attrValue = aAttribute.ValueL();
+    CleanupStack::PushL(attrValue);
+
+    if ( aBuf->Length() )
+        {
+        // Append comma if not first attribute
+        SmartAppendL(aBuf, KComma);
+        }
+
+    SmartAppendL(aBuf, attrName->Des());
+    SmartAppendL(aBuf, KEquals);
+    SmartAppendL(aBuf, attrValue->Des());
+
+    CleanupStack::PopAndDestroy(2); // attrValue, attrName
+    }
+
+/*
+   RFC 2253 (Lightweight Directory Access Protocol (v3):
+   UTF-8 String Representation of Distinguished Names):
+
+   "If the AttributeType is in a published table of attribute types
+   associated with LDAP [4], then the type name string from that table
+   is used, otherwise it is encoded as the dotted-decimal encoding of
+   the AttributeType's OBJECT IDENTIFIER."
+
+   RFC 2256 (A Summary of the X.500(96) User Schema for use with
+   LDAPv3):
+
+   "This document provides an overview of the attribute types and object
+   classes defined by the ISO and ITU-T committees in the X.500
+   documents, in particular those intended for use by directory
+   clients."
+
+   In essence, RFC 2256 lists the most common attribute types and their
+   names.
+
+   We choose to provide "user-friendly" name mapping for the following
+   attribúte types:
+   - countryName
+   - organizationName
+   - organizationalUnitName
+   - localityName
+   - stateOrProvinceName
+   - commonName
+
+   For other attribute types, we use a string representation of the OID
+   as the attribute name.
+*/
+
+HBufC* PkiUtil::AttributeTypeToNameL(const TDesC &aType)
+    {
+    HBufC* name;
+
+    if (aType.Compare(KX520CountryName) == 0)
+        {
+        name = KC().AllocL();
+        }
+    else if (aType.Compare(KX520OrganizationName) == 0)
+        {
+        name = KO().AllocL();
+        }
+    else if (aType.Compare(KX520OrganizationalUnitName) == 0)
+        {
+        name = KOU().AllocL();
+        }
+    else if (aType.Compare(KX520LocalityName) == 0)
+        {
+        name = KL().AllocL();
+        }
+    else if (aType.Compare(KX520StateOrProvinceName) == 0)
+        {
+        name = KST().AllocL();
+        }
+    else if (aType.Compare(KX520CommonName) == 0)
+        {
+        name = KCN().AllocL();
+        }
+    else
+        {
+        // Use the dotted-decimal encoding
+        // of the OID as the attribute name
+        name = aType.AllocL();
+        }
+
+    return name;
+    }
+
+void PkiUtil::SmartAppendL(HBufC*& aBuf, const TDesC& aText)
+    {
+    // Make sure that we have enough space for the new text
+
+    TInt spaceLeft = aBuf->Des().MaxLength() - aBuf->Des().Length();
+
+    if (aText.Length() > spaceLeft)
+        {
+        // Allocate enough space for the new text + some additional
+        // free space so that allocations are not too frequent
+
+        TInt newMaxLength = aBuf->Des().MaxLength() + aText.Length() + KCertDnSizeIncrement;
+
+        aBuf = aBuf->ReAllocL(newMaxLength);
+        }
+
+    aBuf->Des().Append(aText);
+    }
+
+TCertStatus PkiUtil::CertStatusL(RPKIServiceAPI& aPkiService, const TDesC8& aTrustedCaDn,
+                                 const TDesC8& aSubjectDnSuffix, const TDesC8& aRfc822NameFqdn,
+                                 TUint aPrivKeyLength, TInt aCertRenewalThreshold)
+    {
+    // Try to find a user certificate with the
+    // desired properties from the PKI store
+
+    TAny* opContext;
+    TRequestStatus status;
+    TCertStatus certStatus;
+
+    HBufC8* certData = HBufC8::NewL(KExpectedMaxCertSize);
+    HBufC8* subjectNameString;
+    _LIT8(KEmptyString, "");
+    CleanupStack::PushL(certData);
+
+    TPtr8 certDataPtr = certData->Des();
+
+    aPkiService.ReadCertificateL(aTrustedCaDn, aSubjectDnSuffix, aRfc822NameFqdn, EPKIUserCertificate,
+                                 aPrivKeyLength, EPKIRSA, certDataPtr,
+                                 &opContext, status);
+
+    User::WaitForRequest(status);
+
+    aPkiService.Finalize(opContext);
+
+    if (status.Int() == KPKIErrBufferTooShort)
+        {
+        TInt realCertSize;
+        aPkiService.GetRequiredBufferSize(realCertSize);
+
+        CleanupStack::PopAndDestroy(); //  certData
+        certData = HBufC8::NewL(realCertSize);
+        CleanupStack::PushL(certData);
+
+        certDataPtr = certData->Des();
+        aPkiService.ReadCertificateL(aTrustedCaDn, aSubjectDnSuffix, aRfc822NameFqdn, EPKIUserCertificate,
+                                     aPrivKeyLength, EPKIRSA, certDataPtr,
+                                     &opContext, status);
+
+        User::WaitForRequest(status);
+
+        aPkiService.Finalize(opContext);
+        }
+
+
+    // Make sure that the cert, if found, is valid
+    if (status.Int() == KErrNone)
+        {
+        certStatus = PkiUtil::CertStatusL(*certData, aCertRenewalThreshold);
+        }
+    else //if not found, check wether certificate chain exists
+        {
+        certStatus = ECertNotFound;
+        //checking if certificate chain is found
+        CleanupStack::PopAndDestroy(); //  certData
+        
+        certData=NULL;
+        certData = HBufC8::NewL(KExpectedMaxCertSize);
+        CleanupStack::PushL(certData);
+        
+        certDataPtr = certData->Des();
+        
+        //user certificate
+        aPkiService.ReadCertificateL(KEmptyString, aSubjectDnSuffix, aRfc822NameFqdn, EPKIUserCertificate,
+                aPrivKeyLength, EPKIRSA, certDataPtr,
+                &opContext, status);
+        User::WaitForRequest(status);
+        
+        aPkiService.Finalize(opContext);
+        if (status.Int() == KErrNone)
+           {
+            certStatus = PkiUtil::CertStatusL(*certData, aCertRenewalThreshold);
+           }
+        else
+           {
+           certStatus = ECertNotFound;
+           CleanupStack::PopAndDestroy(certData);
+           return certStatus;
+           }
+        
+        //intermediate certificate level 2
+        HBufC* issuerName=CertIssuerNameL(*certData);
+        CleanupStack::PushL(issuerName);
+        
+        subjectNameString=To8BitL(*issuerName);
+        
+        CleanupStack::PopAndDestroy(issuerName);
+        CleanupStack::PopAndDestroy(certData);
+        
+        certData=NULL;
+        certData = HBufC8::NewL(KExpectedMaxCertSize);
+        CleanupStack::PushL(certData);
+        
+        certDataPtr = certData->Des();
+        
+        CleanupStack::PushL(subjectNameString);
+        aPkiService.ReadCertificateL(KEmptyString, *subjectNameString, aRfc822NameFqdn, EPKICACertificate,
+                                    aPrivKeyLength, EPKIRSA, certDataPtr,
+                                    &opContext, status);
+        User::WaitForRequest(status);
+        
+        aPkiService.Finalize(opContext);
+        if (status.Int() == KErrNone)
+           {
+            certStatus = PkiUtil::CertStatusL(*certData, aCertRenewalThreshold);
+           }
+        else
+           {
+           certStatus = ECertNotFound;
+           CleanupStack::PopAndDestroy(subjectNameString);
+           CleanupStack::PopAndDestroy(certData);
+           return certStatus;
+           }
+        if ( subjectNameString->Compare(aTrustedCaDn) !=0 ) //checking if issuer is reached
+            {
+            //intermediate certificate level 1
+            certStatus = ECertNotFound;
+            CleanupStack::PopAndDestroy(subjectNameString);
+            
+            HBufC* issuerName=CertIssuerNameL(*certData);
+            CleanupStack::PushL(issuerName);
+            
+            subjectNameString=To8BitL(*issuerName);
+            
+            CleanupStack::PopAndDestroy(issuerName);
+            CleanupStack::PopAndDestroy(certData);
+            
+            certData = HBufC8::NewL(KExpectedMaxCertSize);
+            CleanupStack::PushL(certData);
+            certDataPtr = certData->Des();
+            
+            CleanupStack::PushL(subjectNameString);
+            
+            aPkiService.ReadCertificateL(KEmptyString, *subjectNameString, aRfc822NameFqdn, EPKICACertificate,
+                                        aPrivKeyLength, EPKIRSA, certDataPtr,
+                                        &opContext, status);
+            User::WaitForRequest(status);
+            
+            aPkiService.Finalize(opContext);
+            if (status.Int() == KErrNone)
+                {
+                certStatus = PkiUtil::CertStatusL(*certData, aCertRenewalThreshold);
+                }
+            else
+                {
+                certStatus = ECertNotFound;
+                CleanupStack::PopAndDestroy(subjectNameString);
+                CleanupStack::PopAndDestroy(certData);
+                return certStatus;
+                }
+            }
+        if ( subjectNameString->Compare(aTrustedCaDn) !=0 )  //checking if issuer is reached
+            {
+             //CA certificate
+             certStatus = ECertNotFound;
+             CleanupStack::PopAndDestroy(subjectNameString);
+                        
+             HBufC* issuerName=CertIssuerNameL(*certData);
+             CleanupStack::PushL(issuerName);
+                        
+             subjectNameString=To8BitL(*issuerName);
+                        
+             CleanupStack::PopAndDestroy(issuerName);
+             CleanupStack::PopAndDestroy(certData);
+                        
+             certData = HBufC8::NewL(KExpectedMaxCertSize);
+             CleanupStack::PushL(certData);
+             certDataPtr = certData->Des();
+                        
+             CleanupStack::PushL(subjectNameString);
+                        
+             aPkiService.ReadCertificateL(KEmptyString, *subjectNameString, aRfc822NameFqdn, EPKICACertificate,
+                                          aPrivKeyLength, EPKIRSA, certDataPtr,
+                                          &opContext, status);
+             User::WaitForRequest(status);
+                        
+             aPkiService.Finalize(opContext);
+             if (status.Int() == KErrNone)
+                 {
+                 certStatus = PkiUtil::CertStatusL(*certData, aCertRenewalThreshold);
+                 }
+             CleanupStack::PopAndDestroy(subjectNameString);
+             }
+        else
+             CleanupStack::PopAndDestroy(subjectNameString);
+        }
+    CleanupStack::PopAndDestroy(certData);
+
+    return certStatus;
+    }
+
+TCertStatus PkiUtil::CertStatusL(const TDesC8& aCertData, TInt aCertRenewalThreshold)
+    {
+    CX509Certificate* certificate = CX509Certificate::NewL(aCertData);
+    CleanupStack::PushL(certificate);
+
+    TCertStatus status = CertStatusL(*certificate, aCertRenewalThreshold);
+
+    CleanupStack::PopAndDestroy(certificate);
+
+    return status;
+    }
+
+
+TCertStatus PkiUtil::CertStatusL(const CX509Certificate& aCert, TInt aCertRenewalThreshold)
+    {
+
+    TTime validationTime;
+    validationTime.UniversalTime();
+
+    TCertStatus certStatus = ECertValid;
+
+    if (aCert.ValidityPeriod().Finish() <= validationTime)
+        {
+        certStatus = ECertExpired;
+        }
+
+    if (aCert.ValidityPeriod().Start() >= validationTime)
+        {
+        certStatus = ECertNotValidYet;
+        }
+
+    // Additional validity check - if a certificate renewal threshold
+    // has been specified, it can cause an otherwise valid certificate
+    // to be marked as expired. This is determined as follows:
+    // - Calculate the entire lifetime of the certificate (entireLifetime)
+    // - Calculate the passed lifetime of the certificate (passedLifetime)
+    // - Calculate thresholdLifetime as aCertRenewalTreshold % * entireLifetime
+    //   (i.e. (aCertRenewalTreshold / 100) * entireLifetime
+    // - If passedLifetime > thresholdLifetime --> certificate expired
+
+    if (certStatus == ECertValid && aCertRenewalThreshold >= 0)
+        {
+        TInt64 entireLifetime = aCert.ValidityPeriod().Finish().Int64() -
+                                aCert.ValidityPeriod().Start().Int64();
+
+        TInt64 passedLifetime = validationTime.Int64() -
+                                aCert.ValidityPeriod().Start().Int64();
+
+        TInt64 thresholdInPercents(aCertRenewalThreshold);
+        TInt64 hundred(100);
+        TInt64 tresholdLifetime = (thresholdInPercents * entireLifetime) / hundred;
+
+        if (passedLifetime > tresholdLifetime)
+            {
+            certStatus = ECertExpired;
+            }
+        }
+
+    return certStatus;
+    }
+
+
+CX509Certificate* PkiUtil::ReadCertificateLC(RPKIServiceAPI& aPkiService,
+                                             const TPKIKeyIdentifier& aKeyId)
+    {
+
+    TAny* opContext;
+    TRequestStatus status;
+
+    HBufC8* certData = HBufC8::NewL(KExpectedMaxCertSize);
+    CleanupStack::PushL(certData);
+
+    TPtr8 certDataPtr = certData->Des();
+
+    aPkiService.ReadCertificateL(aKeyId, certDataPtr,
+                                 &opContext,
+                                 status);
+
+    User::WaitForRequest(status);
+
+    aPkiService.Finalize(opContext);
+
+    if (status.Int() == KPKIErrBufferTooShort)
+        {
+        TInt realCertSize;
+        aPkiService.GetRequiredBufferSize(realCertSize);
+
+        CleanupStack::PopAndDestroy(); //  certData
+        certData = HBufC8::NewL(realCertSize);
+        CleanupStack::PushL(certData);
+
+        certDataPtr = certData->Des();
+        aPkiService.ReadCertificateL(aKeyId, certDataPtr,
+                                     &opContext,
+                                     status);
+
+        User::WaitForRequest(status);
+        aPkiService.Finalize(opContext);
+
+        User::LeaveIfError(status.Int());
+        }
+    else
+        {
+        User::LeaveIfError(status.Int());
+        }
+
+    CX509Certificate* certificate = CX509Certificate::NewL(*certData);
+    CleanupStack::PopAndDestroy(certData);
+    CleanupStack::PushL(certificate);
+
+    return certificate;
+    }
+
+
+CX509Certificate* PkiUtil::ReadCertificateLC(RPKIServiceAPI& aPkiService,
+                                             const TDesC8& aTrustedAuthority,
+                                             const TDesC8& aIdentitySubjectName,
+                                             const TDesC8& aIdentityRfc822Name,
+                                             const TPKICertificateOwnerType aOwnerType)
+    {
+    // Try to find a user certificate with the
+    // desired properties from the PKI store
+    static const TInt KUndefinedKeySize = 0;
+
+    TAny* opContext;
+    TRequestStatus status;
+
+    HBufC8* certData = HBufC8::NewL(KExpectedMaxCertSize);
+    CleanupStack::PushL(certData);
+
+    TPtr8 certDataPtr = certData->Des();
+
+    aPkiService.ReadCertificateL(aTrustedAuthority,
+                                 aIdentitySubjectName,
+                                 aIdentityRfc822Name,
+                                 aOwnerType, KUndefinedKeySize,
+                                 EPKIRSA, certDataPtr,
+                                 &opContext,
+                                 status);
+
+    User::WaitForRequest(status);
+
+    aPkiService.Finalize(opContext);
+
+    if (status.Int() == KPKIErrBufferTooShort)
+        {
+        TInt realCertSize;
+        aPkiService.GetRequiredBufferSize(realCertSize);
+
+        CleanupStack::PopAndDestroy(); //  certData
+        certData = HBufC8::NewL(realCertSize);
+        CleanupStack::PushL(certData);
+
+        certDataPtr = certData->Des();
+        aPkiService.ReadCertificateL(aTrustedAuthority,
+                                     aIdentitySubjectName,
+                                     aIdentityRfc822Name,
+                                     aOwnerType, KUndefinedKeySize,
+                                     EPKIRSA, certDataPtr,
+                                     &opContext,
+                                     status);
+
+        User::WaitForRequest(status);
+        aPkiService.Finalize(opContext);
+
+        User::LeaveIfError(status.Int());
+        }
+    else
+        {
+        User::LeaveIfError(status.Int());
+        }
+
+    CX509Certificate* certificate = CX509Certificate::NewL(*certData);
+    CleanupStack::PopAndDestroy(certData);
+    CleanupStack::PushL(certificate);
+
+    return certificate;
+    }
+
+
+void ResetAndDestroyCleanup(TAny* aArray)
+    {
+    RPointerArray<CX509Certificate>* certificateArray = (RPointerArray<CX509Certificate>*) aArray;
+    certificateArray->ResetAndDestroy();
+    certificateArray->Close();
+    }
+
+void ResetAndDestroyPushL(RPointerArray<CX509Certificate>& aCertificateArray)
+    {
+    CleanupStack::PushL(TCleanupItem(ResetAndDestroyCleanup, &aCertificateArray));
+    }
+
+
+RPointerArray<CX509Certificate> PkiUtil::GetCaCertListL(RPKIServiceAPI& aPkiService,
+                                                        const CArrayFixFlat<TCertInfo*>& aIkeCAList)
+    {
+
+    __ASSERT_ALWAYS(aIkeCAList.Count() > 0, User::Invariant());
+    _LIT8(KEmptyString, "");
+
+    RPointerArray<CX509Certificate> certificateArray;
+    ResetAndDestroyPushL(certificateArray);
+
+    RArray<TUid> applUidArray;
+    CleanupClosePushL(applUidArray);
+
+    for (TInt i = 0; i < aIkeCAList.Count(); ++i)
+        {
+        const TCertInfo* certInfo = aIkeCAList[i];
+        switch(certInfo->iFormat)
+            {
+            case CA_NAME:
+                {
+                // Reserve enough space for UTF-8
+                TInt len = 3*( certInfo->iData.Length() );
+                HBufC8* caName = HBufC8::NewLC(len);
+                TPtr8 caNamePtr(caName->Des());
+
+                if (CnvUtfConverter::ConvertFromUnicodeToUtf8(caNamePtr, certInfo->iData) != 0)
+                    {
+                    User::Leave(KErrCorrupt);
+                    }
+
+                CX509Certificate* cert = ReadCertificateLC(aPkiService,
+                                                           KEmptyString,
+                                                           *caName,
+                                                           KEmptyString,
+                                                           EPKICACertificate);
+
+                User::LeaveIfError(certificateArray.Append(cert));
+                CleanupStack::Pop(cert);
+                CleanupStack::PopAndDestroy(caName);
+                }
+                break;
+            case KEY_ID:
+                {
+                TPKIKeyIdentifier keyId(NULL);
+
+                for (TInt j = 0; j < certInfo->iData.Length(); j += 2)
+                    {
+                    TPtrC hexByte(certInfo->iData.Mid(j, 2));
+                    TLex lex(hexByte);
+                    TUint8 value;
+                    User::LeaveIfError(lex.Val(value, EHex));
+                    keyId.Append(&value, 1);
+                    }
+
+                CX509Certificate* cert = ReadCertificateLC(aPkiService,
+                                                           keyId);
+                User::LeaveIfError(certificateArray.Append(cert));
+                CleanupStack::Pop(cert);
+                }
+                break;
+            case APPL_UID:
+                {
+                TLex lex(certInfo->iData);
+                TUint32 value;
+                User::LeaveIfError(lex.Val(value, EHex));
+                TUid id = { value };
+                User::LeaveIfError(applUidArray.Append(id));
+                }
+                break;
+            default:
+                User::Leave(KErrArgument);
+                break;
+            }
+        }
+
+        if (applUidArray.Count() > 0)
+            {
+            CArrayFix<TCertificateListEntry>* certListArray = NULL;;
+            aPkiService.ListApplicableCertificatesL(applUidArray, certListArray);
+
+            CleanupStack::PushL(certListArray);
+            if (certListArray->Count() == 0)
+                {
+                User::Leave(KErrNotFound);
+                }
+
+            for (TInt i = 0; i < certListArray->Count(); ++i)
+                {
+                TCertificateListEntry entry = (*certListArray)[i];
+                if (entry.iOwnerType == EPKICACertificate)
+                    {
+                    CX509Certificate* cert = ReadCertificateLC(aPkiService,
+                                                               KEmptyString,
+                                                               entry.iIdentitySubjectName,
+                                                               KEmptyString,
+                                                               EPKICACertificate);
+                    User::LeaveIfError(certificateArray.Append(cert));
+                    CleanupStack::Pop(cert);
+                    }
+                }
+            CleanupStack::PopAndDestroy(certListArray);
+            }
+
+        CleanupStack::PopAndDestroy(); //applUidArray
+
+    CleanupStack::Pop();
+    return certificateArray;
+    }
+
+
+TCertStatus PkiUtil::GetValidCaCertSubjectNameListL(RPKIServiceAPI& aPkiService,
+                                                   const CArrayFixFlat<TCertInfo*>& aIkeCAList,
+                                                   CDesC8ArrayFlat& aCaCertNameList)
+    {
+
+    TCertStatus status = ECertValid;
+    RPointerArray<CX509Certificate> certificateList;
+    TRAPD(err, certificateList = PkiUtil::GetCaCertListL(aPkiService, aIkeCAList));
+
+    switch(err)
+        {
+        case KErrNone:
+            for (TInt i = 0; i < certificateList.Count(); ++i)
+                {
+                const CX509Certificate* cert = certificateList[i];
+                status = CertStatusL(*cert, -1);
+
+                if (status == ECertValid)
+                    {
+                    const CX500DistinguishedName& subjectName = cert->SubjectName();
+                    HBufC* subjectNameString = PkiUtil::CertDnL(subjectName);
+                    CleanupStack::PushL(subjectNameString);
+
+                    // Reserve enough space for UTF-8
+                    TInt len = 3*( subjectNameString->Length() );
+                    HBufC8* subjectNameString8Bit = HBufC8::NewLC(len);
+                    TPtr8 subjectNameString8BitPtr = subjectNameString8Bit->Des();
+                    if (CnvUtfConverter::ConvertFromUnicodeToUtf8(subjectNameString8BitPtr,
+                                                                  *subjectNameString) != 0)
+                        {
+                        User::Leave(KErrCorrupt);
+                        }
+                    TRAPD(err, aCaCertNameList.InsertIsqL(*subjectNameString8Bit));
+
+                    CleanupStack::PopAndDestroy(subjectNameString8Bit);
+                    CleanupStack::PopAndDestroy(subjectNameString);
+
+                    err = (err == KErrAlreadyExists) ? KErrNone : err;
+                    User::LeaveIfError(err);
+                    }
+                else
+                    {
+                    aCaCertNameList.Reset();
+                    break;
+                    }
+                }
+            break;
+        case KErrNotFound: // Flow through
+        case KErrArgument: // CA cert is not found if policys CA DATA is invalid
+            status = ECertNotFound;
+            break;
+        default:
+            certificateList.ResetAndDestroy();
+            certificateList.Close();
+            User::Leave(err);
+        }
+
+    certificateList.ResetAndDestroy();
+    certificateList.Close();
+
+    return status;
+    }
+
+
+TCertStatus PkiUtil::CheckUserCertValidityL(RPKIServiceAPI& aPkiService,
+                                            CDesC8ArrayFlat& aValidCaCertNameList,
+                                            TOwnCertInfo& aOwnCert)
+    {
+
+    static const TInt KUndefinedKeySize = 0;
+
+    TCertStatus status = ECertValid;
+
+    HBufC8* subjectName = NULL;
+    HBufC8* rfc822Name = NULL;
+
+    if (aOwnCert.iOwnCertExists)
+        {
+        // Reserve enough space for UTF-8
+        TInt len = 3*( aOwnCert.iSubjectDnSuffix.Length() );
+        subjectName = HBufC8::NewLC(len);
+        TPtr8 subjectNamePtr = subjectName->Des();
+        if (CnvUtfConverter::ConvertFromUnicodeToUtf8(subjectNamePtr, aOwnCert.iSubjectDnSuffix) != 0)
+            {
+            User::Leave(KErrCorrupt);
+            }
+
+        if ( aOwnCert.iIdentityAsRfc822Name == EIdentityAsRfc822NameYes)
+            {
+            rfc822Name = HBufC8::NewLC(aOwnCert.iRfc822NameFqdn.Length());
+            TPtr8 rfc822NamePtr = rfc822Name->Des();
+            if (CnvUtfConverter::ConvertFromUnicodeToUtf8(rfc822NamePtr, aOwnCert.iRfc822NameFqdn) != 0)
+                {
+                User::Leave(KErrCorrupt);
+                }
+
+            }
+        else
+            {
+            rfc822Name = HBufC8::NewLC(1); //empty string
+            }
+
+            status = ECertNotFound;
+            for (TInt i = 0; i < aValidCaCertNameList.Count(); ++i)
+                {
+
+                status = CertStatusL(aPkiService, aValidCaCertNameList[i],
+                                     *subjectName, *rfc822Name,
+                                     KUndefinedKeySize);
+                if (status != ECertNotFound)
+                    {
+                    break;
+                    }
+                }
+
+            CleanupStack::PopAndDestroy(rfc822Name);
+            CleanupStack::PopAndDestroy(subjectName);
+        }
+
+    return status;
+    }
+
+
+CX500DistinguishedName* PkiUtil::DnFromStringL(const TDesC8& aString)
+    {
+    HBufC8* dnDer;
+    CPkcs10Req::BuildDistinguishedNameDerFromTextL(dnDer, aString,
+                                                   EFalse, KNullDesC8);
+    CleanupStack::PushL(dnDer);
+
+    CX500DistinguishedName* dn = CX500DistinguishedName::NewL(*dnDer);
+
+    CleanupStack::PopAndDestroy(); // dnDer
+
+    return dn;
+    }
+
+CX500DistinguishedName* PkiUtil::DnWithoutCnFromStringL(const TDesC8& aString)
+    {
+    HBufC8* dnDer;
+    CPkcs10Req::BuildDistinguishedNameDerFromTextL(dnDer, aString,
+                                                   ETrue, KCN8);
+    CleanupStack::PushL(dnDer);
+
+    CX500DistinguishedName* dn = CX500DistinguishedName::NewL(*dnDer);
+
+    CleanupStack::PopAndDestroy(); // dnDer
+
+    return dn;
+    }
+
+TBool PkiUtil::DnMatchL(const TDesC8& aDnString1, const TDesC8& aDnString2)
+    {
+    TBool exactMatch = EFalse;
+
+    if (aDnString1.Length() == 0 && aDnString2.Length() == 0)
+        {
+        exactMatch = ETrue;
+        }
+    else if (aDnString1.Length() > 0 && aDnString2.Length() > 0)
+        {
+        CX500DistinguishedName* dn1 = DnFromStringL(aDnString1);
+        CleanupStack::PushL(dn1);
+
+        CX500DistinguishedName* dn2 = DnFromStringL(aDnString2);
+        CleanupStack::PushL(dn2);
+
+        if (MatchL(*dn1, *dn2))
+            {
+            exactMatch = ETrue;
+            }
+
+        CleanupStack::PopAndDestroy(2); // dn2, dn1
+        }
+
+    return exactMatch;
+    }
+
+TBool PkiUtil::MatchL(const CX500DistinguishedName& aDn1, const CX500DistinguishedName& aDn2)
+    {
+    if (aDn1.Count() != aDn2.Count())
+        {
+        return EFalse;
+        }
+
+    // For each field in aDn1, aDn2 must contain a field with the same value
+    for (TInt i = 0; i < aDn1.Count(); i++)
+    {
+        if (!HasElementL(aDn2, aDn1.Element(i)))
+            {
+            return EFalse;
+            }
+        }
+    return ETrue;
+    }
+
+TBool PkiUtil::HasElementL(const CX500DistinguishedName& aDn, const CX520AttributeTypeAndValue& aElement)
+    {
+  for (TInt i = 0; i < aDn.Count(); i++)
+    {
+        if (aElement.ExactMatchL(aDn.Element(i)))
+            {
+            return ETrue;
+            }
+        }
+    return EFalse;
+    }
+
+HBufC8* PkiUtil::To8BitL(const TDesC16& aDes)
+    {
+    HBufC8* desCopy;
+    
+    TInt desLength = aDes.Length();
+    
+    if (desLength > 0)
+        {
+        desCopy = HBufC8::NewL(desLength);
+        desCopy->Des().Copy(aDes);
+        }
+    else
+        {
+        desCopy = HBufC8::NewL(1);
+        }
+
+    return desCopy;
+    }