This proposal extends [[!HTML5]] providing APIs to control playback of protected content.

The API supports use cases ranging from simple clear key decryption to high value video (given an appropriate user agent implementation). License/key exchange is controlled by the application, facilitating the development of robust playback applications supporting a range of content decryption and protection technologies.

This specification does not define a content protection or Digital Rights Management system. Rather, it defines a common API that may be used to discover, select and interact with such systems as well as with simpler content encryption systems. Implementation of Digital Rights Management is not required for compliance with this specification: only the Clear Key system is required to be implemented as a common baseline.

The common API supports a simple set of content encryption capabilities, leaving application functions such as authentication and authorization to page authors. This is achieved by requiring content protection system-specific messaging to be mediated by the page rather than assuming out-of-band communication between the encryption system and a license or other server.

The working group maintains a list of all bug reports that the editors have not yet tried to address; there are also open bugs in the previous bug tracker. This draft highlights some of the pending issues that are still to be discussed in the working group. No decision has been taken on the outcome of these issues including whether they are valid.

Implementors should be aware that this specification is not stable. Implementors who are not taking part in the discussions are likely to find the specification changing out from under them in incompatible ways. Vendors interested in implementing this specification before it eventually reaches the Candidate Recommendation stage should join the mailing list mentioned below and take part in the discussions.

Bug 20944 - The specification should do more to encourage/ensure CDM-level interoperability.

This specification contains sections for describing security and privacy considerations. These sections are not final and review is welcome.

Introduction

This specification enables script to select content protection mechanisms, control license/key exchange, and implement custom license management algorithms. It supports a wide range of use cases without requiring client-side modifications in each user agent for each use case. This enables content providers to develop a single application solution for all devices.

Supported content is encrypted per container-specific "common encryption" specifications, enabling use across key systems. Supported content has an unencrypted container, enabling metadata to be provided to the application and maintaining compatibility with other features.

A generic stack implemented using the API is shown below. This diagram shows an example flow; other combinations of API calls and events are possible.

A generic stack implemented using the proposed APIs

Definitions

Content Decryption Module (CDM)

Content Decryption Module (CDM) is the client component that provides the functionality, including decryption, for one or more .

Implementations may or may not separate the implementations of CDMs or treat them as separate from the user agent. This is transparent to the API and application.

All messages and communication to and from the CDM, such as between the CDM and a license server, MUST be passed through the user agent. The CDM MUST NOT make direct out-of band network requests. All messages and communication other than those described in Origin-Independent Individualization MUST be passed through the application via the APIs defined in this specification. Specifically, all communication that contains application-, -, or content-specific information or is sent to a URL specified by the application or based on its origin, MUST pass through the APIs. This includes all license exchange messages.

Key System

A Key System is a generic term for a decryption mechanism and/or content protection provider. Key System strings provide unique identification of a Key System. They are used by the user agent to select a and identify the source of a key-related event. User agents MUST support the Common Key Systems. User agents MAY also provide additional CDMs with corresponding Key System strings.

A Key System string is always a reverse domain name. Key System strings are compared using case-sensitive matching. It is RECOMMENDED that CDMs use simple lower-case ASCII key system strings.

For example, "com.example.somesystem".

Within a given system ("somesystem" in the example), subsystems may be defined as determined by the key system provider. For example, "com.example.somesystem.1" and "com.example.somesystem.1_5". Key System providers should keep in mind that these will be used for comparison and discovery, so they should be easy to compare and the structure should remain reasonably simple.

Key Session

A Key Session, or simply Session, provides a context for message exchange with the CDM as a result of which key(s) are made available to the . Sessions are embodied as MediaKeySession objects. Each Key session is associated with a single instance of provided in the call.

Each Key Session is associated with a single MediaKeys object, and only media element(s) associated with that object may access key(s) associated with the session. Other MediaKeys objects, instances, and media elements MUST NOT access the key session or use its key(s). Key sessions and the keys they contain are no longer usable by the CDM for decryption when the session is closed, including when the MediaKeySession object is destroyed.

Key IDs MUST be unique within a session.

Session ID

A Session ID is a unique string identifier generated by the that can be used by the application to identify MediaKeySession objects.

A new Session ID is generated each time the user agent and CDM successfully create a new session.

Each Session ID SHALL be unique within the browsing context in which it was created. For session types for which the algorithm returns true, Session IDs MUST be unique within the over time, including across browsing sessions.

The underlying content protection protocol does not necessarily need to support Session IDs.

Key

Unless otherwise stated, key refers to a decryption key that can be used to decrypt blocks within . Each such key is uniquely identified by a . A key is associated with the session used to provide it to the CDM. (The same key may be present in multiple sessions.) Such keys MUST only be provided to the via an call. (They may later be loaded by as part of the stored session data.)

A key is considered usable if the CDM is certain the key is currently usable to decrypt

For example, a key is not usable if its license has expired.

Authors SHOULD encrypt each set of stream(s) that requires enforcement of a meaningfully different policy with a distinct key (and key ID). For example, if policies may differ between two video resolutions, stream(s) containing one resolution should not be encrypted with the key used to encrypt stream(s) containing the other resolution. When encrypted, audio streams SHOULD NOT use the same key as any video stream. This is the only way to ensure enforcement and compatibility across clients.

Key ID

A key is associated with a key ID, which uniquely identifies a key. The container specifies the ID of the key that can decrypt a block or set of blocks within the . MAY contain key ID(s) to identify the keys that are needed to decrypt the media data. However, there is no requirement that Initialization Data contain any or all key IDs used in the or . Licenses provided to the CDM associate each key with a key ID so the can select the appropriate key when decrypting an encrypted block of media data.

Known Key

A key is considered to be known to a session if the CDM's implementation of the session contains any information - specifically the - about it, regardless of whether the actual key is usable or its value is known. Known keys are exposed via the attribute.

Keys are considered known even after they become unusable, such as due to expiration. Keys only become unknown when they are explicitly removed from a session.

For example, a key could become unknown if an call provides a new license that does not include the key and includes instructions to replace the license(s) that previously contained the key.

License

A license is key system-specific state information that includes one or more key(s) - each associated with a - and potentially other information about key usage.

Initialization Data

usually require a block of initialization data containing information about the stream to be decrypted before they can construct a license request message. This block could be a simple key or content ID or a more complex structure containing such information. It should always allow unique identification of the key(s) needed to decrypt the content. This initialization information MAY be obtained in some application-specific way or provided with the .

Initialization Data is a generic term for container-specific data that is used by a to generate a license request. Initialization data found with the is provided to the application in the attribute of the event.

The format of the initialization data depends upon the type of container, and containers MAY support more than one format of initialization data. The Initialization Data Type is a string that indicates what format the initialization data is provided in. Initialization Data Type strings are always matched case-sensitively. It is RECOMMENDED that Initialization Data Type strings are lower-case ASCII strings.

The Encrypted Media Extensions Stream Format and Initialization Data Format Registry [[EME-REGISTRY]] provides the mapping from initialization data type string to the specification for each format.

Initialization Data MUST be a fixed value for a given set of stream(s) or . It MUST only contain information related to the keys required to play a given set of stream(s) or . It MUST NOT contain application data, client-specific data, user-specific data, key(s), or executable code.

Initialization Data SHOULD NOT contain Key System-specific data or values. Implementations MUST support the common formats defined [[EME-REGISTRY]] for each they support.

Use of proprietary formats/contents is discouraged, and supporting or using only proprietary formats is strongly discouraged. Proprietary formats should only be used with pre-existing content or on pre-existing devices that do not support the common formats.

Distinctive Identifier

A distinctive identifier is a piece of data, implication of the possession of a piece of data, or an observable behavior or timing for which all of the following criteria hold:

  • It is not shared across a large population of users or devices.

  • It is exposed outside the client device or exposed to the application such that the application has the opportunity to send it (even if in encrypted form if decryptable outside the device) or information about it outside the client device.

  • It is used in more than one session or is potentially used in one persistent session across the point of persistence.

A distinctive identifier is typically unique to a user or device, but an identifier does not need to be strictly unique to be distinctive. For example, an identifier shared among a small number of users could still be distinctive.

Examples of distinctive identifiers include but are not limited to:

  • A string of bytes that is included in key requests and that is different from the string included by other devices.

  • A public key included in key requests that is different from the public keys included in the requests by other devices.

  • Demonstration of possession of a private key (e.g. by signing some data) that other devices do not have.

  • An identifier for such a key.

Examples of things that are not distinctive identifiers:

  • A public key shared among all copies of a given CDM version if the installed base is large.

  • A nonce or ephemeral key that is unique but used in only one session.

  • Device-unique keys used in attestations between, for example, the video pipeline and the CDM when the CDM does not let these attestations further flow to the application and instead makes a new attestation on its own using a key that does not constitute a distinctive identifier.

The source of the identifier does not affect whether it is distinctive. For example, an identifier that is permanently part of the client device, contained in the CDM, generated on the client, or generated as part of some individualization or other provisioning process is considered distinctive if it meets the criteria above.

Cross Origin Limitations

During playback, embedded media data is exposed to script in the embedding . In order for the API to provide in the event, MUST be with the embedding page. If is cross-origin with the embedding document, authors SHOULD use the attribute on the and CORS headers on the response to make it .

Mixed Content Limitations

During playback, embedded media data is exposed to script in the embedding . In order for the API to provide in the event, MUST NOT be Mixed Content [[!MIXED-CONTENT]].

Obtaining Access to Key Systems

This section defines the mechanism for obtaining access to a key system. The inclusion of capabilities in the request also enables feature detection.

Navigator Extension: requestMediaKeySystemAccess()

Promise<MediaKeySystemAccess> requestMediaKeySystemAccess()

Requests access to the specified . When supportedConfigurations is specified, the configuration specified by at least one of its elements must be supported. The resulting MediaKeySystemAccess will correspond to the first such elment.

Any permission checks or user interaction, such as a prompt, MUST be performed before resolving the promise.

If the keySystem is not supported or not allowed (in one at least one of the supportedConfigurations, if specified), the promise is rejected. Otherwise, it is resolved with a new MediaKeySystemAccess object.

DOMString keySystem
The for which access is being requested.
sequence<MediaKeySystemConfiguration> supportedConfigurations
A sequence of MediaKeySystemConfiguration configurations to try in order. The first element with a satisfiable configuration will be used.
  1. If keySystem is the empty string, return a promise rejected with .

  2. If supportedConfigurations is empty, return a promise rejected with .

  3. Let document be the calling context's .

  4. If the incumbant settings object is not a secure context, run the following steps:

    Support for communication from Secure Contexts to devices on a private network is an open issue. A bug will be filed with the Web Application Security Working Group and referenced here.

    1. If the result of running the algorithm is Allowed, skip the next step.

      This step is DEPRECATED. It is expected that removal of this step will be evaluated during Candidate Recommendation (CR). Authors are advised that implementations MAY remove it before then.

    2. Reject promise with .

      Requiring Secure Contexts is not a replacement for other security- and privacy-related requirements and recommendations. Implementations MUST meet all related requirements and SHOULD follow related recommendations such that the risks on in an secure context would be similar.

  5. Let origin be the of document.

  6. Let promise be a new promise.

  7. Run the following steps in parallel:

    1. If keySystem is not one of the supported by the user agent, reject promise with . String comparison is case-sensitive.

    2. Let implementation be the implementation of keySystem.

    3. For each value in supportedConfigurations:

      1. Let candidate configuration be the value.

      2. Let supported configuration be the result of executing the algorithm on implementation, candidate configuration, and origin.

      3. If supported configuration is not null, run the following steps:

        1. Let access be a new MediaKeySystemAccess object, and initialize it as follows:

          1. Set the attribute to keySystem.

          2. Let the configuration value be supported configuration.

          3. Let the cdm implementation value be implementation.

        2. Resolve promise with access and abort these steps.

    4. Reject promise with .

      keySystem was not supported/allowed or none of the configurations in supportedConfigurations were supported/allowed.

  8. Return promise.

Algorithms

Get Supported Configuration

Given a implementation implementation, MediaKeySystemConfiguration candidate configuration, and origin, this algorithm returns a supported configuration or null as appropriate.

