⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 219946 in webkit


Ignore:
Timestamp:
Jul 26, 2017, 7:33:10 AM (9 years ago)
Author:
zandobersek@gmail.com
Message:

[EME][GStreamer] Multi-key support in the GStreamer ClearKey decryptor
​https://bugs.webkit.org/show_bug.cgi?id=174779

Reviewed by Xabier Rodriguez-Calvar.

In the CENC decryptor, the key ID value is retrieved from the info structure
on the GstProtectionMeta object. GstBuffer for that value is retrieved and
passed to the setupCipher() function.

In the ClearKey decryptor (which extends the CENC decryptor), the single
GstBuffer object on the private instance that holds the key value is replaced
with a Vector object that holds pairs of key ID and value GstBuffers. In the
handleKeyResponse() implementation that Vector is emptied and then refilled
with key ID and value pairs that are passed in through the drm-cipher-clearkey
structure that's attached to the GstEvent that signalled new key information.

In the ClearKey decryptor's setupCipher() implementation the passed-in key ID
buffer is used to find a matching key ID and value pair stored on the private
instance. If not found, an error is thrown. If found, the matching key value
is used for decryption.

  • platform/graphics/gstreamer/eme/WebKitClearKeyDecryptorGStreamer.cpp:

(webKitMediaClearKeyDecryptorHandleKeyResponse):
(webKitMediaClearKeyDecryptorSetupCipher):

  • platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp:

(webkitMediaCommonEncryptionDecryptTransformInPlace):
(webKitMediaCommonEncryptionDecryptDefaultSetupCipher):

  • platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.h:
