Add CENC sanitization
authorcturner@igalia.com <cturner@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 8 Aug 2018 10:45:13 +0000 (10:45 +0000)
committercturner@igalia.com <cturner@igalia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 8 Aug 2018 10:45:13 +0000 (10:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=188376

Reviewed by Xabier Rodriguez-Calvar.

LayoutTests/imported/w3c:

* web-platform-tests/encrypted-media/scripts/generate-request-disallowed-input.js:
(runTest): Fixed an incorrect test failure message, added more
invalid init data tests to check the new box parsing methods in
WebCore.

Source/WebCore:

This patch adds support for sanitizing the CENC initialization
data, to ensure there are no obviously bogus values in the
untrusted input from generateRequest, see
https://www.w3.org/TR/encrypted-media/#dom-mediakeysession-generaterequest
for more details on sanitization.

Tested by imported/w3c/web-platform-tests/encrypted-media/clearkey-generate-request-disallowed-input.https.html

* Modules/encryptedmedia/InitDataRegistry.cpp: The diff looks a
bit wonky because I had to reorder extractKeyIDsCenc to come
before sanitizeCenc.
(WebCore::extractKeyIDsCenc): Added implementation, a nullopt
return value here indicates the parsing found an error in the box
values.
(WebCore::sanitizeCenc): Added implementation, if the box can be
parsed, return a copy of the buffer as before, otherwise an error
value.
* Sources.txt: Add the new PSSH box type.
* platform/graphics/iso/ISOProtectionSystemSpecificHeaderBox.cpp:
Added, parsing methods come from ISO/IEC 23001-7-2016 Section
8.1.1.
(WebCore::ISOProtectionSystemSpecificHeaderBox::parse): Ditto.
* platform/graphics/iso/ISOProtectionSystemSpecificHeaderBox.h: Ditto.
(WebCore::ISOProtectionSystemSpecificHeaderBox::boxTypeName): Ditto.
(WebCore::ISOProtectionSystemSpecificHeaderBox::systemID const): Ditto.
(WebCore::ISOProtectionSystemSpecificHeaderBox::keyIDs const):
Ditto.
(WebCore::ISOProtectionSystemSpecificHeaderBox::data const): Ditto.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@234689 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/encrypted-media/scripts/generate-request-disallowed-input.js
Source/WebCore/ChangeLog
Source/WebCore/Modules/encryptedmedia/InitDataRegistry.cpp
Source/WebCore/Sources.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/platform/graphics/iso/ISOProtectionSystemSpecificHeaderBox.cpp [new file with mode: 0644]
Source/WebCore/platform/graphics/iso/ISOProtectionSystemSpecificHeaderBox.h [new file with mode: 0644]

index da835e2..094a322 100644 (file)
@@ -1,3 +1,15 @@
+2018-08-08  Charlie Turner  <cturner@igalia.com>
+
+        Add CENC sanitization
+        https://bugs.webkit.org/show_bug.cgi?id=188376
+
+        Reviewed by Xabier Rodriguez-Calvar.
+
+        * web-platform-tests/encrypted-media/scripts/generate-request-disallowed-input.js:
+        (runTest): Fixed an incorrect test failure message, added more
+        invalid init data tests to check the new box parsing methods in
+        WebCore.
+
 2018-08-08  Manuel Rego Casasnovas  <rego@igalia.com>
 
         [css-grid] Update behavior of percentage row tracks and gutters
index 8b883cc..001c00e 100644 (file)
@@ -24,7 +24,7 @@ function runTest(config,qualifier) {
         0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B,
         0x00, 0x00, 0x00, 0x00                           // datasize
     ]);