Unrecognized dictionary members in candidate configuration are ignored per [[WebIDL]] and will never reach this algorithm. Thus, they cannot be considered as part of the configuration.

  1. Let accumulated configuration be a new MediaKeySystemConfiguration dictionary.

  2. Set the member of accumulated configuration to equal the member of candidate configuration.

  3. If the member is in candidate configuration, run the following steps:

    1. Let supported types be an empty sequence of DOMStrings.

    2. For each value in candidate configuration's member:

      1. Let initDataType be the value.

      2. If the implementation supports generating requests based on initDataType, add initDataType to supported types. String comparison is case-sensitive. The empty string is never supported.

        The initDataType MUST be supported independent of content types in order to avoid unexpectedly rejecting the configuration in later steps. Support for initDataType includes both license generation and, when appropriate, extraction from media data. See Initialization Data Type Support requirements.

    3. If supported types is empty, return null.

    4. Set the member of accumulated configuration to supported types.

  4. Follow the steps for the value of candidate configuration's member from the following list:

    If the implementation does not support a persistent in combination with accumulated configuration, return null.

    Continue.

    If the implementation requires a in combination with accumulated configuration, return null.

  5. Set the member of accumulated configuration to equal candidate configuration's member.

  6. Follow the steps for the value of candidate configuration's member from the following list:

    If the implementation does not support persisting state in combination with accumulated configuration, return null.

    Continue.

    If the implementation requires persisting state in combination with accumulated configuration, return null.

  7. Set the member of accumulated configuration to equal the value of candidate configuration's member.

  8. Follow the steps for the first matching condition from the following list:

    If the member is in candidate configuration

    Let session types be candidate configuration's member.

    Otherwise

    Let session types be [ ].

  9. For each value in session types:

    1. Let session type be the value.

    2. If the implementation does not support session type in combination with accumulated configuration, return null.

      Unsupported combinations include but are not limited to a session type for which the algorithm returns true when accumulated configuration's value is .

    3. If accumulated configuration's value is and the result of running the algorithm on session type is true, change accumulated configuration's value to .

  10. Set the member of accumulated configuration to session types.

  11. If the member is in candidate configuration:

    1. Let video capabilities be the result of executing the algorithm on Video, candidate configuration's member, and accumulated configuration.

    2. If video capabilities is null, return null.

    3. Set the member of accumulated configuration to video capabilities.

  12. If the member is in candidate configuration:

    1. Let audio capabilities be the result of executing the algorithm on Audio, candidate configuration's member, and accumulated configuration.

    2. If audio capabilities is null, return null.

    3. Set the member of accumulated configuration to audio capabilities.

  13. If accumulated configuration's value is , follow the steps for the first matching condition from the following list:

    If the implementation requires a for any of the combinations in accumulated configuration

    Change accumulated configuration's value to .

    Otherwise

    Change accumulated configuration's value to .

  14. If accumulated configuration's value is , follow the steps for the first matching condition from the following list:

    If the implementation requires persisting state for any of the combinations in accumulated configuration

    Change accumulated configuration's value to .

    Otherwise

    Change accumulated configuration's value to .

  15. If implementation in the configuration specified by the combination of the values in accumulated configuration is not supported or not allowed in the origin, return null.

    In this step, "supported" includes the implementation being available for use when this algorithm returns, not just user agent support for such an implementation.

  16. If accumulated configuration's value is :

    1. If the is not unique per-origin and clearable, return null.

    2. If there is no persisted consent covering accumulated configuration for the origin, it is RECOMMENDED that implementations request user consent to use Distinctive Identifier(s).

    A previous user consent for a prompt that did not include use of a (with similar properties) would not be considered as covering this accumulated configuration, which implies use of such an identifier.

    Implementations MAY require consent for other reasons, such as the security properties of the CDM implementation.

    The "unique per-origin" and "clearable" conditions cannot be false in a compliant implementation because implementations MUST use per-origin identifiers and allow the user to clear identifier.

  17. Return accumulated configuration.

Get Supported Capabilities for Media Type

Given a media type (Audio or Video), MediaKeySystemMediaCapability sequence requested media capabilities, and MediaKeySystemConfiguration partial configuration, this algorithm returns a sequence of supported MediaKeySystemMediaCapability valuess for this media type or null as appropriate.

  1. Let local accumulated configuration be a local copy of partial configuration.

  2. Let supported media capabilities be an empty sequence of MediaKeySystemMediaCapability dictionaries.

  3. For each requested media capability in requested media capabilities:

    1. Let contentType be requested media capability's member.

    2. Let robustness be requested media capability's member.

    3. If contentType is the empty string, return null.

    4. If contentType is an invalid or unrecognized MIME type, continue to the next iteration.

    5. Let configuration be empty.

    6. Let container be the container type specified by contentType.

    7. If the user agent does not support container, continue to the next iteration. The case-sensitivity of string comparisons is determined by the appropriate RFC.

      Per RFC 6838 [[RFC6838]], "Both top-level type and subtype names are case-insensitive."

    8. Add container to configuration.

    9. Let parameters be the RFC 6381 [[!RFC6381]] parameters, if any, specified by contentType.

    10. If parameters is not empty, run the following steps:

      1. If the user agent does not recognize one or more parameters, continue to the next iteration.

      2. Let media types be the set of media types specified by parameters. It MAY be empty. The case-sensitivity of string comparisons is determined by the appropriate RFC or other specification.

        For example, all of the codecs. Case-sensitive string comparison is RECOMMENDED because RFC 6381 [[RFC6381]] says, "Values are case sensitive" for some formats.

      3. Add all media types to configuration.

    11. If contentType is not strictly a media type type, continue to the next iteration.

      For example, if media type is Video and the top-level type is not "video" or media types contains non-video codecs.

    12. If robustness is not the empty string, run the following steps:

      1. If robustness is an unrecognized value or not supported by implementation, continue to the next iteration. String comparison is case-sensitive.

      2. Add robustness to configuration.

    13. If the user agent and implementation do not support playback of encrypted as specified by configuration, including all media types, in combination with local accumulated configuration, continue to the next iteration.

      This configuration (content type and robustness) must be supported with all previously added supported configurations.

    14. Add requested media capability to supported media capabilities.

      This step ensures that the values of the members of entries in supported media capabilities are exactly the strings supplied in requested media capability without modification by the User Agent.

    15. If media type is Video:

      Add requested media capability to the member of local accumulated configuration.

      If media type is Audio:

      Add requested media capability to the member of local accumulated configuration.

      This step ensures that configurations are always checked with configurations from previous iterations, including from previous calls to this algorithm. Otherwise, only configurations from previous calls to this algorithm would be checked in subsequent calls.

  4. If supported media capabilities is empty, return null.

    None of the MediaKeySystemMediaCapability elements in requested media capabilities is supported in combination with partial configuration.

  5. Return supported media capabilities.

Are non-secure contexts allowed? - DEPRECATED

This algorithm is DEPRECATED. When removed, callers will behave as if it returned Not Allowed.

Implementations SHOULD return Not Allowed. Implementations MAY return Allowed.

MediaKeySystemConfiguration dictionary

required
When used in a call to
The returned object MUST support this feature.
When returned by a MediaKeySystemAccess object
CDM instances created by the object MAY use this feature.
optional
When used in a call to
The returned object MAY support and use this feature.
When returned by a MediaKeySystemAccess object
This value cannot and MUST NOT be present in such an object.
not-allowed
When used in a call to
The returned object MUST function without using this feature and MUST NOT use it at any time.
When returned by a MediaKeySystemAccess object
CDM instances created by the object MUST NOT use this feature.
DOMString label = ""
An optional label which will be preserved in the MediaKeySystemConfiguration returned from the method of MediaKeySystemAccess.
sequence<DOMString> initDataTypes
A list of supported names. The capability of this object is considered supported if the list is empty or contains one or more values that are supported with all other members (as determined by the algorithm). Values in the sequence MUST not be the empty string.
sequence<MediaKeySystemMediaCapability> audioCapabilities
A list of supported audio type and capability pairs. The audio capability of this object is considered supported if the list is empty or contains one or more values that are supported with all other members (as determined by the algorithm). When there is a conflict between values, the earlier value will be selected.
sequence<MediaKeySystemMediaCapability> videoCapabilities
A list of supported video type and capability pairs. The video capability of this object is considered supported if the list is empty or contains one or more values that are supported with all other members (as determined by the algorithm). When there is a conflict between values, the earlier value will be selected.
MediaKeysRequirement distinctiveIdentifier = "optional"
Whether a persistent is required.

Messages from the CDM, such as events, MUST NOT contain a , even in an encrypted form, when this member is .

MediaKeysRequirement persistentState = "optional"
Whether the ability to persist state is required. This includes session data and any other type of state.

The CDM MUST NOT persist any state related to the application or of this object's when this member is .

For the purposes of this member, persistent state does not include persistent unique identifiers () controlled by the implementation. independently reflects this requirement.

Only sessions may be created when persistent state is not supported.

For sessions, the need and ability to store state is implementation-specific and may vary by feature used.

Applications intending to create non- sessions, should set this member to when calling .

sequence<MediaKeySessionType> sessionTypes
A list of session types that must be supported. All values must be supported.

If this member is when the dictionary is passed to , the dictionary will be treated as if this member is set to [ ].

Implementations SHOULD NOT add members to the this dictionary. Should member(s) be added, they MUST be of type MediaKeysRequirement, and it is RECOMMENDED that they have default values of to support the widest range of application and client combinations.

Dictionary members not recognized by a user agent implementation are ignored per [[WebIDL]] and will not be considered in the algorithm. Should an application use non-standard dictionary member(s), it MUST NOT rely on user agent implementations rejecting a configuration that includes such dictionary members.

This dictionary MUST NOT be used to pass state or data to the CDM.

MediaKeySystemMediaCapability dictionary

DOMString contentType = ""
The type of the media resource. Allows the user agent to determine if it can play this media resource with the requested before fetching the content. If specified, its value must be a valid MIME type. The codecs parameter, which certain MIME types define, might be necessary to specify exactly how the resource is encoded. Contents MUST not be the empty string. [[!RFC6381]].
DOMString robustness = ""
The robustness level associated with the content type. The empty string indicates that any ability to decrypt and decode the content type is acceptable.

The entire , including all codecs, must be supported with in order for the capability represented by this object to be considered supported.

If any of a set of codecs is acceptable, use a separate instances of this dictionary for each codec.

MediaKeySystemAccess Interface

The MediaKeySystemAccess object provides access to a .

readonly attribute DOMString keySystem
Identifies the being used.
MediaKeySystemConfiguration getConfiguration()

Returns the supported combination of configuration options selected by the algorithm.

The returned object is a non-strict subset (plus any implied defaults) of the first satisfiable MediaKeySystemConfiguration configuration passed to the call that returned the promise that was resolved with this object. It does not contain values capabilities not specified in that single configuration (other than implied defaults) and thus may not reflect all capabilities of the implementation. All values in the configuration may be used in any combination. Members of type MediaKeysRequirement reflect whether the capability is required for any combination. They will not have the value .

  1. Return this object's configuration value.

    This results in a new Javascript object being created and initalized from configuration each time this method is called.

Promise<MediaKeys> createMediaKeys()

Creates a new MediaKeys object for keySystem.

  1. Let promise be a new promise.

  2. Run the following steps in parallel:

    1. Let configuration be the value of this object's configuration value.

    2. Let distinctive identifier be the value of configuration's member.

    3. Follow the steps for the value of distinctive identifier from the following list:

      Let use distinctive identifier be true.
      Let use distinctive identifier be false.

      The value of distinctive identifier cannot be .

    4. Let persistent state be the value of configuration's member.

    5. Follow the steps for the value of persistent state from the following list:

      Let persistent state allowed be true.
      Let persistent state allowed be false.

      The value of persistent state cannot be .

    6. Load and initialize the implementation represented by this object's cdm implementation value if necessary.

    7. Let instance be a new instance of the implementation represented by this object's cdm implementation value.

    8. If use distinctive identifier is false, prevent instance from using Distinctive Identifier(s).

    9. If persistent state allowed is false, prevent instance from persisting any state related to the application or of this object's .

    10. If any of the preceding steps failed, reject promise with .

    11. Let media keys be a new MediaKeys object, and initialize it as follows:

      1. Let the use distinctive identifier value be use distinctive identifier.

      2. Let the persistent state allowed value be persistent state allowed.

      3. Let the supported session types value be be the value of configuration's member.

      4. Let the cdm implementation value be this object's cdm implementation value.

      5. Let the cdm instance value be instance.

    12. Resolve promise with media keys.

  3. Return promise.

MediaKeys Interface

The MediaKeys object represents a set of keys that an associated HTMLMediaElement can use for decryption of during playback. It also represents a CDM instance.

A MediaKeys object may be destroyed by the user agent when it is no longer accessible (i.e. there are no Javascript references and no attached media element).

For methods that return a promise, all errors are reported asynchronously by rejecting the returned Promise. This includes [[!WebIDL]] type mapping errors.

The steps of an algorithm are always aborted when resolving or rejecting a promise.

temporary

A session for which the license and record of or data related to the session MUST NOT be persisted.

The application need not worry about managing such storage. Support for this session type is REQUIRED.