Location:
trunk/Source/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r219945 r219946  
     12017-07-26  Zan Dobersek  <zdobersek@igalia.com>
     2
     3        [EME][GStreamer] Multi-key support in the GStreamer ClearKey decryptor
     4        https://bugs.webkit.org/show_bug.cgi?id=174779
     5
     6        Reviewed by Xabier Rodriguez-Calvar.
     7
     8        In the CENC decryptor, the key ID value is retrieved from the info structure
     9        on the GstProtectionMeta object. GstBuffer for that value is retrieved and
     10        passed to the setupCipher() function.
     11
     12        In the ClearKey decryptor (which extends the CENC decryptor), the single
     13        GstBuffer object on the private instance that holds the key value is replaced
     14        with a Vector object that holds pairs of key ID and value GstBuffers. In the
     15        handleKeyResponse() implementation that Vector is emptied and then refilled
     16        with key ID and value pairs that are passed in through the drm-cipher-clearkey
     17        structure that's attached to the GstEvent that signalled new key information.
     18
     19        In the ClearKey decryptor's setupCipher() implementation the passed-in key ID
     20        buffer is used to find a matching key ID and value pair stored on the private
     21        instance. If not found, an error is thrown. If found, the matching key value
     22        is used for decryption.
     23
     24        * platform/graphics/gstreamer/eme/WebKitClearKeyDecryptorGStreamer.cpp:
     25        (webKitMediaClearKeyDecryptorHandleKeyResponse):
     26        (webKitMediaClearKeyDecryptorSetupCipher):
     27        * platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp:
     28        (webkitMediaCommonEncryptionDecryptTransformInPlace):
     29        (webKitMediaCommonEncryptionDecryptDefaultSetupCipher):
     30        * platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.h:
     31
    1322017-07-26  Zan Dobersek  <zdobersek@igalia.com>
    233
  • trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitClearKeyDecryptorGStreamer.cpp

    r217966 r219946  
    3232#define CLEARKEY_SIZE 16
    3333
     34struct Key {
     35    GRefPtr<GstBuffer> keyID;
     36    GRefPtr<GstBuffer> keyValue;
     37};
     38
    3439#define WEBKIT_MEDIA_CK_DECRYPT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), WEBKIT_TYPE_MEDIA_CK_DECRYPT, WebKitMediaClearKeyDecryptPrivate))
    3540struct _WebKitMediaClearKeyDecryptPrivate {
    36     GRefPtr<GstBuffer> key;
     41    Vector<Key> keys;
    3742    gcry_cipher_hd_t handle;
    3843};
    … …  
    4045static void webKitMediaClearKeyDecryptorFinalize(GObject*);
    4146static gboolean webKitMediaClearKeyDecryptorHandleKeyResponse(WebKitMediaCommonEncryptionDecrypt* self, GstEvent*);
    42 static gboolean webKitMediaClearKeyDecryptorSetupCipher(WebKitMediaCommonEncryptionDecrypt*);
     47static gboolean webKitMediaClearKeyDecryptorSetupCipher(WebKitMediaCommonEncryptionDecrypt*, GstBuffer*);
    4348static gboolean webKitMediaClearKeyDecryptorDecrypt(WebKitMediaCommonEncryptionDecrypt*, GstBuffer* iv, GstBuffer* sample, unsigned subSamplesCount, GstBuffer* subSamples);
    4449static void webKitMediaClearKeyDecryptorReleaseCipher(WebKitMediaCommonEncryptionDecrypt*);
    … …  
    121126    const GstStructure* structure = gst_event_get_structure(event);
    122127
    123     if (!gst_structure_has_name(structure, "drm-cipher"))
     128    // Demand the `drm-cipher-clearkey` GstStructure.
     129    if (!gst_structure_has_name(structure, "drm-cipher-clearkey"))
    124130        return FALSE;
    125131
    126     const GValue* value = gst_structure_get_value(structure, "key");
    127     priv->key.clear();
    128     priv->key = adoptGRef(gst_buffer_copy(gst_value_get_buffer(value)));
     132    // Retrieve the `key-ids` GStreamer value list.
     133    const GValue* keyIDsList = gst_structure_get_value(structure, "key-ids");
     134    ASSERT(keyIDsList && GST_VALUE_HOLDS_LIST(keyIDsList));
     135    unsigned keyIDsListSize = gst_value_list_get_size(keyIDsList);
     136
     137    // Retrieve the `key-values` GStreamer value list.
     138    const GValue* keyValuesList = gst_structure_get_value(structure, "key-values");
     139    ASSERT(keyValuesList && GST_VALUE_HOLDS_LIST(keyValuesList));
     140    unsigned keyValuesListSize = gst_value_list_get_size(keyValuesList);
     141
     142    // Bail if somehow the two lists don't match in size.
     143    if (keyIDsListSize != keyValuesListSize)
     144        return FALSE;
     145
     146    // Clear out the previous list of keys.
     147    priv->keys.clear();
     148
     149    // Append the retrieved GstBuffer objects containing each key's ID and value to the list of Key objects.
     150    for (unsigned i = 0; i < keyIDsListSize; ++i) {
     151        GRefPtr<GstBuffer> keyIDBuffer(gst_value_get_buffer(gst_value_list_get_value(keyIDsList, i)));
     152        GRefPtr<GstBuffer> keyValueBuffer(gst_value_get_buffer(gst_value_list_get_value(keyValuesList, i)));
     153        priv->keys.append(Key { WTFMove(keyIDBuffer), WTFMove(keyValueBuffer) });
     154    }
     155
    129156    return TRUE;
    130157}
    131158
    132 static gboolean webKitMediaClearKeyDecryptorSetupCipher(WebKitMediaCommonEncryptionDecrypt* self)
     159static gboolean webKitMediaClearKeyDecryptorSetupCipher(WebKitMediaCommonEncryptionDecrypt* self, GstBuffer* keyIDBuffer)
    133160{
    134161    WebKitMediaClearKeyDecryptPrivate* priv = WEBKIT_MEDIA_CK_DECRYPT_GET_PRIVATE(WEBKIT_MEDIA_CK_DECRYPT(self));
    135162    gcry_error_t error;
    136163
    137     ASSERT(priv->key);
    138     if (!priv->key) {
    139         GST_ERROR_OBJECT(self, "Decryption key not provided");
     164    GRefPtr<GstBuffer> keyBuffer;
     165    {
     166        GstMapInfo keyIDBufferMap;
     167        if (!gst_buffer_map(keyIDBuffer, &keyIDBufferMap, GST_MAP_READ)) {
     168            GST_ERROR_OBJECT(self, "Failed to map key ID buffer");
     169            return false;
     170        }
     171
     172        for (auto& key : priv->keys) {
     173            if (!gst_buffer_memcmp(key.keyID.get(), 0, keyIDBufferMap.data, keyIDBufferMap.size)) {
     174                keyBuffer = key.keyValue;
     175                break;
     176            }
     177        }
     178
     179        gst_buffer_unmap(keyIDBuffer, &keyIDBufferMap);
     180    }
     181
     182    if (!keyBuffer) {
     183        GST_ERROR_OBJECT(self, "Failed to find an appropriate key buffer");
    140184        return false;
    141185    }
    … …  
    148192
    149193    GstMapInfo keyMap;
    150     if (!gst_buffer_map(priv->key.get(), &keyMap, GST_MAP_READ)) {
     194    if (!gst_buffer_map(keyBuffer.get(), &keyMap, GST_MAP_READ)) {
    151195        GST_ERROR_OBJECT(self, "Failed to map decryption key");
    152196        return false;
    … …  
    155199    ASSERT(keyMap.size == CLEARKEY_SIZE);
    156200    error = gcry_cipher_setkey(priv->handle, keyMap.data, keyMap.size);
    157     gst_buffer_unmap(priv->key.get(), &keyMap);
     201    gst_buffer_unmap(keyBuffer.get(), &keyMap);
    158202    if (error) {
    159203        GST_ERROR_OBJECT(self, "gcry_cipher_setkey failed: %s", gpg_strerror(error));
  • trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp

    r217966 r219946  
    4545static gboolean webkitMediaCommonEncryptionDecryptSinkEventHandler(GstBaseTransform*, GstEvent*);
    4646
    47 static gboolean webKitMediaCommonEncryptionDecryptDefaultSetupCipher(WebKitMediaCommonEncryptionDecrypt*);
     47static gboolean webKitMediaCommonEncryptionDecryptDefaultSetupCipher(WebKitMediaCommonEncryptionDecrypt*, GstBuffer*);
    4848static void webKitMediaCommonEncryptionDecryptDefaultReleaseCipher(WebKitMediaCommonEncryptionDecrypt*);
    4949
    … …  
    254254    }
    255255
     256    value = gst_structure_get_value(protectionMeta->info, "kid");
     257    if (!value) {
     258        GST_ERROR_OBJECT(self, "Failed to get key ID for sample");
     259        gst_buffer_remove_meta(buffer, reinterpret_cast<GstMeta*>(protectionMeta));
     260        return GST_FLOW_NOT_SUPPORTED;
     261    }
     262
     263    GstBuffer* keyIDBuffer = gst_value_get_buffer(value);
    256264    WebKitMediaCommonEncryptionDecryptClass* klass = WEBKIT_MEDIA_CENC_DECRYPT_GET_CLASS(self);
    257     if (!klass->setupCipher(self)) {
     265    if (!klass->setupCipher(self, keyIDBuffer)) {
    258266        GST_ERROR_OBJECT(self, "Failed to configure cipher");
    259267        gst_buffer_remove_meta(buffer, reinterpret_cast<GstMeta*>(protectionMeta));
    … …  
    350358
    351359
    352 static gboolean webKitMediaCommonEncryptionDecryptDefaultSetupCipher(WebKitMediaCommonEncryptionDecrypt*)
     360static gboolean webKitMediaCommonEncryptionDecryptDefaultSetupCipher(WebKitMediaCommonEncryptionDecrypt*, GstBuffer*)
    353361{
    354362    return true;
  • trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.h

    r217966 r219946  
    5555    const char* protectionSystemId;
    5656    gboolean (*handleKeyResponse)(WebKitMediaCommonEncryptionDecrypt*, GstEvent* event);
    57     gboolean (*setupCipher)(WebKitMediaCommonEncryptionDecrypt*);
     57    gboolean (*setupCipher)(WebKitMediaCommonEncryptionDecrypt*, GstBuffer*);
    5858    gboolean (*decrypt)(WebKitMediaCommonEncryptionDecrypt*, GstBuffer* ivBuffer, GstBuffer* buffer, unsigned subSamplesCount, GstBuffer* subSamplesBuffer);
    5959    void (*releaseCipher)(WebKitMediaCommonEncryptionDecrypt*);
Note: See TracChangeset for help on using the changeset viewer.