Andrea pruneda
Microsoft Corporation
February 2005
Applies TO:
Microsoft® Windows Media® Rights Manager 10 Software Development Kit (SDK)
Contents
Introduction
How liquense chaining works
Implementing a license chain
Protecting Content
Setting Rights in a license chain
Issuing a chained license
Example Code
For more information
IntroductionLicense CHAINING IS A New Feature Of Microsoft® Windows Media® Rights Manager 10 That Allows A High Volume of Licenses To Be Renewed Quickly. A License Chain Consists of Two Parts, A
Leaf license and a
Root license. Both licenses are Required to Complete the chain and to access protected.
A
simple license is self-contained. When it expires, the entire license is no longer valid and a new one must be issued before the content can be played again. A simple license is the only type that is used in Windows Media Digital Rights Management ( DRM) Versions 9 and Earlier.
A
chained license is composed of a leaf license and a root license. The leaf license unlocks the content, and the root license unlocks the leaf license. In order to access the content, the DRM component of the player must locate both the root and leaf licenses To Complete The Chain. Windows Media DRM 10 Supports Both Simple and Chained Licenses.
The root license and the leaf license each contain a set of rights. Both licenses must be valid and both must allow the actions that are being requested. For example, to play content using a chained license, the root and leaf licenses must contain the right
AllowPlay = true. If Either the root or leaf license expression, the user cannot Access the content Until That License Element is Renewed.
The license chain format is especially useful for the folloading review: Multiple Content Items CAN Share A Root License, But Use Different Leaf licenses.
RESTRICTIONS (SUCH AS Expiration Or Counted Plays) Can Be Included in Just One License Element.
License Configurations, Such As the Rights and Combination of Leaf and root licenses, Are Flexible and can be set up accounting to your business model.
For example, by using license chains, a subscription service with a large catalog can issue one root license with time restrictions and individual leaf licenses. When the subscription expires, only one root license needs to be renewed. For example, when a new consumer signs up for the subscription service, they are issued 10,000 leaf licenses that do not expire and one root license that expires in 30 days. When the subscription expires each month, the consumer renews the subscription and is issued a new root license valid for an additional ............... ..
Back to TOP
How License Chaining WorksIn a license chain, the root license is bound to the computer or device, and unlocks the leaf license. The leaf license is bound to the root license, and unlocks the content. So when a player tries to open protected content, IT Must Reconstruct The license chain.
The Following Diagram Shows How The Player Reconstructs a license chain.
THE PLAYER Uses The key id in the content header to find the leaf license.
The Leaf license contains an
Uplink ID, Which Matches The key id of its root license.
The root license unlocks the leaf license.
The Content Key In The Leaf license unlocks the content.back to top
Implementing a License ChainThis section describes how to set up a license chain, including how to protect the content, how to set the rights, and how to issue the licenses. Example code is included at the end of this section.
Protecting ContentWhen You Protect Content for Which You Want To Use a License Chain, You Should Add To Uplink ID To The Content Header Using The
WMRMHeader.AddUplink method. The key ID that is already required during the protection process points to the leaf license, and the uplink ID in the leaf license points to the root license. While the uplink ID is not required in the content header, it is recommended. When the uplink ID is included, license requests for this content will include license state data that indicates information about existing licenses for this content on the client. The license issuer can find out whether the content already has a license and, if so, how many counted actions are remaining and when the license will expire. For example, to improve the user experience, the license issuer might renew a root license before it expires or renew a leaf license that has used all of its copy counts.
Setting Rights In a license Chaineach License In The Chain Must Contain A Valid Set of Rights. The DRM Component of the Media Player Evaluates The Rights in Both license in The Chain As Follows:
An action is permitted only ified.
If A Root License Specifies Any Output Protection Levels, All Output Protection Levels in the Leaf license area ignored.
If both root and leaf licenses include counts, the counts in both are decremented when both licenses are used. When only the root license is used, only the count in the root license is decremented, such as in license synchronization.To allow content to be BURNED As Part of A Playlist, THE
ALOWPLAYLISTBURN Right Must Be granted in Both the root and the leaf licenses. However, THE
PlaylistburnTrackCount and
MaxPlayListburncount Rights AresuTed Only in a leaf license.
Guidelines
When setting rights for license chains, different results can be achieved, depending on how you set the rights in the leaf and root licenses, especially for counts and expiration. Use the following guidelines when setting rights in a license chain.
Setting Basic Rights.
You Should Explicitly Allow and Deny The Rights in Both Leaf And Root Licenses, Rather Than Depending On Default Values. For example, specify
AllowPlay = True in Both licenses.
Setting counted actions.
Counted actions in a root license are not tracked individually per content item. For example, if 10 content items share a root license that allows one play, only one item can be played once. So, to specify counted actions per content item, you would Specify Counted ActionS in Each Leaf License Only. for Example, Suppose A Subscription Service Wants To A Device Up to Five Times. The Service Would THEN SPECIFY
Allowcopy = 5 in each leaf license.
License rights are flexible, and you can use this behavior in a creative way. For example, you could include extra copy or burn counts in the root license, and the user could choose which content items to use them with.
Setting expiration dates.
Specify expiration dates in the root license. For example, if a subscription service has content that expires at the end of each month, specify the expiration date in the root license only. When users renew their subscription, the root license is reissued with a new Expiration Date.Setting Restrictions.
Specify any restrictions in the root license. First, restrictions in a root license take precedence over those specified in a leaf license. Second, as technologies change, specifying these restrictions in only the root allow you to make changes to the content policy for your business Model by simply renewing the root license.
Issuing a Chained LicenseIssuing a chained license follows a similar process to issuing a simple license-you retrieve the content header from the license challenge (unless you predeliver licenses), generate the corresponding keys, set the rights, and then send the licenses to the client .
However, when issuing a chained license, unless you are issuing the license for the first time, you do not always need to issue both a root and a leaf license. For example, during a subscription renewal, you might only need to issue a root license. At other times, you might only need to issue new leaf licenses for items the user does not have yet. The Windows Media® Rights Manager 10 SDK provides a new interface that, if the content uses a chained license, returns license state data About Any EXISTINGLICENSES ON The Client. for Example, You Could Determine That The Client Already Has A Root License That Expires in 5 Days, OR a Leaf license with 10 Remaining Play Count.
The Windows Media Rights Manager SDK Provides The Following New Interfaces for Working with Chained Licenses:
Because the key for a root license must be 8 bytes long, use thewmrmkeys.generatekeyex method to generate the root license key. Continue To Generate 7-byte keys for simple and leaf licenses.
The Leaf license Must Contain The key and key id of the root license (Also Called The Uplink Key and Key ID). Use T
WMRMLICGEN.UPLINKKEY AND
WMRMLICGEN.UPLINKKID Properties to Specify these.
Use the
WMRMChallenge.Uplinks property to retrieve information about existing chained licenses on the client. (This information is included in the license request as long as the uplink ID is specified in the content header when the content is protected.) Then you can determine whether to issue A root and / or a leaf license. Uses Uses
WMRMUPLINKCOLLECTION,
Wmrmuplink, and
WmrmlicenStatedata Objects to process the data.
EXAMPLE CODETHIS Section Provides The Two Code Examples To show you how to work with chained licenses.
The First Code Example Shows How To Specify The Uplink ID While Protecting Content.
The Second Code Example Shows How To Issue a Chained License IN Response To a License Request That Includes a content
For readability, Error Checking is not included.
Example Code for Protecting Content
<% @ Language = "vbscript"%> <% response.buffer = trueresponse.expires = 0on error resume nextdo '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "DIM KEYOBJ 'WMRMHEADER Object Dim Protectobj' WMRMPROTECT DIM KEYOBJ 'WMRMPROTECT DIM PROTECTOBJ' WMRMPROTECT object Dim Seed 'License key seed Dim ContentServerPrivKey' Private key of the content server Dim ContentServerPubKey 'Public key of the content server Dim LeafKID' Key ID of the leaf license Dim RootKID 'Key ID of the root license Dim contentKey' Key of the leaf License Dim Header 'Content Header Dim Licurl' license Acquisition URL DIM SecVERSION 'Required Individization Version Dim InputFile' Path and Name of the Input File Dim OutputFile 'Path and Name of the Protected File' "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""
"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "", "" "" "" " =
Keyobj.generateKeyid () "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" " 'Generate the content key for the leaf license.'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" Set value Into the content Header and Sign It. '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "Set HeaderObj = Server.CreateObject (" WMRMObjs.WMRMHeader ") HeaderObj.KeyID = LeafKID HeaderObj.AddUplink (RootKID) HeaderObj.LicenseAcqURL = LicURL Call HeaderObj.SetCheckSum (contentKey) HeaderObj.IndividualizedVersion = SecVersion Call headerobj.sign (ContentServerPrivkey) header = headerobj.header '"" "" "" "" "" "" "" "" ""
"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" SET protectobj = server.createObject ( "WMRMObjs.WMRMProtect") ProtectObj.InputFile = InputFile ProtectObj.Key = contentKey ProtectObj.Header = Header ProtectObj.V1KeyID = LeafKID Call ProtectObj.ProtectFile (OutputFile) Response.Write "The file has been protected." Loop While FalseIf Err. Number <> 0 THEN Response.write cstr (HEX (Err.Number)) Err.DescriptionEND IF '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" 'Clear objects.' "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" SET Keyobj = Nothingset headerobj = NothingSet Protectobj = Nothing%> EXAMPLE CODE for Issuing a chained license
<% @Language = "VBScript"%> <% response.buffer = trueresponse.expires = 0do on error resume next '"" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" Dim ChallengeObj 'WMRMCHALLUPLINKCOLLECOLLLOBJ' WMRMUPLINKCOLLECTION OBJECT DIM CHAINOBJ ' WMRMUplink object Dim LeafLicenseStateObj 'WMRMLicenseStateData object Dim RootLicenseStateObj' WMRMLicenseStateData object Dim HeaderObj 'WMRMHeader object Dim KeyObj' WMRMKeys object Dim RightsObj 'WMRMRights object Dim LicenseObj' WMRMLicGen object Dim ResponseObj 'WMRMResponse object Dim ContentServerPubKey' Public key of the content server Dim Seed 'License Key Seed Dim Delivery 'Delivery Flag Dim Silent' Silent Deli Very Flag Dim strlicenserequested 'license Request string Dim VarclientInfo' Client Information Dim Varheader 'Content Header Dim BlnResult'
Signature verification Dim LeafKID 'Key ID of a leaf license Dim IndiVersion' Security version of the DRM component Dim RootKID 'Key ID of the root license Dim RootCat' License state data for root licenses Dim RCountArray 'Count array Dim RDateArray' Date array Dim IssueRoot 'Root license flag Dim Rcounts' Remaining counts Dim RstartDate' Start date Dim RExpDate 'Expiration date Dim LeafCat' License state data for leaf licenses Dim LCountArray 'Count array Dim LDateArray' Date array Dim IssueLeaf 'Leaf license flag Dim Lcounts' Remaining counts Dim LStartDate 'Start Date Dim Lexpdate' Expiration Date Dim Leafkey 'Key for The Leaf License Dim LeafRights' Rights string for the leaf license Dim LeafLicense 'License for the leaf license Dim RootKey' Key for the root license Dim RootRights' Rights string for the root license Dim RootLicense 'Root license Dim LicResponse' License response ' "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "Set variables" "" "
"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ContentServerPubKey =
"" "" "" "" "" "" Set ChallengeObj = Server.CreateObject ( "WMRMObjs.WMRMChallenge") strLicenseRequested = Request.Form ( "challenge") ChallengeObj.Challenge = strLicenseRequested varClientInfo = ChallengeObj.ClientInfo varHeader = ChallengeObj.Header '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" Set headerobj = server.createObject ("WMRMOBJS.WMRMHEADER" HEADEROBJ.HEADER = varHeader BLNRESULT = headerobj.verify (ContentServerPubKey) LeafKID = HeaderObj.KeyID IndiVersion = HeaderObj.IndividualizedVersion 'If IndividualizedVersion is not specified in the' content header, reset the error. If (Err.Number <> 0) Then Err.clear ' "" "" "" " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" RETRIEVE THE LICENSE State Data To Determine Which license '
Elements to Issue. '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "SET chaincollobj = challengeobj.uplinks if (err.Number <> 0) THEN 'NO LICENSE State Data Available' You Might Retrieve The root kid from a database. Rootkid =
The root license has a start date. RDateArray = RootLicenseStateObj.Dates RStartDate = cstr (RDateArray (0)) IssueRoot = False case 4 'The root license has an expiration date. RDateArray = RootLicenseStateObj.Dates RExpDate = cstr (RDateArray (0)) IssueRoot = False case 5 'The root license has start and expiration dates. RDateArray = RootLicenseStateObj.Dates RStartDate = cstr (RDateArray (0)) RExpDate = cstr (RDateArray (1)) IssueRoot = False case 6' The root license has a start date and remaining play counts. RDateArray = RootLicenseStateObj.Dates RStartDate = cstr (RDateArray (0)) RCountArray = RootLicenseStateObj.Counts RCounts = cstr (RCountArray (0)) IssueRoot = False case 7 ' The root license has an expiration date and remaining play counts. RDateArray = RootLicenseStateObj.Dates RExpDate = cstr (RDateArray (0)) RCountArray = RootLicenseStateObj.Counts RCounts = cstr (RCountArray (0)) IssueRoot = False case 8 'The root license has Start and expected play count, 'and remaining play counts. rdateArray = rootlicenseStateObj.dates RstartDate = cstr (rdateArray (0)) Rexpdate = cstr (RdateArray (1)) RcountArray =
RootLicenseStateObj.Counts RCounts = cstr (RCountArray (0)) IssueRoot = False case 9 'The root license expires after first use. IssueRoot = False End Select' Get license state data to determine whether to issue a leaf license. 'Item 0 in the collection corresponds to the leaf. Set ChainObj = ChainCollObj.item (0) 'Get license state data to determine whether to issue a leaf license. Set LeafLicenseStateObj = ChainObj.LicenseState LeafCat = cstr (LeafLicenseStateObj.Category) Select Case LeafCat' In this example , a leaf license is only issued when an existing 'leaf license with rights can not be found (case 0). case 0' The leaf license has no rights. IssueLeaf = True case 1 'The leaf license has unlimited play counts. IssueLeaf = False Case 2 'the Leaf Li cense has remaining play counts. LCountArray = LeafLicenseStateObj.Counts LCounts = cstr (LCountArray (0)) IssueLeaf = False case 3 'The leaf license has a start date. LDateArray = LeafLicenseStateObj.Dates LStartDate = cstr (LDateArray (0)) IssueLeaf = False Case 4 'The Leaf license has an expeflicensestateObj.dates lexpdate = cstr (LdateArray (0)) IssueleAf = False Case 5'
The leaf license has start and expiration dates. LDateArray = LeafLicenseStateObj.Dates LStartDate = cstr (LDateArray (0)) LExpDate = cstr (LDateArray (1)) IssueLeaf = False case 6 'The leaf license has a start date and remaining play counts. LDateArray = LeafLicenseStateObj.Dates LStartDate = cstr (LDateArray (0)) LCountArray = LeafLicenseStateObj.Counts LCounts = cstr (LCountArray (0)) IssueLeaf = False case 7 'The leaf license has an expiration date and remaining play counts. LDateArray = LeafLicenseStateObj. dates LExpDate = cstr (LDateArray (0)) LCountArray = LeafLicenseStateObj.Counts LCounts = cstr (LCountArray (0)) IssueLeaf = False case 8 'The leaf license has start and expiration dates,' and remaini ng play counts. LDateArray = LeafLicenseStateObj.Dates LStartDate = cstr (LDateArray (0)) LExpDate = cstr (LDateArray (1)) LCountArray = LeafLicenseStateObj.Counts LCounts = cstr (LCountArray (0)) IssueLeaf = False case 9 'The root license Expires offfter first use. issueleaf = false end select end if '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""
"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "SET Keyobj = Server.createObject (" WMRMOBJS.WMRMKEYS ") Keyobj.KeyId = seed leafkey = keyobj.generateKey = keyobj.generateKey ) 'Generate the 8-byte key for the root license. Keyobj.Keyid = rootkid rootkey = keyobj.generateKeyex (8)' "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" SET Rightsobj = Server.createObject ( "WMRMObjs.WMRMRights") RightsObj.AllowPlay = True RightsObj.AllowCopy = True RightsObj.AllowCollaborativePlay = False RightsObj.AllowBackupRestore = False RightsObj.AllowPlaylistBurn = False RightsObj.CopyCount = 5 RightsObj.GracePeriod = 24 RightsObj.MinimumClientSDKSecurity = 3000 RightsObj.MinimumSecurityLevel = 1000 'Get The Rights String. Leafrights = Rightsobj.Getallrights' ""
"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "'Set the rights for the root license.'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " "" "" "" "" "" "" "" RightsObj.Reset () RightsObj.AllowPlay = True RightsObj.AllowCopy = True RightsObj.AllowCollaborativePlay = False RightsObj.AllowBackupRestore = False RightsObj.AllowPlaylistBurn = False RightsObj.GracePeriod = 24 RightsObj .MinimumClientSDKSecurity = 3000 RightsObj.MinimumSecurityLevel = 1000 RightsObj.ExpirationDate = "# 20051231Z #" RightsObj.DeleteOnClockRollback = False RightsObj.DisableOnClockRollback = True 'Get the rights string. RootRights = RightsObj.GetAllRights' "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "'Generate a leaf license.' "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" SET licenseobj =
Server.CreateObject ( "WMRMObjs.WMRMLicgen") LicenseObj.KeyID = LeafKID LicenseObj.SetKey "", LeafKey LicenseObj.Priority = 10 LicenseObj.Rights = LeafRights LicenseObj.ClientInfo = varClientInfo LicenseObj.BindToPubKey = ContentServerPubKey LicenseObj.IndividualizedVersion = IndiVersion 'Specify the Key and key id for the root license. licenseobj.uplinkkid = rootkid licenseobj.uplinkKey = rootkey leaflicense = licenseobj.getlicensetodeliver () '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" SET licenseobj = server.createObject ( "WMRMObjs.WMRMLicgen") LicenseObj.KeyID = RootKID LicenseObj.SetKey "", RootKey LicenseObj.Priority = 10 LicenseObj.Rights = RootRights LicenseObj.ClientInfo = varClientInfo LicenseObj.BindToPubKey = ContentServerPubKey LicenseObj.IndividualizedVersion = IndiVersion RootLicense = LicenseObj.Get LicenSetodeliver () Delivery = "Deliver" Loop While False '"" "" "" "" "" "" "" "" "" "" "" ""
"" "" "" "" "" "" "" "" "" "" 'Send an error message or deliver the license.' "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "IF (Delivery =" "and Err." Number <> 0) Then Response.Write cstr (hex (err.number)) ":" & Err.DescriptionElseIf (Delivery = "deliver") Then Set ResponseObj = Server.CreateObject ( "WMRMObjs.WMRMResponse") If (IssueLeaf = True) Then 'Include a leaf license in the license response. Call ResponseObj.AddLicense ( "2.0.0.0", LeafLicense) End If If (IssueRoot = True) Then' Include the root license in the license response. Call ResponseObj.AddLicense ( "2.0.0.0", RootLicense) End If If (Silent = True) Then LicResponse = ResponseObj.GetLicenseResponse () Response.Write LicResponse ElseIf (Silent = False) Then 'This replaces quotes to pass a value.' ResponseObj.ReplaceQuotesWith = "" "" "" "For vbscript. Responseobj.replacequoteswith =" / "" "" for jscript .licresponse = res Ponseobj.getlicenseresponse () 'this Simple_ns.asp is a sample file what is incrighded with' The Windows Media Rights Manager SDK.%> <% end ifendiffness
Clear objects.Set ChallengeObj = NothingSet ChainCollObj = NothingSet ChainObj = NothingSet LicenseStateObj = NothingSet HeaderObj = NothingSet KeyObj = NothingSet RightsObj = NothingSet LicenseObj = NothingSet ResponseObj = Nothing%> Back to Top
For more information
Creating a Windows Media Player 10 Subscription Online Store White Paper (http://www.microsoft.com/windows/windowsmedia/knowledgeultr/
TechnicalArticles.aspx # DigitalRightsManagement).
For General Information About Windows Media® Technologies, See The
Windows Media Web Page (http://www.microsoft.com/windows/WindowsMedia/).
To Learn More About The Components of The Windows Media 10 SDK, See The
About The Windows Media SDK Components Web Page (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnanchor/html/anch_winmedsdk.asp).
To Download The Windows Media Rights Manager 10 SDK, Go To The
Windows Media Licensing Form Web page (http://wmlicense.smdisp.net/licenserequest/) and submit a License Request Form online. You will receive a License Agreement from Microsoft by e-mail. Sign and return the agreement. You will then Be Sent a Password and a link to download the sdk.