Adding the Issuance License to the Compound File

In the following example, the signed issuance license must be added in a new stream to the compound file that holds the encrypted content. This stream must be called \006Primary to enable the Microsoft Rights Management Add-on for Internet Explorer to read it. The example adds an issuance license immediately, to protect the document, then replaces this issuance license when a user queries to download the document, which ensures that the latest user rights are included in the issued document.

The following C++ example from the Cdoclib.dll shows how to insert the signed issuance license in a compound document.

// PaddingLength is a custom function in Cdoclib.cpp that returns the 
// number of padding bytes required to bring a submitted number up to 
// a submitted block size.
 
// VERSIONSTAMP is a structure in Cdoclib.cpp.

// CHECK_STG_ERROR is an error-handling macro.
#define CHECK_STG_ERROR(api,hresult) if(FAILED(hresult))           \
{                                                                  \
printf("Error (%s): %S [%d]\n",api,StorageError(hresult),hresult); \
goto e_Exit;                                                       \
}


WCHAR StorageName_DataSpaces[12]    =    L"*DataSpaces";
WCHAR StorageName_DataSpaceInfo[14] =    L"DataSpaceInfo";
WCHAR StorageName_TransformInfo[14] =    L"TransformInfo";
WCHAR StorageName_DRMTransform[14]  =    L"*DRMTransform";
WCHAR StreamName_DRMViewerContent[18] =  L"*DRMViewerContent";
WCHAR StreamName_Version[8]         =    L"Version";
WCHAR StreamName_DataSpaceMap[13]   =    L"DataSpaceMap";
WCHAR StreamName_DRMDataSpace[14]   =    L"*DRMDataSpace";
WCHAR StreamName_Primary[9]         =    L"*Primary";

...

