extern HRESULT __stdcall StatusCallback(
DRM_STATUS_MSG msg,
HRESULT hr,
void *pvParam,
void *pvContext
);
/*===================================================================
Function: EditSignedIL
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (C) Microsoft Corporation. All rights reserved.
===================================================================*/
/////////////////////////////////////////////////////////////////////
// The EditSignedIL function edits a signed issuance license by adding
// a user while retaining the content key so that content protected
// using the issuance license does not have to be re-encrypted.
//
// Arguments:
// hEnv - [in] Environment handle
// pwszUserID - [in] User email address that needs
// to be added to the IL
// pwszUserRight - [in] Right that needs to be granted
// pwszRAC - [in] RAC of the Republishing user
// pwszCLC - [in] CLC of the Republishing user
// pwszOldSignedIL - [in] Old Signed Issuance License
// pwszEUL - [in] Use License of the Republishing
// user with EDITRIGHTSDATA or OWNER
// ppwszNewSignedIL - [out] New Signed Issuance License
HRESULT EditSignedIL(DRMENVHANDLE hEnv,
PWSTR pwszUserID,
PWSTR pwszUserRight,
PWSTR pwszRAC,
PWSTR pwszCLC,
PWSTR pwszOldSignedIL,
PWSTR pwszEUL,
PWSTR *ppwszNewSignedIL)
{
HRESULT hr = S_OK; // HRESULT return code
DRMPUBHANDLE hOldIssuanceLicense = NULL; // Issuance license handle
DRMPUBHANDLE hNewIssuanceLicense = NULL; // Issuance license handle
DRMPUBHANDLE hUser = NULL; // User handle
DRMPUBHANDLE hRight = NULL; // Right handle
const UINT GUID_LENGTH = 128; // GUID string length
PWSTR pwszNewContentId = NULL; // Unique content ID for new IL
UINT uiNewContentId = 0; // content id length
GUID guid; // Raw Guid: unique content ID
const DWORD DW_WAIT_TIME = 60000;// Maximum signal duration
DWORD dwWaitResult = 0; // Actual signal duration
SYSTEMTIME stTimeFrom; // Validity period start
SYSTEMTIME stTimeUntil; // Validity period end
DRM_CONTEXT context; // Callback context
DRMHANDLE hBoundLicense = NULL; // Bound License handle
DRMHANDLE hDecryptor = NULL; // Decryptor handle
UINT uiOldContentId = 0; // Content Id Length of Old IL
UINT uiOldContentIdType = 0; // Content Id Type Length of Old IL
PWSTR pwszOldContentId = NULL; // Content Id of old IL
PWSTR pwszOldContentIdType = NULL; // Content Id Type of old IL
DRMID idOldContent; // Content Id structure
PWSTR pwszSymmKeyType = NULL; // Symmetric Key Type
UINT cbSymmKeyType = 0; // Symmetric Key Type Length
DRMENCODINGTYPE encodingType; // Encoding Type
DRMBOUNDLICENSEPARAMS bParams; // Bound License params
wprintf(L"\r\nEntering EditSignedIL. \r\n");
// Initialize the callback context.
SecureZeroMemory(&context, sizeof(context));
// Get the system time for the starting and ending times that
// specify the validity period of the unsigned issuance license.
// Add one year to the ending time.
GetSystemTime( &stTimeFrom );
GetSystemTime( &stTimeUntil );
stTimeUntil.wYear++;
// Obtain the Content Id from the Signed issuance license
// a. Create an issuance license handle from the signed IL
// b. Obtain content ID and content ID Type
hr = DRMCreateIssuanceLicense(
&stTimeFrom, // Starting validity time
&stTimeUntil, // Ending validity time
NULL, // Not supported
NULL, // Not supported
NULL, // Handle to license owner
pwszOldSignedIL, // Existing issuance license
NULL, // Bound license handle
&hOldIssuanceLicense); // Handle to the license
if(FAILED(hr)) goto e_Exit;
wprintf(L"DRMCreateIssuanceLicense: hOldIssuanceLicense = %i \r\n",
hOldIssuanceLicense);
hr = DRMGetMetaData(
hOldIssuanceLicense, // Handle to the license
&uiOldContentId, // Content Id Length
NULL, // Content Id
&uiOldContentIdType, // Content Id Type Length
NULL, // Content Id Type
NULL, // SKU ID Length
NULL, // SKU ID
NULL, // SKU ID Type Length
NULL, // SKU ID Type
NULL, // Content Type Length
NULL, // Content Type
NULL, // Content Name Length
NULL); // Content Name
if(FAILED(hr)) goto e_Exit;
pwszOldContentId = new WCHAR[uiOldContentId];
if(NULL == pwszOldContentId)
{
hr = E_OUTOFMEMORY;
goto e_Exit;
}
pwszOldContentIdType = new WCHAR[uiOldContentIdType];
if(NULL == pwszOldContentIdType)
{
hr = E_OUTOFMEMORY;
goto e_Exit;
}
hr = DRMGetMetaData(
hOldIssuanceLicense, // Handle to the license
&uiOldContentId, // Content Id Length
pwszOldContentId, // Content Id
&uiOldContentIdType, // Content Id Type Length
pwszOldContentIdType, // Content Id Type
NULL, // SKU ID Length
NULL, // SKU ID
NULL, // SKU ID Type Length
NULL, // SKU ID Type
NULL, // Content Type Length
NULL, // Content Type
NULL, // Content Name Length
NULL); // Content Name
if(FAILED(hr)) goto e_Exit;
wprintf(L"DRMGetMetadata: pwszOldContentId = %ws \r\n",
pwszOldContentId);
// Create the content id structure for the BOUNDLICENSEPARAMS
idOldContent.uVersion = 0;
idOldContent.wszIDType = pwszOldContentIdType;
idOldContent.wszID = pwszOldContentId;
// Bind the license to the EDITRIGHTSDATA or OWNER right
// to reuse the key.
bParams.hEnablingPrincipal = NULL;
bParams.hSecureStore = NULL;
bParams.wszRightsRequested = L"EDITRIGHTSDATA";
bParams.wszRightsGroup = L"Main-Rights";
bParams.idResource = idOldContent;
bParams.wszDefaultEnablingPrincipalCredentials = pwszRAC;
bParams.cAuthenticatorCount = 0;
hr = DRMCreateBoundLicense(
hEnv, // secure environment handle
&bParams, // additional license options
pwszEUL, // owner license
&hBoundLicense, // handle to bound license
NULL // reserved
);
if(FAILED(hr)) goto e_Exit;
wprintf(L"DRMCreateBoundLicense: hBoundLicense = %i \r\n",
hBoundLicense);
hr = DRMCreateEnablingBitsDecryptor(
hBoundLicense, // bound license handle
NULL, // right name
NULL, // reserved
NULL, // reserved
&hDecryptor // decryptor handle
);
if(FAILED(hr)) goto e_Exit;
wprintf(L"DRMCreateEnablingBitsDecryptor: hDecryptor = %i \r\n",
hDecryptor);
// Obtain the key type set in the decryptor so that it can be
// specified when creating the new issuance license
// g_wszQUERY_SYMMETRICKEYTYPE requires a client that supports
// AES-CBC4K. Otherwise, symmetric key type can always be assumed
// to be "AES"
hr = DRMGetInfo(hDecryptor,
g_wszQUERY_SYMMETRICKEYTYPE,
&encodingType,
&cbSymmKeyType,
NULL);
if(FAILED(hr)) goto e_Exit;
pwszSymmKeyType = new WCHAR[cbSymmKeyType / 2];
if(pwszSymmKeyType == NULL)
{
hr = E_OUTOFMEMORY;
goto e_Exit;
}
SecureZeroMemory(pwszSymmKeyType, cbSymmKeyType);
hr = DRMGetInfo(hDecryptor,
g_wszQUERY_SYMMETRICKEYTYPE,
&encodingType,
&cbSymmKeyType,
(BYTE*)pwszSymmKeyType);
if(FAILED(hr)) goto e_Exit;
wprintf(L"DRMGetInfo: pwszSymmKeyType = %ws \r\n",
pwszSymmKeyType);
// Create an unsigned issuance license from the passed in
// signed issuance license.
hr = DRMCreateIssuanceLicense(
&stTimeFrom, // Starting validity time
&stTimeUntil, // Ending validity time
NULL, // Not supported
NULL, // Not supported
NULL, // Handle to license owner
pwszOldSignedIL, // Existing issuance license
hBoundLicense, // Bound license: get rights
// and content key
&hNewIssuanceLicense); // Handle to the new license
if(FAILED(hr)) goto e_Exit;
wprintf(L"DRMCreateIssuanceLicense: hNewIssuanceLicense = %i \r\n",
hNewIssuanceLicense);
// Create a GUID to use as the unique content ID.
hr = CoCreateGuid(&guid);
if(FAILED(hr)) goto e_Exit;
pwszNewContentId = new WCHAR[GUID_LENGTH];
if (NULL == pwszNewContentId)
{
hr = E_OUTOFMEMORY;
goto e_Exit;
}
uiNewContentId = StringFromGUID2( guid, pwszNewContentId, GUID_LENGTH );
if (0 == uiNewContentId)
{
hr = E_FAIL;
goto e_Exit;
}
wprintf(L"StringFromGUID2: pwszNewContentId = %s \r\n", pwszNewContentId);
// Set your metadata in the unsigned issuance license.
hr = DRMSetMetaData(
hNewIssuanceLicense, // Issuance license handle
pwszNewContentId, // Unique content ID
L"MS-GUID", // Type of content ID
L"SKUId", // SKU ID
L"SKUIdType", // SKU ID type
L"ContentType", // Content type
L"ContentName"); // Content name
if(FAILED(hr)) goto e_Exit;
wprintf(L"DRMSetMetaData succeeded. \r\n");
// Create a user handle.
hr = DRMCreateUser(
pwszUserID, // User ID or name
NULL, // Verified ID
L"Windows", // Type of user ID
&hUser ); // Handle to the user
if(FAILED(hr)) goto e_Exit;
wprintf(L"DRMCreateUser: hUser = %i \r\n", hUser);
// Create a right.
hr = DRMCreateRight(
pwszUserRight, // Name of the right to create
&stTimeFrom, // Starting validity time
&stTimeUntil, // Ending validity time
0, // No extended information
NULL, // Extended information name
NULL, // Extended information value
&hRight ); // Handle to the created right
if(FAILED(hr)) goto e_Exit;
wprintf(L"DRMCreateRight: hRight = %i \r\n", hRight);
// Associate the right with the user and add both to the
// unsigned issuance license.
hr = DRMAddRightWithUser(
hNewIssuanceLicense, // Issuance license handle
hRight, // Right from DRMCreateRight
hUser ); // User from DRMCreateUser
if(FAILED(hr)) goto e_Exit;
wprintf(L"DRMAddRightWithUser succeeded. \r\n");
// Create an event to signal when the license has been signed.
context.hEvent = CreateEvent(
NULL, // No attributes
FALSE, // Automatic reset
FALSE, // Initial state not signaled
NULL); // Event object not named
if(NULL == context.hEvent) goto e_Exit;
// Sign the issuance license offline by using the client
// licensor certificate
hr = DRMGetSignedIssuanceLicense(
hEnv, // Environment handle
hNewIssuanceLicense, // Issuance license handle
DRM_SIGN_OFFLINE | // Sign offline with a CLC
DRM_REUSE_KEY, // Reuse content key from old IL
NULL, // No symmetric key specified
0, // No length specified
pwszSymmKeyType, // Pass in same key type as old IL
pwszCLC, // Client licensor certificate
&StatusCallback, // Callback function
NULL, // No licensing URL specified
(void*)&context); // Callback context parameter
if(FAILED(hr)) goto e_Exit;
wprintf(L"DRMGetSignedIssuanceLicense succeeded. \r\n");
// Wait for the callback to return.
dwWaitResult = WaitForSingleObject(context.hEvent, DW_WAIT_TIME);
if(WAIT_TIMEOUT == dwWaitResult)
{
hr = E_FAIL;
goto e_Exit;
}
if(FAILED(context.hr))
{
hr = context.hr;
goto e_Exit;
}
// Assign the license pointer to the output parameter.
*ppwszNewSignedIL = context.wszData;
context.wszData = NULL;
e_Exit:
if(NULL != context.hEvent)
{
CloseHandle(context.hEvent);
}
if(NULL != context.wszData)
{
delete[] context.wszData;
}
if(NULL != pwszOldContentId)
{
delete[] pwszOldContentId;
}
if(NULL != pwszOldContentIdType)
{
delete[] pwszOldContentIdType;
}
if(NULL != pwszSymmKeyType)
{
delete[] pwszSymmKeyType;
}
if(NULL != hDecryptor)
{
DRMCloseHandle(hDecryptor);
}
if(NULL != hBoundLicense)
{
DRMCloseHandle(hBoundLicense);
}
if(NULL != hOldIssuanceLicense)
{
DRMClosePubHandle(hOldIssuanceLicense);
}
if(NULL != hNewIssuanceLicense)
{
DRMClosePubHandle(hNewIssuanceLicense);
}
if(NULL != hUser)
{
DRMClosePubHandle(hUser);
}
if(NULL != hRight)
{
DRMClosePubHandle(hRight);
}
if(NULL != pwszNewContentId)
{
delete [] pwszNewContentId;
}
wprintf(L"Leaving EditSignedIL: hr = %x \r\n", hr);
return hr;
}