Digital Rights Management (Silverlight 3)

Microsoft Silverlight will reach end of support after October 2021. Learn more.

When you integrate Digital Rights Management (DRM) into your Silverlight applications, you can better protect and more securely deliver content cross-platform for a variety of scenarios, including streaming, progressive download, rentals, and subscriptions.

NoteNote:

This topic is specific to Silverlight 3. To learn about DRM in Silverlight 4 and Silverlight 5, see Digital Rights Management (DRM).

This topic contains the following sections.

  • Silverlight DRM Conceptual Overview
  • PlayReady vs. WMDRM
  • Limitations When Using Silverlight DRM
  • Considerations for Using PlayReady Encryption vs. WMDRM Encryption
  • Playing WMDRM Content in Silverlight
  • Integrating DRM in Silverlight
  • Set up Server Infrastructure
  • Point to DRM Content from a Silverlight Application
  • Detecting DRM State
  • Error Handling
  • Add Custom Logic
  • Related Topics

Silverlight DRM Conceptual Overview

The following diagram summarizes the processes needed for Silverlight to play back DRM content as well as the server/client interactions needed to facilitate those processes. Later, each of these steps is discussed in greater detail.

Diagram of Silverlight DRM

Note   Silverlight DRM scenarios are not supported for a Windows XP operating system installed on FAT32.

1. Silverlight Client Accesses Content

The end user attempts to play some DRM protected content in a Silverlight application that is stored on the distribution server (a distribution server, usually a Web server, is used to distribute your content). The Silverlight client downloads the content (or some of the content in the case of streaming) and the header.

2. Is the Client Individualized?

Before Silverlight requests the license to decrypt the content, Silverlight must first determine whether the end user’s computer has the appropriate DRM software installed. This software is called the individualization component and is the client component of DRM that is required before any protected content can be played. The individualization component software enables the client computer to request and use a DRM License and protects sensitive data used in the decryption process.

If the appropriate individualized component software is not already on the client, the client requests the component from the Microsoft Individualization Service. The process of obtaining the individualized component software is called Individualization. Silverlight individualizes the user's computer by sending information to the Microsoft Individualization Service (note that the end user can block sending this information; see Error Handling later in this topic). Once valid individualization component is installed, the client does not need to individualize again until new versions of the individualization component are made available by Microsoft.

3. Silverlight Requests License

Once valid individualization component software exists on the client, it is ready to play DRM. Now, when a page with DRM content is visited, the Silverlight client will contact the PlayReady License Server to obtain a license (the License Server is controlled by you or your service provider). If the License Server approves the request, it issues a license which will be used by the client to decrypt the particular media file. After this, the content can be played.

PlayReady vs. WMDRM

The Silverlight client can use two forms of DRM encryption/decryption: the traditional Windows Media Digital Rights Management 10 (WMDRM 10), and the newer PlayReady with AES encryption. This enables existing content encrypted using the WMDRM 10 SDK to play back within both Silverlight and other Windows Media playback software that supports DRM (such as Windows Media Player), and Silverlight-only media to offer a higher degree of security.

NoteNote:

PlayReady and its associated AES encryption are not used only in Silverlight. For more information about PlayReady, see PlayReady Whitepaper.

NoteNote:

Although Silverlight can play PlayReady and WMDRM encrypted content, it does not support the entire ecosystems of these technologies. In addition, in order to play WMDRM encrypted content in Silverlight, you still need at least one PlayReady server (see the earlier diagram).

Limitations When Using Silverlight DRM

Even if you are only going to encrypt content using the WMDRM, it is important to note that you will need at least one PlayReady License Server to distribute licenses to the Silverlight client. It is also important to note that Silverlight DRM currently supports only a portion of PlayReady features. The following is a list of important limitations when using Silverlight DRM:

  • Silverlight does not support all the file types that PlayReady does. Silverlight DRM only supports Windows Media Audio (WMA), Windows Media Video (WMV), and PYA/PYV files for PlayReady.

  • PlayReady license can specify rights and restrictions that define exactly how the content may be used and under what conditions; however, when using Silverlight DRM the only license type available is a non-persistent, play-once license.

  • No license caching.

Considerations for Using PlayReady Encryption vs. WMDRM Encryption

