Title: [226621] trunk/Source/WebCore
Revision
226621
Author
[email protected]
Date
2018-01-09 02:02:46 -0800 (Tue, 09 Jan 2018)

Log Message

[EME] Add the CENC initData support in ClearKey CDM
https://bugs.webkit.org/show_bug.cgi?id=180081

Patch by Yacine Bandou <[email protected]> on 2018-01-09
Reviewed by Xabier Rodriguez-Calvar.

Add the "cenc" initDataType support in ClearKey CDM.
Parse the CENC initData and extract the KIDs by following the W3C spec
https://www.w3.org/TR/eme-initdata-cenc/#common-system

Tests: media/encrypted-media/clearKey/clearKey-message-cenc-event.html
       media/encrypted-media/clearKey/clearKey-message-cenc-event-mse.html

* platform/encryptedmedia/clearkey/CDMClearKey.cpp:
(WebCore::extractKeyidsLocationFromCencInitData):
(WebCore::isCencInitData):
(WebCore::extractKeyidsFromCencInitData):
(WebCore::CDMPrivateClearKey::supportsInitDataType const):
(WebCore::CDMPrivateClearKey::supportsInitData const):
(WebCore::CDMInstanceClearKey::requestLicense):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (226620 => 226621)


--- trunk/Source/WebCore/ChangeLog	2018-01-09 09:52:13 UTC (rev 226620)
+++ trunk/Source/WebCore/ChangeLog	2018-01-09 10:02:46 UTC (rev 226621)
@@ -1,3 +1,25 @@
+2018-01-09  Yacine Bandou  <[email protected]>
+
+        [EME] Add the CENC initData support in ClearKey CDM
+        https://bugs.webkit.org/show_bug.cgi?id=180081
+
+        Reviewed by Xabier Rodriguez-Calvar.
+
+        Add the "cenc" initDataType support in ClearKey CDM.
+        Parse the CENC initData and extract the KIDs by following the W3C spec
+        https://www.w3.org/TR/eme-initdata-cenc/#common-system
+
+        Tests: media/encrypted-media/clearKey/clearKey-message-cenc-event.html
+               media/encrypted-media/clearKey/clearKey-message-cenc-event-mse.html
+
+        * platform/encryptedmedia/clearkey/CDMClearKey.cpp:
+        (WebCore::extractKeyidsLocationFromCencInitData):
+        (WebCore::isCencInitData):
+        (WebCore::extractKeyidsFromCencInitData):
+        (WebCore::CDMPrivateClearKey::supportsInitDataType const):
+        (WebCore::CDMPrivateClearKey::supportsInitData const):
+        (WebCore::CDMInstanceClearKey::requestLicense):
+
 2018-01-09  Zan Dobersek  <[email protected]>
 
         [Cairo] Pass state values directly to Cairo operations

Modified: trunk/Source/WebCore/platform/encryptedmedia/clearkey/CDMClearKey.cpp (226620 => 226621)