persistent-license

A session for which the license (and potentially other data related to the session) will be persisted. A of type containing a record of the license's destruction will be generated when is called and on every subsequent call until the record is acknowledged by a response passed to .

The session MUST be loadable via its once is called successfully. The application is responsible for managing any such storage that may be generated by the CDM. See . Can only be created if the configuration associated with the MediaKeySystemAccess object that created this object has a value of . Support for this session type is OPTIONAL.

TBD

Issue 45 - This feature is not sufficiently defined, and there is no consensus on the feature definition. When fully defined, a representative, clear name should be chosen.

A session for ephemeral licenses for which a proof of license release and other data related to the session will be persisted. The license and any key(s) it contains SHALL NOT be persisted.

The session MUST be loadable via its once is called successfully. The application is responsible for managing any such storage that may be generated by the CDM. See . Can only be created if the configuration associated with the MediaKeySystemAccess object that created this object has a value of . Support for this session type is TBD.

MediaKeySession createSession()

Returns a new MediaKeySession object.

optional MediaKeySessionType sessionType = "temporary"
The type of session to create. The session type affects the behavior of the returned object.
  1. If this object's supported session types value does not contain sessionType, throw .

    sessionType values for which the algorithm returns true will fail if this object's persistent state allowed value is false.

  2. Let session be a new MediaKeySession object, and initialize it as follows:

    1. Let the attribute be the empty string.

    2. Let the attribute be NaN.

    3. Let the attribute be a new promise.

    4. Let the attribute be empty.

    5. Let the session type value be sessionType.

    6. Let the uninitialized value be true.

    7. Let the callable value be false.

    8. Let the use distinctive identifier value be this object's use distinctive identifier.

    9. Let the cdm implementation value be this object's cdm implementation.

    10. Let the cdm instance value be this object's cdm instance.

  3. Return session.

Promise<void> setServerCertificate()

Provides a server certificate to be used to encrypt messages to the license server.

Key Systems that use such certificates MUST also support requesting the certificate from the server via the algorithm.

This method allows an application to proactively provide a server certificate to implementations that support it to avod the additional round trip should the CDM request it. It is intended as an optimization, and applications are not required to use it.

BufferSource serverCertificate
The server certificate. The contents are -specific. It MUST NOT contain executable code.
  1. If serverCertificate is an empty array, return a promise rejected with a new .

  2. If the implementation represented by this object's cdm implementation value does not support server certificates, return a promise rejected with .

  3. Let certificate be a copy of the contents of the serverCertificate parameter.

  4. Let promise be a new promise.

  5. Run the following steps in parallel:

    1. Use this object's cdm instance to process certificate.

    2. If the preceding step failed, reject promise with .

    3. Resolve promise.

  6. Return promise.

Algorithms

Is persistent session type?

The Is persistent session type? algorithm is run to determine whether the specified session type supports persistence of any kind. Requests to run this algorithm include a MediaKeySessionType value.

The following steps are run:

  1. Let the message type be the specified MediaKeySessionType value.

  2. Follow the steps for the first matching condition from the following list:

    If session type is
    Return false.
    If session type is
    Return true.
    If session type is
    Return true.

MediaKeySession Interface

The MediaKeySession object represents a key session.

A MediaKeySession object SHALL NOT be destroyed and SHALL continue to receive events if it has not been closed and the MediaKeys object that created it remains accessible. Otherwise, a MediaKeySession object that is no longer accessible to Javascript SHALL NOT receive further events and MAY be destroyed.

The above rule implies that the CDM instance must not be destroyed until all MediaKeys objects and all MediaKeySession objects associated with the CDM instance are destroyed.

For methods that return a promise, all errors are reported asynchronously by rejecting the returned Promise. This includes [[!WebIDL]] type mapping errors.

The steps of an algorithm are always aborted when resolving or rejecting a promise.

readonly attribute DOMString sessionId

The for this object and the associated key(s) or license(s).

readonly attribute unrestricted double expiration

The time, in milliseconds since 01 January, 1970 UTC, after which the key(s) in the session will no longer be usable to decrypt , or NaN if no such time exists or if the license explicitly never expires, as determined by the CDM. The value of Infinity should never be used.

This value MAY change during the session lifetime, such as when an action triggers the start of a window.

readonly attribute Promise<void> closed

Signals when object becomes closed as a result of the algorithm being run. This promise can only be fulfilled and is never rejected.

readonly attribute MediaKeyStatusMap keyStatuses

A reference to a read-only map of key IDs known to the session to the current status of the associated key. Each entry MUST have a unique key ID.

The map entries and their values may be updated whenever the event loop spins. The map can never be inconsistent or partially updated, but it may change between accesses if the event loop spins in between accesses. Key IDs may be added as the result of a or call. Key IDs may be removed as the result of a call that removes knowledge of existing keys (or replaces the existing set of keys with a new set). Key IDs MUST NOT be removed because they became unusable, such as due to expiration. Instead, such keys MUST be given an appropriate status, such as .

Promise<void> generateRequest()

Generates a request based on the initData.

DOMString initDataType
The of the initData.
BufferSource initData
  1. If this object's uninitialized value is false, return a promise rejected with .

  2. Let this object's uninitialized be false.

  3. If initDataType is the empty string, return a promise rejected with .

  4. If initData is an empty array, return a promise rejected with .

  5. If the implementation represented by this object's cdm implementation value does not support initDataType as an , return a promise rejected with . String comparison is case-sensitive.

  6. Let init data be a copy of the contents of the initData parameter.

  7. Let session type be this object's session type.

  8. Let promise be a new promise.

  9. Run the following steps in parallel:

    1. If the init data is not valid for initDataType, reject promise with .

    2. Let sanitized init data be a validated and sanitized version of init data.

      The user agent MUST thoroughly validate the before passing it to the CDM. This includes verifying that the length and values of fields are reasonable, verifying that values are within reasonable limits, and stripping irrelevant, unsupported, or unknown data or fields. It is RECOMMENDED that user agents pre-parse, sanitize, and/or generate a fully sanitized version of the . If the format specified by initDataType support multiple entries, the user agent SHOULD remove entries that are not needed by the CDM.

    3. If the previous step failed, reject promise with .

    4. Let session id be the empty string.

    5. Let message be null.

    6. Let cdm be the CDM instance represented by this object's cdm instance value.

    7. Use the cdm to execute the following steps:

      1. If the init data is not supported by the cdm, reject promise with .

      2. Follow the steps for the first matching condition from the following list:

        If session type is

        Let requested license type be a temporary non-persistable license.

        The returned license must not be persistable or require persisting information related to it.

        If session type is

        Let requested license type be a persistable license.

        If session type is

        Let requested license type be a non-persistable license that will TBD.

      3. Let session id be a unique string.

        If the result of running the algorithm on session type is true, the ID MUST be unique within the of this object's over time, including across Documents and browsing sessions.

      4. Let message be a license request for the requested license type generated based on the init data, which is interpreted per initDataType.

        The cdm MUST NOT use any stream-specific data, including , not provided via the init data.

        The cdm SHOULD NOT store session data, including the session ID, at this point. See .

    8. If any of the preceding steps failed, reject promise with .

    9. Set the attribute to session id.

    10. Let this object's callable be true.

    11. Run the algorithm on the session, providing and message.

    12. Resolve promise.

      Issue 19 - Ensure promises returned by methods are fulfilled before event handlers are executed.

  10. Return promise.

Promise<boolean> load()

Loads the data stored for the specified session into this object.

DOMString sessionId
The of the session to load.
  1. If this object's uninitialized value is false, return a promise rejected with .

  2. Let this object's uninitialized be false.

  3. If sessionId is the empty string, return a promise rejected with .

  4. If the result of running the algorithm on this object's session type is false, return a promise rejected with .

  5. If the object's session type is not a member of , return a promise rejected with .

  6. Let origin be the of this object's .

  7. Let promise be a new promise.

  8. Run the following steps in parallel:

    1. Let sanitized session ID be a validated and/or sanitized version of sessionId.

      The user agent should thoroughly validate the sessionId value before passing it to the CDM. At a minimum, this should include checking that the length and value (e.g. alphanumeric) are reasonable.

    2. If the previous step failed, reject promise with .

    3. If there is an unclosed session in the object's whose attribute is sanitized session ID, reject promise with .

      In other words, do not create a session if a non-closed session, regardless of type, already exists for this sanitized session ID in this browsing context.

    4. Let expiration time be NaN.

    5. Let message be null.

    6. Let message type be null.

    7. Let cdm be the CDM instance represented by this object's cdm instance value.

    8. Use the cdm to execute the following steps:

      1. If there is no data stored for the sanitized session ID in the origin, resolve promise with false.

        Issue 20 - Ensure this object's session type matches the stored session.

      2. Let session data be the data stored for the sanitized session ID in the origin. This MUST NOT include data from other origin(s) or that is not associated with an origin.

      3. If there is an unclosed session in any representing the session data, reject promise with .

        In other words, do not create a session if a non-closed persistent session already exists for this sanitized session ID in any browsing context.

      4. Load the session data.

      5. If the session data indicates an expiration time for the session, let expiration time be the expiration time in milliseconds since 01 January 1970 UTC.

      6. If the session data contains a record of license destruction:

        1. Let message be a message containing or reflecting that record.

        2. Let message type be .

        3. Let expiration time be NaN.

        There can be no known keys in session data, so this object's attribute will remain empty.

      7. If message is null and the CDM needs to send a message:

        1. Let message be a message generated by the based on the session data.

        2. Let message type be the appropriate MediaKeyMessageType for the message.

    9. If any of the preceding steps failed, reject promise with .

    10. Set the attribute to sanitized session ID.

    11. Let this object's callable be true.

    12. If the loaded session contains information about any keys (there are known keys), run the algorithm on the session, providing each key's along with the appropriate MediaKeyStatus.

      Should additional processing be necessary to determine with certainty the status of a key, use . Once the additional processing for one or more keys has completed, run the algorithm again with the actual status(es).

    13. Run the algorithm on the session, providing expiration time.

    14. If message is not null, run the algorithm on the session, providing message type and message.

    15. Resolve promise with true.

      Issue 19 - Ensure promises returned by methods are fulfilled before event handlers are executed.

  9. Return promise.

Promise<void> update()

Provides messages, including licenses, to the CDM.

BufferSource response
A message to be provided to the CDM. The contents are -specific. It MUST NOT contain executable code.
  1. If this object's callable value is false, return a promise rejected with .

  2. If the algorithm has been run on this object, return a promise rejected with .

  3. If response is an empty array, return a promise rejected with .

  4. Let response copy be a copy of the contents of the response parameter.

  5. Let promise be a new promise.

  6. Run the following steps in parallel:

    1. Let sanitized response be a validated and/or sanitized version of response copy.

      The user agent should thoroughly validate the response before passing it to the CDM. This may include verifying values are within reasonable limits, stripping irrelevant data or fields, pre-parsing it, sanitizing it, and/or generating a fully sanitized version. The user agent should check that the length and values of fields are reasonable. Unknown fields should be rejected or removed.

    2. If the previous step failed, reject promise with .

    3. Let message be null.

    4. Let message type be null.

    5. Let cdm be the CDM instance represented by this object's cdm instance value.

    6. Use the cdm to execute the following steps:

      1. If the format of sanitized response is invalid in any way, reject promise with .

      2. Process sanitized response, following the stipulation for the first matching condition from the following list:

        If sanitized response contains a license or key(s)

        This includes an initial license, an updated license, and a license renewal message.

        Process sanitized response, following the stipulation for the first matching condition from the following list:

        If sessionType is and sanitized response does not specify that session data, including any license, key(s), or similar session data it contains, should be stored
        Process sanitized response, not storing any session data.
        If sessionType is and sanitized response contains a persistable license
        Process sanitized response, storing the license/key(s) and related session data contained in sanitized response. Such data MUST be stored such that only the of this object's can access it.
        If sessionType is and sanitized response contains a non-persistable license that specifies TBD
        Process sanitized response, storing TBD. Such data MUST be stored such that only the of this object's can access it. The license and any key(s) it contains MUST NOT be stored.
        Otherwise
        Reject promise with .

        See also .

        When sanitized response contains key(s) and/or related data, cdm will likely cache the key and related data indexed by key ID.

        The replacement algorithm within a session is -dependent.

        Keys from different sessions SHOULD be cached independently such that closing one session does not affect keys in other sessions, even if they have overlapping key IDs.

        It is RECOMMENDED that CDM implementations support a standard and reasonably high minimum number of keys per MediaKeySession object, including a standard replacement algorithm, and a standard and reasonably high minimum number of MediaKeySession objects. This enables a reasonable number of key rotation algorithms to be implemented across user agents and may reduce the likelihood of playback interruptions in use cases that involve various streams in the same element (i.e. adaptive streams, various audio and video tracks) using different keys.

        If sanitized response contains a license destruction acknowledgement and sessionType is

        Run the following steps:

        1. Clear all stored session data associated with this object, including the and license destruction record.

          A subsequent call to with the value of this object's would fail because there is no data stored for that session ID.

        2. Run the algorithm on this object.

        Otherwise
        Process sanitized response, not storing any session data.

        For example, sanitized response may contain information that will be used to generate another event. In this case, there is no need to verify the contents against the sessionType.

      3. If the set of keys known to the CDM for this object changed or the status of any key(s) changed, run the algorithm on the session, providing each known key's along with the appropriate MediaKeyStatus.

        Should additional processing be necessary to determine with certainty the status of a key, use . Once the additional processing for one or more keys has completed, run the algorithm again with the actual status(es).

      4. If the expiration time for the session changed, run the algorithm on the session, providing the new expiration time.

      5. If a message needs to be sent to the server, execute the following steps:

        1. Let message be that message.

        2. Let message type be the appropriate MediaKeyMessageType for the message.

    7. If any of the preceding steps failed, reject promise with .

    8. If message is not null, run the algorithm on the session, providing message type and message.

    9. Resolve promise.

  7. Return promise.