When setting up an architecture for using DRM with Silverlight, there are a number of considerations to keep in mind:

  • If you are streaming content, are you encoding and streaming in real-time from live sources, or are you streaming pre-encrypted files on demand?

  • Are your customers playing content using Silverlight or are they also using Windows Media Player?

  • Do you have a large library of WMDRM encrypted content (encrypted using the WMRM SDK) that you want to serve to Silverlight customers or can you encrypt all of your content using PlayReady?

Regardless of these considerations, if you want to serve DRM content to Silverlight, you need to purchase at least one PlayReady License Server; however, answering these questions can have an effect on whether you can get away with only using PlayReady encryption versus needing to additionally be able to handle WMDRM-encrypted content in your overall DRM solution.

  • Streaming Content: Currently, PlayReady Server SDK only supports file encryption so it does not support live encryption where you encode streaming content in real-time from live sources; rather, you must use WMDRM in this scenario. See Playing WMDRM Content in Silverlight later in this topic for possible solutions for integrating WMDRM with Silverlight. Note that pre-encrypted content streaming is supported by both WMDRM and PlayReady.

  • Client Player: If your customers are only using Silverlight to playback DRM, then you can encrypt everything with PlayReady; however, if some customers are also using Windows Media Player (WMP), then you need to encrypt your content using WMDRM also.

  • Your Content Library: Regardless of whether you are only playing content in Silverlight, if you do not want to re-encrypt your protected content using PlayReady for whatever reason, you will need to create a DRM solution that takes into account WMDRM encrypted content.

NoteNote:

Silverlight does not support WMDRM content with script stream (script streams provide text with the stream such as with closed captioning). If you play WMDRM content with script stream, the audio and video will be played as usual but the script stream will be ignored.

Playing WMDRM Content in Silverlight

The following figure conceptualizes how an existing WMDRM encrypted content library that serves non-Silverlight (legacy WMDRM) clients can be used with Silverlight clients:

Silverlight DRM diagram.

In order to include the library, you will need to include some logic on the Silverlight Client to route the license request to the proper PlayReady License Server (see Point to DRM Content from a Silverlight Application later in this topic).

Integrating DRM in Silverlight

There are a number of steps needed to integrate DRM into Silverlight:

  1. Set up the necessary server infrastructure to serve up DRM protected content.

  2. Point to this protected content from your Silverlight application using MediaElement.

  3. Handle expected errors (for example, when the end user does not allow DRM content).

  4. If needed, subclass the LicenseAcquirer class to gain custom business logic.

Set up Server Infrastructure

In order to use DRM, you must first encrypt the content you wish to protect and make it available to clients from a distribution server. You do this by using encryption software. As already mentioned, you have two options for encryption:

  • WMDRM 10 SDK.

  • PlayReady Server SDK.

To learn more about these technologies and associated server configurations, see PlayReady vs. WMDRM earlier in this topic.

When you encrypt and package your content, you specify a License Acquisition URL (LAURL). You have the opportunity in the Silverlight application to override this value before sending the License Challenge to a License Server – this is particularly useful if you have one library of WMDRM encrypted content and wish to serve that content to both Silverlight and Windows Media Player clients. (See Playing WMDRM Content in Silverlight earlier and Point to DRM Content from a Silverlight Application next).

Point to DRM Content from a Silverlight Application

If you are using only PlayReady servers to encrypt your encoded content you can simply point to the content using the Source property of the MediaElement.

<MediaElement x:Name="myMediaElement" Source="myProtectedVideo.wmv" />

You can do this because content encrypted using the PlayReady SDK includes in its content header the URI location of the licensing server. However, if you are using the WMRM SDK to encrypt your content, the location of the licensing server will not be included in the header and therefore you will need to specify this URI. To do this, use the LicenseServerUriOverride property to specify the URI for the MediaElement to use to find the license:

myMediaElement.LicenseAcquirer.LicenseServerUriOverride = 
    new Uri("http://myLicenseServer.asmx", UriKind.Absolute);

Detecting DRM State

You can use the MediaElementState enumeration to detect what state the MediaElement is in – specifically whether the MediaElement is currently individualizing the Silverlight client or acquiring a license (see Silverlight DRM Conceptual Overview earlier in this topic). One reason for detecting these states is to allow you to give feedback to the user of what is going on while the MediaElement prepares to play the content. For example, you could inform the user when individualization was taking place or when a license was being requested using a TextBlock, as in the following example.