--- trunk/Source/WebCore/platform/encryptedmedia/clearkey/CDMClearKey.cpp	2018-01-09 09:52:13 UTC (rev 226620)
+++ trunk/Source/WebCore/platform/encryptedmedia/clearkey/CDMClearKey.cpp	2018-01-09 10:02:46 UTC (rev 226621)
@@ -43,6 +43,12 @@
 
 namespace WebCore {
 
+// ClearKey CENC SystemID.
+// https://www.w3.org/TR/eme-initdata-cenc/#common-system
+const uint8_t clearKeyCencSystemId[] = { 0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b };
+const unsigned clearKeyCencSystemIdSize = sizeof(clearKeyCencSystemId);
+const unsigned keyIdSize = 16;
+
 class ClearKeyState {
     using KeyStore = HashMap<String, Vector<CDMInstanceClearKey::Key>>;
 
@@ -140,6 +146,119 @@
     return true;
 }
 
+// https://www.w3.org/TR/eme-initdata-cenc/#common-system
+// 4.1 Definition
+// The SystemID is 1077efec-c0b2-4d02-ace3-3c1e52e2fb4b.
+// The PSSH box format is as follows. It follows version 1 of the 'pssh' box as defined in [CENC].
+// pssh = [
+// 0x00, 0x00, 0x00, 0x4c, 0x70, 0x73, 0x73, 0x68, // BMFF box header (76 bytes, 'pssh')
+// 0x01, 0x00, 0x00, 0x00,                         // Full box header (version = 1, flags = 0)
+// 0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, // SystemID
+// 0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b,
+// 0x00, 0x00, 0x00, 0x02,                         // KidCount (2)
+// 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, // First KID ("0123456789012345")
+// 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
+// 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, // Second KID ("ABCDEFGHIJKLMNOP")
+// 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
+// 0x00, 0x00, 0x00, 0x00,                         // Size of Data (0)
+// ];
+
+// This function extracts the KeyIds count and the location of the first KeyId in initData buffer.
+static std::pair<unsigned, unsigned> extractKeyidsLocationFromCencInitData(const SharedBuffer& initData)
+{
+    std::pair<unsigned, unsigned> keyIdsMap(0, 0);
+
+    // Check the initData size.
+    if (initData.isEmpty() || initData.size() > std::numeric_limits<unsigned>::max())
+        return keyIdsMap;
+
+    const char* data = ""
+    unsigned initDataSize = initData.size();
+    unsigned index = 0;
+    unsigned psshSize = 0;
+
+    // Search in the concatenated or the simple InitData, the ClearKey PSSH.
+    bool foundPssh = false;
+    while (true) {
+
+        // Check the overflow InitData.
+        if (index + 12 + clearKeyCencSystemIdSize >= initDataSize)
+            return keyIdsMap;
+
+        psshSize = data[index + 2] * 256 + data[index + 3];
+
+        // 12 = BMFF box header + Full box header.
+        if (!memcmp(&data[index + 12], clearKeyCencSystemId, clearKeyCencSystemIdSize)) {
+            foundPssh = true;
+            break;
+        }
+        index += psshSize;
+    }
+
+    // Check if the InitData contains the ClearKey PSSH.
+    if (!foundPssh)
+        return keyIdsMap;
+
+    index += (12 + clearKeyCencSystemIdSize); // 12 (BMFF box header + Full box header) + SystemID size.
+
+    // Check the overflow.
+    if (index + 3 >= initDataSize)
+        return keyIdsMap;
+
+    keyIdsMap.first = data[index + 3]; // Read the KeyIdsCount.
+    index += 4; // KeyIdsCount size.
+
+    // Check the overflow.
+    if ((index + (keyIdsMap.first * keyIdSize)) >= initDataSize)
+        return keyIdsMap;
+
+    keyIdsMap.second = index; // The location of the first KeyId in initData.
+
+    return keyIdsMap;
+}
+
+// This function checks if the initData sharedBuffer is a valid CENC initData.
+static bool isCencInitData(const SharedBuffer& initData)
+{
+    std::pair<unsigned, unsigned> keyIdsMap = extractKeyidsLocationFromCencInitData(initData);
+    return ((keyIdsMap.first) && (keyIdsMap.second));
+}
+
+static Ref<SharedBuffer> extractKeyidsFromCencInitData(const SharedBuffer& initData)
+{
+    Ref<SharedBuffer> keyIds = SharedBuffer::create();
+
+    std::pair<unsigned, unsigned> keyIdsMap = extractKeyidsLocationFromCencInitData(initData);
+    unsigned keyIdCount = keyIdsMap.first;
+    unsigned index = keyIdsMap.second;
+
+    // Check if initData is a valid CENC initData.
+    if (!keyIdCount || !index)
+        return keyIds;
+
+    const char* data = ""
+
+    auto object = JSON::Object::create();
+    auto keyIdsArray = JSON::Array::create();
+
+    // Read the KeyId
+    // 9.1.3 License Request Format
+    // This section describes the format of the license request provided to the application via the message attribute of the message 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.
+    for (unsigned i = 0; i < keyIdCount; i++) {
+        String keyId = WTF::base64URLEncode(&data[index], keyIdSize);
+        keyIdsArray->pushString(keyId);
+        index += keyIdSize;
+    }
+
+    object->setArray("kids", WTFMove(keyIdsArray));
+    CString jsonData = object->toJSONString().utf8();
+    keyIds->append(jsonData.data(), jsonData.length());
+    return keyIds;
+}
+
 CDMFactoryClearKey& CDMFactoryClearKey::singleton()
 {
     static NeverDestroyed<CDMFactoryClearKey> s_factory;
@@ -170,8 +289,8 @@
 
 bool CDMPrivateClearKey::supportsInitDataType(const AtomicString& initDataType) const
 {
-    // `keyids` is the only supported init data type.
-    return equalLettersIgnoringASCIICase(initDataType, "keyids");
+    // `keyids` and 'cenc' are the only supported init data type.
+    return (equalLettersIgnoringASCIICase(initDataType, "keyids") || equalLettersIgnoringASCIICase(initDataType, "cenc"));
 }
 
 static bool containsPersistentLicenseType(const Vector<CDMSessionType>& types)
@@ -274,15 +393,15 @@
 
 bool CDMPrivateClearKey::supportsInitData(const AtomicString& initDataType, const SharedBuffer& initData) const
 {
-    // Fail for init data types other than 'keyids'.
-    if (!equalLettersIgnoringASCIICase(initDataType, "keyids"))
-        return false;
+    // Validate the initData buffer as an JSON object in keyids case.
+    if (equalLettersIgnoringASCIICase(initDataType, "keyids") && parseJSONObject(initData))
+        return true;
 
-    // Validate the initData buffer as an JSON object.
-    if (!parseJSONObject(initData))
-        return false;
+    // Validate the initData buffer as CENC initData.
+    if (equalLettersIgnoringASCIICase(initDataType, "cenc") && isCencInitData(initData))
+        return true;
 
-    return true;
+    return false;
 }
 
 RefPtr<SharedBuffer> CDMPrivateClearKey::sanitizeResponse(const SharedBuffer& response) const
@@ -340,11 +459,14 @@
     return storageDirectory.isEmpty() ? Succeeded : Failed;
 }
 
-void CDMInstanceClearKey::requestLicense(LicenseType, const AtomicString&, Ref<SharedBuffer>&& initData, LicenseCallback callback)
+void CDMInstanceClearKey::requestLicense(LicenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback callback)
 {
     static uint32_t s_sessionIdValue = 0;
     ++s_sessionIdValue;
 
+    if (equalLettersIgnoringASCIICase(initDataType, "cenc"))
+        initData = extractKeyidsFromCencInitData(initData.get());
+
     callOnMainThread(
         [weakThis = m_weakPtrFactory.createWeakPtr(*this), callback = WTFMove(callback), initData = WTFMove(initData), sessionIdValue = s_sessionIdValue]() mutable {
             if (!weakThis)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to