diff --git a/libwvdrmengine/cdm/core/include/initialization_data.h b/libwvdrmengine/cdm/core/include/initialization_data.h index 4f3d7e52..5ccfec32 100644 --- a/libwvdrmengine/cdm/core/include/initialization_data.h +++ b/libwvdrmengine/cdm/core/include/initialization_data.h @@ -17,7 +17,8 @@ class WvCdmEngineTest; class InitializationData { public: InitializationData(const std::string& type = std::string(), - const CdmInitData& data = CdmInitData()); + const CdmInitData& data = CdmInitData(), + const std::string& oec_version = std::string()); bool is_supported() const { return is_cenc_ || is_webm_ || is_hls_; } bool is_cenc() const { return is_cenc_; } @@ -36,9 +37,15 @@ class InitializationData { std::vector ExtractWrappedKeys() const; private: - // Parse a blob of multiple concatenated PSSH atoms to extract the first - // Widevine PSSH. - bool ExtractWidevinePssh(const CdmInitData& init_data, CdmInitData* output); + bool SelectWidevinePssh(const CdmInitData& init_data, + bool prefer_entitlements, + CdmInitData* output); + // Helpers used by SelectWidevinePssh(). + bool ExtractWidevinePsshs(const CdmInitData& init_data, + std::vector* psshs); + bool ExtractWidevinePsshData(const uint8_t* data, + size_t length, + CdmInitData* output); bool ExtractHlsAttributes(const std::string& attribute_list, CdmHlsMethod* method, std::vector* iv, @@ -58,6 +65,9 @@ class InitializationData { static std::vector ExtractKeyFormatVersions( const std::string& key_format_versions); + static bool DetectEntitlementPreference( + const std::string& oec_version_string); + // For testing only: #if defined(UNIT_TEST) FRIEND_TEST(HlsAttributeExtractionTest, ExtractAttribute); diff --git a/libwvdrmengine/cdm/core/src/initialization_data.cpp b/libwvdrmengine/cdm/core/src/initialization_data.cpp index f7d86cd5..d025c966 100644 --- a/libwvdrmengine/cdm/core/src/initialization_data.cpp +++ b/libwvdrmengine/cdm/core/src/initialization_data.cpp @@ -6,13 +6,16 @@ #include #include +#include #include "buffer_reader.h" +#include "cdm_engine.h" #include "jsmn.h" #include "log.h" #include "properties.h" #include "string_conversions.h" #include "wv_cdm_constants.h" +#include "wv_cdm_types.h" namespace { const char kKeyFormatVersionsSeparator = '/'; @@ -27,6 +30,12 @@ const std::string kKeyIds = "key_ids"; // Being conservative, usually we expect 6 + number of Key Ids const int kDefaultNumJsonTokens = 128; + +// Widevine's registered system ID. +const uint8_t kWidevineSystemId[] = { + 0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE, + 0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED, +}; } // namespace namespace wvcdm { @@ -35,9 +44,13 @@ namespace wvcdm { using video_widevine::WidevinePsshData; using video_widevine::WidevinePsshData_Algorithm; using video_widevine::WidevinePsshData_Algorithm_AESCTR; +using video_widevine::WidevinePsshData_Type; +using video_widevine::WidevinePsshData_Type_ENTITLED_KEY; +using video_widevine::WidevinePsshData_Type_SINGLE; InitializationData::InitializationData(const std::string& type, - const CdmInitData& data) + const CdmInitData& data, + const std::string& oec_version) : type_(type), is_cenc_(false), is_hls_(false), @@ -55,7 +68,12 @@ InitializationData::InitializationData(const std::string& type, if (is_supported()) { if (is_cenc()) { - ExtractWidevinePssh(data, &data_); + bool oec_prefers_entitlements = DetectEntitlementPreference(oec_version); + if (!SelectWidevinePssh(data, oec_prefers_entitlements, &data_)) { + LOGE( + "InitializationData: Unable to select a supported Widevine PSSH " + "from the init data."); + } } else if (is_webm()) { data_ = data; } else if (is_hls()) { @@ -97,158 +115,263 @@ std::vector InitializationData::ExtractWrappedKeys() return keys; } -// Parse a blob of multiple concatenated PSSH atoms to extract the first -// Widevine PSSH. -bool InitializationData::ExtractWidevinePssh(const CdmInitData& init_data, - CdmInitData* output) { - BufferReader reader(reinterpret_cast(init_data.data()), - init_data.length()); +// Parse a blob of multiple concatenated PSSH atoms to extract the Widevine +// PSSH. The blob may have multiple Widevine PSSHs. Devices that prefer +// entitlements should choose the |ENTITLED_KEY| PSSH while other devices should +// stick to the |SINGLE| PSSH. +bool InitializationData::SelectWidevinePssh(const CdmInitData& init_data, + bool prefer_entitlements, + CdmInitData* output) { + // Extract the data payloads from the Widevine PSSHs. + std::vector pssh_payloads; + if (!ExtractWidevinePsshs(init_data, &pssh_payloads)) { + LOGE( + "InitializationData::SelectWidevinePssh: Unable to parse concatenated " + "PSSH boxes."); + return false; + } + if (pssh_payloads.empty()) { + LOGE( + "InitializationData::SelectWidevinePssh: The concatenated PSSH boxes " + "could be parsed, but no Widevine PSSH was found."); + return false; + } - // Widevine's registered system ID. - static const uint8_t kWidevineSystemId[] = { - 0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE, - 0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED, - }; + // If there are multiple PSSHs to choose from and this device prefers + // entitlements, find the first |ENTITLED_KEY| PSSH, if present, and + // select it. + if (prefer_entitlements && pssh_payloads.size() > 1) { + for (size_t i = 0; i < pssh_payloads.size(); ++i) { + WidevinePsshData pssh; + if (!pssh.ParseFromString(pssh_payloads[i])) { + LOGE( + "InitializationData::SelectWidevinePssh: Unable to parse PSSH data " + "%lu into a protobuf.", i); + continue; + } + if (pssh.type() == WidevinePsshData_Type_ENTITLED_KEY) { + *output = pssh_payloads[i]; + return true; + } + } + } + + // Either there is only one PSSH, this device does not prefer entitlements, + // or no entitlement PSSH was found. Regardless of how we got here, select the + // first PSSH, which should be a |SINGLE| PSSH. + *output = pssh_payloads[0]; + return true; +} + +// one PSSH box consists of: +// 4 byte size of the atom, inclusive. (0 means the rest of the buffer.) +// 4 byte atom type, "pssh". +// (optional, if size == 1) 8 byte size of the atom, inclusive. +// 1 byte version, value 0 or 1. (skip if larger.) +// 3 byte flags, value 0. (ignored.) +// 16 byte system id. +// (optional, if version == 1) 4 byte key ID count. (K) +// (optional, if version == 1) K * 16 byte key ID. +// 4 byte size of PSSH data, exclusive. (N) +// N byte PSSH data. + +bool InitializationData::ExtractWidevinePsshs( + const CdmInitData& init_data, std::vector* psshs) { + if (psshs == NULL) { + LOGE("InitializationData::ExtractWidevinePsshs: NULL psshs parameter"); + return false; + } + psshs->clear(); + psshs->reserve(2); // We expect 1 or 2 Widevine PSSHs + + const uint8_t* data_start = reinterpret_cast(init_data.data()); + BufferReader reader(data_start, init_data.length()); - // one PSSH box consists of: - // 4 byte size of the atom, inclusive. (0 means the rest of the buffer.) - // 4 byte atom type, "pssh". - // (optional, if size == 1) 8 byte size of the atom, inclusive. - // 1 byte version, value 0 or 1. (skip if larger.) - // 3 byte flags, value 0. (ignored.) - // 16 byte system id. - // (optional, if version == 1) 4 byte key ID count. (K) - // (optional, if version == 1) K * 16 byte key ID. - // 4 byte size of PSSH data, exclusive. (N) - // N byte PSSH data. while (!reader.IsEOF()) { - size_t start_pos = reader.pos(); + const size_t start_pos = reader.pos(); - // atom size, used for skipping. + // Atom size. Used for bounding the inner reader and knowing how far to skip + // forward after parsing this PSSH. uint64_t size; if (!reader.Read4Into8(&size)) { LOGV( - "InitializationData::ExtractWidevinePssh: Unable to read atom size."); - return false; + "InitializationData::ExtractWidevinePsshs: Unable to read the " + "32-bit atom size."); + return false; // We cannot continue reading safely. Abort. } - std::vector atom_type; - if (!reader.ReadVec(&atom_type, 4)) { + + // Skip the atom type for now. + if (!reader.SkipBytes(4)) { LOGV( - "InitializationData::ExtractWidevinePssh: Unable to read atom type."); - return false; + "InitializationData::ExtractWidevinePsshs: Unable to skip the " + "atom type."); + return false; // We cannot continue reading safely. Abort. } if (size == 1) { + // An "atom size" of 1 means the real atom size is a 64-bit number stored + // after the atom type. if (!reader.Read8(&size)) { LOGV( - "InitializationData::ExtractWidevinePssh: Unable to read 64-bit " - "atom size."); - return false; + "InitializationData::ExtractWidevinePsshs: Unable to read the " + "64-bit atom size."); + return false; // We cannot continue reading safely. Abort. } } else if (size == 0) { + // An "atom size" of 0 means the atom takes up the rest of the buffer. size = reader.size() - start_pos; } - // "pssh" - if (memcmp(&atom_type[0], "pssh", 4)) { + const size_t bytes_read = reader.pos() - start_pos; + const size_t bytes_remaining = size - bytes_read; + + if (!reader.HasBytes(bytes_remaining)) { LOGV( - "InitializationData::ExtractWidevinePssh: PSSH literal not present."); - if (!reader.SkipBytes(size - (reader.pos() - start_pos))) { - LOGV( - "InitializationData::ExtractWidevinePssh: Unable to skip the rest " - "of the atom."); - return false; - } - continue; + "InitializationData::ExtractWidevinePsshs: Invalid atom size. The " + "atom claims to be larger than the remaining init data."); + return false; // We cannot continue reading safely. Abort. } - // version - uint8_t version; - if (!reader.Read1(&version)) { + // Use ExtractWidevinePsshData() to check if this atom is a Widevine PSSH + // and, if so, add its data to the list of PSSHs. + CdmInitData data; + if (ExtractWidevinePsshData(data_start + start_pos, size, &data)) { + psshs->push_back(data); + } + + // Skip past the rest of the atom. + if (!reader.SkipBytes(bytes_remaining)) { LOGV( - "InitializationData::ExtractWidevinePssh: Unable to read PSSH " - "version."); - return false; + "InitializationData::LocateWidevinePsshOffsets: Unable to skip the " + "rest of the atom."); + return false; // We cannot continue reading safely. Abort. } - - if (version > 1) { - // unrecognized version - skip. - if (!reader.SkipBytes(size - (reader.pos() - start_pos))) { - LOGV( - "InitializationData::ExtractWidevinePssh: Unable to skip the rest " - "of the atom."); - return false; - } - continue; - } - - // flags - if (!reader.SkipBytes(3)) { - LOGV( - "InitializationData::ExtractWidevinePssh: Unable to skip the PSSH " - "flags."); - return false; - } - - // system id - std::vector system_id; - if (!reader.ReadVec(&system_id, sizeof(kWidevineSystemId))) { - LOGV( - "InitializationData::ExtractWidevinePssh: Unable to read system ID."); - return false; - } - - if (memcmp(&system_id[0], kWidevineSystemId, sizeof(kWidevineSystemId))) { - // skip non-Widevine PSSH boxes. - if (!reader.SkipBytes(size - (reader.pos() - start_pos))) { - LOGV( - "InitializationData::ExtractWidevinePssh: Unable to skip the rest " - "of the atom."); - return false; - } - LOGV( - "InitializationData::ExtractWidevinePssh: Skipping non-Widevine " - "PSSH."); - continue; - } - - if (version == 1) { - // v1 has additional fields for key IDs. We can skip them. - uint32_t num_key_ids; - if (!reader.Read4(&num_key_ids)) { - LOGV( - "InitializationData::ExtractWidevinePssh: Unable to read num key " - "IDs."); - return false; - } - if (!reader.SkipBytes(num_key_ids * 16)) { - LOGV( - "InitializationData::ExtractWidevinePssh: Unable to skip key IDs."); - return false; - } - } - - // size of PSSH data - uint32_t data_length; - if (!reader.Read4(&data_length)) { - LOGV( - "InitializationData::ExtractWidevinePssh: Unable to read PSSH data " - "size."); - return false; - } - - output->clear(); - if (!reader.ReadString(output, data_length)) { - LOGV( - "InitializationData::ExtractWidevinePssh: Unable to read PSSH data."); - return false; - } - - return true; } - // we did not find a matching record - return false; + return true; +} + +// Checks if the given reader contains a Widevine PSSH. If so, it extracts the +// data from the box. Returns true if a PSSH was extracted, false if there was +// an error or if the data is not a Widevine PSSH. +bool InitializationData::ExtractWidevinePsshData( + const uint8_t* data, size_t length, CdmInitData* output) { + BufferReader reader(data, length); + + // Read the 32-bit size only so we can check if we need to expect a 64-bit + // size. + uint64_t size_32; + if (!reader.Read4Into8(&size_32)) { + LOGV( + "InitializationData::ExtractWidevinePsshData: Unable to read the " + "32-bit atom size."); + return false; + } + const bool has_size_64 = (size_32 == 1); + + // Read the atom type and check that it is "pssh". + std::vector atom_type; + if (!reader.ReadVec(&atom_type, 4)) { + LOGV( + "InitializationData::ExtractWidevinePsshData: Unable to read the atom " + "type."); + return false; + } + if (memcmp(&atom_type[0], "pssh", 4) != 0) { + LOGV( + "InitializationData::ExtractWidevinePsshData: Atom type is not PSSH."); + return false; + } + + // If there is a 64-bit size, skip it. + if (has_size_64) { + if (!reader.SkipBytes(8)) { + LOGV( + "InitializationData::ExtractWidevinePsshData: Unable to skip the " + "64-bit atom size."); + return false; + } + } + + // Read the version number and abort if it is not one we can handle. + uint8_t version; + if (!reader.Read1(&version)) { + LOGV( + "InitializationData::ExtractWidevinePsshData: Unable to read the PSSH " + "version."); + return false; + } + if (version > 1) { + LOGV( + "InitializationData::ExtractWidevinePsshData: Unrecognized PSSH " + "version."); + return false; + } + + // Skip the flags. + if (!reader.SkipBytes(3)) { + LOGV( + "InitializationData::ExtractWidevinePsshData: Unable to skip the PSSH " + "flags."); + return false; + } + + // Read the System ID and validate that it is the Widevine System ID. + std::vector system_id; + if (!reader.ReadVec(&system_id, sizeof(kWidevineSystemId))) { + LOGV( + "InitializationData::ExtractWidevinePsshData: Unable to read the " + "system ID."); + return false; + } + if (memcmp(&system_id[0], + kWidevineSystemId, + sizeof(kWidevineSystemId)) != 0) { + LOGV( + "InitializationData::ExtractWidevinePsshData: Found a non-Widevine " + "PSSH."); + return false; + } + + // Skip the key ID fields, if present. + if (version == 1) { + // Read the number of key IDs so we know how far to skip ahead. + uint32_t num_key_ids; + if (!reader.Read4(&num_key_ids)) { + LOGV( + "InitializationData::ExtractWidevinePsshData: Unable to read the " + "number of key IDs."); + return false; + } + + // Skip the key IDs. + if (!reader.SkipBytes(num_key_ids * 16)) { + LOGV( + "InitializationData::ExtractWidevinePsshData: Unable to skip the key " + "IDs."); + return false; + } + } + + // Read the size of the PSSH data. + uint32_t data_length; + if (!reader.Read4(&data_length)) { + LOGV( + "InitializationData::ExtractWidevinePsshData: Unable to read the PSSH " + "data size."); + return false; + } + + // Read the PSSH data. + output->clear(); + if (!reader.ReadString(output, data_length)) { + LOGV( + "InitializationData::ExtractWidevinePsshData: Unable to read the PSSH " + "data."); + return false; + } + + return true; } // Parse an EXT-X-KEY tag attribute list. Verify that Widevine supports it @@ -605,4 +728,18 @@ std::vector InitializationData::ExtractKeyFormatVersions( return versions; } +bool InitializationData::DetectEntitlementPreference( + const std::string& oec_version_string) { + if (oec_version_string.empty()) { + return false; + } + + uint32_t oec_version_int = 0; + std::istringstream parse_int; + parse_int.str(oec_version_string); + parse_int >> oec_version_int; + + return oec_version_int >= 14; +} + } // namespace wvcdm diff --git a/libwvdrmengine/cdm/core/test/initialization_data_unittest.cpp b/libwvdrmengine/cdm/core/test/initialization_data_unittest.cpp index 76fa080c..587d9903 100644 --- a/libwvdrmengine/cdm/core/test/initialization_data_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/initialization_data_unittest.cpp @@ -6,6 +6,7 @@ #include #include +#include "file_store.h" #include "initialization_data.h" #include "license_protocol.pb.h" #include "string_conversions.h" @@ -23,6 +24,9 @@ using video_widevine::WidevinePsshData; namespace { +// Import names from ::testing for convenience +using ::testing::_; + // Constants for JSON formatting const std::string kLeftBrace = "{"; const std::string kRightBrace = "}"; @@ -130,7 +134,7 @@ const std::string kWidevinePsshAfterV1Pssh = a2bs_hex( const std::string kWidevineV1Pssh = a2bs_hex( // Widevine PSSH box, v1 format - "00000044" // atom size + "00000066" // atom size "70737368" // atom type "pssh" "01000000" // v1, flags=0 "edef8ba979d64acea3c827dcd51d21ed" // system id (Widevine) @@ -168,7 +172,7 @@ const std::string kZeroSizedPsshBox = a2bs_hex( const std::string kSubLicensePsshBox = a2bs_hex( // Widevine PSSH box - "0000009f" // atom size (whole buffer) + "0000009f" // atom size "70737368" // atom type="pssh" "00000000" // v0, flags=0 "edef8ba979d64acea3c827dcd51d21ed" // system id (Widevine) @@ -179,6 +183,93 @@ const std::string kSubLicensePsshBox = a2bs_hex( "5f69645f30120d7375625f6c6963656e73655f305a250a147375625f73657373696f" "6e5f6b65795f69645f31120d7375625f6c6963656e73655f31"); +const std::string kMultipleWidevinePsshBox = a2bs_hex( + // first PSSH box, Widevine with single keys + "00000042" // atom size + "70737368" // atom type "pssh" + "00000000" // v0, flags=0 + "edef8ba979d64acea3c827dcd51d21ed" // system id (Widevine) + "00000022" // data size + // data: + "08011a0d7769646576696e655f74657374220f73747265616d696e675f636c697031" + + // second PSSH box, Widevine with entitled keys + "000001fb" // atom size + "70737368" // atom type="pssh" + "00000000" // v0, flags=0 + "edef8ba979d64acea3c827dcd51d21ed" // system id (Widevine) + "000001db" // data size + // data: + "220b47726f7570563254657374381448" + "e3dc959b065002580272580a10668093" + "381a8c5be48a0168ce372726ac1210c8" + "326486bb5d5c4a958f00b1111afc811a" + "20082cd9d3aed3ebe6239d30fbcf0b22" + "1d28cbb0360ea1295c2363973346ec00" + "512210914781334e864c8eb7f768cf26" + "49073872580a10f872d11d5b1052f2bd" + "a94e60a0e383021210450897c987a85c" + "2e9579f968554a12991a2097e603ceea" + "f35ed8cef1029eae7a0a54701e3d6db6" + "80e7da1de3b22a8db347fb2210b41c34" + "29b7bb96972bbaf6587bc0ddf172580a" + "10bac58b9fce9e5929a42a180e529f19" + "4712103f11f22988d25659b145ce4854" + "3e6b141a20416e22768e5a57b08d155e" + "5210d00658056947ff06d626668bceb3" + "5eb01c6b57221081fb2ff3fef79d332f" + "f98be46233596972580a101261c8036d" + "ae5c8caa968858aa0ca9cc12106d583c" + "b37c1456519843a81cf49912221a20c2" + "1116bb54a226e8d879a4cd41d8879920" + "2ae85b80d83b1b4447e5d7fcad6f6a22" + "100b27a4c3f44771d2b0c7c34c66af35" + "b572580a10ab1c8c259c6b5967991389" + "65bff5ac0c1210b5b4473658565d3786" + "efaf4b85d8e6e21a203ce6a9085285c2" + "ece0b650dc83dd7aa8ac849611a8e3f8" + "3c8f389223c0f3621522101946f0c2a3" + "d543101cc842bbec2d0b30"); +// These are the data payloads of the two PSSH boxes in +// kMultipleWidevinePsshBox. +const CdmInitData kSingleKeyWidevinePsshBoxData = a2bs_hex( + "08011a0d7769646576696e655f74657374220f73747265616d696e675f636c697031"); +const CdmInitData kEntitledKeysWidevinePsshBoxData = a2bs_hex( + "220b47726f7570563254657374381448" + "e3dc959b065002580272580a10668093" + "381a8c5be48a0168ce372726ac1210c8" + "326486bb5d5c4a958f00b1111afc811a" + "20082cd9d3aed3ebe6239d30fbcf0b22" + "1d28cbb0360ea1295c2363973346ec00" + "512210914781334e864c8eb7f768cf26" + "49073872580a10f872d11d5b1052f2bd" + "a94e60a0e383021210450897c987a85c" + "2e9579f968554a12991a2097e603ceea" + "f35ed8cef1029eae7a0a54701e3d6db6" + "80e7da1de3b22a8db347fb2210b41c34" + "29b7bb96972bbaf6587bc0ddf172580a" + "10bac58b9fce9e5929a42a180e529f19" + "4712103f11f22988d25659b145ce4854" + "3e6b141a20416e22768e5a57b08d155e" + "5210d00658056947ff06d626668bceb3" + "5eb01c6b57221081fb2ff3fef79d332f" + "f98be46233596972580a101261c8036d" + "ae5c8caa968858aa0ca9cc12106d583c" + "b37c1456519843a81cf49912221a20c2" + "1116bb54a226e8d879a4cd41d8879920" + "2ae85b80d83b1b4447e5d7fcad6f6a22" + "100b27a4c3f44771d2b0c7c34c66af35" + "b572580a10ab1c8c259c6b5967991389" + "65bff5ac0c1210b5b4473658565d3786" + "efaf4b85d8e6e21a203ce6a9085285c2" + "ece0b650dc83dd7aa8ac849611a8e3f8" + "3c8f389223c0f3621522101946f0c2a3" + "d543101cc842bbec2d0b30"); + +// OEMCrypto Versions known to have and not have entitlement license support. +const std::string kOemCryptoWithoutEntitlements = "13"; +const std::string kOemCryptoWithEntitlements = "14"; + // HLS test attribute key and values const std::string kHlsIvHexValue = "6DF49213A781E338628D0E9C812D328E"; const std::string kHlsIvValue = "0x" + kHlsIvHexValue; @@ -420,6 +511,7 @@ class HlsInitDataConstructionTest : public ::testing::Test {}; class HlsParseTest : public ::testing::TestWithParam {}; class HlsTest : public ::testing::Test {}; + } // namespace TEST_F(InitializationDataTest, BadType) { @@ -437,7 +529,22 @@ INSTANTIATE_TEST_CASE_P( ::testing::Values(kWidevinePssh, kWidevinePsshFirst, kWidevinePsshAfterV0Pssh, kWidevinePsshAfterNonZeroFlags, kWidevinePsshAfterV1Pssh, kWidevineV1Pssh, kOtherBoxFirst, - kZeroSizedPsshBox, kSubLicensePsshBox)); + kZeroSizedPsshBox, kSubLicensePsshBox, + kMultipleWidevinePsshBox)); + +TEST_F(InitializationDataTest, HandlesMultipleWidevinePsshs) { + InitializationData single_init_data(ISO_BMFF_VIDEO_MIME_TYPE, + kMultipleWidevinePsshBox, + kOemCryptoWithoutEntitlements); + EXPECT_FALSE(single_init_data.IsEmpty()); + EXPECT_EQ(kSingleKeyWidevinePsshBoxData, single_init_data.data()); + + InitializationData entitled_init_data(ISO_BMFF_VIDEO_MIME_TYPE, + kMultipleWidevinePsshBox, + kOemCryptoWithEntitlements); + EXPECT_FALSE(entitled_init_data.IsEmpty()); + EXPECT_EQ(kEntitledKeysWidevinePsshBoxData, entitled_init_data.data()); +} TEST_F(InitializationDataTest, ExtractSubLicense) { InitializationData init_data(ISO_BMFF_VIDEO_MIME_TYPE, kSubLicensePsshBox); diff --git a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp index 80d5bbd3..7263eae6 100644 --- a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp +++ b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp @@ -101,7 +101,23 @@ CdmResponseType WvContentDecryptionModule::GenerateKeyRequest( if (sts != NO_ERROR) return sts; cdm_by_session_id_[key_set_id] = cdm_engine; } - InitializationData initialization_data(init_data_type, init_data); + + const SecurityLevel requested_security_level = + property_set->security_level().compare( + wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3) == 0 + ? wvcdm::kLevel3 + : wvcdm::kLevelDefault; + + std::string oec_version; + sts = cdm_engine_.QueryStatus(requested_security_level, + QUERY_KEY_OEMCRYPTO_API_VERSION, + &oec_version); + if (sts != NO_ERROR) { + return sts; + } + InitializationData initialization_data(init_data_type, init_data, + oec_version); + M_TIME(sts = cdm_engine->GenerateKeyRequest(session_id, key_set_id, initialization_data, license_type, app_parameters, key_request),