if (myMediaElement.CurrentState == MediaElementState.Individualizing)
{
    myStateTextBlock.text = "Downloading DRM Client";
}
else if(myMediaElement.CurrentState == MediaElementState.AcquiringLicense)
{
    myStateTextBlock.text = "Aquiring License";
}

Error Handling

There are a number of errors that users may get using DRM in Silverlight. It is important that developers anticipate these errors and display appropriate messages so that users understand why playback is not working the way they expect.

One error users may run into specific to DRM is when the user has opted to not allow DRM by going into the Silverlight Configuration dialog box and un-checking the checkbox shown in the following illustration.

Silverlight Configuration for DRM

This in effect does not allow the user’s client machine to request Individualization from Microsoft Individualization Servers (see Silverlight DRM Conceptual Overview earlier in this topic).

If the MediaElement attempts to play DRM content in this scenario, the MediaElement will raise a new MediaFailed event with the following error: 6008 DRM_E_INDIVIDUALIZATION_DISALLOWED.

You may want to listen for this error and raise your own custom message when it occurs.

Below is a list of errors associated with Silverlight DRM. Notice that the error numbers are consecutive between 6000 and 6008.

6000 DRM_E_UNABLE_TO_PLAY_PROTECTED_CONTENT

MediaElement failed to play the DRM protected content.

6001 DRM_E_INDIV_DOWNLOAD_FAILURE

The individualization component software failed to download to the user’s computer. This error would come up when the MediaElement is in the IndividualizingMediaElementState. One possible reason for this error is that the Silverlight client cannot connect the Microsoft Individualization Server.

6002 DRM_E_LICENSE_ACQUISITION_FAILURE

The license acquisition failed. This error would come up when the MediaElement is in the AcquiringLicenseMediaElementState. One possible reason for this error is that the Silverlight Client cannot connect to the license server.

6003 DRM_E_INDIV_INSTALL_FAILURE

The individualization component software failed to install.

6004 DRM_E_SILVERLIGHT_CLIENT_REVOKED

The Silverlight client certificates are out of date and needs to be updated.

6005 DRM_E_INVALID_PROTECTED_FILE_HEADER

The processing of the file header failed. For example, the header might be mal-formed.

6006 DRM_E_LICENSE_PROCESSING_FAILURE

Processing of the license failed on the Silverlight client. This error would come up when the MediaElement is in the AcquiringLicense MediaElementState.

6007 DRM_E_LICENSE_ACQUISITION_SERVICE_SPECIFIC

The PlayReady License server allows the server developer to return an error specific to the service. This could be something like "You need to pay your bill.", "I'm sorry, the service is unavailable", "You have exhausted your monthly stream count", etc. The SOAP exception returned from the license server has additional data in the CustomData field added by the server. You will need to write application logic in the Silverlight application to interpret this. Mainly these responses will be used when you implement a custom license acquisition (see Add Custom Logic later in this topic).

6008 DRM_E_INDIVIDUALIZATION_DISALLOWED

User disabled DRM in their Silverlight configuration settings (see above in this section).

NoteNote:

If you are implementing your own custom license acquisition, you must add the headers msprdrm_server_redirect_compat:false and msprdrm_server_exception_compat:false to your HTTP Web requests or errors and redirect messages will not work correctly. See the code example in the following section.

NoteNote:

If you start multiple asynchronous operations on the same LicenseAcquirer or DomainAcquirer, an InvalidOperationException is thrown.

Add Custom Logic

The LicenseAcquirer class is used by the MediaElement to handle acquiring licenses for DRM encrypted content from the PlayReady License Server. You can subclass the LicenseAcquirer class and add custom logic like adding your own custom authentication scheme to the license request.

The example below shows how to override the LicenseAcquirer class (named "ManualLicenseAcquirer") and have a MediaElement use it to acquire the license.

<StackPanel x:Name="LayoutRoot" Background="Gray" Orientation="Vertical">
   <MediaElement x:Name="myME" Height="100"/>
</StackPanel>
public partial class Page : UserControl
{

    public Page()
    {
      InitializeComponent();
      this.Loaded += new RoutedEventHandler(Page_Loaded);
    }