-    push_test(config.keysystem, 'cenc', initData, testnamePrefix( qualifier, config.keysystem ) + ', temporary, cenc, invalid initdata (invalid pssh)');
+    push_test(config.keysystem, 'cenc', initData, testnamePrefix( qualifier, config.keysystem ) + ', temporary, cenc, invalid initdata (size too large)');
 
     // Invalid data as type = 'psss'.
     initData = new Uint8Array([
@@ -38,6 +38,58 @@ function runTest(config,qualifier) {
     ]);
     push_test(config.keysystem, 'cenc', initData, testnamePrefix( qualifier, config.keysystem ) + ', temporary, cenc, invalid initdata (not pssh)');
 
+    initData = new Uint8Array([
+        0x00, 0x00, 0x00, 0x44, 0x70, 0x73, 0x73, 0x68, // BMFF box header (68 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, 0x04,                         // KID_count (4) (incorrect)
+        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)
+    ]);
+    push_test(config.keysystem, 'cenc', initData, testnamePrefix( qualifier, config.keysystem ) + ', temporary, cenc, invalid key id length (4 instead of 2)');
+
+    initData = new Uint8Array([
+        0x00, 0x00, 0x00, 0x54, 0x70, 0x73, 0x73, 0x68, // BMFF box header (84 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,                         // KID_count (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, 0x20,                         // Size of Data (32, incorrect)
+        0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+        0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50
+    ]);
+    push_test(config.keysystem, 'cenc', initData, testnamePrefix( qualifier, config.keysystem ) + ', temporary, cenc, invalid data size (32 instead of 16)');
+
+    // Invalid size in a second PSSH blob
+    // The CENC format allows multiple concatenated boxes, see https://www.w3.org/TR/eme-initdata-cenc/#format
+    initData = new Uint8Array([
+        0x00, 0x00, 0x00, 0x20,                          // size = 32
+        0x70, 0x73, 0x73, 0x68,                          // 'pssh'
+        0x00,                                            // version = 0
+        0x00, 0x00, 0x00,                                // flags
+        0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02,  // Common SystemID
+        0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B,
+        0x00, 0x00, 0x00, 0x00,                          // datasize
+
+        0x00, 0x00, 0x00, 0x10,                          // size = 16 (incorrect)
+        0x70, 0x73, 0x73, 0x68,                          // 'pssh'
+        0x00,                                            // version = 0
+        0x00, 0x00, 0x00,                                // flags
+        0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02,  // Common SystemID
+        0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B,
+        0x00, 0x00, 0x00, 0x00                           // datasize
+
+    ]);
+    push_test(config.keysystem, 'cenc', initData, testnamePrefix( qualifier, config.keysystem ) + ', temporary, cenc, invalid initdata (second box has incorrect size)');
+
     // Valid key ID size must be at least 1 character for keyids.
     keyId = new Uint8Array(0);
     initData = stringToUint8Array(createKeyIDs(keyId));
index 5482739..3f02ca7 100644 (file)
@@ -1,3 +1,39 @@
+2018-08-08  Charlie Turner  <cturner@igalia.com>
+
+        Add CENC sanitization
+        https://bugs.webkit.org/show_bug.cgi?id=188376
+
+        Reviewed by Xabier Rodriguez-Calvar.
+
+        This patch adds support for sanitizing the CENC initialization
+        data, to ensure there are no obviously bogus values in the
+        untrusted input from generateRequest, see
+        https://www.w3.org/TR/encrypted-media/#dom-mediakeysession-generaterequest
+        for more details on sanitization.
+
+        Tested by imported/w3c/web-platform-tests/encrypted-media/clearkey-generate-request-disallowed-input.https.html
+
+        * Modules/encryptedmedia/InitDataRegistry.cpp: The diff looks a
+        bit wonky because I had to reorder extractKeyIDsCenc to come
+        before sanitizeCenc.
+        (WebCore::extractKeyIDsCenc): Added implementation, a nullopt
+        return value here indicates the parsing found an error in the box
+        values.
+        (WebCore::sanitizeCenc): Added implementation, if the box can be
+        parsed, return a copy of the buffer as before, otherwise an error
+        value.
+        * Sources.txt: Add the new PSSH box type.
+        * platform/graphics/iso/ISOProtectionSystemSpecificHeaderBox.cpp:
+        Added, parsing methods come from ISO/IEC 23001-7-2016 Section
+        8.1.1.
+        (WebCore::ISOProtectionSystemSpecificHeaderBox::parse): Ditto.
+        * platform/graphics/iso/ISOProtectionSystemSpecificHeaderBox.h: Ditto.
+        (WebCore::ISOProtectionSystemSpecificHeaderBox::boxTypeName): Ditto.
+        (WebCore::ISOProtectionSystemSpecificHeaderBox::systemID const): Ditto.
+        (WebCore::ISOProtectionSystemSpecificHeaderBox::keyIDs const):
+        Ditto.
+        (WebCore::ISOProtectionSystemSpecificHeaderBox::data const): Ditto.
+
 2018-08-08  Zan Dobersek  <zdobersek@igalia.com>
 
         [Nicosia] Add the Nicosia-specific PlatformLayer type alias
index 1d67ed6..fb3e4c0 100644 (file)
@@ -28,6 +28,8 @@
 
 #if ENABLE(ENCRYPTED_MEDIA)
 
