cms/src/CCMSAuthenticatedData.cpp
changeset 0 164170e6151a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cms/src/CCMSAuthenticatedData.cpp	Tue Jan 26 15:20:08 2010 +0200
@@ -0,0 +1,629 @@
+/*
+* Copyright (c) 2002 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: 
+*
+*/
+
+
+// INCLUDE FILES
+#include    "CCMSAuthenticatedData.h"
+#include "CCMSX509AlgorithmIdentifier.h"
+#include "CCMSOriginatorInfo.h"
+#include "CCMSRecipientInfo.h"
+#include "CCMSKeyTransRecipientInfo.h"
+#include "CCMSKeyAgreeRecipientInfo.h"
+#include "CCMSKEKRecipientInfo.h"
+#include "CCMSAttribute.h"
+#include "CCMSX509Certificate.h"
+#include "CCMSCertificateChoices.h"
+#include "CCMSX509CertificateList.h"
+#include <asn1dec.h>
+#include <asn1enc.h>
+
+// CONSTANTS
+const TInt KDefaultGranularity = 1;
+const TInt KMinNumberOfSubModules = 5;
+const TInt KMaxNumberOfSubModules = 9;
+const TTagType KOriginatorInfoTag = 0;
+const TTagType KDigestAlgorithmTag = 1;
+const TTagType KAuthenticatedAttributesTag = 2;
+const TTagType KUnauthenticatedAttributesTag = 3;
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// Destructor
+CCMSAuthenticatedData::CAuthenticatedDataData::~CAuthenticatedDataData()
+    {
+    delete iOriginatorInfo;
+    if( iRecipientInfos )
+        {
+        iRecipientInfos->ResetAndDestroy();
+        delete iRecipientInfos;
+        }
+    delete iMacAlgorithm;
+    delete iDigestAlgorithm;
+    delete iEncapContentInfo;
+    if( iAuthenticatedAttributes )
+        {
+        iAuthenticatedAttributes->ResetAndDestroy();
+        delete iAuthenticatedAttributes;
+        }
+    delete iMac;
+    if( iUnauthenticatedAttributes )
+        {
+        iUnauthenticatedAttributes->ResetAndDestroy();
+        delete iUnauthenticatedAttributes;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::CCMSAuthenticatedData
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CCMSAuthenticatedData::CCMSAuthenticatedData( )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CCMSAuthenticatedData::ConstructL(
+    CArrayPtr< CCMSRecipientInfo >* aRecipientInfos,
+    CCMSX509AlgorithmIdentifier* aMacAlgorithm,
+    CCMSEncapsulatedContentInfo* aEncapContentInfo,
+    const TDesC8& aMac )
+    {
+    iData = new( ELeave ) CAuthenticatedDataData;
+    iData->iMac = aMac.AllocL();
+    
+    // all memory allocations have been done, we can take ownerships
+    iData->iRecipientInfos = aRecipientInfos;
+    iData->iMacAlgorithm = aMacAlgorithm;
+    iData->iEncapContentInfo = aEncapContentInfo;
+    }
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CCMSAuthenticatedData::ConstructL( )
+    {
+    // creating empty/default values
+    iData = new( ELeave ) CAuthenticatedDataData;
+    iData->iRecipientInfos =
+        new( ELeave ) CArrayPtrFlat< CCMSRecipientInfo >( KDefaultGranularity );
+    iData->iMacAlgorithm = CCMSX509AlgorithmIdentifier::NewL();
+    iData->iEncapContentInfo = CCMSEncapsulatedContentInfo::NewL();
+    iData->iMac = KNullDesC8().AllocL();
+    }
+    
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::NewLC
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CCMSAuthenticatedData*
+CCMSAuthenticatedData::NewLC()
+	{
+	// creating with empty values
+    CCMSAuthenticatedData* self =
+        new( ELeave ) CCMSAuthenticatedData();
+    CleanupStack::PushL( self );
+    self->ConstructL( );
+	return self;
+	}
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::NewLC
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CCMSAuthenticatedData*
+CCMSAuthenticatedData::NewLC(
+    CArrayPtr< CCMSRecipientInfo >* aRecipientInfos,
+    CCMSX509AlgorithmIdentifier* aMacAlgorithm,
+    CCMSEncapsulatedContentInfo* aEncapContentInfo,
+    const TDesC8& aMac )
+    {
+    CCMSAuthenticatedData* self =
+        new( ELeave ) CCMSAuthenticatedData();
+    CleanupStack::PushL( self );
+    self->ConstructL( aRecipientInfos, aMacAlgorithm, aEncapContentInfo, aMac );
+
+    return self;
+    }
+
+// Destructor
+CCMSAuthenticatedData::~CCMSAuthenticatedData()
+    {
+	delete iData;
+    }
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::DecodeL
+// Decrypts raw data to this instance
+// -----------------------------------------------------------------------------
+void CCMSAuthenticatedData::DecodeL( const TDesC8& aRawData )
+	{
+    CArrayPtr< TASN1DecGeneric >* items = DecodeSequenceLC(
+        aRawData, KMinNumberOfSubModules, KMaxNumberOfSubModules );
+
+    // now we know that there are at least 5 items
+    TInt itemCount = items->Count();
+    __ASSERT_DEBUG( itemCount >= KMinNumberOfSubModules, User::Invariant() );
+    
+    TInt sequenceCounter = 0;
+
+    CAuthenticatedDataData* data = new( ELeave ) CAuthenticatedDataData;
+    CleanupStack::PushL( data );
+    
+    // decode version
+    TASN1DecInteger intDecoder;
+    data->iVersion =
+        intDecoder.DecodeDERShortL( *items->At( sequenceCounter++ ) );
+
+    // decode originatorInfo, if exist
+    TASN1DecGeneric* originatorInfoDecoder = items->At( sequenceCounter );
+    if( originatorInfoDecoder->Tag() == KOriginatorInfoTag )
+        {
+        data->iOriginatorInfo = CCMSOriginatorInfo::NewL();
+        data->iOriginatorInfo->DecodeImplicitTagL(
+            originatorInfoDecoder->Encoding(), KOriginatorInfoTag );
+        sequenceCounter++;
+        }
+
+    // decode recipientInfos
+    CArrayPtr< TASN1DecGeneric >* recipientInfos = DecodeSequenceLC(
+        items->At( sequenceCounter++)->Encoding() );
+    TInt recipientInfoCount = recipientInfos->Count();
+    data->iRecipientInfos =
+        new( ELeave ) CArrayPtrFlat< CCMSRecipientInfo >( recipientInfoCount );
+    for( TInt i = 0; i < recipientInfoCount; i++ )
+        {
+        TASN1DecGeneric* recipientInfoDecoder = recipientInfos->At( i );
+        CCMSRecipientInfo* recipientInfo = NULL;
+        switch( recipientInfoDecoder->Tag() )
+            {
+            case EASN1Sequence:
+                {
+                recipientInfo = CCMSKeyTransRecipientInfo::NewLC();
+                recipientInfo->DecodeL( recipientInfoDecoder->Encoding() );
+                break;
+                }
+            case KCMSKeyAgreeRecipientInfoTag:
+                {
+                recipientInfo = CCMSKeyAgreeRecipientInfo::NewLC();
+                recipientInfo->DecodeL( recipientInfoDecoder->Encoding() );
+                break;
+                }
+            case KCMSKEKRecipientInfoTag:
+                {
+                recipientInfo = CCMSKEKRecipientInfo::NewLC();
+                recipientInfo->DecodeL( recipientInfoDecoder->Encoding() );
+                break;
+                }
+            default:
+                {
+                User::Leave( KErrArgument );
+                }
+            }
+        data->iRecipientInfos->AppendL( recipientInfo );
+        CleanupStack::Pop( recipientInfo );
+        }
+    CleanupStack::PopAndDestroy( recipientInfos );
+    
+    // decode macAlgorithm
+    data->iMacAlgorithm = CCMSX509AlgorithmIdentifier::NewL();
+    data->iMacAlgorithm->DecodeL( items->At( sequenceCounter++)->Encoding() );
+
+    // decode digestAlgorithm, if exist
+    TASN1DecGeneric* digestAlgorithmDec = items->At( sequenceCounter );
+    if( digestAlgorithmDec->Tag() == KDigestAlgorithmTag )
+        {
+        data->iDigestAlgorithm = CCMSX509AlgorithmIdentifier::NewL();
+        data->iDigestAlgorithm->DecodeL( digestAlgorithmDec->GetContentDER() );
+        sequenceCounter++;
+        }
+
+    // decode encapContentInfo
+    if( sequenceCounter == itemCount )
+        {
+        User::Leave( KErrArgument );
+        }
+    data->iEncapContentInfo = CCMSEncapsulatedContentInfo::NewL();
+    data->iEncapContentInfo->DecodeL(
+        items->At( sequenceCounter++)->Encoding() );
+
+    // decode authenticatedAttributes, if exist
+    if( sequenceCounter == itemCount )
+        {
+        User::Leave( KErrArgument );
+        }
+    TASN1DecGeneric* authAttributesDec = items->At( sequenceCounter );
+    if( authAttributesDec->Tag() == KAuthenticatedAttributesTag )
+        {
+        data->iAuthenticatedAttributes = DecodeAttributesL( authAttributesDec );
+        sequenceCounter++;
+        }
+
+    // decode mac
+    if( sequenceCounter == itemCount )
+        {
+        User::Leave( KErrArgument );
+        }
+    TASN1DecOctetString octetStrDec;
+    data->iMac = octetStrDec.DecodeDERL( *( items->At( sequenceCounter++ ) ) );
+
+    // decode unauthenticatedAttributes, if exist
+    if( itemCount > sequenceCounter )
+        {
+        TASN1DecGeneric* unauthAttributesDec = items->At( sequenceCounter );
+        if( unauthAttributesDec->Tag() != KUnauthenticatedAttributesTag )
+            {
+            User::Leave( KErrArgument );
+            }
+        data->iUnauthenticatedAttributes =
+            DecodeAttributesL( unauthAttributesDec );
+        }
+
+    // all done, change state
+    CleanupStack::Pop( data );
+    CleanupStack::PopAndDestroy( items );
+    delete iData;
+    iData = data;
+	}
+
+
+
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::EncoderLC
+// Returns ASN1 encoder for this instance
+// -----------------------------------------------------------------------------
+CASN1EncBase* CCMSAuthenticatedData::EncoderLC() const
+	{
+    CASN1EncSequence* root = CASN1EncSequence::NewLC();
+
+    // encode version
+    CASN1EncInt* version = CASN1EncInt::NewLC( iData->iVersion );
+    root->AddAndPopChildL( version );
+
+    // encode originatorInfo, if exist
+    if( iData->iOriginatorInfo )
+        {
+        CASN1EncBase* originatorInfo = iData->iOriginatorInfo->EncoderLC();
+        originatorInfo->SetTag( KOriginatorInfoTag );
+        root->AddAndPopChildL( originatorInfo );
+        }
+
+    // encode recipientInfos ::= SET OF RecipientInfo
+    CASN1EncSequence* recipientInfos = CASN1EncSequence::NewLC();
+    TInt recipientInfoCount = iData->iRecipientInfos->Count();
+    TInt i = 0;
+    for( ; i < recipientInfoCount; i++ )
+        {
+        CASN1EncBase* recipientInfo =
+            iData->iRecipientInfos->At( i )->TaggedEncoderLC();
+        recipientInfos->AddAndPopChildL( recipientInfo );
+        }
+    recipientInfos->SetTag( EASN1Set, EUniversal );
+    root->AddAndPopChildL( recipientInfos );
+    
+    // encode macAlgorithm
+    CASN1EncBase* macAlgorithm = iData->iMacAlgorithm->EncoderLC();
+    root->AddAndPopChildL( macAlgorithm );
+
+    // encode digestAlgorithm, if exist
+    if( iData->iDigestAlgorithm )
+        {
+        CASN1EncBase* digestAlgorithm = iData->iDigestAlgorithm->EncoderLC();
+        CleanupStack::Pop( digestAlgorithm );
+        
+        // CASN1EncExplicitTag takes ownership of the parameter, even
+        // if the method leaves.
+        CASN1EncExplicitTag* taggedDigestAlgorithm =
+            CASN1EncExplicitTag::NewLC( digestAlgorithm, KDigestAlgorithmTag );
+        root->AddAndPopChildL( taggedDigestAlgorithm );
+        }
+
+    // encode encapContentInfo
+    CASN1EncBase* encapContentInfo = iData->iEncapContentInfo->EncoderLC();
+    root->AddAndPopChildL( encapContentInfo );
+
+    // encode authenticatedAttributes, if exist
+    if( iData->iAuthenticatedAttributes )
+        {
+        CASN1EncSequence* authAttributes = CASN1EncSequence::NewLC();
+        TInt authAttributeCount = iData->iAuthenticatedAttributes->Count();
+        for( i = 0; i < authAttributeCount; i++ )
+            {
+            CASN1EncBase* attribute =
+                iData->iAuthenticatedAttributes->At( i )->EncoderLC();
+            authAttributes->AddAndPopChildL( attribute );
+            }
+        authAttributes->SetTag( KAuthenticatedAttributesTag );
+        root->AddAndPopChildL( authAttributes );
+        }
+
+    // encode mac
+    CASN1EncOctetString* mac = CASN1EncOctetString::NewLC( *iData->iMac );
+    root->AddAndPopChildL( mac );
+    
+    // encode unauthenticatedAttributes, if exist
+    if( iData->iUnauthenticatedAttributes )
+        {
+        CASN1EncSequence* unauthAttributes = CASN1EncSequence::NewLC();
+        TInt unauthAttributeCount = iData->iUnauthenticatedAttributes->Count();
+        for( i = 0; i < unauthAttributeCount; i++ )
+            {
+            CASN1EncBase* attribute =
+                iData->iUnauthenticatedAttributes->At( i )->EncoderLC();
+            unauthAttributes->AddAndPopChildL( attribute );
+            }
+        unauthAttributes->SetTag( KUnauthenticatedAttributesTag );
+        root->AddAndPopChildL( unauthAttributes );
+        }
+    
+    return root;
+    }
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::Version()
+// Getter for Version
+// -----------------------------------------------------------------------------
+EXPORT_C TInt CCMSAuthenticatedData::Version() const
+	{
+	return iData->iVersion;
+	}
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::OriginatorInfo()
+// Getter for OriginatorInfo
+// -----------------------------------------------------------------------------
+EXPORT_C const CCMSOriginatorInfo* CCMSAuthenticatedData::OriginatorInfo() const
+	{
+	return iData->iOriginatorInfo;
+	}
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::RecipientInfos()
+// Getter for recipientInfos
+// -----------------------------------------------------------------------------
+EXPORT_C const CArrayPtr< CCMSRecipientInfo >&
+CCMSAuthenticatedData::RecipientInfos() const
+	{
+	return *( iData->iRecipientInfos );
+	}
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::MacAlgorithm()
+// Getter for macAlgorithm
+// -----------------------------------------------------------------------------
+EXPORT_C const CCMSX509AlgorithmIdentifier&
+CCMSAuthenticatedData::MacAlgorithm() const
+	{
+	return *( iData->iMacAlgorithm );
+	}
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::DigestAlgorithm()
+// Getter for digestAlgorithm
+// -----------------------------------------------------------------------------
+EXPORT_C const CCMSX509AlgorithmIdentifier*
+CCMSAuthenticatedData::DigestAlgorithm() const
+	{
+	return iData->iDigestAlgorithm;
+	}
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::EncapContentInfo()
+// Getter for encapContentInfo
+// -----------------------------------------------------------------------------
+EXPORT_C const CCMSEncapsulatedContentInfo&
+CCMSAuthenticatedData::EncapContentInfo() const
+	{
+	return *( iData->iEncapContentInfo );
+	}
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::AuthenticatedAttributes()
+// Getter for authenticatedAttributes
+// -----------------------------------------------------------------------------
+EXPORT_C const CArrayPtr< CCMSAttribute >*
+CCMSAuthenticatedData::AuthenticatedAttributes() const
+	{
+	return iData->iAuthenticatedAttributes;
+	}
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::Mac()
+// Getter for mac
+// -----------------------------------------------------------------------------
+EXPORT_C const TDesC8& CCMSAuthenticatedData::Mac() const
+	{
+	return *( iData->iMac );
+	}
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::UnauthenticatedAttributes()
+// Getter for unauthenticatedAttributes
+// -----------------------------------------------------------------------------
+EXPORT_C const CArrayPtr< CCMSAttribute >*
+CCMSAuthenticatedData::UnauthenticatedAttributes() const
+	{
+	return iData->iUnauthenticatedAttributes;
+	}
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::SetVersion()
+// Setter for version
+// -----------------------------------------------------------------------------
+EXPORT_C void CCMSAuthenticatedData::SetVersion( TInt aVersion )
+	{
+    iData->iVersion = aVersion;
+	}
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::SetOriginatorInfoL()
+// Setter for OriginatorInfo
+// -----------------------------------------------------------------------------
+EXPORT_C void CCMSAuthenticatedData::SetOriginatorInfoL(
+    CCMSOriginatorInfo* aOriginatorInfo )
+	{
+    delete iData->iOriginatorInfo;
+    iData->iOriginatorInfo = aOriginatorInfo;
+	}
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::SetRecipientInfosL()
+// Setter for recipientInfos
+// -----------------------------------------------------------------------------
+EXPORT_C void CCMSAuthenticatedData::SetRecipientInfosL(
+    CArrayPtr< CCMSRecipientInfo >* aRecipientInfos )
+	{
+    if( ( !aRecipientInfos ) || ( aRecipientInfos->Count() == 0 ) )
+        {
+        User::Leave( KErrArgument );
+        }
+    
+    if( iData->iRecipientInfos )
+        {
+        iData->iRecipientInfos->ResetAndDestroy();
+        delete iData->iRecipientInfos;
+        }
+    iData->iRecipientInfos = aRecipientInfos;
+	}
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::SetMacAlgorithmL()
+// Setter for macAlgorithm
+// -----------------------------------------------------------------------------
+EXPORT_C void CCMSAuthenticatedData::SetMacAlgorithmL(
+    CCMSX509AlgorithmIdentifier* aMacAlgorithm )
+	{
+    if( !aMacAlgorithm )
+        {
+        User::Leave( KErrArgument );
+        }
+    delete iData->iMacAlgorithm;
+    iData->iMacAlgorithm = aMacAlgorithm;
+	}
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::SetDigestAlgorithmL()
+// Setter for digestAlgorithm
+// -----------------------------------------------------------------------------
+EXPORT_C void CCMSAuthenticatedData::SetDigestAlgorithmL(
+    CCMSX509AlgorithmIdentifier* aDigestAlgorithm )
+	{
+    delete iData->iDigestAlgorithm;
+    iData->iDigestAlgorithm = aDigestAlgorithm;
+	}
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::SetEncapContentInfoL()
+// Setter for encapContentInfo
+// -----------------------------------------------------------------------------
+EXPORT_C void CCMSAuthenticatedData::SetEncapContentInfoL(
+    CCMSEncapsulatedContentInfo* aEncapContentInfo )
+	{
+    if( !aEncapContentInfo )
+        {
+        User::Leave( KErrArgument );
+        }
+    delete iData->iEncapContentInfo;
+    iData->iEncapContentInfo = aEncapContentInfo;
+	}
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::SetAuthenticatedAttributesL()
+// Setter for authenticatedAttributes
+// -----------------------------------------------------------------------------
+EXPORT_C void CCMSAuthenticatedData::SetAuthenticatedAttributesL(
+    CArrayPtr< CCMSAttribute >* aAuthenticatedAttributes )
+	{
+    if( iData->iAuthenticatedAttributes )
+        {
+        iData->iAuthenticatedAttributes->ResetAndDestroy();
+        delete iData->iAuthenticatedAttributes;
+        }
+    iData->iAuthenticatedAttributes = aAuthenticatedAttributes;
+	}
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::SetMacL
+// Setter for mac
+// -----------------------------------------------------------------------------
+EXPORT_C void CCMSAuthenticatedData::SetMacL(
+    const TDesC8& aMac)
+	{
+    HBufC8* mac = aMac.AllocL();
+    delete iData->iMac;
+    iData->iMac = mac;
+	}
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::SetUnauthenticatedAttributesL()
+// Setter for unauthenticatedAttributes
+// -----------------------------------------------------------------------------
+EXPORT_C void CCMSAuthenticatedData::SetUnauthenticatedAttributesL(
+    CArrayPtr< CCMSAttribute >* aUnauthenticatedAttributes )
+	{
+    if( iData->iUnauthenticatedAttributes )
+        {
+        iData->iUnauthenticatedAttributes->ResetAndDestroy();
+        delete iData->iUnauthenticatedAttributes;
+        }
+    iData->iUnauthenticatedAttributes = aUnauthenticatedAttributes;
+	}
+
+// -----------------------------------------------------------------------------
+// CCMSAuthenticatedData::DecodeAttributesL
+// Decodes an array of attributes
+// -----------------------------------------------------------------------------
+CArrayPtrFlat< CCMSAttribute >* CCMSAuthenticatedData::DecodeAttributesL(
+    TASN1DecGeneric* aAttributesDec ) // generic decoder for the sequence
+    {
+    TASN1DecSequence sequenceDecoder;
+    CArrayPtr< TASN1DecGeneric >* attributes =
+        sequenceDecoder.DecodeDERLC( *aAttributesDec );
+    TInt attributeCount = attributes->Count();
+    if( attributeCount <  1 )
+        {
+        User::Leave( KErrArgument );
+        }
+    CArrayPtrFlat< CCMSAttribute >* retVal =
+        new( ELeave ) CArrayPtrFlat< CCMSAttribute >( attributeCount );
+    CleanupStack::PushL( retVal );
+    for( TInt i = 0; i < attributeCount; i++ )
+        {
+        CCMSAttribute* attribute = CCMSAttribute::NewLC();
+        attribute->DecodeL( attributes->At( i )->Encoding() );
+        retVal->AppendL( attribute );
+        // attribute is left in cleanup stack, as retVal has not been pushed
+        // with ResetAndDestroyPushL
+        }
+    CleanupStack::Pop( attributeCount ); // all attributes
+    CleanupStack::Pop( retVal );
+    CleanupStack::PopAndDestroy( attributes );
+    return retVal;
+    }
+
+//  End of File