Promise<void> close()

Indicates that the application no longer needs the session and the CDM should release any resources associated with this object and close it.

The returned promise is resolved when the request has been processed, and the attribute promise is resolved when the session is closed.

  1. If this object's callable value is false, return a promise rejected with .

  2. If the algorithm has been run on this object, return a resolved promise.

  3. Let promise be a new promise.

  4. Run the following steps in parallel:

    1. Let cdm be the CDM instance represented by this object's cdm instance value.

    2. Use the cdm to execute the following steps:

      1. Process the close request.

        Do not remove stored session data. Do not generate or send key or license release messages.

      2. If the previous step caused the session to be closed, run the algorithm on this object.

    3. Resolve promise.

  5. Return promise.

Promise<void> remove()

Removes stored session data associated with this object.

  1. If this object's callable value is false, return a promise rejected with .

  2. If the algorithm has been run on this object, return a promise rejected with .

  3. If the result of running the algorithm on this object's session type is false, return a promise rejected with .

  4. Let promise be a new promise.

  5. If this object's session type is , run the following steps in parallel:

    1. Let cdm be the CDM instance represented by this object's cdm instance value.

    2. Use the cdm to execute the following steps:

      1. Destroy the license and/or keys associated with the session and store a record of this destruction.

      2. Run the algorithm on the session, providing an empty sequence.

      3. Run the algorithm on the session, providing NaN.

      4. Let message be a message containing or reflecting that record.

      5. Let message type be .

      6. If any of the preceding steps failed, reject promise with .

      7. Run the algorithm on the session, providing message type and message.

    3. Resolve promise.

  6. Return promise.

MediaKeyStatusMap Interface

The MediaKeySession object is a read-only map of key IDs to the current status of the associated key.

A key's status is independent of whether the key is currently being used and of media data.

For example, if a key has output requirements that cannot currently be met, the key's status should be or , as appropriate, regardless of whether that key has been or is currently needed to decrypt media data.

iterable <BufferSource, MediaKeyStatus>
The value pairs to iterate over are a snapshot of the set of pairs formed from the and associated MediaKeyStatus value for all known keys, sorted by .
readonly attribute unsigned long size

The number of known keys.

boolean has( BufferSource keyId )

Returns true if the status of the key identified by keyId is known

BufferSource keyId
The of the key.
MediaKeyStatus get()

Returns the MediaKeyStatus of the key identified by keyId.

BufferSource keyId
The of the key.
void forEach()

Calls callback once for each key-value pair present in the MediaKeyStatus map.

ForEachCallback callback
A callback function
BufferSource keyId
The key id
MediaKeyStatus status
The key status
usable
The CDM is certain the key is currently usable to decrypt .
Keys that may not currently be usable MUST NOT have this status.
expired
The key is no longer usable to decrypt because its expiration time has passed.
The time represented by the attribute MUST be earlier than the current time. All other keys in the session MUST have this status.
output-downscaled
The key is not currently usable to decrypt at full quality (e.g. resolution) because its output requirements cannot currently be met. Media data decrypted with this key may be presented at a lower quality (e.g. resolution).
Support for downscaling is OPTIONAL. Applications SHOULD NOT rely on downscaling to ensure uninterrupted playback when output requirements cannot be met.
output-not-allowed
The key is not currently usable to decrypt because its output requirements cannot currently be met.
status-pending
The status of the key is not yet known and is being determined. The status will be updated with the actual status when it has been determined.
internal-error
The key is not currently usable to decrypt because of an error in the CDM unrelated to the other values. This value is not actionable by the application.

MediaKeyMessageEvent

The MediaKeyMessageEvent object is used for the event.

Events are constructed as defined in [[!DOM]].

license-request
The message contains a request for a new license.
license-renewal
The message contains a request to renew an existing license.
license-release
The message contains a record of license destruction.
individualization-request
The message contains a request for per-origin individualization (or re-individualization). See Per-Origin Individualization.
As with all other messages, any identifiers in the message MUST be distinctive per-origin and MUST NOT contain any non-origin-specific .
Constructor(DOMString type, optional MediaKeyMessageEventInit eventInitDict)
readonly attribute MediaKeyMessageType messageType
The type of the message.

Implementations MUST NOT require applications to handle message types. Implementations MUST support applications that do not differentiate messages and MUST NOT require that applications handle message types. Specifically, Key Systems MUST support passing all types of messages to a single URL.

This attribute allows an application to differentiate messages without parsing the message. It is intended to enable optional application and/or server optimizations, but applications are not required to use it.

readonly attribute ArrayBuffer message
The message from the CDM. Messages are Key System-specific.

MediaKeyMessageEventInit

MediaKeyMessageType messageType = "license-request"
The type of the message.
ArrayBuffer message
The message.

Event Summary

In some implementations, MediaKeySession objects may not fire any events until the MediaKeys object is associated with a media element using .

Issue 9 - The above note should be removed.

Event name Interface Dispatched when...
keystatuseschange There has been a change in the keys in the session or their status.
message MediaKeyMessageEvent The CDM has generated a message for the session.

Algorithms

Queue a "message" Event

The Queue a "message" Event algorithm is run when the CDM needs to queue a message event to a MediaKeySession object. Requests to run this algorithm include a target MediaKeySession object, a message type, and a message.

message MUST NOT contain a , even in an encrypted form, if the MediaKeySession object's use distinctive identifier value is false.

The following steps are run:

  1. Let the session be the specified MediaKeySession object.

  2. at the session.

    The event is of type MediaKeyMessageEvent and has:

    • = the specified message type

      = the specified message

Update Key Statuses

The Update Key Statuses algorithm is run when the CDM changes the set of keys known to the session or the status of one or more of the keys. This can happen as the result of a or call or some other event, such as expiration. Requests to run this algorithm include a target MediaKeySession object and a sequence of and associated MediaKeyStatus pairs.

The following steps are run:

  1. Let the session be the associated MediaKeySession object.

  2. Let the input statuses be the sequence of pairs key ID and associated MediaKeyStatus pairs.

  3. Let the statuses be session's attribute.

  4. Run the following steps to replace the contents of statuses:

    1. Empty statuses.

    2. For each pair in input statuses.

      1. Let pair be the pair.

      2. Insert an entry for pair's key ID into statuses with the value of pair's MediaKeyStatus value.

    The effect of this steps is that the contents of session's attribute are replaced without invalidating existing references to the attribute. This replacement is atomic from a script perspective. That is, script MUST NOT ever see a partially populated sequence.

  5. at the session.

  6. algorithm on each of the media element(s) whose attribute is the MediaKeys object that created the session.

    The user agent MAY choose to skip this step if it knows resuming will fail.

    For example, the user agent may skip this step if no additional keys became .

Update Expiration

The Update Expiration algorithm is run when the CDM changes the expiration time of a session. This can happen as the result of an call or some other event. Requests to run this algorithm include a target MediaKeySession object and the new expiration time, which may be NaN.

The following steps are run:

  1. Let the session be the associated MediaKeySession object.

  2. Let expiration time be NaN.

  3. If the new expiration time is not NaN, let expiration time be the new expiration time in milliseconds since 01 January 1970 UTC.

  4. Set the session's attribute to expiration time.

Session Close

The Session Close algorithm is run when the CDM closes the session associated with a MediaKeySession object.

Closing a session means that the license(s) and key(s) associated with it are no longer available to decrypt . All MediaKeySession methods will fail for this object.

The CDM may close a session at any point, such as in response to a call, when the session is no longer needed, or when system resources are lost. Keys in other sessions SHOULD be unaffected, even if they have overlapping key IDs.

The following steps are run:

  1. Let the session be the associated MediaKeySession object.

  2. Run the algorithm on the session, providing an empty sequence.

  3. Run the algorithm on the session, providing NaN.

  4. Let promise be the attribute of the session.

  5. Resolve promise.

Exceptions

The methods report errors by rejecting the returned promise with a . The following DOMException names from WebIDL [[!WebIDL]] are used in the algorithms. Causes specified specified in the algorithms are listed alongside each name, though these names MAY be used for other reasons as well.

Name Possible Causes (non-exhaustive)
NotSupportedError The existing MediaKeys object cannot be removed.
The key system is not supported.
The key system is not supported in an insecure context.
The initialization data type is not supported by the key system.
The session type is not supported by the key system.
The initialization data is not supported by the key system.
The operation is not supported by the key system.
InvalidStateError The existing MediaKeys object cannot be removed at this time.
The session has already been used.
The session is not yet initialized.
The session is closed.

Bug 27283 - InvalidAccessError may not be the correct error in many cases. TypeError or other errors may be more appropriate.

InvalidAccessError The parameter is empty.
Invalid initialization data.
The operation is not supported on sessions of this type.
Invalid response format.
A persistent license was provided for a session.
QuotaExceededError The MediaKeys object cannot be used with additional HTMLMediaElements.
A non-closed session already exists for this sessionId.

Session Storage and Persistence

This section provides an overview of session stroage and persistence that complements the algorithms.

If the result of running the algorithm on this object's session type is false, the user agent and CDM MUST NOT persist a record of or data related to the session at any point. This includes license(s), key(s), records or proof of license destruction, and the .

The remainder of this section applies to session types for which the algorithm returns true.

Persisted data MUST always be stored such that only the of this object's can access it. In addition, the data MUST only be accessible by the current profile of this user agent; other user agent profiles, user agents, and applications MUST NOT be able to access the stored data. See Information Stored on User Devices.

The CDM SHOULD NOT store session data, including the Session ID, until is called the first time. Specifically, the CDM SHOULD NOT store session data during the algorithm. This ensures that the application is aware of the session and knows it needs to eventually remove it.

The CDM MUST ensure that data for a given session is only present in one active unclosed session in any . In other words, MUST fail when there is already a MediaKeySession representing the session specified by the sessionId parameter, either because the object that created it via is still active or it has been loaded into another object via . A session MAY only be loaded again after the algorithm has not been run on the object representing it.

An application that creates a session using a type for which the algorithm returns true SHOULD later remove the stored data using . The CDM MAY also remove sessions as appropriate, but applications SHOULD NOT rely on this.

See the Security and Privacy sections for additional considerations when supporting persistent storage.

HTMLMediaElement Extensions

This section specifies additions to and modifications of the [[!HTML5]] when the Encrypted Media Extensions are supported.

When a is created, its internal waiting for key value is initialized to false.

For methods that return a promise, all errors are reported asynchronously by rejecting the returned Promise. This includes [[!WebIDL]] type mapping errors.

The steps of an algorithm are always aborted when resolving or rejecting a promise.

readonly attribute MediaKeys? mediaKeys

The MediaKeys being used when decrypting encrypted for this media element.

attribute EventHandler onencrypted

Event handler for the event MUST be supported by all HTMLMediaElements as both a content attribute and an IDL attribute.

Promise<void> setMediaKeys()

Provides the MediaKeys to use when decrypting media data during playback.

Support for clearing or replacing the associated MediaKeys object during playback is a quality of implementation issue. In many cases it will result in a bad user experience or rejected promise.

As a best practice, applications should create a MediaKeys object and call before providing (for example, setting the attribute). This avoids potential delays in some implementations.

Some implementations may only support decrypting media data provided via Media Source Extensions [[MEDIA-SOURCE]]. This is not reflected in the results of calling .

