Title: [219946] trunk/Source/WebCore
Revision
219946
Author
[email protected]
Date
2017-07-26 07:33:10 -0700 (Wed, 26 Jul 2017)

Log 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:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (219945 => 219946)


--- trunk/Source/WebCore/ChangeLog	2017-07-26 14:31:13 UTC (rev 219945)
+++ trunk/Source/WebCore/ChangeLog	2017-07-26 14:33:10 UTC (rev 219946)
@@ -1,5 +1,36 @@
 2017-07-26  Zan Dobersek  <[email protected]>
 
+        [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:
+
+2017-07-26  Zan Dobersek  <[email protected]>
+
         [EME][GStreamer] Handle ClearKey as a supported key system
         https://bugs.webkit.org/show_bug.cgi?id=174778
 

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitClearKeyDecryptorGStreamer.cpp (219945 => 219946)


--- trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitClearKeyDecryptorGStreamer.cpp	2017-07-26 14:31:13 UTC (rev 219945)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitClearKeyDecryptorGStreamer.cpp	2017-07-26 14:33:10 UTC (rev 219946)
@@ -31,15 +31,20 @@
 
 #define CLEARKEY_SIZE 16
 
+struct Key {
+    GRefPtr<GstBuffer> keyID;
+    GRefPtr<GstBuffer> keyValue;
+};
+
 #define WEBKIT_MEDIA_CK_DECRYPT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), WEBKIT_TYPE_MEDIA_CK_DECRYPT, WebKitMediaClearKeyDecryptPrivate))
 struct _WebKitMediaClearKeyDecryptPrivate {
-    GRefPtr<GstBuffer> key;
+    Vector<Key> keys;
     gcry_cipher_hd_t handle;
 };
 
 static void webKitMediaClearKeyDecryptorFinalize(GObject*);
 static gboolean webKitMediaClearKeyDecryptorHandleKeyResponse(WebKitMediaCommonEncryptionDecrypt* self, GstEvent*);
-static gboolean webKitMediaClearKeyDecryptorSetupCipher(WebKitMediaCommonEncryptionDecrypt*);
+static gboolean webKitMediaClearKeyDecryptorSetupCipher(WebKitMediaCommonEncryptionDecrypt*, GstBuffer*);
 static gboolean webKitMediaClearKeyDecryptorDecrypt(WebKitMediaCommonEncryptionDecrypt*, GstBuffer* iv, GstBuffer* sample, unsigned subSamplesCount, GstBuffer* subSamples);
 static void webKitMediaClearKeyDecryptorReleaseCipher(WebKitMediaCommonEncryptionDecrypt*);
 
@@ -120,23 +125,62 @@
     WebKitMediaClearKeyDecryptPrivate* priv = WEBKIT_MEDIA_CK_DECRYPT_GET_PRIVATE(WEBKIT_MEDIA_CK_DECRYPT(self));
     const GstStructure* structure = gst_event_get_structure(event);
 
-    if (!gst_structure_has_name(structure, "drm-cipher"))
+    // Demand the `drm-cipher-clearkey` GstStructure.
+    if (!gst_structure_has_name(structure, "drm-cipher-clearkey"))
         return FALSE;
 
-    const GValue* value = gst_structure_get_value(structure, "key");
-    priv->key.clear();
-    priv->key = adoptGRef(gst_buffer_copy(gst_value_get_buffer(value)));
+    // Retrieve the `key-ids` GStreamer value list.
+    const GValue* keyIDsList = gst_structure_get_value(structure, "key-ids");
+    ASSERT(keyIDsList && GST_VALUE_HOLDS_LIST(keyIDsList));
+    unsigned keyIDsListSize = gst_value_list_get_size(keyIDsList);
+
+    // Retrieve the `key-values` GStreamer value list.
+    const GValue* keyValuesList = gst_structure_get_value(structure, "key-values");
+    ASSERT(keyValuesList && GST_VALUE_HOLDS_LIST(keyValuesList));
+    unsigned keyValuesListSize = gst_value_list_get_size(keyValuesList);
+
+    // Bail if somehow the two lists don't match in size.
+    if (keyIDsListSize != keyValuesListSize)
+        return FALSE;
+
+    // Clear out the previous list of keys.
+    priv->keys.clear();
+
+    // Append the retrieved GstBuffer objects containing each key's ID and value to the list of Key objects.
+    for (unsigned i = 0; i < keyIDsListSize; ++i) {
+        GRefPtr<GstBuffer> keyIDBuffer(gst_value_get_buffer(gst_value_list_get_value(keyIDsList, i)));
+        GRefPtr<GstBuffer> keyValueBuffer(gst_value_get_buffer(gst_value_list_get_value(keyValuesList, i)));
+        priv->keys.append(Key { WTFMove(keyIDBuffer), WTFMove(keyValueBuffer) });
+    }
+
     return TRUE;
 }
 