CDOCLIB_API HRESULT __stdcall AddPublishingLicense(
                                 WCHAR* wcsPubLicense, 
                                 WCHAR* wcsRmhFilePath)
{
    int HeaderLen           = 0;
    int EntryCount          = 0;
    int EntryLength         = 0;
    int RefComponentCount   = 0;
    int RefComponentType    = 0;
    int RefComponentLen     = 0;
    int RefComponentPad     = 0;
    int DataSpaceNameLen    = 0;
    int DataSpaceNamePad    = 0;
    int TotalLength         = 0;

    LPWSTR RefComponent     = NULL;
    LPWSTR DataSpaceName    = NULL;

    // Storages and streams.
    IStorage *pStorage              = NULL;
    IStorage *pDataSpaceStorage     = NULL;
    IStorage *pDataSpaceInfoStorage = NULL;
    IStorage *pTransformInfoStorage = NULL;
    IStorage *pDRMTransformStorage  = NULL;
    IStream  *pStream               = NULL;

    HRESULT hResult     = NULL;
    ULONG bytesWritten  = 0;
    BYTE *dataspacemap  = NULL;
    LPSTR szB64Username = NULL;
    LPSTR szRightsLabel = NULL;
    BYTE *drm_transform = NULL;

    // Insert special characters into storage/stream names.
    short char_nine = 9;
    short char_six  = 6;
    memcpy(StorageName_DataSpaces, &char_six, 2);
    memcpy(StorageName_DRMTransform, &char_nine, 2);
    memcpy(StreamName_DRMDataSpace, &char_nine, 2);
    memcpy(StreamName_Primary, &char_six, 2);


    // Structure needed for the transform header.
    VERSIONSTAMP version;
    version.ReaderVersionMajor  = 1;
    version.ReaderVersionMinor  = 0;
    version.UpdaterVersionMajor = 1;
    version.UpdaterVersionMinor = 0;
    version.WriterVersionMajor  = 1;
    version.WriterVersionMinor  = 0;


    // Open the output compound file.
    hResult = StgOpenStorageEx( 
                 wcsRmhFilePath,         // File name
                 STGM_READWRITE|         // File access
                   STGM_SHARE_EXCLUSIVE, 
                 STGFMT_STORAGE,         // Compound file
                 0,              
                 NULL,           
                 0,              
                 IID_IStorage,           // IStorage IID
                 (void **)&pStorage);    // IStorage pointer

    CHECK_STG_ERROR("StgCreateStorageEx", hResult);

    // Create \006DataSpaces storage.
    hResult = pStorage->CreateStorage(
                 StorageName_DataSpaces,
                 STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
                 0,
                 0,
                 &pDataSpaceStorage);
    CHECK_STG_ERROR("IStorage::CreateStorage", hResult);

   // Create Version Stream.
   // Stream Format:
   // STAMP
   //   int32 FeatureIdentifierLength
   //   WCHAR FeatureIdentifier[]
   //   int16 ReaderVersionMajor
   //   int16 ReaderVersionMinor
   //   int16 UpdaterVersionMajor
   //   int16 UpdaterVersionMinor
   //   int16 WriterVersionMajor
   //   int16 WriterVersionMinor
   // END STAMP
    BYTE version_stamp[76];
    ZeroMemory(version_stamp, 76);
    version_stamp[0]=60;
    memcpy(version_stamp+4, L"Microsoft.Container.DataSpaces", 60);
    memcpy(version_stamp+64, &version, 12);
    hResult = pDataSpaceStorage->CreateStream(
                StreamName_Version,    // Required name
                STGM_READWRITE |       // File access
                STGM_SHARE_EXCLUSIVE,
                0,                     
                0,                     
                &pStream);             // IStream pointer
   CHECK_STG_ERROR("IStorage::CreateStream", hResult);
   hResult = pStream->Write(version_stamp, 76, &bytesWritten);
   CHECK_STG_ERROR("IStream::Write", hResult);


   // Create DataSpaceMap stream.
   // Stream Format:
   // HEADER
   //   int32 HeaderLen
   //   int32 EntryCount
   // END HEADER
   // MAP ENTRY
   //   int32 EntryLength
   //   int32 RefComponentCount
   //   REFCOMPONENT
   //     int32 RefComponentType
   //     int32 RefComponentLen
   //     WCHAR RefComponent[]
   //   END REFCOMPONENT (DWORD ALIGN)
   //   int32 DataSpaceNameLen
   //   WCHAR DataSpaceName[] 
   // END MAP ENTRY (DWORD ALIGN)
   hResult = pDataSpaceStorage->CreateStream(
                StreamName_DataSpaceMap,   // Required name
                STGM_READWRITE |           // File access 
                    STGM_SHARE_EXCLUSIVE, 
                0,                     
                0,                     
                &pStream);                 // IStream pointer
   CHECK_STG_ERROR("IStorage::CreateStream", hResult);

   // Calculate the size of the buffer needed to hold all
   // data for the DataSpaceMap stream.
   HeaderLen            = 8;
   EntryCount           = 1;
   RefComponentCount    = 1;
   RefComponentType     = 0;
   RefComponentLen      = (int)wcslen(
                          StreamName_DRMViewerContent)*sizeof(WCHAR);
   RefComponentPad      = PaddingLength(RefComponentLen,sizeof(DWORD));
   RefComponent         = StreamName_DRMViewerContent;
   DataSpaceNameLen     = (int)wcslen(StreamName_DRMDataSpace)
                          *sizeof(WCHAR);
   DataSpaceNamePad     = PaddingLength(DataSpaceNameLen, 
                          sizeof(DWORD));
   DataSpaceName        = StreamName_DRMDataSpace;
   EntryLength          = sizeof(DWORD)*5+
                          RefComponentLen+RefComponentPad+
                          DataSpaceNameLen+DataSpaceNamePad;
   TotalLength          = sizeof(DWORD)*2+EntryLength;

   // Allocate buffer and copy headers and data to the buffer.
   dataspacemap = (BYTE *)HeapAlloc(
                            GetProcessHeap(), 
                            0, 
                            TotalLength);
   if (dataspacemap == NULL)
   {
       hResult = E_OUTOFMEMORY;
       goto e_Exit;
   }
   ZeroMemory(dataspacemap, TotalLength);
   memcpy(dataspacemap+0, &HeaderLen, 4);
   memcpy(dataspacemap+4, &EntryCount, 4);
   memcpy(dataspacemap+8, &EntryLength, 4);
   memcpy(dataspacemap+12, &RefComponentCount, 4);
   memcpy(dataspacemap+16, &RefComponentType, 4);
   memcpy(dataspacemap+20, &RefComponentType, 4);
   memcpy(dataspacemap+24, RefComponent, RefComponentLen);
   memcpy(dataspacemap+24+RefComponentLen+RefComponentPad, 
          &DataSpaceNameLen, 4);
   memcpy(dataspacemap+28+RefComponentLen+RefComponentPad,
          DataSpaceName,DataSpaceNameLen);

   // Copy buffer to the new DataSpaceMap stream.
   hResult = pStream->Write(
                (void *)dataspacemap, 
                TotalLength, 
                &bytesWritten); 
   CHECK_STG_ERROR("IStream::Write", hResult);

   // Release the stream. 
   if (pStream != NULL)
   {
        pStream->Release();
        pStream = NULL;
   }

   // Create DataSpaceInfo storage.
   hResult = pDataSpaceStorage->CreateStorage(
                 StorageName_DataSpaceInfo,
                 STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
                 0,
                 0,
                 &pDataSpaceInfoStorage);
   CHECK_STG_ERROR("IStorage::CreateStorage[DataSpaceInfo]", 
                 hResult);

   // Create \009DRMDataSpace stream.
   // Stream Format:
   // HEADER
   //   int32 HeaderLen
   //   int32 TransformCount
   // END HEADER
   // TRANSFORM
   //   Int32 TransformNameLen
   //   WCHAR TransformName[]
   // END TRANSFORM
   hResult = pDataSpaceInfoStorage->CreateStream(
                  StreamName_DRMDataSpace,    // Required name
                  STGM_READWRITE |            // Eile access
                     STGM_SHARE_EXCLUSIVE, 
                  0,                          // Required
                  0,                          // Required 
                  &pStream);                  // IStream pointer
   CHECK_STG_ERROR("IStorage::CreateStream", hResult);

   HeaderLen            = 8;
   int TransformCount   = 1;
   int TransformNameLen = 26;
   LPWSTR TransformName = StorageName_DRMTransform;

   // Copy data to buffer. 
   BYTE dataspace[40];
   ZeroMemory(dataspace, 40);
   memcpy(dataspace+0, &HeaderLen, 4);
   memcpy(dataspace+4, &TransformCount, 4);
   memcpy(dataspace+8, &TransformNameLen, 4);
   memcpy(dataspace+12, TransformName, TransformNameLen+2);

   // Write \009DRMDataSpace stream.
   hResult = pStream->Write(
                  (void *)dataspace, 
                  40, 
                  &bytesWritten); 
   CHECK_STG_ERROR("IStream::Write", hResult);

   // Create TransformInfo storage.
   hResult = pDataSpaceStorage->CreateStorage(
                  StorageName_TransformInfo,
                  STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
                  0,
                  0,
                  &pTransformInfoStorage);
   CHECK_STG_ERROR("IStorage::CreateStorage[TransformInfo]", 
                  hResult);

   // Create \009DRMTransform storage.
   memcpy(StorageName_DRMTransform, &char_nine, 2);
   hResult = pTransformInfoStorage->CreateStorage( 
                  StorageName_DRMTransform,
                  STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
                  0,
                  0,
                  &pDRMTransformStorage);
   CHECK_STG_ERROR("IStorage::CreateStorage[DRMTransform]", 
                  hResult);

   // Create \006Primary stream.
   hResult = pDRMTransformStorage->CreateStream(
                  StreamName_Primary,      // Required name
                  STGM_READWRITE |         // File access
                     STGM_SHARE_EXCLUSIVE, 
                  0,                       // Required value
                  0,                       // Required value
                  &pStream);               // IStream pointer
   CHECK_STG_ERROR("IStorage::CreateStream", hResult);

   LPWSTR ClassID  = L"{C73DFACD-061F-43B0-8B64-0C620D2A8B50}";
   LPWSTR FeatureIdentifier = L"Microsoft.Metadata.DRMTransform";
   LPWSTR wszSignedIL  = wcsPubLicense;
   int IndexOfFeatureIdentifierLength   = 88;
   int TheNumberOne  = 1;
   int ClassIDLength  = (int)wcslen(ClassID)*sizeof(WCHAR);
   int FeatureIdentifierLength = (int)wcslen(FeatureIdentifier)
                                 *sizeof(WCHAR);
   int TheNumberFour  = 4;
   short TheNumberZero  = 0;
   szRightsLabel = (CHAR *)HeapAlloc(GetProcessHeap(),
                   0, 
                   wcslen(wszSignedIL)+1);
   if ( NULL == szRightsLabel )
   {
       printf("Error (%s): E_OUTOFMEMORY\n", "HeapAlloc");
       goto e_Exit;
   }
   StringCchPrintf(szRightsLabel, 
                   wcslen(wszSignedIL)+1, 
                   "%S", 
                   wszSignedIL);
   int RightsLabelLength  = (int)strlen(szRightsLabel);
   int TransformLength    = 38 + ClassIDLength + 
                            FeatureIdentifierLength + 
                            RightsLabelLength +     
                            PaddingLength(
                               RightsLabelLength, 
                               sizeof(DWORD));
   
   // Allocate buffer to hold \006Primary stream data.
   drm_transform = (BYTE *)HeapAlloc(GetProcessHeap(),
                  0, 
                  TransformLength);
   if ( NULL == drm_transform )
   {
       printf("Error (%s): E_OUTOFMEMORY\n", "HeapAlloc");
       goto e_Exit;
   }
   ZeroMemory(drm_transform, TransformLength);

   // Copy headers and issuance license to buffer.
   memcpy(drm_transform+0, &IndexOfFeatureIdentifierLength, 4);
   memcpy(drm_transform+4, &TheNumberOne, 4);
   memcpy(drm_transform+8, &ClassIDLength, 4);
   memcpy(drm_transform+12, ClassID, ClassIDLength);
   memcpy(drm_transform+12+ClassIDLength,
          &FeatureIdentifierLength, 
          4);
   memcpy(drm_transform+16+ClassIDLength, 
          FeatureIdentifier, 
          FeatureIdentifierLength);
   memcpy(drm_transform+16+ClassIDLength+FeatureIdentifierLength,
          &TheNumberZero, 
          2);
   memcpy(drm_transform+18+ClassIDLength+FeatureIdentifierLength,
          &version,
          12);
   memcpy(drm_transform+30+ClassIDLength+FeatureIdentifierLength, 
          &TheNumberFour,
          4);
   memcpy(drm_transform+34+ClassIDLength+FeatureIdentifierLength,
          &RightsLabelLength,
          4);
   memcpy(drm_transform+38+ClassIDLength+FeatureIdentifierLength,
          szRightsLabel,
          RightsLabelLength);

   // Copy buffer to \006Primary stream.
   hResult = pStream->Write(
                 (void *)drm_transform, 
                 TransformLength, 
                 &bytesWritten); 
   CHECK_STG_ERROR("IStream::Write", hResult);
   
   // Commit changes to root storage.
   pStorage->Commit(STGC_DEFAULT);

e_Exit:
   // Clean up.
   if (NULL != dataspacemap) HeapFree(GetProcessHeap(),
                  0, 
                  dataspacemap);
   if (NULL != szB64Username) HeapFree(GetProcessHeap(),
                  0, 
                  szB64Username);
   if (NULL != szRightsLabel) HeapFree(GetProcessHeap(),
                  0, 
                  szRightsLabel);
   if (NULL != drm_transform) HeapFree(GetProcessHeap(), 
                  0, 
                  drm_transform);

   if (pStorage != NULL)
       pStorage->Release();
   if (pDataSpaceStorage != NULL)
       pDataSpaceStorage->Release();
   if (pDataSpaceInfoStorage != NULL)
       pDataSpaceInfoStorage->Release();
   if (pTransformInfoStorage != NULL)
       pTransformInfoStorage->Release();
   if (pDRMTransformStorage != NULL)
       pDRMTransformStorage->Release();
   if (pStream != NULL)
       pStream->Release();
    
   return hResult;
}

See Also

Building a Protected Document Library

Send comments about this topic to Microsoft

Build date: 3/13/2008