MediaKeys? mediaKeys
A MediaKeys object.
  1. If mediaKeys and the attribute are the same object, return a resolved promise.

  2. If this object's attaching media keys value is true, return a promise rejected with .

  3. Let this object's attaching media keys value be true.

  4. Let promise be a new promise.

  5. Run the following steps in parallel:

    1. If mediaKeys is not null, it is already in use by another media element, and the user agent is unable to use it with this element, let this object's attaching media keys value be false and reject promise with .

    2. If the attribute is not null, run the following steps:

      1. If the user agent or CDM do not support removing the association, let this object's attaching media keys value be false and reject promise with .

      2. If the association cannot currently be removed, let this object's attaching media keys value be false and reject promise with .

        For example, some implementations may not allow removal during playback.

      3. Stop using the CDM instance represented by the attribute to decrypt and remove the association with the media element.

      4. If the preceding step failed, let this object's attaching media keys value be false and reject promise with .

    3. If mediaKeys is not null, run the following steps:

      1. Associate the CDM instance represented by mediaKeys with the media element for decrypting .

      2. If the preceding step failed, run the following steps:

        1. Set the attribute to null.

        2. Let this object's attaching media keys value be false.

        3. Reject promise with .

      3. algorithm on the media element.

        The user agent MAY choose to skip this step if it knows resuming will fail.

        For example, the user agent may skip this step if mediaKeys has no sessions.

    4. Set the attribute to mediaKeys.

    5. Let this object's attaching media keys value be false.

    6. Resolve promise.

  6. Return promise.

MediaEncryptedEvent

The MediaEncryptedEvent object is used for the event.

Events are constructed as defined in [[!DOM]].

Constructor(DOMString type, optional MediaEncryptedEventInit eventInitDict)
readonly attribute DOMString initDataType
Indicates the of the contained in the attribute.
readonly attribute ArrayBuffer? initData
The for the event.

MediaEncryptedEventInit

DOMString initDataType = ""
The .
ArrayBuffer? initData = null
The .

Event Summary

Event name Interface Dispatched when... Preconditions
encrypted MediaEncryptedEvent The user agent encounters in the . The element's is equal to or greater.

It is possible that the element is playing or has played.

waitingforkey Playback is blocked waiting for a key. The element is and its is equal to or greater.

Algorithms

Initialization Data Encountered

The following steps are run when the media element encounters in the during the algorithm:

  1. Let initDataType be the empty string.

  2. Let initData be null.

  3. If the is and not mixed content, run the following steps:

    1. Let initDataType be the string representing the of the Initialization Data.

    2. Let initData be the Initialization Data.

    While the media element may allow loading of "Optionally-blockable Content" [[MIXED-CONTENT]], the user agent MUST NOT expose Initialization Data from such media data to the application.

  4. at the media element.

    The event is of type MediaEncryptedEvent and has:

    • = initDataType

      = initData

    is not changed and no algorithms are aborted. This event merely provides information.

    The attribute will be null if the media data is not or is mixed content. Applications may retrieve the Initialization Data from an alternate source.

  5. If the media element's attribute is null, run the following steps:

    These steps may be reached when applications create a MediaKeys object and call before providing and there is no usable key for the block.

    1. Run the algorithm on the media element.

    2. Wait for a signal to resume playback.

  6. Continue Normal Flow: Continue with the existing media element's algorithm.

Encrypted Block Encountered

The following steps are run when the media element encounters a block of encrypted during the algorithm:

  1. If the media element's attribute is not null, run the following steps:

    1. Let media keys be the MediaKeys object referenced by that atribute.

    2. Let cdm be the CDM instance represented by media keys's cdm instance value.

    3. If there is at least one MediaKeySession created by the media keys on which the algorithm has not been run, run the following steps:

      This check ensures the cdm has finished loading and is a prequisite for a matching key being available.

      1. Let the block key ID be the key ID of the current block.

        The key ID is generally specified by the container.

      2. Use the cdm to execute the following steps:

        1. Let available keys be the union of keys in sessions that were created by the media keys.

        2. Let block key be null.

        3. If any of the available keys corresponds to the block key ID and is usable, let block key be that key.

          If multiple sessions contain a usable key for the block key ID, which key to use is -dependent.

        4. If the status of any of the available keys changed as the result of running the previous step, run the algorithm on each affected session, providing all key ID(s) in the session along with the appropriate MediaKeyStatus value(s) for each.

        5. If block key is not null, run the following steps:

          1. Use the cdm to decrypt the block using block key.

          2. Follow the steps for the first matching condition from the following list:

            If decryption fails

            Abort the media element's algorithm, run the steps to report a error, and abort these steps.

            Otherwise

            Abort these steps and process the decrypted block as normal.

            In other words, decode the block.

            Not all decryption problems (i.e. using the wrong key) will result in a decryption failure. In such cases, no error is fired here but one may be fired during decode.

          Otherwise, there is no key for the block key ID in any session so continue.

  2. Run the following steps:

    These steps are reached when there is no usable key for the block.

    1. Run the algorithm on the media element.

    2. Wait for a signal to resume playback.

For frame-based encryption, this may be implemented as follows when the media element attempts to decode a frame as part of the algorithm:

  1. Let encrypted be false.

  2. Detect whether the frame is encrypted.

    If the frame is encrypted
    Run the steps above.
    Otherwise
    Continue.
  3. Decode the frame.

  4. Provide the frame for rendering.

Queue a "waitingforkey" Event

The Queue a "waitingforkey" Event algorithm is run when the CDM cannot decrypt the current block. It should only be called when the object is and its is equal to or greater. Requests to run this algorithm include a target object.

The following steps are run:

  1. Let the media element be the specified object.

  2. If the media element's waiting for key value is false, at the media element.

  3. Set the media element's waiting for key value to true.

  4. Suspend playback.

Attempt to Resume Playback If Necessary

The Attempt to Resume Playback If Necessary algorithm is run when one or more keys becomes available. If playback is blocked waiting for a key, it resumes playback if a necessary key has been provided. Requests to run this algorithm include a target object.

The following steps are run:

  1. Let the media element be the specified object.

  2. If the media element's waiting for key is false, abort these steps.

  3. Attempt to resume the algorithm by running the algorithm.

  4. If the user agent can advance the in the , set the media element's waiting for key value to false.

Media Element Restrictions

Media data processed by a CDM MAY be unavailable through Javascript APIs in the usual way (for example using the CanvasRenderingContext2D drawImage() method and the AudioContext MediaElementAudioSourceNode). This specification does not define conditions for such non-availability of media data, however, if media data is not available to Javascript APIs then these APIs MAY behave as if no media data was present at all.

Where media rendering is not performed by the UA, for example in the case of a hardware protected media pipeline, then the full set of HTML rendering capabilities, for example CSS Transforms, MAY be unavailable. One likely restriction is that video media MAY be constrained to appear only in rectangular regions with sides parallel to the edges of the window and with normal orientation.

Implementation Requirements

This section defines implementation requirements - for both user agents and , including the CDM and server - that may not be explicitly addressed in the algorithms.

Identifiers

The use of by implementations presents a privacy concern. This defines requirements for avoiding or at least mitigating such concerns.

Limit or Avoid use of Distinctive Identifiers

  • Implementations SHOULD avoid use of .

    For example, use keys or identifiers that apply to a group of clients or devices rather than individual clients.

  • Implementations SHOULD only use when necessary to enforce the policies related to the specific CDM instance and session.

    For example, and sessions may have different requirements.

  • Implementations that use Distinctive Identifier(s) SHOULD support the option to not use it. When supported, applications can select for this mode using = . Selecting such an option MAY affect the results of the call and/or the license requests that are generated from subsequently generated sessions.

Encrypt Identifiers

When exposed to the application - either from a event or a message from the server, such as one that is passed to - MUST be encrypted at the message exchange level. The encryption MUST ensure that the ciphertext cannot be used as a proxy for the actual identifier, even given the same plaintext. The CDM MUST verify that the encryption key belongs to a valid license server for its Key System.

Add more specific text about ensuring the desired privacy properties when encrypting identifiers.

This MAY be implemented using a server certificate.

The license server MUST NOT expose a to any entity other than the CDM that sent it.

Specifically, it should not be provided to the application or included unencrypted in messages to the CDM. This can be accomplished by encrypting the identifier or message with the identifier or such that it is only decryptable by that specific CDM.

Among other things, this means that:

  • Every signature made with device-specific or user-specific keys MUST be different, even given the same plaintext.

  • Identifiers, keys, or certificates relating to device-specific or user-specific keys MUST be encrypted for the license server.

  • Messages from the license server to the CDM MUST NOT expose recipient-unique identifiers, such as the ID of the intended decryption key, on the outside of the encryption envelope.

Use Per-Origin Identifiers

All MUST be distinctive per . That is, the Distinctive Identifier(s) used for one using these APIs MUST be different from those used for any other origin using the APIs.

Bug 27269 - It has been suggested that the be distinctive for the combination of top-level origin and the origin using these APIs.

It MUST NOT be possible (with a reasonable amount of time and effort) to correlate identifiers from multiple origins, such as to determine that they came from the same client or user. Specifically, implementations that derive per-origin identifiers from an origin-independent identifier, MUST do so in a non-reversible way.

Add more specific text about ensuring the desired non-reversible properties.

Allow Identifiers to be Cleared

Implementations that use Distinctive Identifier(s) MUST allow the user to clear those identfiers such that they are no longer retrievable both outside, such as via the APIs defined in this specification, and on the client device. Once cleared, new different values MUST be generated when Distinctive Identifier(s) are subsequently needed.

Implementations SHOULD allow users to clear Distinctive Identifier(s) along with cookies [[!COOKIES]] and other site data. It is RECOMMENDED that users be offered the option to clear Distinctive Identifier(s) as part of user agent features to clear browsing history.

It is RECOMMENDED that users be able to request that be forgotten on a per-origin basis, particularly as part of a "Forget about this site" feature that forgets cookies [[!COOKIES]], databases, etc. associated with a particular site in an operation that is sufficiently atomic to prevent "cookie resurrection" type of recorrelation of a new identifier with the old by relying on another type of locally stored data that did not get cleared at the same time.

Support Multiple Keys

Implementations MUST support multiple keys in each MediaKeySession object.

The mechanics of how multiple keys are supported is an implementation detail, but it MUST be transparent to the application and these APIs.

Implementations MUST support seamless switching between keys during playback. This includes both keys in the same MediaKeySession and keys in separate MediaKeySession objects.

Initialization Data Type Support

Licenses Generated are Independent of Content Type

Implementations SHOULD allow licenses generated with any they support to be used with any content type.

Otherwise, the algorithm might, for example, reject a MediaKeySystemConfiguration because one of the is not supported with one of the .

Support Extraction From Media Data

For any supported that may appear in a supported container, the user agents MUST support extracting that type of from each such supported container.

In other words, indicating support for an implies both CDM support for generating license requests and, for container-specific types, user agent support for extracting it from the container. This does not mean that implementations must be able to parse any supported from any supported content type.

Supported Media

This section defines properties of content (media resources) supported by implementations of this specification.

Unencrypted Container

The media container MUST NOT be encrypted. This specification relies on the user agent's ability to parse the media container without having to decrypt any of the media data. This includes the and algorithms as well as supporting standard [[!HTML5]] functionality, such as seeking.

Interoperably Encrypted

Media resources, including all tracks, MUST be encrypted and packaged per a container-specific "common encryption" specification that allows the content to be decrypted in a fully specified and compatible way when a key or keys are provided.

The Encrypted Media Extensions Stream Format and Initialization Data Format Registry [[EME-REGISTRY]] provides references to such stream formats.

Unencrypted In-band Support Content

In-band support content, such as captions, described audio, and transcripts, SHOULD NOT be encrypted.

Decryption of such tracks - especially such that they can be provided back the user agent - is not generally supported by implementations. Thus, encrypting such tracks would prevent them from being widely available for use with accessibility features in user agent implementations.

Implementations that choose to support encrypted support content MUST provide the decrypted data to the user agent to be processed in the same way as equivalent unencrypted .

Common Key Systems

All user agents MUST support the common key systems described in this section.

This ensures that there is a common baseline level of protection that is guaranteed to be supported in all user agents, including those that are entirely open source. Thus, content providers that need only basic protection can build simple applications that will work on all platforms without needing to work with any content protection providers.

Clear Key

The "org.w3.clearkey" uses plain-text clear (unencrypted) key(s) to decrypt the source. No additional client-side content protection is required. This Key System is described below.

Capabilities

The following describe how Clear Key supports key system-specific capabilities:

  • MediaKeySystemConfiguration:

    1. : Only the empty string is supported.

    2. : is not supported.

    3. : Not unless the application intends to create non- sessions, if supported.

  • The MediaKeySessionType: Implementations MAY support this type.

  • The MediaKeySessionType: Implementations MAY support this type.

    A format for messages may need to be defined.

  • The method: Not supported.

  • The method: Implementations MAY support associating the MediaKeys object with more than one .

