cms/src/CCMSSignerInfo.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 26 Jan 2010 15:20:08 +0200
changeset 0 164170e6151a
permissions -rw-r--r--
Revision: 201004

/*
* 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    "CCMSSignerInfo.h"
#include    "TCMSTimeUtil.h"

#include <x500dn.h>
#include <asn1dec.h>
#include <asn1enc.h>
#include <signed.h>

// CONSTANTS
const TInt KMinNumberOfSubModules = 5;
const TInt KMaxNumberOfSubModules = 7;
const TInt KDefaultGranularity = 2;
const TInt KCMSVersion1 = 1;
const TInt KCMSVersion3 = 3;
const TInt KSignedAttrsTag = 0;
const TInt KUnsignedAttrsTag = 1;

// CMS SignedAttributes useful types
_LIT( KContentTypeOID, "1.2.840.113549.1.9.3" );
_LIT( KMessageDigestOID, "1.2.840.113549.1.9.4" );
_LIT( KSignTimeOID, "1.2.840.113549.1.9.5" );

// Additional oid for adding certificates
_LIT( KPKCS9SigCertOID, "1.2.840.113549.1.9.16.2.12" );

// X509 URL certificate OID
_LIT( KURLCertificateOID, "2.23.43.2.1" );

// Defaulta id-data oid
_LIT( KIDDataOID, "1.2.840.113549.1.7.1" );

// ============================ MEMBER FUNCTIONS ===============================

// Destructor
CCMSSignerInfo::CSignerInfoData::~CSignerInfoData()
    {
	delete iIssuerAndSerial;
	delete iSubjectKeyIdentifier;

 	if( iSignedAttributes )
 		{
 		iSignedAttributes->ResetAndDestroy();
		delete iSignedAttributes;
		}

	if( iUnsignedAttributes )
		{
		iUnsignedAttributes->ResetAndDestroy();
		delete iUnsignedAttributes;
		}

	delete iDigestAI;
	delete iSignatureAI;
	delete iSignatureValue;
    }

// -----------------------------------------------------------------------------
// CCMSSignerInfo::CCMSSignerInfo
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
EXPORT_C CCMSSignerInfo::CCMSSignerInfo()
    {
    }

// -----------------------------------------------------------------------------
// CCMSSignerInfo::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
EXPORT_C void CCMSSignerInfo::ConstructL(
	const TDesC8& aCertificateUrl,
	const TDesC8& aSubjectKeyID,
	const TDesC8& aMessageDigest )
    {
	iData = new(ELeave) CSignerInfoData();
	BaseConstructL( aMessageDigest );
	SetCertificateUrlL( aCertificateUrl, aSubjectKeyID );
    }

// -----------------------------------------------------------------------------
// CCMSSignerInfo::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
EXPORT_C void CCMSSignerInfo::ConstructL(
	const CCMSX509Certificate& aCertificate,
	const TDesC8& aMessageDigest )
    {
	iData = new(ELeave) CSignerInfoData();
	BaseConstructL( aMessageDigest );
	SetCertificateL( aCertificate );
    }

void CCMSSignerInfo::BaseConstructL( const TDesC8& aMessageDigest )
	{
	iData->iDigestAI = CCMSX509AlgorithmIdentifier::NewL( ESHA1 );
	iData->iSignatureAI = CCMSX509AlgorithmIdentifier::NewL();
	TTime time;
	time.UniversalTime();
	iData->iSignedAttributes = new(ELeave)CArrayPtrFlat<CCMSAttribute>( KDefaultGranularity );
	SetSignedAttributesL( KIDDataOID(),
						  aMessageDigest,
						  time,
						  NULL );
	iData->iUnsignedAttributes = new(ELeave)CArrayPtrFlat<CCMSAttribute>( KDefaultGranularity );
    SetSignatureValueL( aMessageDigest );
	}

// -----------------------------------------------------------------------------
// CCMSSignerInfo::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
EXPORT_C CCMSSignerInfo* CCMSSignerInfo::NewL()
	{
	// creating with empty values
	CCMSSignerInfo* self = NewL( KNullDesC8(),
								 KNullDesC8(),
								 KNullDesC8() );

	return self;
	}

// -----------------------------------------------------------------------------
// CCMSSignerInfo::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
EXPORT_C CCMSSignerInfo* CCMSSignerInfo::NewL(
	const TDesC8& aCertificateUrl,
	const TDesC8& aSubjectKeyID,
	const TDesC8& aMessageDigest )
    {
    CCMSSignerInfo* self = new( ELeave ) CCMSSignerInfo();
    CleanupStack::PushL( self );
    self->ConstructL( aCertificateUrl, aSubjectKeyID, aMessageDigest );
    CleanupStack::Pop();

    return self;
    }

// -----------------------------------------------------------------------------
// CCMSSignerInfo::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
EXPORT_C CCMSSignerInfo* CCMSSignerInfo::NewL(
	const CCMSX509Certificate& aCertificate,
	const TDesC8& aMessageDigest )
    {
    CCMSSignerInfo* self = new( ELeave ) CCMSSignerInfo();
    CleanupStack::PushL( self );
    self->ConstructL( aCertificate, aMessageDigest );
    CleanupStack::Pop();

    return self;
    }

// Destructor
CCMSSignerInfo::~CCMSSignerInfo()
    {
	delete iData;
    }

// -----------------------------------------------------------------------------
// CCMSSignerInfo::DecodeL
// Decrypts raw data to this instance
// -----------------------------------------------------------------------------
void CCMSSignerInfo::DecodeL( const TDesC8& aRawData )
	{
	CSignerInfoData* tmpData = new(ELeave) CSignerInfoData();
	CleanupStack::PushL( tmpData );
	CArrayPtr<TASN1DecGeneric>* signerInfo = DecodeSequenceLC( aRawData,
															  KMinNumberOfSubModules,
															  KMaxNumberOfSubModules );
	// we would not get this far if there is not min 5 elements
	TInt pos = 0;
	// decode Version
	TASN1DecInteger version;
	tmpData->iVersion = version.DecodeDERShortL( *signerInfo->At( pos++ ) );

	if( tmpData->iVersion == KCMSVersion1 )
		{
		// decode IssuerAndSerialNumber
		tmpData->iIssuerAndSerial =
			CCMSIssuerAndSerialNumber::NewL();
		tmpData->iIssuerAndSerial->DecodeL( signerInfo->At( pos++ )->Encoding() );
		}
	else
		{
		// decode SubjectKeyIdentifier
		TASN1DecOctetString subjectKey;
		tmpData->iSubjectKeyIdentifier =
			subjectKey.DecodeDERL( *signerInfo->At( pos++ ) );
		}

	// decode DigestAlgorithIdentifier
	tmpData->iDigestAI = CCMSX509AlgorithmIdentifier::NewL();
	tmpData->iDigestAI->DecodeL( signerInfo->At( pos++ )->Encoding() );

	// decode possible SignedAttributes
	tmpData->iSignedAttributes =
		new( ELeave )CArrayPtrFlat<CCMSAttribute>( KDefaultGranularity );
	if( signerInfo->At( pos )->Tag() == KSignedAttrsTag )
		{
		DecodeAttributesL( signerInfo->At( pos++ )->Encoding(),
						   tmpData->iSignedAttributes );
		}

	// decode SignatureAlgorithIdentifier
	tmpData->iSignatureAI = CCMSX509AlgorithmIdentifier::NewL();
	tmpData->iSignatureAI->DecodeL( signerInfo->At( pos++ )->Encoding() );

	// check that we have enough parameters for mandatory fields
	if( pos >= signerInfo->Count() )
		{
		User::Leave( KErrArgument );
		}

	// decode SignatureValue
	TASN1DecOctetString signValue;
	tmpData->iSignatureValue = signValue.DecodeDERL( *signerInfo->At( pos++ ) );

	// decode possible UnsignedAttributes
	tmpData->iUnsignedAttributes =
		new( ELeave )CArrayPtrFlat<CCMSAttribute>( KDefaultGranularity );
	if( ( pos < signerInfo->Count() ) &&
		( signerInfo->At( pos )->Tag() == KUnsignedAttrsTag ) )
		{
		DecodeAttributesL( signerInfo->At( pos++ )->Encoding(),
						   tmpData->iUnsignedAttributes );
		}

	CleanupStack::PopAndDestroy( signerInfo );

	delete iData;
	iData = tmpData;
	CleanupStack::Pop( tmpData );
	}

// -----------------------------------------------------------------------------
// CCMSSignerInfo::EncoderLC
// Returns ASN1 encoder for this instance
// -----------------------------------------------------------------------------

CASN1EncBase* CCMSSignerInfo::EncoderLC() const
	{
	CASN1EncSequence* root = CASN1EncSequence::NewLC();

	// Add version
	CASN1EncInt* version = CASN1EncInt::NewLC( iData->iVersion );
	root->AddAndPopChildL( version );

	// Add IssuerAndSerialNumber or SubjectKeyIdentifier
	if( iData->iIssuerAndSerial )
		{
		CASN1EncBase* issuer = iData->iIssuerAndSerial->EncoderLC();
		root->AddAndPopChildL( issuer );
		}
	else
		{
		CASN1EncOctetString* subjectKey =
			CASN1EncOctetString::NewLC( *iData->iSubjectKeyIdentifier );
		root->AddAndPopChildL( subjectKey );
		}

	// Add DigestAlgorithmIdentifier
	CASN1EncBase* digestAlg = iData->iDigestAI->EncoderLC();
	root->AddAndPopChildL( digestAlg );

	// Add SignedAttributes if they exists
	TInt signedAttributes = iData->iSignedAttributes->Count();
	if( signedAttributes > 0 )
		{
		CASN1EncSequence* signedAttributesSet
				= CASN1EncSequence::NewLC();
		signedAttributesSet->SetTag( KSignedAttrsTag );

		for( TInt i = 0; i < signedAttributes; i++ )
			{
			CASN1EncBase* attribute = iData->iSignedAttributes->At( i )->EncoderLC();
			signedAttributesSet->AddAndPopChildL( attribute );
			}
		root->AddAndPopChildL( signedAttributesSet );
		}

	// Add SignatureAlgorithmIdentifier
	CASN1EncBase* signatureAlg =  iData->iSignatureAI->EncoderLC();
	root->AddAndPopChildL( signatureAlg );

	// Add SignatureValue
	CASN1EncOctetString* signValue =
			CASN1EncOctetString::NewLC( *iData->iSignatureValue );
	root->AddAndPopChildL( signValue );

	// Add UnsignedAttributes if they exists
	TInt unsignedAttributes = iData->iUnsignedAttributes->Count();
	if( unsignedAttributes > 0 )
		{
		CASN1EncSequence* unsignedAttributesSet
			= CASN1EncSequence::NewLC();
		unsignedAttributesSet->SetTag( KUnsignedAttrsTag );

		for( TInt i = 0; i < unsignedAttributes; i++ )
			{
			CASN1EncBase* attribute = iData->iUnsignedAttributes->At( i )->EncoderLC();
			unsignedAttributesSet->AddAndPopChildL( attribute );
			}
		root->AddAndPopChildL( unsignedAttributesSet );
		}

	return root;
	}

// -----------------------------------------------------------------------------
// CCMSSignerInfo::CMSVersion()
// Getter for Version
// -----------------------------------------------------------------------------
EXPORT_C TInt CCMSSignerInfo::CMSVersion() const
	{
	return iData->iVersion;
	}

// -----------------------------------------------------------------------------
// CCMSSignerInfo::IssuerAndSerialNumber()
// Getter for IssuerAndSerialNumber
// -----------------------------------------------------------------------------
EXPORT_C const CCMSIssuerAndSerialNumber* CCMSSignerInfo::IssuerAndSerialNumber() const
	{
	return iData->iIssuerAndSerial;
	}

// -----------------------------------------------------------------------------
// CCMSSignerInfo::SubjectKeyIdentifier()
// Getter for SubjectKeyIdentifier
// -----------------------------------------------------------------------------
EXPORT_C const TDesC8* CCMSSignerInfo::SubjectKeyIdentifier() const
	{
	return iData->iSubjectKeyIdentifier;
	}

// -----------------------------------------------------------------------------
// CCMSSignerInfo::DigestAlgorithmIdentifier()
// Getter for DigestAlgorithmIdentifier
// -----------------------------------------------------------------------------
EXPORT_C const CCMSX509AlgorithmIdentifier& CCMSSignerInfo::DigestAlgorithmIdentifier() const
	{
	return *iData->iDigestAI;
	}

// -----------------------------------------------------------------------------
// CCMSSignerInfo::SignedAttributes()
// Getter for SignedAttributes
// -----------------------------------------------------------------------------
EXPORT_C const CArrayPtrFlat<CCMSAttribute>& CCMSSignerInfo::SignedAttributes() const
	{
	return *iData->iSignedAttributes;
	}

// -----------------------------------------------------------------------------
// CCMSSignerInfo::SignedAttributesEncodedL()
// Getter for encoded SignedAttributes
// -----------------------------------------------------------------------------
EXPORT_C HBufC8* CCMSSignerInfo::SignedAttributesEncodedL() const
	{
    HBufC8* retVal = NULL;
	TInt signedAttributes = iData->iSignedAttributes->Count();
	if( signedAttributes > 0 )
		{
		CASN1EncSequence* signedAttributesSet
				= CASN1EncSequence::NewLC();
		signedAttributesSet->SetTag( EASN1Set, EUniversal );

		for( TInt i = 0; i < signedAttributes; i++ )
			{
			CASN1EncBase* attribute = iData->iSignedAttributes->At( i )->EncoderLC();
			signedAttributesSet->AddAndPopChildL( attribute );
			}
        retVal = CreateDerEncodingL( signedAttributesSet );
        CleanupStack::PopAndDestroy( signedAttributesSet );
		}
    return retVal;
	}

// -----------------------------------------------------------------------------
// CCMSSignerInfo::SignatureAlgorithmIdentifier()
// Getter for SignatureAlgorithmIdentifier
// -----------------------------------------------------------------------------
EXPORT_C const CCMSX509AlgorithmIdentifier& CCMSSignerInfo::SignatureAlgorithmIdentifier() const
	{
	return *iData->iSignatureAI;
	}

// -----------------------------------------------------------------------------
// CCMSSignerInfo::SignatureValue()
// Getter for SignatureValue
// -----------------------------------------------------------------------------
EXPORT_C const TDesC8& CCMSSignerInfo::SignatureValue()	 const
	{
	return *iData->iSignatureValue;
	}

// -----------------------------------------------------------------------------
// CCMSSignerInfo::UnsignedAttributes()
// Getter for UnsignedAttributes
// -----------------------------------------------------------------------------
EXPORT_C const CArrayPtrFlat<CCMSAttribute>& CCMSSignerInfo::UnsignedAttributes() const
	{
	return *iData->iUnsignedAttributes;
	}

// -----------------------------------------------------------------------------
// CCMSSignerInfo::SetCertificateL()
// Setter for Certificate
// -----------------------------------------------------------------------------
EXPORT_C void CCMSSignerInfo::SetCertificateL( const CCMSX509Certificate& aCertificate )
	{
	// creating Issuer and serial
	CCMSIssuerAndSerialNumber* tmpIssuer = CCMSIssuerAndSerialNumber::NewL(
														aCertificate.Issuer(),
														aCertificate.SerialNumber() );

	delete iData->iIssuerAndSerial;
	iData->iIssuerAndSerial = tmpIssuer;

	// setting normal certificate, deleting possible certificate url
	// and subject key identifier
	TInt unsignedAttCount = iData->iUnsignedAttributes->Count();
	for( TInt i = 0; i < unsignedAttCount; i++ )
		{
		CCMSAttribute* att = iData->iUnsignedAttributes->At( i );
		if( att->AttributeType() == KURLCertificateOID() )
			{
			iData->iUnsignedAttributes->Delete( i );
			delete att;
			}
		}
	delete iData->iSubjectKeyIdentifier;
	iData->iSubjectKeyIdentifier = NULL;

	// changing version to 1
	iData->iVersion = KCMSVersion1;
	}

// -----------------------------------------------------------------------------
// CCMSSignerInfo::SetCertificateUrlL()
// Setter for certificate URL
// -----------------------------------------------------------------------------
EXPORT_C void CCMSSignerInfo::SetCertificateUrlL( const TDesC8& aCertificateUrl,
												  const TDesC8& aSubjectKeyID )
	{
	CCMSAttribute* certUrl = CreateCertificateUrlLC( aCertificateUrl );
	
	// remove possible URL from unsigned attributes
	TInt unsignedAttCount = iData->iUnsignedAttributes->Count();
	for( TInt i = 0; i < unsignedAttCount; i++ )
		{
		CCMSAttribute* att = iData->iUnsignedAttributes->At( i );
		if( att->AttributeType() == KURLCertificateOID() )
			{
			iData->iUnsignedAttributes->Delete( i );
			delete att;
			}
		}
	iData->iUnsignedAttributes->AppendL( certUrl );
	CleanupStack::Pop( certUrl );

	// taking copy of subject key identifier
	HBufC8* tmpSubjectKeyID = aSubjectKeyID.AllocL();

	delete iData->iSubjectKeyIdentifier;
	iData->iSubjectKeyIdentifier = tmpSubjectKeyID;

	// Issuer and serial is only for real certificates
	delete iData->iIssuerAndSerial;
	iData->iIssuerAndSerial = NULL;

	// changing version to 3
	iData->iVersion = KCMSVersion3;
	}

// -----------------------------------------------------------------------------
// CCMSSignerInfo::SetDigestAlgorithmIdentifier()
// Setter for DigestAlgorithmIdentifier
// -----------------------------------------------------------------------------
EXPORT_C void CCMSSignerInfo::SetDigestAlgorithmIdentifier(
				CCMSX509AlgorithmIdentifier& aDigestAI )
	{
	delete iData->iDigestAI;
	iData->iDigestAI = &aDigestAI;
	}

// -----------------------------------------------------------------------------
// CCMSSignerInfo::SetSignatureAlgorithmIdentifier()
// Setter for SignatureAlgorithmIdentifier
// -----------------------------------------------------------------------------
EXPORT_C void CCMSSignerInfo::SetSignatureAlgorithmIdentifier(
				CCMSX509AlgorithmIdentifier& aSignatureAI )
	{
	delete iData->iSignatureAI;
	iData->iSignatureAI = &aSignatureAI;
	}

// -----------------------------------------------------------------------------
// CCMSSignerInfo::SetSignatureValueL()
// Setter for SignatureValue
// -----------------------------------------------------------------------------
EXPORT_C void CCMSSignerInfo::SetSignatureValueL( const TDesC8& aSignatureValue )
	{
	HBufC8* tmpSignValue = aSignatureValue.AllocL();
	delete iData->iSignatureValue;
	iData->iSignatureValue = tmpSignValue;
	}

// -----------------------------------------------------------------------------
// CCMSSignerInfo::SetSignedAttributesL()
// Setter for Signed attributes
// -----------------------------------------------------------------------------
EXPORT_C void CCMSSignerInfo::SetSignedAttributesL( const TDesC& aContentType,
													const TDesC8& aMessageDigest,
													const TTime& aSigningTime,
													const TDesC8* aCertHash )
	{
	CArrayPtrFlat<CCMSAttribute>* tmpAttributes =
		new(ELeave)CArrayPtrFlat<CCMSAttribute>( KDefaultGranularity );
	CleanupStack::PushL( tmpAttributes );
	CleanupResetAndDestroy< CArrayPtrFlat<CCMSAttribute> >::PushL( *tmpAttributes );


	if( aContentType != KNullDesC() )
		{
		// creating content type
		CASN1EncObjectIdentifier* contOid =
			CASN1EncObjectIdentifier::NewLC( aContentType );
		HBufC8* contentType = CreateDerEncodingL( contOid );
		CleanupStack::PushL( contentType );
		CCMSAttribute* contType = CCMSAttribute::NewLC( KContentTypeOID, *contentType );
		tmpAttributes->AppendL( contType );
		CleanupStack::Pop( contType );
		CleanupStack::PopAndDestroy( contentType );
		CleanupStack::PopAndDestroy( contOid );
		}

	if( aMessageDigest != KNullDesC8() )
		{
		// creating MessageDigest
		CASN1EncOctetString* signature =
			CASN1EncOctetString::NewLC( aMessageDigest );
		HBufC8* messageDigest = CreateDerEncodingL( signature );
		CleanupStack::PushL( messageDigest );
		CCMSAttribute* mDigest = CCMSAttribute::NewLC( KMessageDigestOID, *messageDigest );
		tmpAttributes->AppendL( mDigest );
		CleanupStack::Pop( mDigest );
		CleanupStack::PopAndDestroy( messageDigest );
		CleanupStack::PopAndDestroy( signature );
		}

	// creating Signing time
    CASN1EncBase* signTimeDER = TCMSTimeUtil::ConvertToEncoderLC( aSigningTime );
	HBufC8* signTime = CreateDerEncodingL( signTimeDER );
	CleanupStack::PushL( signTime );
	CCMSAttribute* sTime = CCMSAttribute::NewLC( KSignTimeOID, *signTime );
	tmpAttributes->AppendL( sTime );
	CleanupStack::Pop( sTime );
	CleanupStack::PopAndDestroy( signTime );
	CleanupStack::PopAndDestroy( signTimeDER );

	// are we adding certificates
	if( aCertHash )
		{
		CCMSAttribute* signingCert = 
			CCMSAttribute::NewLC( KPKCS9SigCertOID, *aCertHash );
		tmpAttributes->AppendL( signingCert );
		CleanupStack::Pop( signingCert );
		}

	iData->iSignedAttributes->ResetAndDestroy();
	delete iData->iSignedAttributes;
	iData->iSignedAttributes = tmpAttributes;
	CleanupStack::Pop( tmpAttributes ); // ResetAndDestroy
	CleanupStack::Pop( tmpAttributes );
	}

// -----------------------------------------------------------------------------
// CCMSSignerInfo::SetUnsignedAttributesL()
// Setter for Unsigned attributes
// -----------------------------------------------------------------------------
EXPORT_C void CCMSSignerInfo::SetUnsignedAttributesL(
	CArrayPtrFlat<CCMSAttribute>& aUnsignedAttributes )
	{
	iData->iUnsignedAttributes->ResetAndDestroy();
	delete iData->iUnsignedAttributes;
	iData->iUnsignedAttributes = &aUnsignedAttributes;
	}


// -----------------------------------------------------------------------------
// CCMSSignerInfo::DecodeAttributesL()
// Decodes Attributes to array
// -----------------------------------------------------------------------------
void CCMSSignerInfo::DecodeAttributesL(
	const TDesC8& aRawData,
	CArrayPtrFlat<CCMSAttribute>* aAttributes )
	{
	TASN1DecSet attributeDec;
	TInt pos = 0;
	CArrayPtrFlat<TASN1DecGeneric>* attributes =
		attributeDec.DecodeDERLC( aRawData, pos );

	TInt numOfAttributes = attributes->Count();
	for( TInt i = 0; i < numOfAttributes; i++ )
		{
		CCMSAttribute* att = CCMSAttribute::NewLC();
		att->DecodeL( attributes->At( i )->Encoding() );
		aAttributes->AppendL( att );
		CleanupStack::Pop( att );
		}
	CleanupStack::PopAndDestroy( attributes );
	}

// -----------------------------------------------------------------------------
// CCMSSignerInfo::CreateCertificateUrlLC()
// Creates certificate url attribute
// -----------------------------------------------------------------------------
CCMSAttribute* CCMSSignerInfo::CreateCertificateUrlLC( const TDesC8& aCertificateUrl )
	{
	// Add certificate URL to unsigned attributes
	CASN1EncOctetString* certificateUrlEnc =
		CASN1EncOctetString::NewLC( aCertificateUrl );
	//change tag to IA5
	certificateUrlEnc->SetTag( EASN1IA5String );

	HBufC8* certificateURL = CreateDerEncodingL( certificateUrlEnc );
	CleanupStack::PushL( certificateURL );
	CCMSAttribute* certUrl = CCMSAttribute::NewL( KURLCertificateOID, *certificateURL );
	CleanupStack::PopAndDestroy( certificateURL );
	CleanupStack::PopAndDestroy( certificateUrlEnc );
	CleanupStack::PushL( certUrl );
	return certUrl;
	}
//  End of File