+#include "ISOProtectionSystemSpecificHeaderBox.h"
+#include <JavaScriptCore/DataView.h>
 #include "NotImplemented.h"
 #include "SharedBuffer.h"
 #include <wtf/JSONValues.h>
 
 namespace WebCore {
 
+namespace {
+    const uint32_t kCencMaxBoxSize = 64 * KB;
+}
+
 static std::optional<Vector<Ref<SharedBuffer>>> extractKeyIDsKeyids(const SharedBuffer& buffer)
 {
     // 1. Format
@@ -92,20 +98,43 @@ static RefPtr<SharedBuffer> sanitizeKeyids(const SharedBuffer& buffer)
     return SharedBuffer::create(jsonData.data(), jsonData.length());
 }
 
-static RefPtr<SharedBuffer> sanitizeCenc(const SharedBuffer& buffer)
+static std::optional<Vector<Ref<SharedBuffer>>> extractKeyIDsCenc(const SharedBuffer& buffer)
 {
     // 4. Common SystemID and PSSH Box Format
     // https://w3c.github.io/encrypted-media/format-registry/initdata/cenc.html#common-system
-    notImplemented();
-    return buffer.copy();
+    if (buffer.size() >= kCencMaxBoxSize)
+        return std::nullopt;
+
+    unsigned offset = 0;
+    Vector<Ref<SharedBuffer>> keyIDs;
+
+    auto view = JSC::DataView::create(buffer.tryCreateArrayBuffer(), offset, buffer.size());
+    while (auto optionalBoxType = ISOBox::peekBox(view, offset)) {
+        auto& boxTypeName = optionalBoxType.value().first;
+        auto& boxSize = optionalBoxType.value().second;
+
+        if (boxTypeName != ISOProtectionSystemSpecificHeaderBox::boxTypeName() || boxSize > buffer.size())
+            return std::nullopt;
+
+        ISOProtectionSystemSpecificHeaderBox psshBox;
+        if (!psshBox.read(view, offset))
+            return std::nullopt;
+
+        for (auto& value : psshBox.keyIDs())
+            keyIDs.append(SharedBuffer::create(WTFMove(value)));
+    }
+
+    return keyIDs;
 }
 
-static std::optional<Vector<Ref<SharedBuffer>>> extractKeyIDsCenc(const SharedBuffer&)
+static RefPtr<SharedBuffer> sanitizeCenc(const SharedBuffer& buffer)
 {
     // 4. Common SystemID and PSSH Box Format
     // https://w3c.github.io/encrypted-media/format-registry/initdata/cenc.html#common-system
-    notImplemented();
-    return std::nullopt;
+    if (!extractKeyIDsCenc(buffer))
+        return nullptr;
+
+    return buffer.copy();
 }
 
 static RefPtr<SharedBuffer> sanitizeWebM(const SharedBuffer& buffer)
index dfd1b52..7941575 100644 (file)
@@ -1700,6 +1700,7 @@ platform/graphics/gpu/GPUTextureDescriptor.cpp
 platform/graphics/iso/ISOBox.cpp
 platform/graphics/iso/ISOOriginalFormatBox.cpp
 platform/graphics/iso/ISOProtectionSchemeInfoBox.cpp
+platform/graphics/iso/ISOProtectionSystemSpecificHeaderBox.cpp
 platform/graphics/iso/ISOSchemeInformationBox.cpp
 platform/graphics/iso/ISOSchemeTypeBox.cpp
 platform/graphics/iso/ISOTrackEncryptionBox.cpp
index f18198f..68116d7 100644 (file)
                CD871C621FB52B6500F0B965 /* ISOBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ISOBox.h; sourceTree = "<group>"; };
                CD871C631FB52B6600F0B965 /* ISOSchemeInformationBox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ISOSchemeInformationBox.cpp; sourceTree = "<group>"; };
                CD871C641FB52B6700F0B965 /* ISOSchemeInformationBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ISOSchemeInformationBox.h; sourceTree = "<group>"; };
+               451A49F8F8726BE071518BE2 /* ISOProtectionSystemSpecificHeaderBox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ISOProtectionSystemSpecificHeaderBox.cpp; sourceTree = "<group>"; };
+               12F75A9A86EA03DAF24B7971 /* ISOProtectionSystemSpecificHeaderBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ISOProtectionSystemSpecificHeaderBox.h; sourceTree = "<group>"; };
                CD871C651FB52B6700F0B965 /* ISOVTTCue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ISOVTTCue.h; sourceTree = "<group>"; };
                CD871C661FB52B6800F0B965 /* ISOTrackEncryptionBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ISOTrackEncryptionBox.h; sourceTree = "<group>"; };
                CD871C671FB52B6800F0B965 /* ISOOriginalFormatBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ISOOriginalFormatBox.h; sourceTree = "<group>"; };
                                CD871C671FB52B6800F0B965 /* ISOOriginalFormatBox.h */,
                                CD871C5E1FB52B6400F0B965 /* ISOProtectionSchemeInfoBox.cpp */,
                                CD871C601FB52B6500F0B965 /* ISOProtectionSchemeInfoBox.h */,
+                               451A49F8F8726BE071518BE2 /* ISOProtectionSystemSpecificHeaderBox.cpp */,
+                               12F75A9A86EA03DAF24B7971 /* ISOProtectionSystemSpecificHeaderBox.h */,
                                CD871C631FB52B6600F0B965 /* ISOSchemeInformationBox.cpp */,
                                CD871C641FB52B6700F0B965 /* ISOSchemeInformationBox.h */,
                                CD871C5F1FB52B6400F0B965 /* ISOSchemeTypeBox.cpp */,
diff --git a/Source/WebCore/platform/graphics/iso/ISOProtectionSystemSpecificHeaderBox.cpp b/Source/WebCore/platform/graphics/iso/ISOProtectionSystemSpecificHeaderBox.cpp
new file mode 100644 (file)
index 0000000..394fdfc
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ISOProtectionSystemSpecificHeaderBox.h"
+
+#include <JavaScriptCore/DataView.h>
+
+using JSC::DataView;
+
+namespace WebCore {
+
+bool ISOProtectionSystemSpecificHeaderBox::parse(DataView& view, unsigned& offset)
+{
+    if (!ISOFullBox::parse(view, offset))
+        return false;
+
+    // ISO/IEC 23001-7-2016 Section 8.1.1
+    auto buffer = view.possiblySharedBuffer();
+    if (!buffer)
+        return false;
+    auto systemID = buffer->slice(offset, offset + 16);
+    if (!systemID)
+        return false;
+
+    offset += 16;
+
+    m_systemID.resize(16);
+    memcpy(m_systemID.data(), systemID->data(), 16);
+
+    if (m_version) {
+        uint32_t keyIDCount = 0;
+        if (!checkedRead<uint32_t>(keyIDCount, view, offset, BigEndian))
+            return false;
+        if (buffer->byteLength() - offset < keyIDCount * 16)
+            return false;
+        m_keyIDs.resize(keyIDCount);
+        for (unsigned keyID = 0; keyID < keyIDCount; keyID++) {
+            auto& currentKeyID = m_keyIDs[keyID];
+            currentKeyID.resize(16);
+            auto parsedKeyID = buffer->slice(offset, offset + 16);
+            if (!parsedKeyID)
+                return false;
+            offset += 16;
+            memcpy(currentKeyID.data(), parsedKeyID->data(), 16);
+        }
+    }
+
+    uint32_t dataSize = 0;
+    if (!checkedRead<uint32_t>(dataSize, view, offset, BigEndian))
+        return false;
+    if (buffer->byteLength() - offset < dataSize)
+        return false;
+    auto parsedData = buffer->slice(offset, offset + dataSize);
+    if (!parsedData)
+        return false;
+
+    offset += dataSize;
+
+    m_data.resize(dataSize);
+    memcpy(m_data.data(), parsedData->data(), dataSize);
+
+    return true;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/iso/ISOProtectionSystemSpecificHeaderBox.h b/Source/WebCore/platform/graphics/iso/ISOProtectionSystemSpecificHeaderBox.h
new file mode 100644 (file)
index 0000000..35e1b4f
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "ISOBox.h"
+
+namespace WebCore {
+
+class ISOProtectionSystemSpecificHeaderBox : public ISOFullBox {
+public:
+    using KeyID = Vector<uint8_t>;
+    static FourCC boxTypeName() { return "pssh"; }
+
+    Vector<uint8_t> systemID() const { return m_systemID; }
+    Vector<KeyID> keyIDs() const { return m_keyIDs; }
+    Vector<uint8_t> data() const { return m_data; }
+
+protected:
+    bool parse(JSC::DataView&, unsigned& offset) override;
+
+    Vector<uint8_t> m_systemID;
+    Vector<KeyID> m_keyIDs;
+    Vector<uint8_t> m_data;
+};
+
+}
+
+SPECIALIZE_TYPE_TRAITS_ISOBOX(ISOProtectionSystemSpecificHeaderBox)