Behavior

The following describe how Clear Key implements key system-specific behaviors:

  • In the algorithm:

    • The generated message is a JSON object encoded in UTF-8 as described in License Request Format.

    • The request is generated by extracting the key IDs from the init data.

    • The "type" member value is the value of the sessionType parameter.

  • The attribute is a numerical value representable by a 32-bit integer.

  • The attribute is always NaN.

  • In the algorithm:

    • The response parameter is a JWK Set as described in License Format.

    • sanitized response is considered invalid if it is not a valid JWK Set with at least one valid JWK key of a valid length for the media type.

  • The attribute method always contains all key IDs that have been provided via , and their status is always .

  • : Implementations MAY support any combination of registered Initialization Data Types [[EME-REGISTRY]]. Implementations SHOULD support the "keyids" type and other types appropriate for content types supported by the user agent.

License Request Format

This section describes the format of the license request provided to the application via the attribute of the event.

The format is a JSON object containing the following members:

"kids"
An array of key IDs. Each element of the array is the base64url encoding of the octet sequence containing the key ID value.
"type"
The requested MediaKeySessionType

When contained in the ArrayBuffer attribute of a MediaKeyMessageEvent object, the JSON string is encoded in UTF-8 as specified in the Encoding specification [[!ENCODING]]. Applications MAY decode the contents of the ArrayBuffer to a JSON string using the [[!ENCODING]].

Example

The following example is a license request for a temporary license for two key IDs. (Line breaks are for readability only.)

{
  'kids':
    [
     'LwVHf8JLtPrv2GUXFW2v',
     '0DdtU9od-Bh5L3xbv0Xf'
    ],
  'type':
}

License Format

This section describes the format of the license to be provided via the response parameter of the method.

The format is a JSON Web Key (JWK) Set containing representation of the symmetric key to be used for decryption, as defined in the JSON Web Key (JWK) specification [[!JWK]].

For each JWK in the set, the parameter values are as follows:

"kty" (key type)
"oct" (octet sequence)
"alg" (algorithm)
"A128KW" (AES key wrap using a 128-bit key)
"k" (key value)
The base64url encoding of the octet sequence containing the symmetric key value
"kid" (key ID)
The base64url encoding of the octet sequence containing the value

The JSON object MAY have an optional "type" member value, which MUST be one of the MediaKeySessionType values. If not specified, the default value of is used. The algorithm compares this value to the sessionType.

When passed to the method as the ArrayBuffer response parameter, the JSON string MUST be encoded in UTF-8 as specified in the Encoding specification [[!ENCODING]]. Applications MAY encode the JSON string using the [[!ENCODING]].

Example

The following example is a JWK Set containing a single symmetric key. (Line breaks are for readability only.)

{
  'keys':
    [{
      'kty':'oct',
      'alg':'A128KW',
      'k':'tQ0bJVWb6b0KPL6KtZIy',
      'kid':'LwVHf8JLtPrv2GUXFW2v'
    }],
  'type':
}

Using base64url

For more information on base64url and working with it, see the "Base64url Encoding" terminology definition and "Notes on implementing base64url encoding without padding" in [[JWS]]. Specifically, there is no '=' padding, and the characters '-' and '_' MUST be used instead of '+' and '/', respectively.

Security

Input Data Attacks and Vulnerabilities

User Agent and Key System implementations MUST consider , , data passed to , licenses, key data, and all other data provided by the application as untrusted content and potential attack vectors. They MUST use appropriate safeguards to mitigate any associated threats and take care to safely parse, decrypt, etc. such data. User Agents SHOULD validate data before passing it to the CDM.

Such validation is especially important if the CDM does not run in the same (sandboxed) context as, for example, the DOM.

Implementations MUST NOT return active content or passive content that affects program control flow to the application.

For example, it is not safe to expose URLs or other information that may have come from media data, such as is the case for the passed to . Applications must determine the URLs to use. The attribute of the event can be used by the application to select among a set of URLs if applicable.

CDM Attacks and Vulnerabilities

User Agents are responsible for providing users with a secure way to browse the web, including any functionality, such as CDMs, from third parties. User agent implementers MUST obtain sufficient information from Key System implementers to enable them to properly assess the security implications of integrating with the Key System. User agent implementers MUST ensure CDM implementations provide and/or support sufficient controls for the user agent to provide security for the user. User agent implementers MUST ensure CDM implementations can and will be quickly and proactively updated in the event of security vulnerabilities.

Exploiting a CDM implementation that is not fully sandboxed and/or uses platform features may allow an attacker to access OS or platform features, elevate privilege (e.g. to run as system or root), and/or access drivers, kernel, firmware, hardware, etc. Such features, software, and hardware may not be written to be robust against hostile software or web-based attacks and may not be updated with security fixes, especially compared to the user agent. Lack of, infrequent, or slow updates for fixes to security vulnerabilities in CDM implementations increases the risk. Such CDM implementations and UAs that expose them MUST be especially careful in all areas of security, including parsing of all data.

User agents should be especially diligent when using a CDM or underlying mechanism that is part of or provided by the client OS, platform and/or hardware.

If a user agent chooses to support a Key System implementation that cannot be sufficiently sandboxed or otherwise secured, the user agent SHOULD ensure that users are fully informed and/or give explicit consent before loading or invoking it. Such implementations SHOULD only be supported on secure contexts to mitigate the potential for Network Attacks.

Granting permissions to unauthenticated origins is equivalent to granting the permissions to any origin in the presence of a network attacker. See also User Alerts / Prompts and Use Secure Origin and Transport.

Network Attacks

Potential Attacks

Potential network attacks and their implications include:

  • DNS spoofing attacks: One cannot guarantee that a host claiming to be in a certain domain () really is from that domain.

  • Passive network attacks: One cannot guarantee that data, including , transmitted between the client and server is not viewed by other entities. See User Tracking.

  • Active network attacks: One cannot guarantee that Additional scripts or iframes are not injected into pages (both those that use these APIs for legitimate purposes and pages that do not use these APIs). The consequences are that:

    • Calls to these APIs can be injected into any page.

    • Calls to these APIs from pages using them for legitimate reasons can be manipulated, including modifying the requested functionality, modifying or adding calls, and modifying or injecting data. See also Input Data Attacks and Vulnerabilities

    • Data, including , transmitted between the client and server can be viewed and/or modified by other entities. See User Tracking.

Mitigations

The following techniques may mitigate the risks:

Use TLS

Applications using TLS can be sure that only the user, software working on behalf of the user, and other pages using TLS that have certificates identifying them as being from the same domain, can interact with that application. Furthermore, -specific permissions in combination with a secure origin, ensure that permissions granted to an application cannot be abused by a network attacker.

User agents MAY choose to only support these APIs and/or specific Key Systems (i.e. based on privacy and security risks) on secure origins. This is especially important if a user agent chooses to support a Key System implementation that cannot be sufficiently sandboxed or otherwise secured. See also Secure Origin and Transport.

Block Mixed Content

User agents MUST properly handle Mixed Content [[!MIXED-CONTENT]], including blocking "Blockable Content" [[!MIXED-CONTENT]] to avoid potential exposure to insecure content. Such exposure could compromise other mitigations, such as use of TLS.

User agents MAY choose to block all Mixed Content, including "Optionally-blockable Content" [[!MIXED-CONTENT]] to further increase security by preventing untrusted media data from being passed to the CDM (see CDM Attacks and Vulnerabilities).

Per-origin user alerts / prompts and permissions

User Agents SHOULD ensure that users are fully informed and/or give explicit consent before a Key System that presents security concerns that are greater than other user agent features (e.g. DOM content) may be accessed by an . Such alerts and consent SHOULD be per to avoid valid uses enabling subsequent malicious access. (A full MUST be used rather than just the domain because the protocol is important for security as described above.) User agents SHOULD only persist consent for secure origins (see Secure Origin and Transport), to mitigate the potential for future abuse via Network Attacks.

