NetflixWebCryptoUseCase

From W3C Wiki
Revision as of 01:52, 20 December 2011 by Mzolling (Talk | contribs)

Jump to: navigation, search

SUMMARY


Netflix would like to implement a fast, lightweight, secure application protocol for communication between a Netflix client implemented in Javascript, running in a browser or other HTML/CSS/JS-based platform and Netflix servers (running on a cloud computing platform). Authentication may be bootstrapped from some pre-provisioned credential bound to the device. This secure protocol is then used for functions such as authorization to play movies, DRM license exchanges and reporting of usage statistics.


DETAILS


Key Store and Key Naming

This document assumes the availability of key storage in the browser or browser framework. This “key store” must not allow Javascript code to access the raw bytes of a key (public keys being a notable exception) but instead marshals requests for cryptographic operations using the stored keys. In most cases, it will be desirable to have a per-origin key store. The key named “MySecretKey” used by an app running from “foo.com” may not be accessed by an app running from “bar.com”. Further, “bar.com” may have its own key named “MySecretKey” without conflicting with the key of the same name for domain “foo.com”.

Each key has a unique local identifier used to refer to it over the Javascript API. In this document we assume this is simply a string value chosen by the calling code. Additionally, the key store allows keys to be added, deleted, etc.

At a minimum the key store should allow the following:


Function Description
exists(keyName) returns a boolean notifying the caller if such named key exists
length(keyName) returns the length of the key
delete(keyName) deletes the named key
generate(keyName, size) generate the named key with the given size


For the sake of simplicity, this document references keys by names in calls to functions like encrypt(). An actual API definition may want to have more flexibility, supporting a first class KeyHandle object, for example.


Key Deployment This document assumes that every cryptographic key is one of the following types:

  • Pre-provisioned keys. These keys are pre-shared or field-provisioned keys which are put into a key store by a device manufacturer, by an individual user, an enterprise IT staff or some other entity. These keys already exist prior to the running of apps that use them. Note that the distinction between pre-shared and field-provisioned keys is fuzzy enough in some cases to simply lump them all together into “pre-provisioned”: a manufacturer may burn “pre-shared” keys into a device’s ROM, but later decide to field provision a new set of keys via firmware update. In this case, the app writer doesn’t really care whether the keys were “pre-shared” or “field-provisioned”; all that matter is that the keys are “pre-provisioned”.
  • Session keys. These keys are exchanged, derived or otherwise created at runtime of the application using them.

The APIs in this document are agnostic to the type of key deployment used. In other words, a cryptographic operation using a pre-provisioned key looks just like a cryptographic operation using a session key.

Continuity of Device / Key Identification

When pre-provisioned symmetric keys are used, some kind of globally unique identifier must also be provided so that services can look up the key in their own server-side database. For public-private key pairs, the same approach could be used, or a certificate could be used.

As noted in the above description of pre-provisioned keys, keys may change at the whim of a device manufacturer, network operator, etc. We have seen multiple examples of keys changing due to firmware updates, creation of short-lived secondary credentials (IPSEC with pre-shared keys leveraged to affect an X.509 certificate enrollment, where resultant certs were only valid for a number of hours), swapping of cryptographic hardware tokens, etc. It can be expected that services which use such keys are notified of the new keys before they change. However, when keys change in such a manner, we must be able to identify a device across such key changes to maintain continuity of services.

To achieve this continuity, at present, we use a per-device, per-domain unique identifier which is constant. This approach may be fine for devices, but for a browser the constant nature of this identifier may not be possible. In this case, so long as there is a “key store ID” or some such per-browser per-domain identifier that does not change unless a user reinstalls their browser, we achieve the same goal.

To create commonality in both the device & browser contexts, we propose a common API to access such an identifier.


Message Security

Each message sent to and received from Netflix servers is authenticated, integrity protected and (optionally) encrypted using a lightweight arbitrary security message envelope, referred to here as MsgSec.


Security Prior to Bootstrapping Session Keys & Tokens Before a device or browser has a session key and a session token, the MsgSec protocol wrapper will rely on either pre-provisioned keys or runtime generated keys which are associated to a domain specific unique identifier.

Example Request The following table describes a MsgSec wrapped request message from the client when using pre-provisioned or runtime generated keys. (The packaging of this data into an over-the-wire format is beyond the scope of this document.)

Element Example Value Description
MsgType “request” “request” (or) “response”
ID “client-12345” unique identifier for the client browser or device
Msg “jIPx3TCNguQ=” Base-64 encoded encrypted message
MAC “0D2Yeh/jbX2GXYAKHrLBGQ==” Base-64 encoded MAC

The “ID” field may be a domain specific GUID, an actual hardware identifier or some other device and/or browser identifier which is guaranteed unique. The “Msg” field is an arbitrary message which may be encrypted. The “MAC” is a message authentication code.

In this example, the WebCrypto APIs are used to:

  • Generate the “MAC” message authentication code on the request using a pre-provisioned or runtime generated, client MAC key.
  • Encrypt the “Msg” using a pre-provisioned or runtime generated symmetric key.

To support creation of the above message, we might do something like this:

// In this example, we use the following webcrypto APIs:
//   webcrypto.encrypt(msg, keyName, cipherAlgorithm)
//   webcrypto.mac(msg, keyName, macAlgorithm)

// wrap a request using pre-shared or runtime generated keys
// msg: the message to wrap
// id: the client ID
function wrapMsg(msg, id)
{
  // encrypt the msg
  var encMsg =
    webcrypto.encrypt(msg, “ClientEncryptionKey”, “aes-128-cbc”);
  // create a partial message that we will MAC
  // make it “name=value” pairs with comma delimiters for simplicity
  var partialMsg = “MsgType=request,ID=”+id+“,Msg=”+encMsg;
  // create the MAC
  var mac = webcrypto.mac(partialMsg, “ClientMACKey”, “HmacSha256”);
  // create complete message with MAC
  var completeMsg = partialMsg+”,MAC=”+mac;
  // return the encrypted & MAC’d message to the caller
  return completeMsg;
}

Example Response The following table describes a MsgSec wrapped response message from the server when using pre-provisioned or runtime generated keys.

Element Example Value Description
MsgType “response” “request” (or) “response”
Msg “jIPx3TCNguQ=” Base-64 encoded encrypted message
MAC “0D2Yeh/jbX2GXYAKHrLBGQ==” Base-64 encoded MAC

In this example, the WebCrypto APIs are used to:

  • Verify the “MAC” using a pre-provisioned or runtime generated server MAC key.
  • Decrypt the “Msg” using a pre-provisioned or runtime generated server symmetric key.

To support unwrapping this response from the server, we might do something like this:

// In this example, we use the following webcrypto APIs:
//   webcrypto.decrypt(encMsg, keyName, cipherAlgorithm)
//   webcrypto.mac(msg, keyName, macAlgorithm)

// unwrap a response using pre-shared or runtime generated keys
// msg: the encrypted message to unwrap
function unwrapMsg(msg)
{
  // parse name/value pairs here
  // output vars: msgType, msg, mac

  // create a partial message to MAC
  var partialMsg = “MsgType=”+msgType+”,Msg=”+msg
  // mac the partial msg
  var genMac = webcrypto.mac(partialMsg, “ServerHMACKey”, “HmacSha256”);
  // compare the two MACs
  if(genMac != mac) {
    error();
  }
 // decrypt the msg
 var decMsg = webcrypto.decrypt(msg, “ServerEncryptionKey”, “aes-128-cbc”);
 // return our decrypted, MAC-verified msg
 return decMsg;

}