    void Page_Loaded(object sender, RoutedEventArgs e)
    {
      // Test a full fledged manual acquirer

      // Set the LicenseAcquirer of the MediaElement to the custom License Acquirer
      // defined in this sample.
      myME.LicenseAcquirer = new ManualLicenseAcquirer(myME.Name);

      // Set the License URI to proper License Server address.
      myME.LicenseAcquirer.LicenseServerUriOverride = new Uri("https://contoso.com/myLicenseServer.asmx", UriKind.Absolute);
      myME.MediaFailed += new EventHandler<ExceptionRoutedEventArgs>(myME_MediaFailed);

      // Set the source of the MediaElement to the URL of the media encrypted with WMDRM.
      myME.Source = new Uri("https://contoso.com/wmdrm_url.wmv", UriKind.Absolute);
    }

    void myME_MediaFailed(object sender, ExceptionRoutedEventArgs e)
    {
      string errorMessage = "";
      if (e.ErrorException.ToString().Contains(" 6001 "))
      {
          errorMessage = "The individualization component software failed to" +
                         " download to the user’s computer. This error would" +
                         " come up when the MediaElement is in the Individualizing" +
                         " MediaElementState. One possible reason for this error is" +
                         " that the Silverlight client cannot connect the Microsoft" +
                         " Individualization Server.";
      }
      else if (e.ErrorException.ToString().Contains(" 6004 "))
      {
          errorMessage = "The individualization software on the Silverlight client is" +
                         " out of date and needs to be updated.";  
      }
      else
      {
          errorMessage = "MediaFailed: " + e.ErrorException.Message + ".";
      }
      System.Windows.Browser.HtmlPage.Window.Alert(errorMessage);
    }

    // makes license request explicitly
    public class ManualLicenseAcquirer : LicenseAcquirer
    {
      private string challengeString;
      string _mediaElementName;

    public ManualLicenseAcquirer(string mediaElementName)
    {
      _mediaElementName = mediaElementName;
    }

    // The default implementation of OnAcquireLicense calls into the MediaElement to acquire a
    //  license. It is called when the Media pipeline is building a topology and will be raised
    // before MediaOpened is raised.
    protected override void OnAcquireLicense(System.IO.Stream licenseChallenge, Uri licenseServerUri)
    {
      StreamReader sr = new StreamReader(licenseChallenge);
      challengeString = sr.ReadToEnd();

      // Need to resolve the URI for the License Server -- make sure it is correct
      // and store that correct URI as resolvedLicenseServerUri.
      Uri resolvedLicenseServerUri;
      if (LicenseServerUriOverride == null)
        resolvedLicenseServerUri = licenseServerUri;
      else
      resolvedLicenseServerUri = LicenseServerUriOverride;

      // Make a HttpWebRequest to the License Server.
      HttpWebRequest request = WebRequest.Create(resolvedLicenseServerUri) as HttpWebRequest;
      request.Method = "POST";

      // Set ContentType through property    
      request.ContentType = "application/xml";

      //  ADD REQUIRED HEADERS.
      // The headers below are necessary so that error handling and redirects are handled 
      // properly via the Silverlight client.
      request.Headers["msprdrm_server_redirect_compat"] = "false";
      request.Headers["msprdrm_server_exception_compat"] = "false";

      //  Initiate getting request stream  
      IAsyncResult asyncResult = request.BeginGetRequestStream(new AsyncCallback(RequestStreamCallback), request);
    }

    // This method is called when the asyncrhonous operation completes.
    void RequestStreamCallback(IAsyncResult ar)
    {
      HttpWebRequest request = ar.AsyncState as HttpWebRequest;

      // populate request stream  
      request.ContentType = "text/xml";
      Stream requestStream = request.EndGetRequestStream(ar);
      StreamWriter streamWriter = new StreamWriter(requestStream, System.Text.Encoding.UTF8);

      streamWriter.Write(challengeString);
      streamWriter.Close();

      // Make async call for response  
      request.BeginGetResponse(new AsyncCallback(ResponseCallback), request);
    }