Granting permissions to unauthenticated origins is equivalent to granting the permissions to any origin in the presence of a network attacker. Alerting or prompting the user for consent on insecure origins without persisting the choice provides at least a minimum level of security because the user would be alerted to unexpected use (e.g. on a site that does not have protected media.

iframe Attacks

Potential Attacks

Malicious pages could host legitimate applications in an iframe in an attempt hide an attack or deceive the user as to the source, such as making the use appear to be from a legitimate content provider. This is especially relevent for user agents that support have user alerts, prompts, and/or permissions. In addition to Network Attacks, attackers could try to exploit legitimate uses of these APIs by hosting them in an iframe. By having the legitimate application performing the actions, the attacker can reuse existing granted permissions (or whitelisting) and/or appear to be a legitimate request or use.

Mitigations

User agents are RECOMMENDED to base the UI and persistence of user alerts, prompts, and/or permissions on the combination of of the top-level and the using these APIs. This ensures that users are informed of the main document making the request and that persisting a permission for one (legitimate) combination does not inadvertently allow malicious use to go undetected.

Authors are RECOMMENDED to prevent other entities from hosting their applications in iframes. Applications that must support being hosted for legitimate application-design reasons SHOULD NOT allow hosting documents to provide any data to be passed to the CDM - either via these APIs or as media data - and SHOULD NOT allow hosting frames to invoke these APIs.

Cross-Directory Attacks

Different authors sharing one host name, for example users hosting content on geocities.com, all share one . User agents do not provide features to restrict access to APIs by pathname.

Using these APIs on shared hosts compromises origin-based security and privacy mitigations implemented by user agents. For example, per-origin are shared by all authors on one host name, and peristed data may be accessed and manipulated by any author on the host. The latter is especially important if, for example, modification or deletion of such data could erase a user's right to specific content.

Even if a path-restriction feature was made available by user agents, the usual DOM scripting security model would make it trivial to bypass this protection and access the data from any path.

Authors on shared hosts are therefore RECOMMENDED to avoid using these APIs because doing so compromises origin-based security and privacy mitigations in user agents.

Privacy

The presence or use of Key System(s) on a user's device raises a number of privacy issues, falling into two categories: (a) user-specific information that may be disclosed by the EME interface itself or within Key System messages and (b) user-specific information that may be persistently stored on the user's device.

User Agents MUST take responsibility for providing users with adequate control over their own privacy. Since User Agents may integrate with third party CDM implementations, CDM implementers MUST provide sufficient information and controls to user agent implementers to enable them to implement appropriate techniques to ensure users have control over their privacy, including but not limited to the techniques described below.

Information Disclosed by EME and Key Systems

Concerns regarding information disclosed by EME and Key Systems fall into two categories: (a) concerns about non-specific information that may nevertheless contribute to the possibility of fingerprinting a user agent or device and (b) user-specific information that may be used directly for user tracking.

Fingerprinting

Malicious applications may be able to fingerprint users or user agents by detecting or enumerating the list of Key Systems that are supported and related information. If proper origin protections are not provided this could include detection of sites that have been visited and information stored for those sites. In particular, Key Systems MUST not share key or other data between origins.

Information Leakage

Concerns

CDMs, especially those implemented outside the user agent, may not have the same fundamental isolations as the web platform. It is important that steps be taken to avoid information leakage, especially across origins. This includes both in-memory and stored data. Failure to do so could lead to information leakage to/from private browsing sessions, across profiles, and even across different browsers, applications, and operating system user accounts.

Mitigations

To avoid such issues, user agent and CDM implementations MUST ensure that:

  • CDMs have a concept of a CDM instance that is associated one-to-one with a MediaKeys object.

  • Keys, licenses, other session data, and the presence of sessions are restricted to the CDM instance associated with the MediaKeys object that created the session.

  • Session data is not shared between MediaKeys objects or CDM instances.

  • Session data is not shared with media elements not associated with the MediaKeys object that created the session. Among other things, this means a session's keys MUST not be used to decrypt content loaded by a media element whose attribute is not that MediaKeys object.

  • MediaKeys objects and the underlying implementation do not expose information outside the .

  • Persisted session data, if applicable, is stored on a per- basis.

  • Only data stored by the requesting may be loaded.

User Tracking

Concerns

A third-party host (or any entity, such as an advertiser, capable of getting content distributed to multiple sites) could use a or data, including keys, stored in the 's client-side database to track a user across multiple sessions (including across profiles and user accounts on the client device), building a profile of the user's activities or interests. Such tracking would undermine the privacy protections provided by the rest of the web platform and could, for example, enable highly-targeted advertising not otherwise possible. In conjunction with a site that is aware of the user's real identity (for example, a content provider or e-commerce site that requires authenticated credentials), this could allow oppressive groups to target individuals with greater accuracy than in a world with purely anonymous Web usage.

User- or client-specific information that could be obtained via the APIs in this specification includes:

  • Distinctive Identifier(s)

  • Origins visisted (via stored or in-memory data, permissions, etc.)

  • Content viewed (via stored or in-memory keys, key IDs, data, etc.)

This specification presents a specific concern because such information is commonly stored outside the user agent (and its profile storage), often in the CDM.

Key Systems may access or create persistent or semi-persistent identifier(s), Distinctive Identifier(s), for a device or user of a device. In some cases these identifiers may be bound to a specific device in a secure manner. If these identifiers are present in Key System messages, then devices and/or users may be tracked. If the mitigations below are not applied this could include both tracking of users / devices over time and associating multiple users of a given device.

It is important to note that such identifiers, especially those that are non-clearable, non--specific or hardware-bound, exceed the tracking impact of existing techniques such as cookies [[COOKIES]] or session identifiers embedded in URLs.

If not mitigated, such tracking may take three forms depending on the design of the Key System:

  • In all cases, such identifiers are expected to be available to sites and/or servers that fully support the Key System (and thus can interpret Key System messages) enabling tracking by such sites.

  • If identifiers exposed by Key Systems are not origin-specific, then two sites and/or servers that fully support the Key System may collude to track the user.

  • If Key System messages contain information derived from a user identifier in a consistent manner, for example such that a portion of the initial Key System message for a specific content item does not change over time and is dependent on the user identifier, then this information could be used by any application to track the device or user over time.

In addition, if a Key System permits keys to be stored and to be re-used between origins, then it may be possible for two origins to collude and track a unique user by recording their ability to access a common key.

Finally, if any user interface for user control of Key Systems presents data separately from data in HTTP session cookies [[COOKIES]] or persistent storage, then users are likely to modify site authorization or delete data in one and not the others. This would allow sites to use the various features as redundant backup for each other, defeating a user's attempts to protect his privacy.

The following section describes techniques that may mitigate the risks of tracking without user consent.

Mitigations

Do not use

Key System implementations SHOULD avoid using whenever possible and only use them when they meaningfully contribute to the robustness of the implementation. See Limit or Avoid use of Distinctive Identifiers.

User deletion of

User agents MUST provide users with the ability to clear any maintained by Key Systems. See Allow Identifiers to be Cleared.

Use of (non-reversible) per-origin identifiers

Implementations that use MUST use a different value for each , either by allocation of different identifiers for different origins or by use of a non-reversible origin-specific mapping from an origin-independent identifier. See Use Per-Origin Identifiers and non-reversible identifiers.

Encryption of

in Key System messages MUST be encrypted, together with a timestamp or nonce, such that the Key System messages are always different. This prevents the use of Key System messages for tracking except by servers fully supporting the Key System. See Encrypt Identifiers.

Blocking third-party access

User agents MAY restrict access to Key Systems and/or features to scripts originating at the of the top-level of the browsing context. For example, may deny requests for certain configurations for pages from other origins running in iframes.

Expiring stored data

User agents MAY, possibly in a manner configured by the user, automatically delete and/or other Key System data after a period of time.

For example, a user agent could be configured to such data as session-only storage, deleting the data once the user had closed all the browsing contexts that could access it.

This can restrict the ability of a site to track a user, as the site would then only be able to track the user across multiple sessions when he authenticates with the site itself (e.g. by making a purchase or logging in to a service).

However, this can also put the user's access to content, especially purchased or rented content, at risk if the user does not fully understand the implications of such expiration.

Treating and Key System stored data like cookies / web storage

User agents SHOULD present the presence of and data stored by Key Systems to the user in a way that associates them strongly with HTTP session cookies [[!COOKIES]]. This might encourage users to view such identifiers with healthy suspicion. User agents SHOULD help the user avoid Incomplete Clearing of Data.

Site-specific white-listing of access to each Key System

User agents MAY require the user to explicitly authorize access to each Key System - and/or certain features - before a site can use it. User agents SHOULD enable users to revoke this authorization either temporarily or permanently.

Shared blacklists

User agents MAY allow users to share their Key System blacklists. This would allow communities to act together to protect their privacy.

Per-origin user alerts / prompts and permissions

User agents MUST ensure that users are fully informed and/or give explicit consent before Distinctive Identifier(s) are exposed, such as in messages from the Key System implementation.

User agents MUST prompt or otherwise inform the user before allowing use of a that is not unique per-origin and/or not clearable is used. User agents SHOULD prompt or otherwise inform the user before allowing use of all other .

The "not unique per-origin" and "not clearable" conditions cannot be true in a compliant implementation because implementations MUST use per-origin identifiers and allow the user to clear identifier.

Such alerts and consent SHOULD be per to avoid valid uses enabling subsequent malicious access. User agent implementers that consider such alerts or consent appropriate for a Key System implementation SHOULD only support such Key Systems on secure origins (see Secure Origin and Transport), especially if they allow such consent to be persisted.

Granting permissions to unauthenticated origins is equivalent to granting the permissions to any origin in the presence of a network attacker.

User controls to disable Key Systems or Key System use of identifiers

User Agents SHOULD provide users with a global control of whether a Key System is enabled and/or whether Key System use of Distinctive Identifier(s) is enabled (if supported by the Key System). User agents SHOULD help the user avoid Incomplete Clearing of Data.

While these suggestions prevent trivial use of this API for user tracking, they do not block it altogether. Within a single origin, a site can continue to track the user during a session, and can then pass all this information to a third party along with any identifying information (names, credit card numbers, addresses) obtained by the site. If a third party cooperates with multiple sites to obtain such information, and if identifiers are not unique per-origin, then a profile can still be created.

Individualization

Distinctive Identifier(s) are sometimes obtained via a process called individualization or provisioning.

Individualization MAY be origin-independent or per-origin. The resulting identifier MUST be origin-independent or per-origin, respectively. In the former case the resulting identifier MUST NOT be provided to the application. The mechanisms and flow are for the two types of individualization are different, as described in the following sections.

In all cases, implementations SHOULD avoid sending origin(s) or -specific information to centralized servers since this could create a central record of all origins visited by a user or device.

Individualizaiton MAY be performed multiple times, such as after identifier(s) are cleared.

Origin-Independent Individualization

Origin-independent individualization is performed between the and an origin- and application-independent server. The process MUST be performed by the user agent and MUST NOT use these APIs.

For example, such a process may initialize a client device by communicating with a pre-determined server hosted by the user agent or CDM vendor, possibly using identifiers from the client device. Such communication would not involve providing application- or origin-specific information.

The resulting identifier MUST be origin- and application-independent. Such identifiers MUST NOT be provided to applications (see Use Per-Origin Identifiers), even encrypted. Implementations MAY derive non-reversible per-origin identifiers from such identifiers and provide those to the application (encrypted)

For such individualization, all message exchanges:

  • MUST be handled by the user agent and performed by the user agent via the user agent's network stack.

  • MUST NOT be performed directly by the CDM.

  • MUST NOT be passed to or through the application via these APIs.

  • MUST be sent to a URL selected independently of any origin and application.

Per-Origin Individualization

Per- individualization is performed between the and an application-selected server and results in a per-origin identifier. The process MUST be performed via these APIs and MUST NOT involve other types of communication. Any used MUST be origin-specific.

For such individualization, all message exchanges:

  • MUST be passed to or through the application via these APIs (message type ).

  • MUST NOT be performed by the user agent.

  • MUST NOT be performed directly by the CDM.

  • MUST NOT contain non-origin-specific per-client information, such as a .

  • As with all other uses of the APIs, responses passed to the CDM MUST NOT contain executable code.

With appropriate precautions, such individualization can provide better privacy than origin-independent individualization, though not as good as models that do not use . To preserve the benefits of such a design and to avoid introducing other privacy concerns:

  • Such implementations MUST NOT use Distinctive Identifier(s) for a device or user of a device in the individualization process.

  • Such implementations and the applications that support them SHOULD also avoid deferring or forwarding individualization messages to a central server or other server not controlled by the application author.

Information Stored on User Devices

Concerns

Key Systems may store information on a user's device, or user agents may store information on behalf of Key Systems. Potentially, this could reveal information about a user to another user of the same device, including potentially the origins that have used a particular Key System (i.e. sites visited) or even the content that has been decrypted using a Key System.

If information stored by one origin affects the operation of the Key System for another origin, then potentially the sites visited or content viewed by a user on one site may be revealed to another, potentially malicious, site.

If information stored for one browsing profile, browser, or user account on the client device affects the operation of the Key System for other profiles, browsers, or accounts, then potentially the sites visited or content viewed by in one may be revealed by or correlatable with another profile, browser, or account.

Mitigations

In summary, user agent and CDM implementations that allow the CDM to persist data:

  • MUST ensure it is restricted to the for which it was created.

  • MUST ensure it is restricted to the current profile and does not leak to or from private browsing sessions.

  • MUST allow the user to clear it, preferably by .

  • SHOULD treat it like other site data, including presenting it along with cookies [[!COOKIES]], including it in "remove all data", and presenting it in the same UI locations.

Origin-specific Key System storage

Any data persistently stored by the CDM that might impact messages or behavior in an application- or license server-visible way MUST be stored in an -specific way. Session data, licenses, and keys that are persistently stored MUST be stored per-. See .

User deletion of Key System storage

User agents SHOULD present the user with a way to delete Key System storage for a specific or all origins. User agents SHOULD help the user avoid Incomplete Clearing of Data.

Treating and Key System stored data like cookies / web storage

See the identical section above.

Encryption or obfuscation of Key System stored data

User agents SHOULD treat data stored by Key Systems as potentially sensitive; it is quite possible for user privacy to be compromised by the release of this information. To this end, user agents SHOULD ensure that such data is securely stored and when deleting data, it is promptly deleted from the underlying storage.

Incomplete Clearing of Data

Concerns

A user's attempts to protect his or her privacy by clearing and stored data and/or disabling a Key System may be defeated if all such data and functionality as well as cookies [[!COOKIES]] and other site data are not cleared and/or disabled at the same time. For example:

  • If a user clears cookies or other persistent storage without also clearing and data stored by Key Systems, sites can defeat those attempts by using the various features as redundant backup for each other.

  • If a user disables a key system, especially for a specific , without also clearing cookies or other persistent storage, sites can defeat those attempts by using the remaining features.

  • If a user disables a key system, then later decide to enable the key system, without also clearing clearing cookies or other persistent storage, , and data stored by Key Systems, sites may be able to associate data prior to the disabling with data and behavior after the key system is re-enabled.

Mitigations

User agents SHOULD present the interfaces for clearing and Key System stored data in a way that helps users to understand this possibility and enables them to delete data in all persistent identification and storage features, including HTTP session cookies [[!COOKIES]] and web storage, simultaneously. Likewise, User agents SHOULD present the interfaces for disabling and re-enabling a Key System in a way that helps users to understand this possibility and enables them to delete all such data in all persistent storage features simultaneously.

Private Browsing Modes

User agents may support a mode (e.g. private browsing) of operation intended to preserve user anonymity and/or ensure records of browsing activity are not persisted on the client. The privacy concerns discussed in previous sections may be expecially concerning for users employing such modes.

User agent implementers that support such mode(s) SHOULD carefully consider whether access to Key Systems should be disabled in these mode(s). For example, such modes MAY prohibit creation of MediaKeySystemAccess objects that support or use or a (either as part of the CDM implementation or because the application indicated they were ). If implementations do not prohibit such creation, they SHOULD inform the user of the implications and potential consequences for the expected privacy properties of such modes before allowing their use.

Secure Origin and Transport

In order to protect identifiers and other information discussed in previous sections, user agents MAY choose to only support these APIs and/or specific Key Systems (i.e. based on privacy and security risks) on secure origins. This is especially important if a user agent chooses to support a Key System implementation that expose or other such information without effectively anonymizing it in transit.

Regardless of user agent limitations, applications SHOULD use secure transport (e.g. HTTPS) for all traffic containing messages from the CDM (i.e. all data passed from events and to ).

All user agents MUST properly handle Mixed Content [[!MIXED-CONTENT]] to avoid exposure to insecure content or transport when the user agent or application wish to enforce secure origin and transport.

Examples

This section contains example solutions for various use cases using the proposed extensions. These are not the only solutions to these use cases. Video elements are used in the examples, but the same would apply to all media elements. In some cases, such as using synchronous XHR, the examples are simplified to keep the focus on the extensions.

Source and Key Known at Page Load (Clear Key)

In this simple example, the source file and clear-text license are hard-coded in the page. Only one session will ever be created.

<script>
  function onLoad() {
    var video = document.getElementById('video');

    if (!video.) {
      navigator.('org.w3.clearkey', [
        { : ['webm'],
          : [{ : 'video/webm; codecs="vp8"' }] }
      ]).then(
        function(keySystemAccess) {
          var promise =  keySystemAccess.();
          promise.catch(
            console.error.bind(console, 'Unable to create MediaKeys')
          );
          promise.then(
            function(createdMediaKeys) {
              return video.(createdMediaKeys);
            }
          ).catch(
            console.error.bind(console, 'Unable to set MediaKeys')
          );
          promise.then(
            function(createdMediaKeys) {
              var initData = new Uint8Array([ ... ]);
              var keySession = createdMediaKeys.();
              keySession.addEventListener("", handleMessage, false);
              return keySession.('webm', initData);
            }
          ).catch(
            console.error.bind(console, 'Unable to create or initialize key session')
          );
        }
      );
    }
  }

  function handleMessage(event) {
    var keySession = event.target;

    var license = new Uint8Array([ ... ]);
    keySession.(license).catch(
      console.error.bind(console, 'update() failed')
    );
  }
</script>

<body onload='onLoad()'>
  <video src='foo.webm' autoplay id='video'></video>
</body>

Selecting a Supported Key System and Using Initialization Data from the "encrypted" Event

This example selects a supported using the method then uses the from the to generate the license request and send it to the appropriate license server. One of the supported key systems uses a serverCertificate, which is provided proactively.

<script>
  var licenseUrl;
  var serverCertificate;

  // Returns a Promise<MediaKeys>.
  function createSupportedKeySystem() {
    someSystemOptions = [
     { : ['keyids', 'webm'],
       : [
         { : 'audio/webm; codecs="opus"' },
         { : 'audio/webm; codecs="vorbis"' }
       ],
       : [
         { : 'video/webm; codecs="vp9"' },
         { : 'video/webm; codecs="vp8"' }
       ]
     }
    ];
    clearKeyOptions = [
     { : ['keyids', 'webm'],
       : [
         { : 'audio/webm; codecs="opus"' },
         { : 'audio/webm; codecs="vorbis"' }
       ],
       : [
         { : 'video/webm; codecs="vp9"',
           : 'foo' },
         { : 'video/webm; codecs="vp9"',
           : 'bar' },
         { : 'video/webm; codecs="vp8"',
           : 'bar' },
       ]
     }
    ];

    return navigator.('com.example.somesystem', someSystemOptions).then(
      function(keySystemAccess) {
        // Not shown:
        // 1. Use both attributes of keySystemAccess..[0]
        //    and both attributes of keySystemAccess..[0]
        //    to retrieve appropriate stream(s).
        // 2. Set video.src.

        licenseUrl = 'https://license.example.com/getkey';
        serverCertificate = new Uint8Array([ ... ]);
        return keySystemAccess.();
      }
    ).catch(
      function(error) {
        // Try the next key system.
        navigator.('org.w3.clearkey', clearKeyOptions).then(
          function(keySystemAccess) {
            // Not shown:
            // 1. Use keySystemAccess..[0].
            //    and keySystemAccess..[0].
            //    to retrieve appropriate stream(s).
            // 2. Set video.src.

            licenseUrl = 'https://license.example.com/clearkey/request';
            return keySystemAccess.();
          }
        );
      }
    ).catch(
      console.error.bind(console, 'Unable to instantiate a key system supporting the required combinations')
    );
  }

  function handleInitData(event) {
    var video = event.target;
    if (video.mediaKeysObject === undefined) {
      video.mediaKeysObject = null; // Prevent entering this path again.
      video.pendingSessionData = []; // Will store all initData until the MediaKeys is ready.
      createSupportedKeySystem().then(
        function(createdMediaKeys) {
          video.mediaKeysObject = createdMediaKeys;

          if (serverCertificate)
            createdMediaKeys.(serverCertificate);

          for (var i = 0; i < video.pendingSessionData.length; i++) {
            var data = video.pendingSessionData[i];
            makeNewRequest(video.mediaKeysObject, data.initDataType, data.initData);
          }
          video.pendingSessionData = [];

          return video.(createdMediaKeys);
        }
      ).catch(
        console.error.bind(console, 'Failed to create and initialize a MediaKeys object')
      );
    }
    addSession(video, event., event.);
  }

  function addSession(video, initDataType, initData) {
    if (video.mediaKeysObject) {
      makeNewRequest(video.mediaKeysObject, initDataType, initData);
    } else {
      video.pendingSessionData.push({initDataType: initDataType, initData: initData});
    }
  }

  function makeNewRequest(mediaKeys, initDataType, initData) {
    var keySession = mediaKeys.();
    keySession.addEventListener("", licenseRequestReady, false);
    keySession.(initDataType, initData).catch(
      console.error.bind(console, 'Unable to create or initialize key session')
    );
  }

  function licenseRequestReady(event) {
    var request = event.;

    var xmlhttp = new XMLHttpRequest();
    xmlhttp.keySession = event.target;
    xmlhttp.open("POST", licenseUrl);
    xmlhttp.onreadystatechange = function() {
      if (xmlhttp.readyState == 4) {
        var license = new Uint8Array(xmlhttp.response);
        xmlhttp.keySession.(license).catch(
          console.error.bind(console, 'update() failed')
        );
      }
    }
    xmlhttp.send(request);
  }
</script>

<video autoplay ='handleInitData(event)'></video>

Create MediaKeys Before Loading Media

Initialization is much simpler if encrypted events do not need to be handled during MediaKeys initialization. This can be accomplished either by providing the in other ways or setting the source after the MediaKeys object has been created. This example does the latter.

<script>
  var licenseUrl;
  var serverCertificate;
  var mediaKeys;

  // See the previous example for implementations of these functions.
  function createSupportedKeySystem() { ... }
  function makeNewRequest(mediaKeys, initDataType, initData) { ... }
  function licenseRequestReady(event) { ... }

  function handleInitData(event) {
    makeNewRequest(mediaKeys, event., event.);
  }

  createSupportedKeySystem().then(
    function(createdMediaKeys) {
      mediaKeys = createdMediaKeys;
      var video = document.getElementById("v");
      video.src = 'foo.webm';
      if (serverCertificate)
        mediaKeys.(serverCertificate);
      return video.(mediaKeys);
    }
  ).catch(
    console.error.bind(console, 'Failed to create and initialize a MediaKeys object')
  );
</script>

<video id="v" autoplay ='handleInitData(event)'></video>

Using All Events

This is a more complete example showing all events being used.

Note that handleMessage() could be called multiple times, including in response to the call if multiple round trips are required and for any other reason the Key System might need to send a message.

<script>
  var licenseUrl;
  var serverCertificate;
  var mediaKeys;

  // See previous examples for implementations of these functions.
  // createSupportedKeySystem() additionally sets renewalUrl.
  function createSupportedKeySystem() { ... }
  function handleInitData(event) { ... }

  // This replaces the implementation in the previous example.
  function makeNewRequest(mediaKeys, initDataType, initData) {
    var keySession = mediaKeys.();
    keySession.addEventListener('', handleMessage, false);
    keySession.addEventListener('', handlekeyStatusesChange, false);
    keySession..then(
      console.log.bind(console, 'Session closed')
    );
    keySession.(initDataType, initData).catch(
      console.error.bind(console, 'Unable to create or initialize key session')
    );
  }

  function handleMessageResponse(keySession, response) {
    var license = new Uint8Array(response);
    keySession.(license).catch(
      function(err) {
        console.error('update() failed: ' + err);
      }
    );
  }

  function sendMessage(type, message, keySession) {
    var url = licenseUrl;
    if (type == )
      url = renewalUrl;
    xmlhttp = new XMLHttpRequest();
    xmlhttp.keySession = keySession;
    xmlhttp.open('POST', url);
    xmlhttp.onreadystatechange = function() {
      if (xmlhttp.readyState == 4)
        handleMessageResponse(xmlhttp.keySession, xmlhttp.response);
    }
    xmlhttp.send(message);
  }

  function handleMessage(event) {
    sendMessage(event., event., event.target);
  }

  function handlekeyStatusesChange(event) {
    // Evaluate the current state using one of the map-like methods exposed by
    // event.target..
    // For example:
    event.target..forEach(function(status, keyId, map) {
      switch (value) {
        case :
          break;
        case :
          // Report an expired key.
          break;
        case :
          // The status is not yet known. Consider the key unusable until the status is updated.
          break;
        default:
          // Do something with |keyId| and |status|.
        }
      }
    })
  }

  createSupportedKeySystem().then(
    function(createdMediaKeys) {
      mediaKeys = createdMediaKeys;
      var video = document.getElementById("v");
      video.src = 'foo.webm';
      if (serverCertificate)
        mediaKeys.(serverCertificate);
      return video.(mediaKeys);
    }
  ).catch(
    console.error.bind(console, 'Failed to create and initialize a MediaKeys object')
  );