-static gboolean webKitMediaClearKeyDecryptorSetupCipher(WebKitMediaCommonEncryptionDecrypt* self)
+static gboolean webKitMediaClearKeyDecryptorSetupCipher(WebKitMediaCommonEncryptionDecrypt* self, GstBuffer* keyIDBuffer)
 {
     WebKitMediaClearKeyDecryptPrivate* priv = WEBKIT_MEDIA_CK_DECRYPT_GET_PRIVATE(WEBKIT_MEDIA_CK_DECRYPT(self));
     gcry_error_t error;
 
-    ASSERT(priv->key);
-    if (!priv->key) {
-        GST_ERROR_OBJECT(self, "Decryption key not provided");
+    GRefPtr<GstBuffer> keyBuffer;
+    {
+        GstMapInfo keyIDBufferMap;
+        if (!gst_buffer_map(keyIDBuffer, &keyIDBufferMap, GST_MAP_READ)) {
+            GST_ERROR_OBJECT(self, "Failed to map key ID buffer");
+            return false;
+        }
+
+        for (auto& key : priv->keys) {
+            if (!gst_buffer_memcmp(key.keyID.get(), 0, keyIDBufferMap.data, keyIDBufferMap.size)) {
+                keyBuffer = key.keyValue;
+                break;
+            }
+        }
+
+        gst_buffer_unmap(keyIDBuffer, &keyIDBufferMap);
+    }
+
+    if (!keyBuffer) {
+        GST_ERROR_OBJECT(self, "Failed to find an appropriate key buffer");
         return false;
     }
 
@@ -147,7 +191,7 @@
     }
 
     GstMapInfo keyMap;
-    if (!gst_buffer_map(priv->key.get(), &keyMap, GST_MAP_READ)) {
+    if (!gst_buffer_map(keyBuffer.get(), &keyMap, GST_MAP_READ)) {
         GST_ERROR_OBJECT(self, "Failed to map decryption key");
         return false;
     }
@@ -154,7 +198,7 @@
 
     ASSERT(keyMap.size == CLEARKEY_SIZE);
     error = gcry_cipher_setkey(priv->handle, keyMap.data, keyMap.size);
-    gst_buffer_unmap(priv->key.get(), &keyMap);
+    gst_buffer_unmap(keyBuffer.get(), &keyMap);
     if (error) {
         GST_ERROR_OBJECT(self, "gcry_cipher_setkey failed: %s", gpg_strerror(error));
         return false;

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp (219945 => 219946)


--- trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp	2017-07-26 14:31:13 UTC (rev 219945)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.cpp	2017-07-26 14:33:10 UTC (rev 219946)
@@ -44,7 +44,7 @@
 static GstFlowReturn webkitMediaCommonEncryptionDecryptTransformInPlace(GstBaseTransform*, GstBuffer*);
 static gboolean webkitMediaCommonEncryptionDecryptSinkEventHandler(GstBaseTransform*, GstEvent*);
 
-static gboolean webKitMediaCommonEncryptionDecryptDefaultSetupCipher(WebKitMediaCommonEncryptionDecrypt*);
+static gboolean webKitMediaCommonEncryptionDecryptDefaultSetupCipher(WebKitMediaCommonEncryptionDecrypt*, GstBuffer*);
 static void webKitMediaCommonEncryptionDecryptDefaultReleaseCipher(WebKitMediaCommonEncryptionDecrypt*);
 
 GST_DEBUG_CATEGORY_STATIC(webkit_media_common_encryption_decrypt_debug_category);
@@ -253,8 +253,16 @@
         subSamplesBuffer = gst_value_get_buffer(value);
     }
 
+    value = gst_structure_get_value(protectionMeta->info, "kid");
+    if (!value) {
+        GST_ERROR_OBJECT(self, "Failed to get key ID for sample");
+        gst_buffer_remove_meta(buffer, reinterpret_cast<GstMeta*>(protectionMeta));
+        return GST_FLOW_NOT_SUPPORTED;
+    }
+
+    GstBuffer* keyIDBuffer = gst_value_get_buffer(value);
     WebKitMediaCommonEncryptionDecryptClass* klass = WEBKIT_MEDIA_CENC_DECRYPT_GET_CLASS(self);
-    if (!klass->setupCipher(self)) {
+    if (!klass->setupCipher(self, keyIDBuffer)) {
         GST_ERROR_OBJECT(self, "Failed to configure cipher");
         gst_buffer_remove_meta(buffer, reinterpret_cast<GstMeta*>(protectionMeta));
         return GST_FLOW_NOT_SUPPORTED;
@@ -349,7 +357,7 @@
 }
 
 
-static gboolean webKitMediaCommonEncryptionDecryptDefaultSetupCipher(WebKitMediaCommonEncryptionDecrypt*)
+static gboolean webKitMediaCommonEncryptionDecryptDefaultSetupCipher(WebKitMediaCommonEncryptionDecrypt*, GstBuffer*)
 {
     return true;
 }

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.h (219945 => 219946)


--- trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.h	2017-07-26 14:31:13 UTC (rev 219945)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/eme/WebKitCommonEncryptionDecryptorGStreamer.h	2017-07-26 14:33:10 UTC (rev 219946)
@@ -54,7 +54,7 @@
 
     const char* protectionSystemId;
     gboolean (*handleKeyResponse)(WebKitMediaCommonEncryptionDecrypt*, GstEvent* event);
-    gboolean (*setupCipher)(WebKitMediaCommonEncryptionDecrypt*);
+    gboolean (*setupCipher)(WebKitMediaCommonEncryptionDecrypt*, GstBuffer*);
     gboolean (*decrypt)(WebKitMediaCommonEncryptionDecrypt*, GstBuffer* ivBuffer, GstBuffer* buffer, unsigned subSamplesCount, GstBuffer* subSamplesBuffer);
     void (*releaseCipher)(WebKitMediaCommonEncryptionDecrypt*);
 };
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to