    private void ResponseCallback(IAsyncResult ar)
    {
      HttpWebRequest request = ar.AsyncState as HttpWebRequest;
      WebResponse response = request.EndGetResponse(ar);
      SetLicenseResponse(response.GetResponseStream());
    }
  }
}
Public Class Page
    Inherits UserControl
    
    Public Sub New()
        MyBase.New
        InitializeComponent
        AddHandler Loaded, AddressOf Me.Page_Loaded
    End Sub
    
    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
        ' Test a full fledged manual acquirer
        ' Set the LicenseAcquirer of the MediaElement to the custom License Acquirer
        ' defined in this sample.
        myME.LicenseAcquirer = New ManualLicenseAcquirer(myME.Name)
        ' Set the License URI to proper License Server address.
        myME.LicenseAcquirer.LicenseServerUriOverride = New Uri("https://contoso.com/myLicenseServer.asmx", UriKind.Absolute)
        AddHandler myME.MediaFailed, AddressOf Me.myME_MediaFailed
        ' Set the source of the MediaElement to the URL of the media encrypted with WMDRM.
        myME.Source = New Uri("http:, contoso.com/wmdrm_url.wmv", UriKind.Absolute);)
    End Sub
    
    Private Sub myME_MediaFailed(ByVal sender As Object, ByVal e As ExceptionRoutedEventArgs)
        Dim errorMessage As String = ""
        If e.ErrorException.ToString.Contains(" 6001 ") Then
            errorMessage = "The individualization component software failed to" & _
                           " download to the user's computer. This error would" & _
                           " come up when the MediaElement is in the Individualizing" & _
                           " MediaElementState. One possible reason for this error is" & _
                           " that the Silverlight client cannot connect the Microsoft" & _
                           " Individualization Server."
        ElseIf e.ErrorException.ToString.Contains(" 6004 ") Then
            errorMessage = "The individualization software on the Silverlight client is" & _
                           " out of date and needs to be updated."
        Else
            errorMessage = "MediaFailed: " & _
                        +  e.ErrorException.Message + "."
        End If
        System.Windows.Browser.HtmlPage.Window.Alert(errorMessage)
    End Sub
    
    ' makes license request explicitly
    Public Class ManualLicenseAcquirer
        Inherits LicenseAcquirer
        
        Private challengeString As String
        
        Private _mediaElementName As String
        
        Public Sub New(ByVal mediaElementName As String)
            MyBase.New
            _mediaElementName = mediaElementName
        End Sub
        
        ' The default implementation of OnAcquireLicense calls into the MediaElement to acquire a
        '  license. It is called when the Media pipeline is building a topology and will be raised
        ' before MediaOpened is raised.
        Protected Overrides Sub OnAcquireLicense(ByVal licenseChallenge As System.IO.Stream, ByVal licenseServerUri As Uri)
            Dim sr As StreamReader = New StreamReader(licenseChallenge)
            challengeString = sr.ReadToEnd
            ' Need to resolve the URI for the License Server -- make sure it is correct
            ' and store that correct URI as resolvedLicenseServerUri.
            Dim resolvedLicenseServerUri As Uri
            If (LicenseServerUriOverride Is Nothing) Then
                resolvedLicenseServerUri = licenseServerUri
            Else
                resolvedLicenseServerUri = LicenseServerUriOverride
            End If
            ' Make a HttpWebRequest to the License Server.
            Dim request As HttpWebRequest = CType(WebRequest.Create(resolvedLicenseServerUri),HttpWebRequest)
            request.Method = "POST"
            ' Set ContentType through property    
            request.ContentType = "application/xml"
            '  ADD REQUIRED HEADERS.
            ' The headers below are necessary so that error handling and redirects are handled 
            ' properly via the Silverlight client.
            request.Headers("msprdrm_server_redirect_compat") = "false"
            request.Headers("msprdrm_server_exception_compat") = "false"
            '  Initiate getting request stream  
            Dim asyncResult As IAsyncResult = request.BeginGetRequestStream(New AsyncCallback(RequestStreamCallback), request)
        End Sub
        
        ' This method is called when the asyncrhonous operation completes.
        Private Sub RequestStreamCallback(ByVal ar As IAsyncResult)
            Dim request As HttpWebRequest = CType(ar.AsyncState,HttpWebRequest)
            ' populate request stream  
            request.ContentType = "text/xml"
            Dim requestStream As Stream = request.EndGetRequestStream(ar)
            Dim streamWriter As StreamWriter = New StreamWriter(requestStream, System.Text.Encoding.UTF8)
            streamWriter.Write(challengeString)
            streamWriter.Close
            ' Make async call for response  
            request.BeginGetResponse(New AsyncCallback(ResponseCallback), request)
        End Sub
        
        Private Sub ResponseCallback(ByVal ar As IAsyncResult)
            Dim request As HttpWebRequest = CType(ar.AsyncState,HttpWebRequest)
            Dim response As WebResponse = request.EndGetResponse(ar)
            SetLicenseResponse(response.GetResponseStream)
        End Sub
    End Class
End Class