</script>

<video id="v" autoplay ='handleInitData(event)'></video>

Stored License

This example requests a persistent license for future use and stores it. It also provides functions for later retrieving the license and for destroying it.

<script>
  var licenseUrl;
  var serverCertificate;
  var mediaKeys;

  // See the previous examples for implementations of these functions.
  // createSupportedKeySystem() additionally sets :  in each options dictionary.
  function createSupportedKeySystem() { ... }
  function sendMessage(message, keySession) { ... }
  function handleMessage(event) { ... }

  // Called if the application does not have a stored sessionId for the media resource.
  function makeNewRequest(mediaKeys, initDataType, initData) {
    var keySession = mediaKeys.();
    keySession.addEventListener('', handleMessage, false);
    keySession..then(
      function() {
        console.log('Session ' + this. + ' closed');
      }.bind(keySession)
    );
    keySession.(initDataType, initData).then(
      function() {
        // Store this. in the application.
      }.bind(keySession)
    ).catch(
      console.error.bind(console, 'Unable to request a persistent license')
    );
  }

  // Called if the application has a stored sessionId for the media resource.
  function loadStoredSession(mediaKeys, sessionId) {
    var keySession = mediaKeys.();
    keySession.addEventListener('', handleMessage, false);
    keySession..then(
      console.log.bind(console, 'Session closed')
    );
    keySession.(sessionId).then(
      function(loaded) {
        if (!loaded) {
          console.error('No stored session with the ID ' + sessionId + ' was found.');
          // The application should remove its record of |sessionId|.
          return;
        }
      }
    ).catch(
      console.error.bind(console, 'Unable to load or initialize the stored session with the ID ' + sessionId)
    );
  }

  // Called when the application wants to stop using the session without removing the stored license.
  function closeSession(keySession) {
    keySession.();
  }

  // Called when the application wants to remove the stored license.
  // The stored session data has not been completely removed until the promise returned by remove() is fulfilled.
  // The remove() call may initiate a series of messages to/from the server that must be completed before this occurs.
  function removeStoredSession(keySession) {
    keySession.().then(
      function() {
        console.log('Session ' + this. + ' removed');
        // The application should remove its record of this..
      }.bind(keySession)
    ).catch(
      console.error.bind(console, 'Failed to remove the session')
    );
  }

  // This replaces the implementation in the previous example.
  function handleMessageResponse(keySession, response) {
    var license = new Uint8Array(response);
    keySession.(license).then(
      function() {
        // If this was the last required message from the server, the license is
        // now stored. Update the application state as appropriate.
      }
    ).catch(
      console.error.bind(console, 'update() failed')
    );
  }

  createSupportedKeySystem().then(
    function(createdMediaKeys) {
      mediaKeys = createdMediaKeys;
      var video = document.getElementById("v");
      if (serverCertificate)
        mediaKeys.(serverCertificate);
      return video.(mediaKeys);
    }
  ).catch(
    console.error.bind(console, 'Failed to create and initialize a MediaKeys object')
  );
</script>

<video id='v' src='foo.webm' autoplay></video>

Revision History

Version Comment
13 November 2014 Repository moved to GitHub.
10 October 2014 Converted to ReSpec.
3 September 2014 Reorganized by object.
27 August 2014 Moved license request generation and session loading to MediaKeySession.
18 August 2014 Produced candidate WD.
14 April 2014 Use promises.
1 April 2014 Moved Container Guidelines to the Encrypted Media Extensions Stream Format and Initialization Data Format Registry.
3 February 2014 Produced candidate WD.
17 September 2013 Produced candidate WD.
6 May 2013 Produced updated candidate FPWD.
14 January 2013 Produced candidate FPWD.
16 August 2012 Converted to the object-oriented API.
0.1b Last non-object-oriented revision.
0.1a Corrects minor mistakes in 0.1.
0.1 Initial Proposal