vpnengine/utlpkcs10/src/pkcs10.cpp
changeset 0 33413c0669b9
child 10 68dc8923de26
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vpnengine/utlpkcs10/src/pkcs10.cpp	Thu Dec 17 09:14:51 2009 +0200
@@ -0,0 +1,1375 @@
+/*
+* Copyright (c) 2003 - 2007 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: Pkcs10 certificate request.
+*
+*/
+
+
+
+#include <eikenv.h>
+#include <asn1cons.h>
+#include <asn1enc.h>
+#include <x520ava.h>
+
+#include "pkcs10.h"
+#include "base64.h"
+#include "pkidefs.h"
+#include "utlcrypto.h"
+
+//////////////////////////////////////////////////////////////////////////////
+// Destructor
+//////////////////////////////////////////////////////////////////////////////
+EXPORT_C CPkcs10Req::~CPkcs10Req()
+{
+    delete iDNDerBuf;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Set distinguished name parameter, Only CommonName given
+//////////////////////////////////////////////////////////////////////////////
+EXPORT_C TInt CPkcs10Req::SetDistinguishedName(const TDesC8 &aDistinguishedName)
+{
+    TInt status = KErrNone;
+
+    // Set distiguished name
+    if(aDistinguishedName.Length() > 0)
+    {
+        iDistinguishedName.Set(aDistinguishedName);
+        iUseExtendedDistinguishedName = EFalse;
+    }
+    else
+        status = KErrArgument;
+
+    return (status);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// SetDistinguishedNameExtended
+//////////////////////////////////////////////////////////////////////////////
+// Set distinguished name parameter. Complete distinguished name in format
+// CN=xxx,O=abc,OU=def or CN=xxx/O=abc/OU=def
+// OIds and corresponding texts (case insensitive):
+// KX520CountryName             "2.5.4.6"       "c"                     {0x55, 0x04, 0x06}
+// KX520OrganizationName        "2.5.4.10"      "o"                     {0x55, 0x04, 0x0a}
+// KX520OrganizationalUnitName  "2.5.4.11"      "ou"                    {0x55, 0x04, 0x0b}
+// KX520LocalityName            "2.5.4.7"       "l"                     {0x55, 0x04, 0x07}
+// KX520StateOrProvinceName     "2.5.4.8"       "st"                    {0x55, 0x04, 0x08}
+// KX520Title                   "2.5.4.12"      "title"                 {0x55, 0x04, 0x0c}
+// KX520CommonName              "2.5.4.3"       "cn"                    {0x55, 0x04, 0x03}
+// KX520GivenName               "2.5.4.42"      "GivenName"             {0x55, 0x04, 0x2a}
+// KX520Surname                 "2.5.4.4"       "sn"                    {0x55, 0x04, 0x04}
+// KX520Initials                "2.5.4.43"      "initials"              {0x55, 0x04, 0x2b}
+// KX520GenerationQualifier     "2.5.4.44"      "generationQualifier"   {0x55, 0x04, 0x2c}
+// KX520DNQualifier             "2.5.4.46"      "dnQualifier"           {0x55, 0x04, 0x2e}
+// KX520SerialNumber            "2.5.4.5"       "serialNumber"          {0x55, 0x04, 0x05}
+////////////////////////////////////////////////////////////////////////////////////////
+EXPORT_C TInt CPkcs10Req::SetDistinguishedNameExtendedL(const TDesC8 &aDistinguishedName)
+{
+    TInt status = KErrNone;
+
+    // Set distiguished name
+    if(aDistinguishedName.Length() > 0)
+    {
+        delete iDNDerBuf;       // delete possible old buffer
+        iDNDerBuf = NULL;
+        TRAPD(status, BuildDistinguishedNameDerFromTextL(iDNDerBuf, aDistinguishedName, EFalse, KCountryName()));
+        if(status == KErrNone)
+        {
+            iUseExtendedDistinguishedName = ETrue;
+        }
+    }
+    else
+        status = KErrArgument;
+
+    return (status);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// BuildDistinguishedNameDerFromText
+//////////////////////////////////////////////////////////////////////////////
+EXPORT_C void CPkcs10Req::BuildDistinguishedNameDerFromTextL(
+    HBufC8        *&derBuffer,
+    const TDesC8   &aDistinguishedName,
+    TBool           aByPass,
+    const TDesC8   &aByPassType
+)
+{    
+    HBufC8 *shrinkedBuffer;
+    
+    CArrayFixFlat<TIndexPair> *valueIndexArray  =
+      new (ELeave) CArrayFixFlat<TIndexPair>(1);
+    
+    CleanupStack::PushL(valueIndexArray);
+    
+    CArrayFixFlat<TIndexPair> *typeIndexArray  =
+      new (ELeave) CArrayFixFlat<TIndexPair>(1);
+    
+    CleanupStack::PushL(typeIndexArray);
+    
+    CArrayFixFlat<TPtr8> *valuePtrArray  =
+      new (ELeave) CArrayFixFlat<TPtr8>(1);
+    
+    CleanupStack::PushL(valuePtrArray);
+    
+    CArrayFixFlat<TPtr8> *typePtrArray  =
+      new (ELeave) CArrayFixFlat<TPtr8>(1);
+    
+    CleanupStack::PushL(typePtrArray);
+
+    // Scan input and build index arrays for types and values
+    CPkcs10Req::BuildIndexPairsLC(
+        shrinkedBuffer,
+        aDistinguishedName,
+        typeIndexArray,
+        valueIndexArray
+    );
+    
+    CPkcs10Req::BuildDerL(
+        shrinkedBuffer,
+        derBuffer,
+        typeIndexArray,
+        valueIndexArray,
+        typePtrArray,
+        valuePtrArray,
+        aByPass,
+        aByPassType
+    );
+    
+    CleanupStack::PopAndDestroy(5);    
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// AttributeTypeOidToText
+//////////////////////////////////////////////////////////////////////////////
+EXPORT_C TPtrC8 CPkcs10Req::AttributeTypeOidToText(const TDesC &aType)
+{
+    TPtrC8 temp;
+
+    if(aType.Compare(KX520CountryName) == 0)
+        temp.Set(KCountryName);
+    else if(aType.Compare(KX520OrganizationName) == 0)
+        temp.Set(KOrganizationName);
+    else if(aType.Compare(KX520OrganizationalUnitName) == 0)
+        temp.Set(KOrganizationalUnitName);
+    else if(aType.Compare(KX520LocalityName) == 0)
+        temp.Set(KLocalityName);
+    else if(aType.Compare(KX520StateOrProvinceName) == 0)
+        temp.Set(KStateOrProvinceName);
+    else if(aType.Compare(KX520Title) == 0)
+        temp.Set(KTitle);
+    else if(aType.Compare(KX520CommonName) == 0)
+        temp.Set(KCommonName);
+    else if(aType.Compare(KX520GivenName) == 0)
+        temp.Set(KGivenName);
+    else if(aType.Compare(KX520Surname) == 0)
+        temp.Set(KSurname);
+    else if(aType.Compare(KX520Initials) == 0)
+        temp.Set(KInitials);
+    else if(aType.Compare(KX520GenerationQualifier) == 0)
+        temp.Set(KGenerationQualifier);
+    else if(aType.Compare(KX520DNQualifier) == 0)
+        temp.Set(KDNQualifier);
+    else if(aType.Compare(KX520SerialNumber) == 0)
+        temp.Set(KSerialNumber);
+    else if(aType.Compare(KRFC2247DomainComponent) == 0)
+        temp.Set(KDomainComponent);
+    else
+        {
+        // Return dotted oid, length = 0
+        }
+    
+    return temp;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// BuildIndexPairsLC
+//////////////////////////////////////////////////////////////////////////////
+void CPkcs10Req::BuildIndexPairsLC(
+    HBufC8                     *&buffer,
+    const TDesC8                &aDistinguishedName,
+    CArrayFixFlat<TIndexPair>   *aTypePairArray,
+    CArrayFixFlat<TIndexPair>   *aValuePairArray
+)
+{
+    // Some rules:
+    // 1) Separator: ','
+    // 2) Escape character '\'
+    // 3) Value may be quoted. Then separator in value is allowed
+    //    (without preceding escape char)
+
+    HBufC8 *sourceBuffer;
+    HBufC8 *targetBuffer;
+    TUint i, j;
+    targetBuffer = HBufC8::NewLC(aDistinguishedName.Length());
+    targetBuffer->Des().SetLength(aDistinguishedName.Length());
+    sourceBuffer = HBufC8::NewLC(aDistinguishedName.Length());
+    sourceBuffer->Des().Copy(aDistinguishedName);
+    TPtr8 sourcePointer = sourceBuffer->Des();
+    TPtr8 targetPointer = targetBuffer->Des();
+    TBool insideQuotes = EFalse;
+    TIndexPair pair;
+    TUint elementStartPosition = 0;
+    TUint elementEndPosition = 0;
+
+    // Delete leading and trailing spaces
+    sourcePointer.Trim();
+
+    // Scan text in order to collect name value pairs
+    for(i = 0, j = 0; (TInt)i < sourcePointer.Length(); i++)
+    {
+        if(sourcePointer[i] == '"')
+        {
+            // Toggle quote state
+            // Don't ignore quotes in order to ease trimming.
+            // (Spaces inside quotes are meaningful)
+            insideQuotes = !insideQuotes;
+            targetPointer[j] = sourcePointer[i];
+            j++;
+            continue;
+        }       
+
+        if(insideQuotes)
+        {
+            // Allow any character
+            // Check for escape
+            if(sourcePointer[i] == '\\')
+            {
+                if((TInt)i < sourcePointer.Length() - 1)
+                {
+                    targetPointer[j] = sourcePointer[i + 1];
+                    j++;
+                    i++;    // skip char
+                }
+                else
+                    User::Leave(KErrArgument);
+            }
+            else
+            {
+                targetPointer[j] = sourcePointer[i];
+                j++;
+            }
+            continue;
+        }
+
+        // Check for escape
+        if(sourcePointer[i] == '\\')
+        {
+            if((TInt)i < sourcePointer.Length() - 1)
+            {
+                targetPointer[j] = sourcePointer[i + 1];
+                j++;
+                i++;    // skip char
+            }
+            else
+                User::Leave(KErrArgument);
+
+            continue;
+        }
+
+        // Check for pair separator
+        if(sourcePointer[i] == ',')
+        {
+            // End of type/value pair
+            elementEndPosition = j;
+            pair.startIndex = elementStartPosition;
+            pair.endIndex = elementEndPosition;
+            aValuePairArray->AppendL(pair);
+            elementStartPosition = j;
+        }
+        // Check for type/value separator
+        else if(sourcePointer[i] == '=')
+        {
+            elementEndPosition = j;
+            pair.startIndex = elementStartPosition;
+            pair.endIndex = elementEndPosition;
+            aTypePairArray->AppendL(pair);
+            elementStartPosition = j;
+        }
+        else
+        {
+            // Plain copy
+            targetPointer[j] = sourcePointer[i];
+            j++;
+        }
+    }
+
+    // Append final value
+    elementEndPosition = j;
+    pair.startIndex = elementStartPosition;
+    pair.endIndex = elementEndPosition;
+    aValuePairArray->AppendL(pair);
+    
+    // Ensure we have consistent type/value pairs
+    if(aTypePairArray->Count() != aValuePairArray->Count())
+    {
+        User::Leave(KErrArgument);
+    }
+
+    CleanupStack::PopAndDestroy(1);         // source
+    // Return allocated shrinked buffer and OK status
+    targetBuffer->Des().SetLength(j);
+    buffer = targetBuffer;    
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// BuildDerLC
+//////////////////////////////////////////////////////////////////////////////
+void CPkcs10Req::BuildDerL(
+    HBufC8                      *aSource,
+    HBufC8                     *&derBuffer,
+    CArrayFixFlat<TIndexPair>   *aTypeIndexArray,
+    CArrayFixFlat<TIndexPair>   *aValueIndexArray,
+    CArrayFixFlat<TPtr8>        *aTypePtrArray,
+    CArrayFixFlat<TPtr8>        *aValuePtrArray,
+    TBool                        aByPass,
+    const TDesC8                &aByPassType
+)
+{
+    TUint i;
+    // trim types and values and count required der length
+    TUint elementLength = 0;
+    TUint totalLength = 0;
+    TUint wholeLength = 0;
+    TUint setLength = 0;
+    TUint seqLength = 0;
+    TUint oidLength = COMMON_NAME_OID_LTH;
+    TUint stringLength = 0;
+    TUint contentLength = 0;
+    TUint oidIndex = 0;
+    TBuf8<32> dottedOidDer;
+
+    CArrayFixFlat<HBufC8 *> *elementArray =
+      new (ELeave) CArrayFixFlat<HBufC8 *>(1);
+    
+    CleanupStack::PushL(elementArray);
+
+    for(i = 0; (TInt)i < aTypeIndexArray->Count(); i++)  // counts are equal
+    {
+        TPtr8 tempPtr(
+            CONST_CAST(TUint8*, aSource->Des().Ptr()) + aTypeIndexArray->At(i).startIndex,
+            aTypeIndexArray->At(i).endIndex - aTypeIndexArray->At(i).startIndex
+        );
+        
+        tempPtr.SetLength(
+            aTypeIndexArray->At(i).endIndex - aTypeIndexArray->At(i).startIndex
+        );
+        
+        aTypePtrArray->AppendL(tempPtr);
+        
+        tempPtr.Set(
+            CONST_CAST(TUint8*, aSource->Des().Ptr()) + aValueIndexArray->At(i).startIndex,
+            aValueIndexArray->At(i).endIndex - aValueIndexArray->At(i).startIndex,
+            aValueIndexArray->At(i).endIndex - aValueIndexArray->At(i).startIndex
+        );
+        
+        tempPtr.SetLength(aValueIndexArray->At(i).endIndex - aValueIndexArray->At(i).startIndex);
+        
+        tempPtr.Trim();
+
+        if(0 == tempPtr.Length())
+        {
+            User::Leave(KErrArgument);
+        }
+        
+        // Remove quotes. Spaces inside quotes are meaningful,
+        // so Trim must be called before this operation
+        if(tempPtr[0] == '"')
+        {
+            if(tempPtr[tempPtr.Length() -1 ] != '"')
+            {                
+                User::Leave(KErrArgument);
+            }
+            else
+            {
+                TInt tempLength = tempPtr.Length() - 2; 
+                tempPtr.Set(CONST_CAST(TUint8*, tempPtr.Ptr() + 1), tempLength, tempLength);
+                tempPtr.SetLength(tempLength);
+            }
+        }
+        
+        if(0 == tempPtr.Length())
+        {
+            User::Leave(KErrArgument);
+        }
+        
+        aValuePtrArray->AppendL(tempPtr);
+        
+        aTypePtrArray->At(i).Trim();
+        aTypePtrArray->At(i).UpperCase();
+        
+        // Check if type is supported, it is ignored if not
+        if(CPkcs10Req::OidExistsL(aTypePtrArray->At(i), oidIndex, dottedOidDer))
+        {
+            if(KNullAttributeIndex == oidIndex)
+            {
+                oidLength = dottedOidDer.Length() - ASN1_SHORT_TAG_HDR_LTH;
+            }
+            else if(KDomainComponentIndex == oidIndex)
+            {
+                oidLength = DC_OID_LTH;
+            }
+            else
+            {
+                oidLength = COMMON_NAME_OID_LTH;
+            }
+
+            if(!(aByPass && aTypePtrArray->At(i).Compare(aByPassType) == 0))
+            {
+                // Printable string
+                elementLength = aValuePtrArray->At(i).Length();
+                stringLength = elementLength;
+                if(elementLength > 127)
+                    elementLength++;
+                if(elementLength > 255)
+                    elementLength++;
+                elementLength += ASN1_SHORT_TAG_HDR_LTH;
+
+                elementLength += oidLength;               // Oid 
+                elementLength += ASN1_SHORT_TAG_HDR_LTH;        
+                seqLength = elementLength;
+                if(elementLength > 127)
+                    elementLength++;
+                if(elementLength > 255)
+                    elementLength++;
+                elementLength += ASN1_SHORT_TAG_HDR_LTH;  // Sequence
+                setLength = elementLength;
+                if(elementLength > 127)
+                    elementLength++;
+                if(elementLength > 255)
+                    elementLength++;
+                elementLength += ASN1_SHORT_TAG_HDR_LTH;  // Set
+                wholeLength = elementLength;
+
+                // Build one element
+                CPkcs10Req::BuildElementDerLC(
+                    elementArray,
+                    wholeLength, 
+                    setLength,
+                    seqLength, 
+                    oidLength,
+                    stringLength, 
+                    oidIndex,
+                    dottedOidDer, 
+                    aValuePtrArray->At(i)
+                );            
+
+                totalLength += elementLength;
+            }
+        }
+    }
+    
+    if( 0 == totalLength )
+    {
+        User::Leave(KErrArgument);
+    }
+    
+    contentLength = totalLength;
+    if(totalLength > 127)                                   // Sequence
+        totalLength++;
+    if(totalLength > 255)
+        totalLength++;
+    
+    totalLength += ASN1_SHORT_TAG_HDR_LTH;
+
+    // Allocate buffer
+    derBuffer = HBufC8::NewL(totalLength);
+    derBuffer->Des().SetLength(totalLength);
+    TUint8 *derBufferPtr = (TUint8 *)derBuffer->Ptr();
+    derBufferPtr+= CPkcs10Req::DERSetTag(derBufferPtr, (EASN1Sequence | ASN1_CONSTRUCTED));
+    derBufferPtr+= CPkcs10Req::DERSetLength(derBufferPtr, contentLength);
+    
+    for(i = 0; (TInt)i < elementArray->Count(); i++)
+    {
+        derBufferPtr+= CPkcs10Req::ASNCopy(
+            derBufferPtr,
+            CONST_CAST(unsigned char *, elementArray->At(i)->Des().Ptr()),
+            elementArray->At(i)->Length()
+        );
+    }
+    
+    CleanupStack::PopAndDestroy(elementArray->Count());
+    CleanupStack::PopAndDestroy(elementArray);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// OidExistsLC
+///////////////////////////////////////////////////////////////////////////////
+TBool CPkcs10Req::OidExistsL(
+    TPtr8 &aTypePtrArray,
+    TUint &aIndex,
+    TBuf8<32> &aDottedOidDer
+)
+{
+TBool validOId = EFalse;
+ 
+    aIndex = KNullAttributeIndex;
+        
+    if(aTypePtrArray.Compare(KCountryName) == 0)
+        aIndex = KCountryNameIndex;
+    else if(aTypePtrArray.Compare(KOrganizationName) == 0)
+        aIndex = KOrganizationNameIndex;
+    else if(aTypePtrArray.Compare(KOrganizationalUnitName) == 0)
+        aIndex = KOrganizationalUnitNameIndex;
+    else if(aTypePtrArray.Compare(KLocalityName) == 0)
+        aIndex = KLocalityNameIndex;
+    else if(aTypePtrArray.Compare(KStateOrProvinceName) == 0)
+        aIndex = KStateOrProvinceNameIndex;
+    else if(aTypePtrArray.Compare(KTitle) == 0)
+        aIndex = KTitleIndex;
+    else if(aTypePtrArray.Compare(KCommonName) == 0)
+        aIndex = KCommonNameIndex;
+    else if(aTypePtrArray.Compare(KGivenName) == 0)
+        aIndex = KGivenNameIndex;
+    else if(aTypePtrArray.Compare(KSurname) == 0)
+        aIndex = KSurnameIndex;
+    else if(aTypePtrArray.Compare(KInitials) == 0)
+        aIndex = KInitialsIndex;
+    else if(aTypePtrArray.Compare(KGenerationQualifier) == 0)
+        aIndex = KGenerationQualifierIndex;
+    else if(aTypePtrArray.Compare(KDNQualifier) == 0)
+        aIndex = KDNQualifierIndex;
+    else if(aTypePtrArray.Compare(KSerialNumber) == 0)
+        aIndex = KSerialNumberIndex;
+    else if(aTypePtrArray.Compare(KDomainComponent) == 0)
+        aIndex = KDomainComponentIndex;
+
+    if(KNullAttributeIndex != aIndex)
+    {
+        validOId = ETrue;
+    }
+    else
+    {
+        if(aTypePtrArray.Find(KDot) != KErrNotFound)
+        {
+            // Dotted oid notation
+            TUint offset = 0;
+            TBuf<32> tempOidBuf;
+            tempOidBuf.Copy(aTypePtrArray);
+            
+            CASN1EncObjectIdentifier *oidIdentifier =
+              CASN1EncObjectIdentifier::NewLC(tempOidBuf);
+            
+            // WriteDERL uses Length() instead of MaxLength() ?
+            aDottedOidDer.SetLength(32);
+            oidIdentifier->WriteDERL(aDottedOidDer, offset);
+            aDottedOidDer.SetLength(oidIdentifier->LengthDER());
+            CleanupStack::PopAndDestroy();  // oidIdentifier
+            validOId = ETrue;
+        }
+    }
+
+    return validOId;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// GetOid
+////////////////////////////////////////////////////////////////////////////////////////
+TInt CPkcs10Req::GetOid(TUint aIndex, const TUint8 *&aValue)
+{
+    switch(aIndex)
+    {
+        case KCountryNameIndex:
+            aValue = KCountryNameOid;
+            break;
+        case KOrganizationNameIndex: 
+            aValue = KOrganizationNameOid;
+            break;
+        case KOrganizationalUnitNameIndex: 
+            aValue = KOrganizationalUnitNameOid;
+            break;
+        case KLocalityNameIndex: 
+            aValue = KLocalityNameOid;
+            break;
+        case KStateOrProvinceNameIndex: 
+            aValue = KStateOrProvinceNameOid;
+            break;
+        case KTitleIndex: 
+            aValue = KTitleOid;
+            break;
+        case KCommonNameIndex: 
+            aValue = KCommonNOid;
+            break;
+        case KGivenNameIndex: 
+            aValue = KGivenNameOid;
+            break;
+        case KSurnameIndex: 
+            aValue = KSurnameOid;
+            break;
+        case KInitialsIndex:    
+            aValue = KInitialsOid;
+            break;
+        case KGenerationQualifierIndex:    
+            aValue = KGenerationQualifierOid;
+            break;
+        case KDNQualifierIndex:    
+            aValue = KDNQualifierOid;
+            break;
+        case KSerialNumberIndex:    
+            aValue = KSerialNumberOid;
+            break;
+        case KDomainComponentIndex:
+            aValue = KDomainComponentOid;
+            break;
+        default:
+            return KErrArgument;
+    }
+    
+  return KErrNone;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// FillDer
+////////////////////////////////////////////////////////////////////////////////////////
+void CPkcs10Req::BuildElementDerLC(CArrayFixFlat<HBufC8 *> *aElementArray, TUint aWholeLength, TUint aSetLength, TUint aSeqLength, TUint aOidLength, TUint aStringLength, TUint aOidIndex, TBuf8<32> &aDottedOidDer, TPtr8 &aValuePtr)
+{
+    HBufC8 *elementBuffer = HBufC8::NewLC(aWholeLength);
+    elementBuffer->Des().SetLength(aWholeLength);
+    TUint8 *elementBufferPtr = (TUint8 *)elementBuffer->Ptr();
+    const TUint8 *oidPtr;
+    
+    elementBufferPtr+= CPkcs10Req::DERSetTag(elementBufferPtr, (EASN1Set | ASN1_CONSTRUCTED));
+    elementBufferPtr+= CPkcs10Req::DERSetLength(elementBufferPtr, aSetLength);
+    elementBufferPtr+= CPkcs10Req::DERSetTag(elementBufferPtr, (EASN1Sequence | ASN1_CONSTRUCTED));
+    elementBufferPtr+= CPkcs10Req::DERSetLength(elementBufferPtr, aSeqLength);
+    if(aOidIndex != 0)
+        {
+        GetOid(aOidIndex, oidPtr);
+        elementBufferPtr+= CPkcs10Req::DERSetTag(elementBufferPtr, EASN1ObjectIdentifier);
+        elementBufferPtr+= CPkcs10Req::DERSetLength(elementBufferPtr, aOidLength);
+        elementBufferPtr+= CPkcs10Req::DERSetOid(elementBufferPtr, oidPtr, aOidLength);
+        }
+    else
+        {
+        // Dotted oid representation
+        elementBufferPtr+= CPkcs10Req::ASNCopy(elementBufferPtr, CONST_CAST(unsigned char *, aDottedOidDer.Ptr()), aDottedOidDer.Length()); 
+        }
+    elementBufferPtr+= CPkcs10Req::DERSetTag(elementBufferPtr, EASN1UTF8String);
+    elementBufferPtr+= CPkcs10Req::DERSetLength(elementBufferPtr, aStringLength);
+    elementBufferPtr+= CPkcs10Req::ASNCopy(elementBufferPtr, CONST_CAST(unsigned char *, aValuePtr.Ptr()), aValuePtr.Length());
+    
+    aElementArray->AppendL(elementBuffer);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Set subject alt name extension, email
+////////////////////////////////////////////////////////////////////////////////////////
+EXPORT_C TInt CPkcs10Req::SetSubjectAltNameRfc822(const TDesC8 &aSubjectAltNameRfc822)
+{
+    TInt status = KErrNone;
+    
+    // Set subject alt name
+    if(aSubjectAltNameRfc822.Length() > 0)
+        iSubjectAltName.Set(aSubjectAltNameRfc822);
+
+    return (status);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Set DNSname extension
+////////////////////////////////////////////////////////////////////////////////////////
+EXPORT_C TInt CPkcs10Req::SetDNSName(const TDesC8 &aDNSName)
+{
+    TInt status = KErrNone;
+
+    // Set subject alt name
+    if(aDNSName.Length() > 0)
+        iDNSName.Set(aDNSName);
+
+    return (status);    // DNS name is optional
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Set challenge password extension
+////////////////////////////////////////////////////////////////////////////////////////
+EXPORT_C TInt CPkcs10Req::SetChallengePw(const TDesC8 &aChallengePw)
+{
+    // Set challenge password
+    if(aChallengePw.Length() > 0)
+        iChallengePW.Set(aChallengePw);
+    
+    return KErrNone;    // ChallengePw is optional
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Set public key and key type (only RSA supported!)
+////////////////////////////////////////////////////////////////////////////////////////
+EXPORT_C TInt CPkcs10Req::SetPublicKey(const TDesC8 &aPublicKeyBits)
+{
+    TInt status = KErrNone;
+
+    // Build public key DER
+    if(aPublicKeyBits.Length() > 0 )
+    {
+        iPublicKey.Set(aPublicKeyBits);
+    }
+    else
+    {        
+        status = KErrArgument;
+    }
+    
+    return (status);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Create the request
+//
+//  In:     THashType aSignatureAlgorithmId, MD5 os SHA1
+//          const TDesC& aPrivateKeyFilename, keyid used in kmdserver
+//          TBool doPEM, set ETrue if PEM encoding requested, otherwise out format is DER
+//          TSignCallback aSignCallBackL, signing callback function address, defined in pkcs10.h
+//  Out:    HBufC8 * containing the request. Remember to pop it out of the cleanupstack and delete it when not needed anymore.
+//
+//  Output format is either der (in example below, ASN1 decoding done)
+//
+//  0:d=0  hl=4 l= 431 cons: SEQUENCE
+//  4:d=1  hl=4 l= 281 cons:  SEQUENCE
+//  8:d=2  hl=2 l=   1 prim:   INTEGER           :00
+//  11:d=2  hl=2 l=  52 cons:   SEQUENCE             : Distinguished name
+//  13:d=3  hl=2 l=  16 cons:    SET
+//  15:d=4  hl=2 l=  14 cons:     SEQUENCE
+//  17:d=5  hl=2 l=   3 prim:      OBJECT            :commonName
+//  22:d=5  hl=2 l=   7 prim:      PRINTABLESTRING   :subject
+//  31:d=3  hl=2 l=  32 cons:    SET                                        // 
+//  33:d=4  hl=2 l=  30 cons:     SEQUENCE
+//  35:d=5  hl=2 l=   9 prim:      OBJECT            :emailAddress
+//  46:d=5  hl=2 l=  17 prim:      IA5STRING
+//  65:d=2  hl=3 l= 138 cons:   SEQUENCE
+//  68:d=3  hl=2 l=  13 cons:    SEQUENCE
+//  70:d=4  hl=2 l=   9 prim:     OBJECT            :rsaEncryption
+//  81:d=4  hl=2 l=   0 prim:     NULL
+//  83:d=3  hl=2 l= 121 prim:    BIT STRING
+//  206:d=2  hl=2 l=  81 cons:   cont [ 0 ]
+//  208:d=3  hl=2 l=  26 cons:    SEQUENCE
+//  210:d=4  hl=2 l=   9 prim:     OBJECT            :challengePassword
+//  221:d=4  hl=2 l=  13 cons:     SET
+//  223:d=5  hl=2 l=  11 prim:      PRINTABLESTRING   :challengepw
+//  236:d=3  hl=2 l=  51 cons:    SEQUENCE
+//  238:d=4  hl=2 l=   9 prim:     OBJECT            :Extension Request
+//  249:d=4  hl=2 l=  38 cons:     SET
+//  251:d=5  hl=2 l=  36 cons:      SEQUENCE
+//  253:d=6  hl=2 l=  34 cons:       SEQUENCE
+//  255:d=7  hl=2 l=   9 prim:        OBJECT            :emailAddress
+//  266:d=7  hl=2 l=  21 prim:        OCTET STRING
+//  289:d=1  hl=2 l=  13 cons:  SEQUENCE
+//  291:d=2  hl=2 l=   9 prim:   OBJECT            :sha1WithRSAEncryption
+//  302:d=2  hl=2 l=   0 prim:   NULL
+//  304:d=1  hl=3 l= 129 prim:  BIT STRING
+//
+//  or PEM, which looks like this
+//  -----BEGIN NEW CERTIFICATE REQUEST-----
+//  MIIBqDCCARECAQAwFjEUMBIGA1UEAxMLa3Vra3VsdXVydXUwgZ8wDQYJKoZIhvcN
+//  AQEBBQADgY0AMIGJAoGBALCCSQ305j5l/qh4TeIJeaLdLEtKe9IpAPTCvZqZhIv/
+//  VpVRw3fdq2qgBMe6zsO0kctBYkvdZ67Yq3Gdmzx1Ofx4S0F4BUDT6TGH2uP3zi04
+//  zMb3IoDxF9BAp9drc6BKzMnhN5HBIV0RUoTLhQ8HKbFcwmqIAo0uJkUx2gbr+aOD
+//  AgMBAAGgUjAXBgkqhkiG9w0BCQcxChMIcGFzc3dvcmQwNwYJKoZIhvcNAQkOMSow
+//  KDAmBgNVHREEHzAdggtrdWtrdWx1dXJ1dYEOanVraUBub2tpYS5jb20wDQYJKoZI
+//  hvcNAQEEBQADgYEAbltAG0DNe2NuyMHoJPg4QQExhUb9rep6eSJvrACbyT2qVgJe
+//  vrdpOesdw7//MsOhgTP+MU36DlTVRbpoUJ8xO1wM10ljrxkWcwNfdEU4kf3NOiWB
+//  4i+V99jPK2nbK/ofNpJU7m2nMvi4Z66WlM/kDEwVJe5GWwIzOIyOlfkiyc8=
+//  -----END NEW CERTIFICATE REQUEST-----
+//
+///////////////////////////////////////////////////////////////////////////////
+EXPORT_C HBufC8* CPkcs10Req::CreateCertificateRequestLC(
+THashType aSignatureAlgorithmId, 
+const TPKIKeyIdentifier& aPrivateKeyFilename, 
+TBool aDoBase64, 
+TBool aDoPEM, 
+TSignCallback aSignCallBackL, 
+TAny* aSignCallBackContext)
+{
+    // Build certificate request
+    HBufC8  *CRInfoBuffer = NULL;
+    HBufC8  *CRBuffer = NULL;
+    TBuf8<SHA1_HASH_LTH> hash;
+    TBase64Codec base64Codec;
+    HBufC8 *encodedCRBuffer = NULL;
+    HBufC8 *tempBuffer = NULL;
+    TBuf8<MAX_SIGNATURE_LENGTH> signature;
+
+    // Create CertificationRequestInfo consisting
+    //
+    //      - subject distinguished name
+    //      - public key
+    //      - Attributes
+    //          -Subject alt name Rfc822
+    //          -Challenge PW
+
+    CRInfoBuffer = ASNEncodeCertificationRequestInfoLC();
+    if(CRInfoBuffer)
+    {
+        // Sign CertificationRequestInfo
+        //
+        //      - create hash using the defined signature algorithm
+        //      - create digital signature of the hash by calling the given callback function
+
+        DigestL(CRInfoBuffer->Des(), hash, aSignatureAlgorithmId);
+
+        // Capsulate hash in digest info
+        TUint digestInfoLength = hash.Length() + 5 * ASN1_SHORT_TAG_HDR_LTH + MD5SIGNATURE_OID_LTH;
+        HBufC8 *digestInfo = HBufC8::NewLC(digestInfoLength);
+        
+        digestInfo->Des().SetLength(digestInfoLength);
+        TUint8 *digestInfoPtr = (TUint8*)digestInfo->Ptr();
+        digestInfoPtr+= CPkcs10Req::DERSetTag(digestInfoPtr, (EASN1Sequence | ASN1_CONSTRUCTED));
+        digestInfoPtr+= CPkcs10Req::DERSetLength(digestInfoPtr, digestInfoLength - ASN1_SHORT_TAG_HDR_LTH);
+        digestInfoPtr+= CPkcs10Req::DERSetTag(digestInfoPtr, (EASN1Sequence | ASN1_CONSTRUCTED));
+        digestInfoPtr+= CPkcs10Req::DERSetLength(digestInfoPtr, MD5SIGNATURE_OID_LTH + 2 * ASN1_SHORT_TAG_HDR_LTH);
+        digestInfoPtr+= CPkcs10Req::DERSetTag(digestInfoPtr, EASN1ObjectIdentifier);
+        digestInfoPtr+= CPkcs10Req::DERSetLength(digestInfoPtr, MD5SIGNATURE_OID_LTH);
+        digestInfoPtr+= CPkcs10Req::DERSetOid(digestInfoPtr, (TUint8*)KMd5SignatureOid, MD5SIGNATURE_OID_LTH);
+        digestInfoPtr+= CPkcs10Req::DERSetTag(digestInfoPtr, EASN1Null);
+        digestInfoPtr+= CPkcs10Req::DERSetLength(digestInfoPtr, 0);
+        digestInfoPtr+= CPkcs10Req::DERSetTag(digestInfoPtr, EASN1OctetString);
+        digestInfoPtr+= CPkcs10Req::DERSetLength(digestInfoPtr, hash.Length());
+        digestInfoPtr+= CPkcs10Req::ASNCopy(digestInfoPtr, CONST_CAST(TUint8 *, hash.Ptr()), hash.Length());
+
+        // Sign it
+        // Only RSA supported by now
+        iSignatureAlgorithmId = aSignatureAlgorithmId;
+        aSignCallBackL(
+        	*digestInfo, 
+        	signature, 
+        	aPrivateKeyFilename, 
+        	aSignCallBackContext);
+        CleanupStack::PopAndDestroy( digestInfo );
+
+        // Collect CertificationRequestInfo, signature algoritm identifier (NO OPTIONS)
+        // and signature into PKCS#10 CertificationRequest
+
+        CRBuffer = ASNEncodeCertificationRequestLC(CRInfoBuffer->Des(), signature);
+        if(CRBuffer)
+        {
+            if(aDoBase64)
+            {
+                // Base64 encode the CertificationRequest
+                tempBuffer = base64Codec.Base64EncodeLC(CRBuffer->Des());
+                if(tempBuffer != NULL)
+                {
+                    // Append PEM header and trailer
+                    encodedCRBuffer = HBufC8::NewL(tempBuffer->Length() + HEADERLENGTH + TRAILERLENGTH + 1);
+                    TPtr8 encodedCRBufferPtr = encodedCRBuffer->Des();
+                    if(aDoPEM)
+                    {
+                        encodedCRBufferPtr.Copy(HEADER);
+                        encodedCRBufferPtr.Append(tempBuffer->Des());
+                        encodedCRBufferPtr.Append(TRAILER);
+                    }
+                    else
+                        encodedCRBufferPtr.Copy(tempBuffer->Des());
+                        
+                    CleanupStack::PopAndDestroy(3);  //tempBuffer, CRInfoBuffer, CRBuffer
+                    CleanupStack::PushL(encodedCRBuffer);
+                }
+                else
+                    CleanupStack::PopAndDestroy(2);  //CRInfoBuffer, CRBuffer
+            }
+            else
+            {
+                CleanupStack::Pop(1);
+                CleanupStack::PopAndDestroy(1);  //CRInfoBuffer
+                CleanupStack::PushL(CRBuffer);
+                return (CRBuffer);
+            }
+        }
+        else
+            CleanupStack::PopAndDestroy(1);  //CRInfoBuffer
+    }
+    
+    return (encodedCRBuffer);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////////
+// MD5 hash function
+////////////////////////////////////////////////////////////////////////////////////////
+void CPkcs10Req::MD5_HashL(const TDesC8 &aInData, TDes8& aOutData)
+{
+    CUtlMessageDigest* md5 = TUtlCrypto::MakeMessageDigesterL(TUtlCrypto::EUtlMessageDigestMd5);
+    aOutData.Copy(md5->Final(aInData));
+    delete md5;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// SHA1 hash function
+////////////////////////////////////////////////////////////////////////////////////////
+void CPkcs10Req::SHA1_HashL(const TDesC8 &aInData, TDes8& aOutData)
+{
+    CUtlMessageDigest* sha1 = TUtlCrypto::MakeMessageDigesterL(TUtlCrypto::EUtlMessageDigestSha1);
+    aOutData.Copy(sha1->Final(aInData));
+    delete sha1;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Digest function, calling either MD5 or SHA1 hash
+////////////////////////////////////////////////////////////////////////////////////////
+void CPkcs10Req::DigestL(const TDesC8& aData, TDes8& aDigest, THashType aHashType)
+{
+    if (aHashType == HASH_TYPE_MD5)
+        MD5_HashL(aData, aDigest);
+    else
+        SHA1_HashL(aData, aDigest);
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+//
+//  ASN1 related operations
+//
+///////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////
+// Set ASN1 length
+////////////////////////////////////////////////////////////////////////////////////////
+TInt CPkcs10Req::DERSetLength(TUint8 *p, TInt aLen)
+{
+/*------------------------------------------------------
+ *
+ * Encode length value (max value supported 65535)
+ *
+ *------------------------------------------------------*/
+    TInt CodingLth;
+    aLen &= ASN1_MAX_LENGTH;
+    if ( aLen > 127 )
+    {
+        if ( aLen < 256 )
+        {  
+            *p = 0x81;
+            CodingLth = 2;         
+        }
+        else
+        {
+            *p = 0x82;
+            p ++;
+            *p = (TUint8)((aLen >> 8) & 0xff);
+            CodingLth = 3;
+        }  
+        p ++;        
+    }
+    else
+    {
+        CodingLth = 1;       
+    }
+    *p = (TUint8)(aLen & 0xff);
+
+    return CodingLth;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Set ASN1 integer
+////////////////////////////////////////////////////////////////////////////////////////
+TInt CPkcs10Req::DERSetInteger(TUint8 *p, TInt aValue)
+{
+/*------------------------------------------------------
+ *
+ * Encode Integer value (max value supported 65535)
+ *
+ *------------------------------------------------------*/
+    TInt CodingLth; 
+    aValue &= ASN1_MAX_INTEGER;
+    if ( aValue > 255 ) 
+        CodingLth = CPkcs10Req::DERSetLength(p, 2);
+    else CodingLth = CPkcs10Req::DERSetLength(p, 1);
+
+    p += CodingLth;  //skip length  
+    if ( aValue > 255 ) {
+        *p = (TUint8)((aValue >> 8) & 0xff);
+        p ++;
+        CodingLth ++;
+    }
+    *p = (TUint8)(aValue & 0xff);
+    CodingLth ++;   
+
+    return CodingLth;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Encode Certification Request Info
+////////////////////////////////////////////////////////////////////////////////////////
+HBufC8* CPkcs10Req::ASNEncodeCertificationRequestInfoLC()
+{
+    // Build certificate request info
+    HBufC8  *CRInfoBuffer = NULL;
+    TUint8  *CRInfoPtr;
+    TUint   requestInfoLength;
+    TUint   coverSeqHeaderLength = 2;
+
+    HBufC8 *commonAttributes;
+    HBufC8 *pkiInfo;
+    HBufC8 *extendedAttributes;
+
+    // Build components
+    // Encode common attributes
+    commonAttributes = ASNEncodeCommonAttributesLC();
+    // Encode private key
+    pkiInfo = ASNEncodePKIinfoLC();
+    // Encode common attributes
+    extendedAttributes = ASNEncodeExtendedAttributesLC();
+    
+    requestInfoLength   =  commonAttributes->Length() + pkiInfo->Length() + extendedAttributes->Length() + ASN1_SHORT_TAG_HDR_LTH + 1;  // Fixed one byte version number!
+    
+    if(requestInfoLength > 127)
+        coverSeqHeaderLength++;
+    if(requestInfoLength > 255)
+        coverSeqHeaderLength++;
+    
+    requestInfoLength   =  requestInfoLength + coverSeqHeaderLength;
+
+    if(requestInfoLength > 0)
+    {
+        CRInfoBuffer = HBufC8::NewL(requestInfoLength);
+        CRInfoBuffer->Des().SetLength(requestInfoLength);   
+        CRInfoPtr   = (TUint8*)CRInfoBuffer->Ptr();
+
+        // Build header
+        CRInfoPtr += CPkcs10Req::DERSetTag(CRInfoPtr, (EASN1Sequence | ASN1_CONSTRUCTED));
+        CRInfoPtr += CPkcs10Req::DERSetLength(CRInfoPtr, requestInfoLength - coverSeqHeaderLength);
+        CRInfoPtr += CPkcs10Req::DERSetTag(CRInfoPtr, EASN1Integer);
+        CRInfoPtr += DERSetInteger(CRInfoPtr, 0);       // version
+
+        // Copy component ders
+        if(commonAttributes != NULL && commonAttributes->Length() > 0)
+            CRInfoPtr += CPkcs10Req::ASNCopy(CRInfoPtr, CONST_CAST(TUint8 *, commonAttributes->Ptr()), commonAttributes->Length());
+
+        if(pkiInfo != NULL && pkiInfo->Length() > 0)
+            CRInfoPtr += CPkcs10Req::ASNCopy(CRInfoPtr, CONST_CAST(TUint8 *, pkiInfo->Ptr()), pkiInfo->Length());
+
+        if(extendedAttributes != NULL && extendedAttributes->Length() > 0)
+            CRInfoPtr += CPkcs10Req::ASNCopy(CRInfoPtr, CONST_CAST(TUint8 *, extendedAttributes->Ptr()), extendedAttributes->Length());
+    }
+    
+    if(extendedAttributes != NULL)
+    {
+        delete extendedAttributes;
+        CleanupStack::Pop(1);
+    }
+    if(pkiInfo != NULL)
+    {
+        delete pkiInfo;
+        CleanupStack::Pop(1);
+    }
+    if(commonAttributes != NULL)
+    {
+        delete commonAttributes;
+        CleanupStack::Pop(1);
+    }
+    if(CRInfoBuffer != NULL)
+        CleanupStack::PushL(CRInfoBuffer);      // to be destroyed by the caller
+    
+    return (CRInfoBuffer);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Encode Certification Request
+////////////////////////////////////////////////////////////////////////////////////////
+HBufC8* CPkcs10Req::ASNEncodeCertificationRequestLC(const TDes8 &CRInfoBuffer, const TDes8 &signature)
+{
+    HBufC8 *CRBuffer = NULL;
+    TUint8 *CRPtr;
+    TUint   requestLength;
+    TUint   coverSeqHeaderLength = 2;
+    TUint   signatureLength = 0;
+
+    if(CRInfoBuffer.Length() > 0 && signature.Length() > 0)
+    {
+        signatureLength = signature.Length() + 1; // No padding zero added
+        if(signatureLength > 127)
+            signatureLength++;
+        if(signatureLength > 255)
+            signatureLength++;
+
+        if(iSignatureAlgorithmId == HASH_TYPE_MD5)
+            requestLength = CRInfoBuffer.Length() + signatureLength + 4 * ASN1_SHORT_TAG_HDR_LTH + MD5WITHRSA_OID_LTH;
+        else
+            requestLength = CRInfoBuffer.Length() + signatureLength + 4 * ASN1_SHORT_TAG_HDR_LTH + SHA1WITHRSA_OID_LTH;
+
+        if(requestLength > 127)
+            coverSeqHeaderLength++;
+        if(requestLength > 255)
+            coverSeqHeaderLength++;
+
+        requestLength = requestLength + coverSeqHeaderLength;
+        
+        CRBuffer = HBufC8::NewL(requestLength);
+        CRBuffer->Des().SetLength(requestLength);   
+        CRPtr   = (TUint8*)CRBuffer->Ptr();
+
+        CRPtr += CPkcs10Req::DERSetTag(CRPtr, (EASN1Sequence | ASN1_CONSTRUCTED));
+        CRPtr += CPkcs10Req::DERSetLength(CRPtr, requestLength - coverSeqHeaderLength);
+
+        // Copy Certificate request info
+        CRPtr += CPkcs10Req::ASNCopy(CRPtr, CONST_CAST(TUint8 *, CRInfoBuffer.Ptr()), CRInfoBuffer.Length());
+        CRPtr += CPkcs10Req::DERSetTag(CRPtr, (EASN1Sequence | ASN1_CONSTRUCTED));
+        CRPtr += CPkcs10Req::DERSetLength(CRPtr, MD5WITHRSA_OID_LTH + 2 * ASN1_SHORT_TAG_HDR_LTH);      // null included!
+        // Set algorithm identifier
+        CRPtr += CPkcs10Req::DERSetTag(CRPtr, EASN1ObjectIdentifier);
+        if(iSignatureAlgorithmId == HASH_TYPE_MD5)
+        {
+            CRPtr += CPkcs10Req::DERSetLength(CRPtr, MD5WITHRSA_OID_LTH);
+            CRPtr += CPkcs10Req::DERSetOid(CRPtr, (TUint8*)KMd5WithRSAEncryptionOid, MD5WITHRSA_OID_LTH);
+        }
+        else
+        {
+            CRPtr += CPkcs10Req::DERSetLength(CRPtr, SHA1WITHRSA_OID_LTH);
+            CRPtr += CPkcs10Req::DERSetOid(CRPtr, (TUint8*)KSha1WithRSAEncryptionOid, SHA1WITHRSA_OID_LTH);
+        }
+            
+        CRPtr += CPkcs10Req::DERSetTag(CRPtr, EASN1Null);
+        CRPtr += CPkcs10Req::DERSetLength(CRPtr, 0);
+        // Copy signature
+        CRPtr += CPkcs10Req::DERSetTag(CRPtr, EASN1BitString);
+        CRPtr += CPkcs10Req::DERSetLength(CRPtr, signature.Length() + 1);
+        CRPtr += CPkcs10Req::DERSetLength(CRPtr, 0);    // add 0, no padding
+        CRPtr += CPkcs10Req::ASNCopy(CRPtr, CONST_CAST(TUint8 *, signature.Ptr()), signature.Length());
+
+        CleanupStack::PushL(CRBuffer);          // to be destroyed by the caller
+    }
+    return (CRBuffer);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Encode common attributes
+////////////////////////////////////////////////////////////////////////////////////////
+HBufC8* CPkcs10Req::ASNEncodeCommonAttributesLC()
+{
+    HBufC8 *commonAttributesBuffer = NULL;
+    TUint8 *commonAttributesPtr;
+    TUint distinguishedNameAttrLength;
+    TUint totalLength = 0;
+    TUint coverSeqHeaderLength = 2;
+
+    if(iUseExtendedDistinguishedName)
+    {
+        if(iDNDerBuf != NULL && iDNDerBuf->Des().Length() > 0)
+            commonAttributesBuffer = iDNDerBuf->Des().AllocLC();
+        return (commonAttributesBuffer);
+    }
+    if(iDistinguishedName.Length() == 0)
+        distinguishedNameAttrLength = 0;
+    else
+        distinguishedNameAttrLength = 4 * ASN1_SHORT_TAG_HDR_LTH + COMMON_NAME_OID_LTH + iDistinguishedName.Length();
+    
+    totalLength = distinguishedNameAttrLength;
+    if(totalLength > 127)
+        coverSeqHeaderLength++;
+    if(totalLength > 255)
+        coverSeqHeaderLength++;
+
+    totalLength = totalLength + coverSeqHeaderLength;
+    
+    if(totalLength > 0)
+    {
+        commonAttributesBuffer = HBufC8::NewL(totalLength);
+        commonAttributesBuffer->Des().SetLength(totalLength);
+        commonAttributesPtr = (TUint8*)commonAttributesBuffer->Ptr();
+
+        commonAttributesPtr+= CPkcs10Req::DERSetTag(commonAttributesPtr, (EASN1Sequence | ASN1_CONSTRUCTED));
+        commonAttributesPtr+= CPkcs10Req::DERSetLength(commonAttributesPtr, totalLength - coverSeqHeaderLength);
+        
+        if(iDistinguishedName.Length() > 0)
+        {
+            // Encode common name
+            commonAttributesPtr+= CPkcs10Req::DERSetTag(commonAttributesPtr, (EASN1Set | ASN1_CONSTRUCTED));
+            commonAttributesPtr+= CPkcs10Req::DERSetLength(commonAttributesPtr, distinguishedNameAttrLength - ASN1_SHORT_TAG_HDR_LTH);
+            commonAttributesPtr+= CPkcs10Req::DERSetTag(commonAttributesPtr, (EASN1Sequence | ASN1_CONSTRUCTED));
+            commonAttributesPtr+= CPkcs10Req::DERSetLength(commonAttributesPtr, distinguishedNameAttrLength - 2 * ASN1_SHORT_TAG_HDR_LTH);
+            commonAttributesPtr+= CPkcs10Req::DERSetTag(commonAttributesPtr, EASN1ObjectIdentifier);
+            commonAttributesPtr+= CPkcs10Req::DERSetLength(commonAttributesPtr, COMMON_NAME_OID_LTH);
+            commonAttributesPtr+= CPkcs10Req::DERSetOid(commonAttributesPtr, (TUint8*)KCommonNameOid, COMMON_NAME_OID_LTH);
+            commonAttributesPtr+= CPkcs10Req::DERSetTag(commonAttributesPtr, EASN1UTF8String);
+            commonAttributesPtr+= CPkcs10Req::DERSetLength(commonAttributesPtr, iDistinguishedName.Length());
+            commonAttributesPtr+= CPkcs10Req::ASNCopy(commonAttributesPtr, CONST_CAST(TUint8 *, iDistinguishedName.Ptr()), iDistinguishedName.Length());
+        }
+        CleanupStack::PushL(commonAttributesBuffer);
+    }
+    return (commonAttributesBuffer);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Encode Private key information
+////////////////////////////////////////////////////////////////////////////////////////
+HBufC8* CPkcs10Req::ASNEncodePKIinfoLC()
+{
+    HBufC8 *pkiInfoBuffer = NULL;
+    TUint8 *pkiInfoPtr;
+    TUint entityLength;
+    TUint bitStringHeaderLength = 2;
+    TUint coverSeqHeaderLength = 2;
+    
+    if(iPublicKey.Length() == 0)
+        entityLength = 0;
+    else
+    {
+        entityLength = iPublicKey.Length() + 1;   // Add 1 for padding indicator byte
+        if(entityLength > 127)
+            bitStringHeaderLength++;
+        if(entityLength > 255)
+            bitStringHeaderLength++;
+        
+        entityLength = entityLength + bitStringHeaderLength + 3 * ASN1_SHORT_TAG_HDR_LTH + KEY_TYPE_RSA_OID_LTH;
+        
+        if(entityLength > 127)
+            coverSeqHeaderLength++;
+        if(entityLength > 255)
+            coverSeqHeaderLength++;
+        
+        entityLength = entityLength + coverSeqHeaderLength;
+    }
+
+    if(entityLength > 0)
+    {
+        pkiInfoBuffer = HBufC8::NewL(entityLength);
+        pkiInfoBuffer->Des().SetLength(entityLength);
+        pkiInfoPtr = (TUint8*)pkiInfoBuffer->Ptr();
+
+        pkiInfoPtr+= CPkcs10Req::DERSetTag(pkiInfoPtr, (EASN1Sequence | ASN1_CONSTRUCTED));
+        pkiInfoPtr+= CPkcs10Req::DERSetLength(pkiInfoPtr, entityLength - coverSeqHeaderLength);
+        pkiInfoPtr+= CPkcs10Req::DERSetTag(pkiInfoPtr, (EASN1Sequence | ASN1_CONSTRUCTED));
+        pkiInfoPtr+= CPkcs10Req::DERSetLength(pkiInfoPtr, KEY_TYPE_RSA_OID_LTH + ASN1_SHORT_TAG_HDR_LTH + ASN1_NULL_LTH);
+        // Only RSA key supported
+        pkiInfoPtr+= CPkcs10Req::DERSetTag(pkiInfoPtr, EASN1ObjectIdentifier);
+        pkiInfoPtr+= CPkcs10Req::DERSetLength(pkiInfoPtr, KEY_TYPE_RSA_OID_LTH);
+        pkiInfoPtr+= CPkcs10Req::DERSetOid(pkiInfoPtr, (TUint8*)KKeyTypeRSAOid, KEY_TYPE_RSA_OID_LTH);
+        pkiInfoPtr+= CPkcs10Req::DERSetTag(pkiInfoPtr, EASN1Null);
+        pkiInfoPtr+= CPkcs10Req::DERSetLength(pkiInfoPtr, 0);
+        pkiInfoPtr+= CPkcs10Req::DERSetTag(pkiInfoPtr, EASN1BitString);
+        pkiInfoPtr+= CPkcs10Req::DERSetLength(pkiInfoPtr, iPublicKey.Length() + 1);
+        pkiInfoPtr+= CPkcs10Req::DERSetLength(pkiInfoPtr, 0);   // add 0, no padding
+        pkiInfoPtr+= CPkcs10Req::ASNCopy(pkiInfoPtr, CONST_CAST(TUint8 *, iPublicKey.Ptr()), iPublicKey.Length());
+
+        CleanupStack::PushL(pkiInfoBuffer);
+    }
+    return (pkiInfoBuffer);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Encode Extended attributes
+////////////////////////////////////////////////////////////////////////////////////////
+HBufC8* CPkcs10Req::ASNEncodeExtendedAttributesLC()
+{
+    HBufC8 *extendedAttributesBuffer = NULL;
+    TUint8 *extendedAttributesPtr;
+    TUint challengePWLength;
+    TUint DNSLength;
+    TUint SubAltNLength;
+    TUint emailExtensionLength;
+    TUint totalLength;
+    TUint tempLength;
+    TUint coverTagLength = 2;
+    
+    if(iChallengePW.Length() == 0)
+        challengePWLength = 0;
+    else
+        challengePWLength = 4 * ASN1_SHORT_TAG_HDR_LTH + CHALLENGEPW_OID_LTH + iChallengePW.Length();
+
+    if((iSubjectAltName.Length() == 0) && (iDNSName.Length() == 0))
+        emailExtensionLength = 0;
+    else
+        // Header part
+        emailExtensionLength = 8 * ASN1_SHORT_TAG_HDR_LTH + SUBJECTALTNAME_OID_LTH + PKCS10_EXTENSION_OID_LTH;
+    
+    if(iSubjectAltName.Length() == 0)
+        SubAltNLength = 0;
+    else
+        SubAltNLength = ASN1_SHORT_TAG_HDR_LTH + iSubjectAltName.Length();
+    
+    emailExtensionLength = emailExtensionLength + SubAltNLength;
+
+    if(iDNSName.Length() == 0)
+        DNSLength = 0;
+    else
+        DNSLength = ASN1_SHORT_TAG_HDR_LTH + iDNSName.Length();
+
+    emailExtensionLength = emailExtensionLength + DNSLength;
+    totalLength = challengePWLength + emailExtensionLength;
+
+    if(totalLength > 127)
+        coverTagLength++;
+
+    totalLength = totalLength + coverTagLength;
+    
+    if(totalLength > 0)
+    {
+        extendedAttributesBuffer = HBufC8::NewL(totalLength);
+        extendedAttributesBuffer->Des().SetLength(totalLength);
+        extendedAttributesPtr = (TUint8*)extendedAttributesBuffer->Ptr();
+
+        extendedAttributesPtr+= CPkcs10Req::DERSetTag(extendedAttributesPtr, (EASN1EOC | ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED));
+        extendedAttributesPtr+= CPkcs10Req::DERSetLength(extendedAttributesPtr, totalLength - coverTagLength);
+
+        if(challengePWLength > 0)
+        {
+            // Challenge password
+            extendedAttributesPtr+= CPkcs10Req::DERSetTag(extendedAttributesPtr, (EASN1Sequence | ASN1_CONSTRUCTED));
+            extendedAttributesPtr+= CPkcs10Req::DERSetLength(extendedAttributesPtr, challengePWLength - ASN1_SHORT_TAG_HDR_LTH );
+            extendedAttributesPtr+= CPkcs10Req::DERSetTag(extendedAttributesPtr, EASN1ObjectIdentifier);
+            extendedAttributesPtr+= CPkcs10Req::DERSetLength(extendedAttributesPtr, CHALLENGEPW_OID_LTH);
+            extendedAttributesPtr+= CPkcs10Req::DERSetOid(extendedAttributesPtr, (TUint8*)KChallengePWOid, CHALLENGEPW_OID_LTH);
+            extendedAttributesPtr+= CPkcs10Req::DERSetTag(extendedAttributesPtr, (EASN1Set | ASN1_CONSTRUCTED));
+            extendedAttributesPtr+= CPkcs10Req::DERSetLength(extendedAttributesPtr, iChallengePW.Length() + ASN1_SHORT_TAG_HDR_LTH );
+            extendedAttributesPtr+= CPkcs10Req::DERSetTag(extendedAttributesPtr, (EASN1PrintableString));
+            extendedAttributesPtr+= CPkcs10Req::DERSetLength(extendedAttributesPtr, iChallengePW.Length());
+            extendedAttributesPtr+= CPkcs10Req::ASNCopy(extendedAttributesPtr, CONST_CAST(TUint8 *, iChallengePW.Ptr()), iChallengePW.Length());
+        }
+        
+        if(emailExtensionLength > 0)
+        {
+            // SubjectAltName.Email assumed to be less than 97 bytes
+            extendedAttributesPtr+= CPkcs10Req::DERSetTag(extendedAttributesPtr, (EASN1Sequence | ASN1_CONSTRUCTED));
+            extendedAttributesPtr+= CPkcs10Req::DERSetLength(extendedAttributesPtr, emailExtensionLength - ASN1_SHORT_TAG_HDR_LTH );
+            extendedAttributesPtr+= CPkcs10Req::DERSetTag(extendedAttributesPtr, EASN1ObjectIdentifier);
+            extendedAttributesPtr+= CPkcs10Req::DERSetLength(extendedAttributesPtr, PKCS10_EXTENSION_OID_LTH);
+            extendedAttributesPtr+= CPkcs10Req::DERSetOid(extendedAttributesPtr, (TUint8*)KPkcs10ExtensionOid, PKCS10_EXTENSION_OID_LTH);
+            extendedAttributesPtr+= CPkcs10Req::DERSetTag(extendedAttributesPtr, (EASN1Set | ASN1_CONSTRUCTED));
+            tempLength = SUBJECTALTNAME_OID_LTH + 5 * ASN1_SHORT_TAG_HDR_LTH + DNSLength + SubAltNLength;
+            extendedAttributesPtr+= CPkcs10Req::DERSetLength(extendedAttributesPtr, tempLength);
+            extendedAttributesPtr+= CPkcs10Req::DERSetTag(extendedAttributesPtr, (EASN1Sequence | ASN1_CONSTRUCTED));
+            extendedAttributesPtr+= CPkcs10Req::DERSetLength(extendedAttributesPtr, tempLength - ASN1_SHORT_TAG_HDR_LTH );
+            extendedAttributesPtr+= CPkcs10Req::DERSetTag(extendedAttributesPtr, (EASN1Sequence | ASN1_CONSTRUCTED));
+            extendedAttributesPtr+= CPkcs10Req::DERSetLength(extendedAttributesPtr, tempLength - 2 * ASN1_SHORT_TAG_HDR_LTH);
+            extendedAttributesPtr+= CPkcs10Req::DERSetTag(extendedAttributesPtr, EASN1ObjectIdentifier);
+            extendedAttributesPtr+= CPkcs10Req::DERSetLength(extendedAttributesPtr, SUBJECTALTNAME_OID_LTH);
+            extendedAttributesPtr+= CPkcs10Req::DERSetOid(extendedAttributesPtr, (TUint8*)KSubjectAltNameOid, SUBJECTALTNAME_OID_LTH);
+            extendedAttributesPtr+= CPkcs10Req::DERSetTag(extendedAttributesPtr, EASN1OctetString);
+            extendedAttributesPtr+= CPkcs10Req::DERSetLength(extendedAttributesPtr,  ASN1_SHORT_TAG_HDR_LTH + DNSLength + SubAltNLength);
+            extendedAttributesPtr+= CPkcs10Req::DERSetTag(extendedAttributesPtr, (EASN1Sequence | ASN1_CONSTRUCTED));
+            extendedAttributesPtr+= CPkcs10Req::DERSetLength(extendedAttributesPtr, DNSLength  + SubAltNLength);
+
+            if(SubAltNLength > 0)
+            {
+                extendedAttributesPtr+= CPkcs10Req::DERSetTag(extendedAttributesPtr, (EASN1EOC | ASN1_CONTEXT_SPECIFIC | 0x1));     // context specific 1
+                extendedAttributesPtr+= CPkcs10Req::DERSetLength(extendedAttributesPtr,  iSubjectAltName.Length());
+                extendedAttributesPtr+= CPkcs10Req::ASNCopy(extendedAttributesPtr, CONST_CAST(TUint8 *, iSubjectAltName.Ptr()), iSubjectAltName.Length());
+            }
+            
+            if(DNSLength > 0)
+            {
+                extendedAttributesPtr+= CPkcs10Req::DERSetTag(extendedAttributesPtr, (EASN1EOC | ASN1_CONTEXT_SPECIFIC | 0x2));     // context specific 2
+                extendedAttributesPtr+= CPkcs10Req::DERSetLength(extendedAttributesPtr,  iDNSName.Length());
+                extendedAttributesPtr+= CPkcs10Req::ASNCopy(extendedAttributesPtr, CONST_CAST(TUint8 *, iDNSName.Ptr()), iDNSName.Length());
+            }
+        }
+        CleanupStack::PushL(extendedAttributesBuffer);
+    }
+
+    return (extendedAttributesBuffer);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// ASN1 copy
+////////////////////////////////////////////////////////////////////////////////////////
+TInt CPkcs10Req::ASNCopy(TUint8 *dataPtr, TUint8 *valuePtr, TInt length)
+{
+    Mem::Copy(dataPtr, valuePtr, length);
+    return (length);
+}