--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/omadrm/drmlicensemanager/src/DRMLicenseManager.cpp Thu Dec 17 08:52:27 2009 +0200
@@ -0,0 +1,814 @@
+/*
+* Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Implementation of the license manager functionality used in the
+* install process
+*
+*/
+
+
+// INCLUDE FILES
+#include <e32std.h>
+#include <e32base.h>
+#include <apmstd.h>
+#include <e32math.h>
+#include <f32file.h>
+#include <s32buf.h>
+#include <s32crypt.h>
+#include <utf.h>
+#include <DrmRights.h>
+#include <DrmCommon.h>
+#include <Oma1DcfCreator.h>
+#include <SysUtil.h> // Disk space checking
+
+#include "ZipFile.h"
+#include "ZipFileMemberIterator.h"
+#include "DRMLicenseManager.h"
+
+// LOCAL CONSTANTS AND MACROS
+_LIT(KDefinitionFileName, "datafiles.def");
+_LIT(KSISSuffix, ".sis");
+_LIT(KSISXSuffix, ".sisx");
+_LIT8(KDefaultMIMEType, "application/binary");
+_LIT8( KIssuer , "Rights-Issuer" );
+
+const TInt KSISBufferSize = 512;
+const TInt KMaxTypeLength = 11 + 2; // Length of "application" + CR + LF
+const TInt KMaxFileDescriptionLength = KMaxPath + KMaxPath + KMaxDataTypeLength;
+
+
+// ============================ LOCAL FUNCTIONS ================================
+// -----------------------------------------------------------------------------
+// DriveOfPathL
+// -----------------------------------------------------------------------------
+LOCAL_C inline TInt DriveOfPathL(
+ RFs& aFs,
+ const TDesC aPathName,
+ TInt aFallbackDrive = KDefaultDrive )
+ {
+ // find drive for destination for free space check
+ TInt driveNumber( KDefaultDrive );
+ TParsePtrC pptr( aPathName );
+ TInt err( KErrNone );
+ if ( pptr.DrivePresent() )
+ {
+ err = RFs::CharToDrive( pptr.Drive()[ 0 ], driveNumber );
+ User::LeaveIfError( err );
+ }
+ else if ( aFallbackDrive != KDefaultDrive )
+ {
+ driveNumber = aFallbackDrive;
+ }
+ else
+ {
+ HBufC* sessionPath( HBufC::NewLC( KMaxPath ) );
+ TPtr pathPtr( sessionPath->Des() );
+ User::LeaveIfError( aFs.SessionPath( pathPtr ) );
+
+ TParsePtrC sPPtr( pathPtr );
+ if ( sPPtr.DrivePresent() )
+ {
+ err = RFs::CharToDrive( sPPtr.Drive()[ 0 ], driveNumber );
+ User::LeaveIfError( err );
+ }
+ else
+ {
+ driveNumber = RFs::GetSystemDrive();
+ }
+ CleanupStack::PopAndDestroy( sessionPath );
+ }
+ return driveNumber;
+ }
+
+// -----------------------------------------------------------------------------
+// CheckNeededFreeSpaceL
+// -----------------------------------------------------------------------------
+LOCAL_C void CheckNeededFreeSpaceL(
+ RFs& aFs,
+ CZipFile*& aZipFile,
+ RPointerArray< TDRMDataFile >& aDataFiles,
+ const TDesC& aDestination,
+ TInt& aError )
+ {
+ static const TInt KExtraSpaceForDcf( 1024 );
+ CArrayFixFlat< TInt >* arrayOfNeededSpaces( NULL );
+ // Get target drive for relative files
+ TInt driveForRelativePath( DriveOfPathL( aFs, aDestination ) );
+
+ arrayOfNeededSpaces = new ( ELeave ) CArrayFixFlat< TInt >( KMaxDrives );
+ CleanupStack::PushL( arrayOfNeededSpaces );
+
+ arrayOfNeededSpaces->SetReserveL( KMaxDrives );
+ for ( TInt j( 0 ); j < KMaxDrives; ++j )
+ {
+ arrayOfNeededSpaces->AppendL(0);
+ }
+
+ for ( TInt i = 0; i < aDataFiles.Count() && aError == KErrNone; i++ )
+ {
+ TDRMDataFile* dataFile(
+ static_cast< TDRMDataFile* >( aDataFiles[ i ] ) );
+ CZipFileMember* member(
+ aZipFile->CaseInsensitiveMemberL( dataFile->iSourceName ) );
+ if ( member )
+ {
+ CleanupStack::PushL( member );
+ TInt driveNumber( DriveOfPathL(
+ aFs, dataFile->iTargetName, driveForRelativePath ) );
+ ( *arrayOfNeededSpaces )[ driveNumber ] +=
+ member->UncompressedSize() + KExtraSpaceForDcf;
+ CleanupStack::PopAndDestroy( member );
+ }
+ else
+ {
+ aError = CDRMLicenseManager::EPIPInvalid;
+ }
+ }
+
+ for ( TInt j( 0 ); j < KMaxDrives; ++j )
+ {
+ TUint element( ( *arrayOfNeededSpaces )[ j ] );
+ if ( element && // no need to check if no space required
+ SysUtil::DiskSpaceBelowCriticalLevelL( &aFs, element, j) )
+ {
+ User::Leave( KErrDiskFull );
+ }
+ }
+ CleanupStack::PopAndDestroy( arrayOfNeededSpaces );
+ }
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CDRMLicenseManager::CDRMLicenseManager
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CDRMLicenseManager::CDRMLicenseManager():
+ iFs(NULL), iRights(NULL), iRightsIssuer(NULL)
+ {
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMLicenseManager::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CDRMLicenseManager::ConstructL()
+ {
+ iFs = new RFs();
+ User::LeaveIfNull(iFs);
+ User::LeaveIfError(iFs->Connect());
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMLicenseManager::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CDRMLicenseManager* CDRMLicenseManager::NewL()
+ {
+ CDRMLicenseManager* self = new( ELeave ) CDRMLicenseManager;
+
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop( self );
+
+ return self;
+ }
+
+
+// Destructor
+EXPORT_C CDRMLicenseManager::~CDRMLicenseManager()
+ {
+ iFs->Close();
+ delete iFs;
+
+ iDataFiles.ResetAndDestroy();
+
+ if (iZipFile)
+ {
+ iZipFile->Close();
+ delete iZipFile;
+ }
+
+ if (iRights)
+ {
+ delete iRights;
+ }
+
+ if (iRightsIssuer)
+ {
+ delete iRightsIssuer;
+ }
+ }
+
+LOCAL_C TBool GetRightsIssuerL(const TFileName aFileName, HBufC8*& aRightsIssuerURL)
+ {
+ TInt err(KErrNotFound);
+
+ HBufC8* name = HBufC8::NewLC(16);
+ TPtr8 headerName( name->Des() );
+ headerName.Copy( KIssuer );
+
+ DRMCommon* c = DRMCommon::NewL();
+ CleanupStack::PushL(c);
+ err = c->GetFileHeader(aFileName, headerName, aRightsIssuerURL);
+ CleanupStack::PopAndDestroy(c);
+ CleanupStack::PopAndDestroy(name);
+
+ if(err == DRMCommon::EOk && aRightsIssuerURL)
+ {
+ return ETrue;
+ }
+
+ return EFalse;
+ }
+
+LOCAL_C TBool GetRightsIssuerL(RFile aFileName, HBufC8*& aRightsIssuerURL)
+ {
+ TInt err(KErrNotFound);
+
+ HBufC8* name = HBufC8::NewLC(16);
+ TPtr8 headerName( name->Des() );
+ headerName.Copy( KIssuer );
+
+ DRMCommon* c = DRMCommon::NewL();
+ CleanupStack::PushL(c);
+ err = c->GetFileHeader(aFileName, headerName, aRightsIssuerURL);
+ CleanupStack::PopAndDestroy(c);
+ CleanupStack::PopAndDestroy(name);
+
+ if(err == DRMCommon::EOk && aRightsIssuerURL)
+ {
+ return ETrue;
+ }
+
+ return EFalse;
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMLicenseManager::ProcessL
+// Read the PIP definition file and encrypt each referenced data file
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CDRMLicenseManager::ProcessL(
+ const TDesC& aZIPFile,
+ const TDesC& aDestination)
+ {
+ TInt r = KErrNone;
+ DRMCommon* drm = NULL;
+ RPointerArray<CDRMRights>* rights = NULL;
+
+ // Clean up
+ if (iZipFile)
+ {
+ iZipFile->Close();
+ delete iZipFile;
+ iZipFile = NULL;
+ }
+
+ if (iRights)
+ {
+ delete iRights;
+ iRights = NULL;
+ }
+
+ if (iRightsIssuer)
+ {
+ delete iRightsIssuer;
+ iRightsIssuer = NULL;
+ }
+
+ GetRightsIssuerL(aZIPFile, iRightsIssuer);
+
+ iDataFiles.ResetAndDestroy();
+
+ // Get rights object for the PIP file
+ iZipFile = CZipFile::NewL(*iFs, aZIPFile);
+ drm = DRMCommon::NewL();
+ CleanupStack::PushL(drm);
+ r = drm->GetDetailedFileRights(aZIPFile, rights);
+
+ // Read the definition file
+ if (r == KErrNone)
+ {
+ iRights = (*rights)[0];
+ rights->Remove(0);
+ rights->ResetAndDestroy();
+ delete rights;
+ r = ReadDefinitionFileL();
+ }
+
+ // Process data files
+ if (r == KErrNone)
+ {
+ r = ProcessDataFilesL(aDestination);
+ }
+
+ CleanupStack::PopAndDestroy(drm);
+
+ return r;
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMLicenseManager::ProcessL
+// Read the PIP definition file and encrypt each referenced data file
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CDRMLicenseManager::ProcessL(
+ RFile& aZIPFile,
+ const TDesC& aDestination)
+ {
+ TInt r = KErrNone;
+ DRMCommon* drm = NULL;
+ RPointerArray<CDRMRights>* rights = NULL;
+
+ // Clean up
+ if (iZipFile)
+ {
+ iZipFile->Close();
+ delete iZipFile;
+ iZipFile = NULL;
+ }
+
+ if (iRights)
+ {
+ delete iRights;
+ iRights = NULL;
+ }
+
+ if (iRightsIssuer)
+ {
+ delete iRightsIssuer;
+ iRightsIssuer = NULL;
+ }
+
+ GetRightsIssuerL(aZIPFile, iRightsIssuer);
+
+ iDataFiles.ResetAndDestroy();
+
+ // Get rights object for the PIP file
+ iZipFile = CZipFile::NewL(*iFs, aZIPFile);
+ drm = DRMCommon::NewL();
+ CleanupStack::PushL(drm);
+ r = drm->GetDetailedFileRights(aZIPFile, rights);
+
+ // Read the definition file
+ if (r == KErrNone)
+ {
+ iRights = (*rights)[0];
+ rights->Remove(0);
+ rights->ResetAndDestroy();
+ delete rights;
+ r = ReadDefinitionFileL();
+ }
+
+ // Process data files
+ if (r == KErrNone)
+ {
+ r = ProcessDataFilesL(aDestination);
+ }
+
+ CleanupStack::PopAndDestroy(drm);
+
+ return r;
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMLicenseManager::ExtractSISFileL
+// Find the SIS member of the ZIP file and write it to the target destination.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CDRMLicenseManager::ExtractSISFileL(
+ const TDesC& aZIPFile,
+ const TDesC& aDestination)
+ {
+ CZipFileMember* sisFile = NULL;
+ TInt r = KErrNone;
+
+ if (iZipFile)
+ {
+ iZipFile->Close();
+ delete iZipFile;
+ iZipFile = NULL;
+ }
+
+ if (iRightsIssuer)
+ {
+ delete iRightsIssuer;
+ iRightsIssuer = NULL;
+ }
+
+ GetRightsIssuerL(aZIPFile, iRightsIssuer);
+
+ iZipFile = CZipFile::NewL(*iFs, aZIPFile);
+
+ __UHEAP_MARK;
+ sisFile = GetSISMemberL();
+
+ if (sisFile)
+ {
+ WriteSISMemberL(sisFile, aDestination);
+ delete sisFile;
+ }
+ else
+ {
+ r = ESISNotFound;
+ }
+ __UHEAP_MARKEND;
+
+ return r;
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMLicenseManager::ExtractSISFileL
+// Find the SIS member of the ZIP file and write it to the target destination.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CDRMLicenseManager::ExtractSISFileL(
+ RFile& aZIPFile,
+ const TDesC& aDestination)
+ {
+ CZipFileMember* sisFile = NULL;
+ TInt r = KErrNone;
+
+ if (iZipFile)
+ {
+ iZipFile->Close();
+ delete iZipFile;
+ iZipFile = NULL;
+ }
+
+ if (iRightsIssuer)
+ {
+ delete iRightsIssuer;
+ iRightsIssuer = NULL;
+ }
+
+ GetRightsIssuerL(aZIPFile, iRightsIssuer);
+
+ iZipFile = CZipFile::NewL(*iFs, aZIPFile);
+
+ __UHEAP_MARK;
+ sisFile = GetSISMemberL();
+
+ if (sisFile)
+ {
+ WriteSISMemberL(sisFile, aDestination);
+ delete sisFile;
+ }
+ else
+ {
+ r = ESISNotFound;
+ }
+ __UHEAP_MARKEND;
+
+ return r;
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMLicenseManager::GetSISMemberL
+// Finds the SIS member in the ZIP file by looking for the .sis file ending.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CZipFileMember* CDRMLicenseManager::GetSISMemberL(void)
+ {
+ CZipFileMemberIterator* members = NULL;
+ CZipFileMember* sisFile = NULL;
+ CZipFileMember* member = NULL;
+
+ members = iZipFile->GetMembersL();
+ CleanupStack::PushL(members);
+
+ member = members->NextL();
+
+ while (member && !sisFile)
+ {
+ if (member->Name()->Right(4).CompareF(KSISSuffix) == 0)
+ {
+ sisFile = member;
+ }
+ else if (member->Name()->Right(5).CompareF(KSISXSuffix) == 0)
+ {
+ sisFile = member;
+ }
+ else
+ {
+ delete member;
+ member = NULL;
+ member = members->NextL();
+ }
+ }
+
+ CleanupStack::PopAndDestroy(members);
+
+ if(!sisFile)
+ {
+ User::Leave(KErrNotFound);
+ }
+
+ return sisFile;
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMLicenseManager::WriteSISMemberL
+// Write a SIS member to disk.
+// -----------------------------------------------------------------------------
+//
+void CDRMLicenseManager::WriteSISMemberL(
+ CZipFileMember* aSisMember,
+ const TDesC& aDestination)
+ {
+ RZipFileMemberReaderStream* input = NULL;
+ RFileWriteStream output;
+ TBuf8<KSISBufferSize> buffer;
+
+ // Check free space and leave if not enough space available
+ if ( SysUtil::DiskSpaceBelowCriticalLevelL(
+ iFs,
+ aSisMember->UncompressedSize(),
+ DriveOfPathL( *iFs, aDestination ) ) )
+ {
+ User::Leave( KErrDiskFull );
+ }
+
+ iZipFile->GetInputStreamL(aSisMember, input);
+ CleanupStack::PushL(input);
+
+ iFs->SetSessionPath(aDestination);
+ User::LeaveIfError(output.Replace(*iFs, *aSisMember->Name(), EFileWrite));
+ output.PushL();
+ do
+ {
+ input->Read(buffer, KSISBufferSize);
+ if (buffer.Size() > 0)
+ {
+ output.WriteL(buffer);
+ }
+ }
+ while (buffer.Size() > 0);
+ output.Close();
+
+ CleanupStack::PopAndDestroy(&output);
+ CleanupStack::PopAndDestroy(input);
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMLicenseManager::ReadDefinitionFileL
+// Read the PIP type and definition lines from the definition file.
+// -----------------------------------------------------------------------------
+//
+TInt CDRMLicenseManager::ReadDefinitionFileL(void)
+ {
+ CZipFileMember* definitionFile = NULL;
+ RZipFileMemberReaderStream* input = NULL;
+ TBuf8<KMaxTypeLength> type;
+ TInt r = KErrNone;
+
+ TRAP(r, definitionFile =
+ iZipFile->CaseInsensitiveMemberL(KDefinitionFileName));
+
+ if (r == KErrNone && definitionFile)
+ {
+ CleanupStack::PushL(definitionFile);
+ iZipFile->GetInputStreamL(definitionFile, input);
+ ReadLine(input, type);
+ while (r == KErrNone)
+ {
+ r = ReadFileDescription(input);
+ }
+ delete input;
+ CleanupStack::PopAndDestroy(definitionFile);
+ }
+ else
+ {
+ r = EPIPInvalid;
+ }
+
+ if (r == KErrEof)
+ {
+ r = KErrNone;
+ }
+
+ return r;
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMLicenseManager::ReadFileDescription
+// Read the name, type and target name of a data file.
+// -----------------------------------------------------------------------------
+//
+TInt CDRMLicenseManager::ReadFileDescription(
+ RZipFileMemberReaderStream* aStream)
+ {
+ TBuf8<KMaxFileDescriptionLength> description;
+ TInt r = KErrNone;
+ TDRMDataFile* dataFile = NULL;
+
+ ReadLine(aStream, description);
+ description.TrimAll();
+ if (description.Length() > 0)
+ {
+ TLex8 lex(description);
+
+ dataFile = new TDRMDataFile();
+ if( !dataFile )
+ {
+ return KErrNoMemory;
+ }
+
+ // Get the original file name
+ lex.SkipSpaceAndMark();
+ lex.SkipCharacters();
+ CnvUtfConverter::ConvertToUnicodeFromUtf8(
+ dataFile->iSourceName, lex.MarkedToken());
+
+ // Get the MIME type. If not present, "application/binary" is used
+ // and the target file name is the source file name
+ lex.SkipSpaceAndMark();
+ lex.SkipCharacters();
+ if (lex.TokenLength() > 0)
+ {
+ dataFile->iMimeType = lex.MarkedToken();
+
+ // Get the target file name. If not present, the target file name
+ // will be the original file name, stored in the install directory.
+ lex.SkipSpaceAndMark();
+ lex.SkipCharacters();
+ if (lex.TokenLength() > 0)
+ {
+ CnvUtfConverter::ConvertToUnicodeFromUtf8(
+ dataFile->iTargetName, lex.MarkedToken());
+ }
+ else
+ {
+ dataFile->iTargetName = dataFile->iSourceName;
+ }
+ }
+ else
+ {
+ dataFile->iMimeType = KDefaultMIMEType;
+ dataFile->iTargetName = dataFile->iSourceName;
+ }
+
+ iDataFiles.Append(dataFile);
+ }
+ else
+ {
+ r = KErrEof;
+ }
+ return r;
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMLicenseManager::ReadLine
+// Read one line ending with 0x0d or until the input buffer is full.
+// -----------------------------------------------------------------------------
+//
+void CDRMLicenseManager::ReadLine(
+ RZipFileMemberReaderStream* aStream,
+ TDes8& aLine)
+ {
+ TBuf8<1> c;
+ TInt n = 0;
+ TBool done = EFalse;
+
+ while (!done)
+ {
+ if (aLine.Length() < aLine.MaxLength())
+ {
+ aStream->Read(c, 1);
+ if (c.Length() > 0 && c[0] != 0x0d)
+ {
+ aLine.Append(c);
+ n++;
+ if (n == aLine.MaxLength() + 1)
+ {
+ done = ETrue;
+ }
+ }
+ else
+ {
+ done = ETrue;
+ }
+ }
+ else
+ {
+ done = ETrue;
+ }
+ }
+
+ if (c.Length() > 0 && c[0] == 0x0d)
+ {
+ aStream->Read(c, 1);
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMLicenseManager::ProcessDataFilesL
+// Get all data files from the ZIP file and encrypt them.
+// -----------------------------------------------------------------------------
+//
+TInt CDRMLicenseManager::ProcessDataFilesL(
+ const TDesC& aDestination)
+ {
+ TDRMDataFile* dataFile( NULL );
+ CZipFileMember* member( NULL );
+ TInt r( KErrNone );
+
+ // check if there is enough free space for the process
+ CheckNeededFreeSpaceL( *iFs, iZipFile, iDataFiles, aDestination, r );
+
+ for ( TInt i = 0; i < iDataFiles.Count() && r == KErrNone; i++ )
+ {
+ dataFile = static_cast< TDRMDataFile* >( iDataFiles[ i ] );
+ member = iZipFile->CaseInsensitiveMemberL( dataFile->iSourceName );
+ if ( member )
+ {
+ CleanupStack::PushL(member);
+ EncryptDataFileL(dataFile, aDestination, member);
+ CleanupStack::PopAndDestroy(member);
+ }
+ else
+ {
+ r = EPIPInvalid;
+ }
+ }
+
+ return r;
+ }
+
+// -----------------------------------------------------------------------------
+// CDRMLicenseManager::EncryptDataFileL
+// Encrypt a single data file, reusing the outer PIP's RO. For application
+// protection, the file is encrypted again.
+// -----------------------------------------------------------------------------
+//
+void CDRMLicenseManager::EncryptDataFileL(
+ TDRMDataFile* aDataFile,
+ const TDesC& aDestination,
+ CZipFileMember* aZipMember)
+ {
+ RZipFileMemberReaderStream* input = NULL;
+ RFileWriteStream output;
+ TBuf8<KSISBufferSize> buffer;
+ COma1DcfCreator* drm = NULL;
+ TFileName outputFile;
+ DRMCommon* common = NULL;
+
+ drm = COma1DcfCreator::NewL();
+ CleanupStack::PushL(drm);
+
+ iZipFile->GetInputStreamL(aZipMember, input);
+ CleanupStack::PushL(input);
+
+ // Set the path so we can use relative paths
+ iFs->SetSessionPath(aDestination);
+
+ output.PushL();
+ // Create the output file stream
+ User::LeaveIfError(output.Replace(*iFs, aDataFile->iTargetName,
+ EFileWrite));
+
+ // Encrypt
+ drm->EncryptInitializeL(output, aDataFile->iMimeType, iRights);
+ do
+ {
+ input->Read(buffer, KSISBufferSize);
+ if (buffer.Size() > 0)
+ {
+ drm->EncryptUpdateL(buffer);
+ }
+ }
+ while (buffer.Size() > 0);
+ drm->EncryptFinalizeL();
+ output.Close();
+ CleanupStack::PopAndDestroy( &output );
+
+ // Add the rights issuer uri to the file if it exists
+ if( iRightsIssuer )
+ {
+ common = DRMCommon::NewL();
+ CleanupStack::PushL(common);
+ outputFile.Append( aDataFile->iTargetName );
+ common->SetFileHeader( outputFile, KIssuer,
+ iRightsIssuer->Des());
+ CleanupStack::PopAndDestroy(common);
+ }
+ CleanupStack::PopAndDestroy(input);
+ CleanupStack::PopAndDestroy(drm);
+ }
+
+