These are a set of CLs merged from the wv cdm repo to the android repo. * Level3 cleanup for SHA + field provision headers Author: Srujan Gaddam <srujzs@google.com> [ Merge of http://go/wvgerrit/37581 ] Moved some redundant macro and struct definitions out of hmac.cpp and sha.cpp into a separate header file to make the build easier and cleaner. Also cleaned up unnecessary includes and method signatures in field_provision.h. * Address CDM_All_Tests failures Author: Rahul Frias <rfrias@google.com> [ Merge of http://go/wvgerrit/37580 ] CDM engine tests for CE CDM occasionally fails when CDM_All_Tests is run by the build server. The failures are due to a nonce generation error. If provisioning fails due to a nonce generation error, a delay followed by a retry will be attempted. * Update OEMCrypto version to 13 in cdm.gyp Author: Gene Morgan <gmorgan@google.com> [ Merge of http://go/wvgerrit/37520 ] * Use per-session service certificates for licensing Author: Rahul Frias <rfrias@google.com> [ Merge of http://go/wvgerrit/37260 ] These changes allow for service certificates to be specified on a per-session basis rather than use one common to a CdmEngine instance. This also allows for a service certificate request and response handling when allowed on the platform, when privacy mode is enabled and a service certificate is not provided. Request license tests accept a service certificate command line parameter in hex (ascii). Earlier it expected it in binary. Bug: 68328352 * Refactor service certificate parsing Author: Rahul Frias <rfrias@google.com> [ Merge of http://go/wvgerrit/37060 ] Service certificates may still be set in CdmEngine but service certificate requests and responses have been moved from CdmEngine to ServiceCertificate. This allows them to be called from lower in the heirarchy (a class that CdmEngine depends on). Bug: 68328352 * Revert "C++11: Replace OVERRIDE def with override keyword" Author: Gene Morgan <gmorgan@google.com> [ Merge of http://go/wvgerrit/37020 ] This reverts commit 2d3fb5c4c8f4cf5c986ee43723914a23cf76e8f0. * Modified scripts/makefiles for L3 build Author: Srujan Gaddam <srujzs@google.com> [ Merge of http://go/wvgerrit/37220 ] Changed build-android-haystack.sh and make_fastball_libwvlevel3.sh to build using the new liboemcrypto.cpp file. Also changed makefiles to build using the new file. Renamed liboemcrypto.cc to liboemcrypto.cpp to make it consistent across android and CE CDM. Added static libraries that were rebuilt using this change. * Added android implementations for Level3 Author: Srujan Gaddam <srujzs@google.com> [ Merge of http://go/wvgerrit/37181 ] Moved getUniqueID and added Level3FileSystem implementations for android. Also deleted redundant and unnecessary methods from anroid_keybox.cpp. * Refactored getUniqueID and updated libl3oemcrypto.cc Author: Srujan Gaddam <srujzs@google.com> [ Merge of http://go/wvgerrit/37160 ] Renamed getUniqueID header and added comments to make it clear what the function is doing. Also removed obfuscation of the method name since it is implemented by the partner. Updated the libl3oemcrypto.cc file to reflect the change as well as be obfuscated. * Moved clear_cache function out of entry_points Author: Srujan Gaddam <srujzs@google.com> [ Merge of http://go/wvgerrit/37040 ] clear_cache function is unobfuscated and relies on compiler flags to work properly, and therefore should be removed from the libl3oemcrypto.cpp file and linked during the final build. * Minor gyp changes and added L3 build file Author: Srujan Gaddam <srujzs@google.com> [ Merge of http://go/wvgerrit/36480 ] Gyp changes to cdm_unittests.gyp to make the test Level3FileSystem build only on a level3 build and to oec_level3.gyp to be compatible with the changes to the x86-64 platform settings changes (and to use -Wno-unused to catch all unused warnings the libl3oemcrypto.cc might cause). This change also includes an x86-64 libl3oemcrypto.cc so a Level3 OEMCrypto can build. * Merge CE & Linux file system/factory + dynamic adapter changes Author: Srujan Gaddam <srujzs@google.com> [ Merge of http://go/wvgerrit/36220 ] This CL merges the changes from I27f5037e4fcea94abd84181f55053843b68f3e8d - it adds the CE implementation for the file system, as well as the factory methods needed to build the file system (and their implementations for both CE and linux). As part of the merge, since the Linux build relies on the dynamic adapter, that was fixed and gyp changes were made to reflect the change. * Cherry pick change to retrieve/save provisioning cert Author: Srujan Gaddam <srujzs@google.com> [ Merge of http://go/wvgerrit/30000 ] This is cherry pick from level3-dev-3.3 of a merge of I4f5dc5c216fa916e0bca0631c4ceda68859baf1d to save the certificate for future tests with the current test host setup. * Merged changes of usage/linux impl of L3FileSystem Author: Srujan Gaddam <srujzs@google.com> [ Merge of http://go/wvgerrit/35541 ] This is a merge of change I15d38b3c36933d061d168e0ec30bcefd0182f32d. It also adds a similar change in usage of L3FileSystem write for a line in usage_table.cpp. * Add cdm build changes for new Level3 build Author: Srujan Gaddam <srujzs@google.com> [ Merge of http://go/wvgerrit/34600 ] Original CL: Ib611cf8a8589afa5cd25d6dc5b0aa43922cfda1e Adds level3 oemcrypto library for static adapter. Includes changes to gyp files to choose between oemcrypto libraries. Also includes changes to the dynamic adapter, level3 headers, and entry_points to be compatible with the function signature differences when using the static adapter. * Merge OEMCrypto Level3FileSystem interface Author: Srujan Gaddam <srujzs@google.com> [ Merge of http://go/wvgerrit/34541 ] This merges in the interface for the Level3FileSystem object from level3_dev_3.3 as well as the linux implementation. Furthermore, this merge includes changes in properties and gyp files to allow compilation. The associated changes are I3f1c58f0e3782de0669a96725a38673a26cc1a49, I9fb2d10b0f966896bea685166c6b6b2e33c995dd, and I4c87a5412a8a022fa9cfba43f33bd4d683e61536. * Merged misc. changes to Level3 files Author: Srujan Gaddam <srujzs@google.com> [ Merge of http://go/wvgerrit/33303 ] Continuation of I03d3aa1a308f2f010dcb6f5e15f927e81e42925b. These changes are miscellaneous changes from level3-dev-3.3 involving include statements, Caligo compatibility, and new Level3 signatures from changes Ibc5befd492b295970e839f3481e2b512b52dcb08 and If599e62c72b5eb40c53633cd72a4d20dc859ee52. * Merged change involving getUniqueId() Author: Srujan Gaddam <srujzs@google.com> [ Merge of http://go/wvgerrit/33302 ] This is a merge from level3-dev-3.3. This change (Ibc5befd492b295970e839f3481e2b512b52dcb08) involves separating out the method getUniqueId() from the linux_ and android_keybox.cpp. This was done so that clients can supply the necessary implementation for the method. * Merged needle file changes from level3-dev-3.3 Author: Srujan Gaddam <srujzs@google.com> [ Merge of http://go/wvgerrit/33301 ] Continuation of I3dbf34bab526945720280f819dd3212ae982d2f7. These are changes (Ibc5befd492b295970e839f3481e2b512b52dcb08) involving the compiled needles for Haystack. Major changes include function signature changes, adding non-state needles automatically, and include statements. * Merged keybox/usage table access and function sigs Author: Srujan Gaddam <srujzs@google.com> [ Merge of http://go/wvgerrit/33300 ] These are changes from level3-dev-3.3. They involve changing function signatures/include files for the new Haystack runtime (Ibc5befd492b295970e839f3481e2b512b52dcb08). They are also related to change I0285e6d85e80b06b7df1ed298cd1145a6c9c4842. Keybox and usage table file names are replaced with constant needles. Furthermore, a state needle was added that removes the OldUsageTable file. In addition, this CL includes removals of method references that are now stale due to the introduction of change I9fb2d10b0f966896bea685166c6b6b2e33c995dd. * Android unit test build fixes Author: Srujan Gaddam <srujzs@google.com> [ Merge of http://go/wvgerrit/37380 ] Removed crypto_session_unittest from build script (introduced in http://go/wvgerrit/32824), since crypto_session.cpp requires some changes to be merged over from oc-mr1-dev (b/64456400). Added oemcrypto_session_tests_helper.cpp to the oemcrypto test makefile so the oemcrypto unit tests can link in the methods from the refactor in http://go/wvgerrit/36562. BUG: 71650075 Test: Not currently passing. Will be addressed in a subsequent commit in the chain. Change-Id: I7e45901a151e51da96d192d359edddc5fe74946e
3975 lines
168 KiB
C++
3975 lines
168 KiB
C++
// Copyright 2013 Google Inc. All Rights Reserved.
|
|
|
|
#include <errno.h>
|
|
#include <getopt.h>
|
|
#include <sstream>
|
|
|
|
#include <cutils/properties.h>
|
|
#include <gmock/gmock.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
#include "cdm_identifier.h"
|
|
#include "config_test_env.h"
|
|
#include "device_files.h"
|
|
#include "file_store.h"
|
|
#include "file_utils.h"
|
|
#include "license_protocol.pb.h"
|
|
#include "license_request.h"
|
|
#include "log.h"
|
|
#include "oemcrypto_adapter.h"
|
|
#include "OEMCryptoCENC.h"
|
|
#include "properties.h"
|
|
#include "string_conversions.h"
|
|
#include "test_base.h"
|
|
#include "test_printers.h"
|
|
#include "url_request.h"
|
|
#include "wv_cdm_constants.h"
|
|
#include "wv_cdm_event_listener.h"
|
|
#include "wv_content_decryption_module.h"
|
|
|
|
using ::testing::_;
|
|
using ::testing::AllOf;
|
|
using ::testing::AtLeast;
|
|
using ::testing::Contains;
|
|
using ::testing::Each;
|
|
using ::testing::Invoke;
|
|
using ::testing::IsEmpty;
|
|
using ::testing::Not;
|
|
using ::testing::Pair;
|
|
using ::testing::StrictMock;
|
|
|
|
namespace {
|
|
|
|
#define N_ELEM(a) (sizeof(a)/sizeof(a[0]))
|
|
|
|
const char kPathDelimiter = '/';
|
|
|
|
// HTTP response codes.
|
|
const int kHttpOk = 200;
|
|
const int kHttpBadRequest = 400;
|
|
const int kHttpInternalServerError = 500;
|
|
|
|
const wvcdm::CdmIdentifier kExampleIdentifier = {
|
|
wvcdm::EMPTY_SPOID,
|
|
"com.example",
|
|
"com.example"
|
|
};
|
|
|
|
// Protobuf generated classes
|
|
using video_widevine::LicenseIdentification;
|
|
using video_widevine::LicenseRequest_ContentIdentification;
|
|
|
|
// Default license server, can be configured using --server command line option
|
|
// Default key id (pssh), can be configured using --keyid command line option
|
|
std::string g_client_auth;
|
|
wvcdm::ConfigTestEnv* g_config = NULL;
|
|
wvcdm::KeyId g_key_id;
|
|
wvcdm::CdmKeySystem g_key_system;
|
|
std::string g_license_server;
|
|
wvcdm::KeyId g_wrong_key_id;
|
|
wvcdm::ServerConfigurationId g_server_configuration_id =
|
|
wvcdm::kContentProtectionUatServer;
|
|
std::string g_service_certificate;
|
|
|
|
// TODO(rfrias): refactor to print out the decryption test names
|
|
struct SubSampleInfo {
|
|
bool retrieve_key;
|
|
size_t num_of_subsamples;
|
|
bool validate_key_id;
|
|
bool is_encrypted;
|
|
bool is_secure;
|
|
wvcdm::KeyId key_id;
|
|
std::vector<uint8_t> encrypt_data;
|
|
std::vector<uint8_t> decrypt_data;
|
|
std::vector<uint8_t> iv;
|
|
size_t block_offset;
|
|
uint8_t subsample_flags;
|
|
};
|
|
|
|
SubSampleInfo clear_sub_sample = {
|
|
true, 1, true, false, false,
|
|
wvcdm::a2bs_hex("371EA35E1A985D75D198A7F41020DC23"),
|
|
wvcdm::a2b_hex(
|
|
"217ce9bde99bd91e9733a1a00b9b557ac3a433dc92633546156817fae26b6e1c"
|
|
"942ac20a89ff79f4c2f25fba99d6a44618a8c0420b27d54e3da17b77c9d43cca"
|
|
"595d259a1e4a8b6d7744cd98c5d3f921adc252eb7d8af6b916044b676a574747"
|
|
"8df21fdc42f166880d97a2225cd5c9ea5e7b752f4cf81bbdbe98e542ee10e1c6"
|
|
"ad868a6ac55c10d564fc23b8acff407daaf4ed2743520e02cda9680d9ea88e91"
|
|
"029359c4cf5906b6ab5bf60fbb3f1a1c7c59acfc7e4fb4ad8e623c04d503a3dd"
|
|
"4884604c8da8a53ce33db9ff8f1c5bb6bb97f37b39906bf41596555c1bcce9ed"
|
|
"08a899cd760ff0899a1170c2f224b9c52997a0785b7fe170805fd3e8b1127659"),
|
|
wvcdm::a2b_hex(
|
|
"217ce9bde99bd91e9733a1a00b9b557ac3a433dc92633546156817fae26b6e1c"
|
|
"942ac20a89ff79f4c2f25fba99d6a44618a8c0420b27d54e3da17b77c9d43cca"
|
|
"595d259a1e4a8b6d7744cd98c5d3f921adc252eb7d8af6b916044b676a574747"
|
|
"8df21fdc42f166880d97a2225cd5c9ea5e7b752f4cf81bbdbe98e542ee10e1c6"
|
|
"ad868a6ac55c10d564fc23b8acff407daaf4ed2743520e02cda9680d9ea88e91"
|
|
"029359c4cf5906b6ab5bf60fbb3f1a1c7c59acfc7e4fb4ad8e623c04d503a3dd"
|
|
"4884604c8da8a53ce33db9ff8f1c5bb6bb97f37b39906bf41596555c1bcce9ed"
|
|
"08a899cd760ff0899a1170c2f224b9c52997a0785b7fe170805fd3e8b1127659"),
|
|
wvcdm::a2b_hex("f6f4b1e600a5b67813ed2bded913ba9f"), 0,
|
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample};
|
|
|
|
SubSampleInfo clear_sub_sample_no_key = {
|
|
false, 1, false, false, false,
|
|
wvcdm::a2bs_hex("77777777777777777777777777777777"),
|
|
wvcdm::a2b_hex(
|
|
"217ce9bde99bd91e9733a1a00b9b557ac3a433dc92633546156817fae26b6e1c"
|
|
"942ac20a89ff79f4c2f25fba99d6a44618a8c0420b27d54e3da17b77c9d43cca"
|
|
"595d259a1e4a8b6d7744cd98c5d3f921adc252eb7d8af6b916044b676a574747"
|
|
"8df21fdc42f166880d97a2225cd5c9ea5e7b752f4cf81bbdbe98e542ee10e1c6"
|
|
"ad868a6ac55c10d564fc23b8acff407daaf4ed2743520e02cda9680d9ea88e91"
|
|
"029359c4cf5906b6ab5bf60fbb3f1a1c7c59acfc7e4fb4ad8e623c04d503a3dd"
|
|
"4884604c8da8a53ce33db9ff8f1c5bb6bb97f37b39906bf41596555c1bcce9ed"
|
|
"08a899cd760ff0899a1170c2f224b9c52997a0785b7fe170805fd3e8b1127659"),
|
|
wvcdm::a2b_hex(
|
|
"217ce9bde99bd91e9733a1a00b9b557ac3a433dc92633546156817fae26b6e1c"
|
|
"942ac20a89ff79f4c2f25fba99d6a44618a8c0420b27d54e3da17b77c9d43cca"
|
|
"595d259a1e4a8b6d7744cd98c5d3f921adc252eb7d8af6b916044b676a574747"
|
|
"8df21fdc42f166880d97a2225cd5c9ea5e7b752f4cf81bbdbe98e542ee10e1c6"
|
|
"ad868a6ac55c10d564fc23b8acff407daaf4ed2743520e02cda9680d9ea88e91"
|
|
"029359c4cf5906b6ab5bf60fbb3f1a1c7c59acfc7e4fb4ad8e623c04d503a3dd"
|
|
"4884604c8da8a53ce33db9ff8f1c5bb6bb97f37b39906bf41596555c1bcce9ed"
|
|
"08a899cd760ff0899a1170c2f224b9c52997a0785b7fe170805fd3e8b1127659"),
|
|
wvcdm::a2b_hex("f6f4b1e600a5b67813ed2bded913ba9f"), 0,
|
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample};
|
|
|
|
SubSampleInfo single_encrypted_sub_sample = {
|
|
// key SD, encrypted, 256b
|
|
true, 1, true, true, false,
|
|
wvcdm::a2bs_hex("371EA35E1A985D75D198A7F41020DC23"),
|
|
wvcdm::a2b_hex(
|
|
"64ab17b3e3dfab47245c7cce4543d4fc7a26dcf248f19f9b59f3c92601440b36"
|
|
"17c8ed0c96c656549e461f38708cd47a434066f8df28ccc28b79252eee3f9c2d"
|
|
"7f6c68ebe40141fe818fe082ca523c03d69ddaf183a93c022327fedc5582c5ab"
|
|
"ca9d342b71263a67f9cb2336f12108aaaef464f17177e44e9b0c4e56e61da53c"
|
|
"2150b4405cc82d994dfd9bf4087c761956d6688a9705db4cf350381085f383c4"
|
|
"9666d4aed135c519c1f0b5cba06e287feea96ea367bf54e7368dcf998276c6e4"
|
|
"6497e0c50e20fef74e42cb518fe7f22ef27202428688f86404e8278587017012"
|
|
"c1d65537c6cbd7dde04aae338d68115a9f430afc100ab83cdadf45dca39db685"),
|
|
wvcdm::a2b_hex(
|
|
"217ce9bde99bd91e9733a1a00b9b557ac3a433dc92633546156817fae26b6e1c"
|
|
"942ac20a89ff79f4c2f25fba99d6a44618a8c0420b27d54e3da17b77c9d43cca"
|
|
"595d259a1e4a8b6d7744cd98c5d3f921adc252eb7d8af6b916044b676a574747"
|
|
"8df21fdc42f166880d97a2225cd5c9ea5e7b752f4cf81bbdbe98e542ee10e1c6"
|
|
"ad868a6ac55c10d564fc23b8acff407daaf4ed2743520e02cda9680d9ea88e91"
|
|
"029359c4cf5906b6ab5bf60fbb3f1a1c7c59acfc7e4fb4ad8e623c04d503a3dd"
|
|
"4884604c8da8a53ce33db9ff8f1c5bb6bb97f37b39906bf41596555c1bcce9ed"
|
|
"08a899cd760ff0899a1170c2f224b9c52997a0785b7fe170805fd3e8b1127659"),
|
|
wvcdm::a2b_hex("f6f4b1e600a5b67813ed2bded913ba9f"), 0,
|
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample};
|
|
|
|
SubSampleInfo switch_key_encrypted_sub_samples[2] = {
|
|
// block 0, key SD, encrypted, 256b
|
|
{true, 2, true, true, false,
|
|
wvcdm::a2bs_hex("371EA35E1A985D75D198A7F41020DC23"),
|
|
wvcdm::a2b_hex(
|
|
"9efe1b7a3973324525e9b8c516855e554b52a73ce35cd181731b005a6525624f"
|
|
"a03875c89aee02f1da7f556b7e7d9a3eba89fe3061194bc2d1446233ca022892"
|
|
"ab95083f127d6ccb01b1368e6b6fa77e3570d84477a5517f2965ff72f8e0740c"
|
|
"d8282c22e7724ce44d88526dcd2d601002b717d8ca3b97087d28f9e3810efb8e"
|
|
"d4b08ee2da6bdb05a790b6363f8ee65cae8328e86848e4caf9be92db3e5492ad"
|
|
"6363a26051c23cf23b9aee79a8002470c4a5834c6aae956b509a42f4110262e0"
|
|
"565a043befd8ef3a335c9dfedca8d218f364215859d7daf7d040b1f0cb2eda87"
|
|
"c1be18f323fb0235dd9a6e7b3b2fea1cb9c6e5bc2b349962f0b8f0b92e749db2"),
|
|
wvcdm::a2b_hex(
|
|
"38a715e73c9209544c47e5eb089146de8136df5c6ed01e3e8d9cea8ae18a81c9"
|
|
"8c9c8ec67bf379dd80a21f57b0b00575827a240cd11332c5212defe9f1ef8b8e"
|
|
"2399271767bfe81e5a11abf7bca1307578217c4d5f8b942ab04351b4725d6e24"
|
|
"cd171fa3083570f7d7ae2b297224f701fd04d699c12c53e9ce9d3dab64ee6332"
|
|
"5fba183b7a1f3f20acaeabc0c446c9ca0df39fafb1e2891c72500741ad5b7941"
|
|
"4651729e30e9ddbb22f47a5026e09c795ff15a858123a7979e7be716cb8cd075"
|
|
"e8bfb91bc0cc83f7cacd5c4772f7479a1193d9307bc5f837185faed5499e66a7"
|
|
"e27db50b5d018d022279032016862883befd113b6c784889be8f9e6eb0f335f7"),
|
|
wvcdm::a2b_hex("fd38d7f754a97128b78440433e1ef4a8"), 0,
|
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample},
|
|
// block 1, key HD, encrypted, 256b
|
|
{true, 2, true, true, false,
|
|
wvcdm::a2bs_hex("6D665122C01767FC087F340E6C335EA4"),
|
|
wvcdm::a2b_hex(
|
|
"d9392411d15f47de0d7dd854eae5eb5ffbd2d3f86c530d2ef619fc81725df866"
|
|
"2e6267041b947863e5779812da3220824a3d154e7b094c1af70238c65877454e"
|
|
"3c3bdcce836962ba29b69442d5e5b4a4ff32a4b026521f3fa4d442a400081cdd"
|
|
"ba6ed313c43cc34443c4dc2b9cdcc9dbd478bf6afc4d515c07b42d8b151c15cc"
|
|
"165270f6083ecd5c75313c496143068f45966bb53e35906c7568424e93e35989"
|
|
"7da702fb89eb7c970af838d56a64a7a68f7cffe529807765d62540bb06bbc633"
|
|
"6eeec62d20f5b639731e57a0851e23e146cb9502dbde93dc4aca20e471a3fa0b"
|
|
"df01a74ecb48d5f57ac2be98fb21d19de7587d8d1e6e1788726e1544d05137f6"),
|
|
wvcdm::a2b_hex(
|
|
"c48a94d07c34c4315e01010dbcc63a038d50a023b1ff2a07deae6e498cb03f84"
|
|
"57911d8c9d72fa5184c738d81a49999504b7cd4532b465436b7044606a6d40a2"
|
|
"74a653c4b93ebaf8db585d180211a02e5501a8027f2235fe56682390325c88ee"
|
|
"2ada85483eddb955c56f79634a2ceeb36d04b5d6faf7611817577d9b0fda088e"
|
|
"921fbdd7fa594ee4f557f7393f51f3049cd36973f645badf7cc4672ef8d973da"
|
|
"7dae8e59f32bf950c6569845a5261b5ed9cc500706eccf8d41f015b32026e16e"
|
|
"ab274465d880ff99a5eaea603eea66c7b0e6679bfd87145de0ec1a73ebfff092"
|
|
"866346a1d66db2923bca30664f417a6b66c07e91fb491be7872ebe5c9c2d03c2"),
|
|
wvcdm::a2b_hex("f56ab022666de858920e532f19bb32f6"), 0,
|
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample}};
|
|
|
|
SubSampleInfo partial_encrypted_sub_samples[3] = {
|
|
// block 1, key SD, encrypted, 1-125b, offset 0
|
|
{true, 3, true, true, false,
|
|
wvcdm::a2bs_hex("371EA35E1A985D75D198A7F41020DC23"),
|
|
wvcdm::a2b_hex(
|
|
"53cc758763904ea5870458e6b23d36db1e6d7f7aaa2f3eeebb5393a7264991e7"
|
|
"ce4f57b198326e1a208a821799b2a29c90567ab57321b06e51fc20dc9bc5fc55"
|
|
"10720a8bb1f5e002c3e50ff70d2d806a9432cad237050d09581f5b0d59b00090"
|
|
"b3ad69b4087f5a155b17e13c44d33fa007475d207fc4ac2ef3b571ecb9"),
|
|
wvcdm::a2b_hex(
|
|
"52e65334501acadf78e2b26460def3ac973771ed7c64001a2e82917342a7eab3"
|
|
"047f5e85449692fae8f677be425a47bdea850df5a3ffff17043afb1f2b437ab2"
|
|
"b1d5e0784c4ed8f97fc24b8f565e85ed63fb7d1365980d9aea7b8b58f488f83c"
|
|
"1ce80b6096c60f3b113c988ff185b26e798da8fc6f327e4ff00e4b3fbf"),
|
|
wvcdm::a2b_hex("6ba18dd40f49da7f64c368e4db43fc88"), 0,
|
|
OEMCrypto_FirstSubsample},
|
|
// block 2, key SD, encrypted, 126-187b, offset 5
|
|
{true, 3, true, true, false,
|
|
wvcdm::a2bs_hex("371EA35E1A985D75D198A7F41020DC23"),
|
|
wvcdm::a2b_hex(
|
|
"f3c852"
|
|
"ce00dc4806f0c6856ae1732e20308096478e1d822d75c2bb768119565d3bd6e6"
|
|
"901e36164f4802355ee758fc46ef6cf5f852dd5256c7b1e5f96d29"),
|
|
wvcdm::a2b_hex(
|
|
"b1ed0a"
|
|
"a054bce40ccb0ebc70b181d1a12055f46ac55e29c7c2473a29d2a366d240ec48"
|
|
"7cede274f012813a877f99159e7062b6a37cfc9327a7bc2195814e"),
|
|
wvcdm::a2b_hex("6ba18dd40f49da7f64c368e4db43fc8f"), 13, 0},
|
|
// block 3, key SD, encrypted, 188-256b, offset 5
|
|
{true, 3, true, true, false,
|
|
wvcdm::a2bs_hex("371EA35E1A985D75D198A7F41020DC23"),
|
|
wvcdm::a2b_hex(
|
|
"3b20525d5e"
|
|
"78b8e5aa344d5c4e425e67ddf889ea7c4bb1d49af67eba67718b765e0a940402"
|
|
"8d306f4ce693ad6dc0a931d507fa14fff4d293d4170280b3e0fca2d628f722e8"),
|
|
wvcdm::a2b_hex(
|
|
"653b818d1d"
|
|
"4ab9a9128361d8ca6a9d2766df5c096ee29f4f5204febdf217a94a5b560cd692"
|
|
"cc36d3e071df789fdeac2fb7ec6dcd7af94bb1f85c22025b25e702e38212b927"),
|
|
wvcdm::a2b_hex("6ba18dd40f49da7f64c368e4db43fc93"), 11,
|
|
OEMCrypto_LastSubsample}};
|
|
|
|
SubSampleInfo single_encrypted_sub_sample_short_expiry = {
|
|
// key 1, encrypted, 256b
|
|
true, 1, true, true, false,
|
|
wvcdm::a2bs_hex("9714593E1EEE57859D34ECFA821702BB"),
|
|
wvcdm::a2b_hex(
|
|
"3b2cbde084973539329bd5656da22d20396249bf4a18a51c38c4743360cc9fea"
|
|
"a1c78d53de1bd7e14dc5d256fd20a57178a98b83804258c239acd7aa38f2d7d2"
|
|
"eca614965b3d22049e19e236fc1800e60965d8b36415677bf2f843d50a6943c4"
|
|
"683c07c114a32f5e5fbc9939c483c3a1b2ecd3d82b554d649798866191724283"
|
|
"f0ab082eba2da79aaca5c4eaf186f9ee9a0c568f621f705a578f30e4e2ef7b96"
|
|
"5e14cc046ce6dbf272ee5558b098f332333e95fc879dea6c29bf34acdb649650"
|
|
"f08201b9e649960f2493fd7677cc3abf5ae70e5445845c947ba544456b431646"
|
|
"d95a133bff5f57614dda5e4446cd8837901d074149dadf4b775b5b07bb88ca20"),
|
|
wvcdm::a2b_hex(
|
|
"5a36c0b633b58faf22156d78fdfb608e54a8095788b2b0463ef78d030b4abf82"
|
|
"eff34b8d9b7b6352e7d72de991b599662aa475da355033620152e2356ebfadee"
|
|
"06172be9e1058fa177e223b9fdd191380cff53c3ea810c6fd852a1df4967b799"
|
|
"415179a2276ec388ef763bab89605b9c6952c28dc8d6bf86b03fabbb46b392a3"
|
|
"1dad15be602eeeeabb45070b3e25d6bb0217073b1fc44c9fe848594121fd6a91"
|
|
"304d605e21f69615e1b57db18312b6b948725724b74e91d8aea7371e99532469"
|
|
"1b358bdee873f1936b63efe83d190a53c2d21754d302d63ff285174023473755"
|
|
"58b938c2e3ca4c2ce48942da97f9e45797f2c074ac6004734e93784a48af6160"),
|
|
wvcdm::a2b_hex("4cca615fc013102892f91efee936639b"), 0,
|
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample};
|
|
|
|
SubSampleInfo usage_info_sub_samples_icp[] = {
|
|
{true, 1, true, true, false,
|
|
wvcdm::a2bs_hex("E82DDD1D07CBB31CDD31EBAAE0894609"),
|
|
wvcdm::a2b_hex(
|
|
"fe8670a01c86906c056b4bf85ad278464c4eb79c60de1da8480e66e78561350e"
|
|
"a25ae19a001f834c43aaeadf900b3c5a6745e885a4d1d1ae5bafac08dc1d60e5"
|
|
"f3465da303909ec4b09023490471f670b615d77db844192854fdab52b7806203"
|
|
"89b374594bbb6a2f2fcc31036d7cb8a3f80c0e27637b58a7650028fbf2470d68"
|
|
"1bbd77934af165d215ef325c74438c9d99a20fc628792db28c05ed5deff7d9d4"
|
|
"dba02ddb6cf11dc6e78cb5200940af9a2321c3a7c4c79be67b54a744dae1209c"
|
|
"fa02fc250ce18d30c7da9c3a4a6c9619bf8561a42ff1e55a7b14fa3c8de69196"
|
|
"c2b8e3ff672fc37003b479da5d567b7199917dbe5aa402890ebb066bce140b33"),
|
|
wvcdm::a2b_hex(
|
|
"d08733bd0ef671f467906b50ff8322091400f86fd6f016fea2b86e33923775b3"
|
|
"ebb4c8c6f3ba8b78dd200a74d3872a40264ab99e1d422e4f819abb7f249114aa"
|
|
"b334420b37c86ce81938615ab9d3a6b2de8db545cd88e35091031e73016fb386"
|
|
"1b754298329b52dbe483de3a532277815e659f3e05e89257333225b933d92e15"
|
|
"ef2deff287a192d2c8fc942a29a5f3a1d54440ac6385de7b34bb650b889e4ae9"
|
|
"58c957b5f5ff268f445c0a6b825fcad55290cb7b5c9814bc4c72984dcf4c8fd7"
|
|
"5f511c173b2e0a3163b18a1eac58539e5c188aeb0751b946ad4dcd08ea777a7f"
|
|
"37326df26fa509343faa98dff667629f557873f1284903202e451227ef465a62"),
|
|
wvcdm::a2b_hex("7362b5140c4ce0cd5f863858668d3f1a"), 0,
|
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample},
|
|
{true, 1, true, true, false,
|
|
wvcdm::a2bs_hex("04B2B456405CAD7170BE848CA75AA2DF"),
|
|
wvcdm::a2b_hex(
|
|
"ccb68f97b03e7af1a9e208d91655ba645cc5a5d454f3cb7c3d621e98a7592d90"
|
|
"4ff7023555f0e99bcf3918948f4fca7a430faf17d7d67268d81d8096d7c48809"
|
|
"c14220e634680fbe0c760571dd86a1905835035f4a238c2d7f17bd1363b113c1"
|
|
"91782aebb77a1064142a68b59ecdcc6990ed4244082464d91dbfe09e08744b2f"
|
|
"d1e850a008acbbe129fbd050c8dc1b28cb8cc2c1e2d920ea458f74809297b513"
|
|
"85307b481cbb81d6759385ee782d6c0e101c20ca1937cfd0d6e024da1a0f718a"
|
|
"fb7c4ff3df1ca87e67602d28168233cc2448d44b79f405d4c6e67eb88d705050"
|
|
"2a806cb986423e3b0e7a97738e1d1d143b4f5f926a4e2f37c7fbe65f56d5b690"),
|
|
wvcdm::a2b_hex(
|
|
"fa35aa1f5e5d7b958880d5eed9cc1bb81d36ebd04c0250a8c752ea5f413bbdcf"
|
|
"3785790c8dba7a0b21c71346bb7f946a9b71c0d2fe87d2e2fab14e35ee8400e7"
|
|
"097a7d2d9a25b468e848e8dee2388f890967516c7dab96db4713c7855f717aed"
|
|
"2ae9c2895baaa636e4a610ab26b35d771d62397ba40d78694dab70dcbdfa91c3"
|
|
"6af79ad6b6ebb479b4a5fbc242a8574ebe6717f0813fbd6f726ce2af4d522e66"
|
|
"b36c940fce519c913db56a6372c3636b10c0149b4cd97e74c576765b533abdc2"
|
|
"729f1470dd7f9a60d3572dcc9839582a4606ee17eaced39797daef8f885d3f8f"
|
|
"e14877ae530451c4242bbc3934f85a5bb71b363351894f881896471cfeaf68b2"),
|
|
wvcdm::a2b_hex("4a59e3e5f3e4f7e2f494ad09c12a9e4c"), 0,
|
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample},
|
|
{true, 1, true, true, false,
|
|
wvcdm::a2bs_hex("3AE243D83B93B3311A1D777FF5FBE01A"),
|
|
wvcdm::a2b_hex(
|
|
"934997779aa1aeb45d6ba8845f13786575d0adf85a5e93674d9597f8d4286ed7"
|
|
"dcce02f306e502bbd9f1cadf502f354038ca921276d158d911bdf3171d335b18"
|
|
"0ae0f9abece16ff31ee263228354f724da2f3723b19caa38ea02bd6563b01208"
|
|
"fb5bf57854ac0fe38d5883197ef90324b2721ff20fdcf9a53819515e6daa096e"
|
|
"70f6f5c1d29a4a13dafd127e2e1f761ea0e28fd451607552ecbaef5da3c780bc"
|
|
"aaf2667b4cc4f858f01d480cac9e32c3fbb5705e5d2adcceebefc2535c117208"
|
|
"e65f604799fc3d7223e16908550f287a4bea687008cb0064cf14d3aeedb8c705"
|
|
"09ebc5c2b8b5315f43c04d78d2f55f4b32c7d33e157114362106395cc0bb6d93"),
|
|
wvcdm::a2b_hex(
|
|
"2dd54eee1307753508e1f250d637044d6e8f5abf057dab73e9e95f83910e4efc"
|
|
"191c9bac63950f13fd51833dd94a4d03f2b64fb5c721970c418fe53fa6f74ad5"
|
|
"a6e16477a35c7aa6e28909b069cd25770ef80da20918fc30fe95fd5c87fd3522"
|
|
"1649de17ca2c7b3dc31f936f0cbdf97c7b1c15de3a86b279dc4b4de64943914a"
|
|
"99734556c4b7a1a0b022c1933cb0786068fc18d49fed2f2b49f3ac6d01c32d07"
|
|
"92175ce2844eaf9064e6a3fcffade038d690cbed81659351163a22432f0d0545"
|
|
"037e1c805d8e92a1272b4196ad0ce22f26bb80063137a8e454d3b97e2414283d"
|
|
"ed0716cd8bceb80cf59166a217006bd147c51b04dfb183088ce3f51e9b9f759e"),
|
|
wvcdm::a2b_hex("b358ab21ac90455bbf60490daad457e3"), 0,
|
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample},
|
|
{true, 1, true, true, false,
|
|
wvcdm::a2bs_hex("5292104C011418973C31235953FC8205"),
|
|
wvcdm::a2b_hex(
|
|
"d433adfd3d892d5c3e7d54ab0218ee0712400a920d4b71d553912451169f9b79"
|
|
"3f103260cf04c34f6a5944bb96da79946a62bdbcd804ca28b17656338edfa700"
|
|
"5c090f2750663a026fd15a0b0e448adbbfd53f613ea3993d9fd504421b575f28"
|
|
"12020bb8cca0ce333eabee0403df9f410c6473d7673d6991caab6ea2ece8f743"
|
|
"5a3ca049fa00c96c9b7c47e3073d25d08f23b47ffc509c48a81a2f98c9ec8a1d"
|
|
"e41764c14a5010df8b4692e8612a45bf0645601d4910119e6268ca4f6d8016a8"
|
|
"3d933d53f44243674b522bae43043c068c8cae43f0ac224198de71315b3a6f82"
|
|
"c1b523bbdcdb3e9f162c308684dd17e364b448ed0e90b0e496b8cf633a982708"),
|
|
wvcdm::a2b_hex(
|
|
"5efb5e5b913785e9935e67e763b8ff29a6687ac6c18d5a7e16951beb704f9c95"
|
|
"f081ca28f54c3e237fb5a7b0444e9a3e17da91e5cf2c0a8f009a873fb079c339"
|
|
"81b0ebc565b2c56d983ee33686fa5057c9891e246b67bb6950400acb06d5ae50"
|
|
"0e61a7e9289ea67ec2e88e8d0cc3c494fd996e93270e9b264a21818987e969c5"
|
|
"1e2955c5a53202e5aec1e2c906e1c006325112eb5c33ee37d0c07ea97d80c17f"
|
|
"d56e0efcf40c8c98981a86c18a159f05d851891236c124641d4584c49ccd7478"
|
|
"4f328a9cacae0f945238d98741b2969fe258903e85f963daba7168f05c18b09f"
|
|
"660dae18de41b1c49769cd38e24b135c37a65b69533f5c7d085898faedfbed5d"),
|
|
wvcdm::a2b_hex("cef7e8aaa6ec1154cb68a988f7c9e803"), 0,
|
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample},
|
|
{true, 1, true, true, false,
|
|
wvcdm::a2bs_hex("D7C01C2F868AE314BCB893E4E9C6AC75"),
|
|
wvcdm::a2b_hex(
|
|
"fa5d28677721de488ffc209321529728c77bc338accd45ccc98ab2063fc8c373"
|
|
"48c7698534175d72bf185690d19474d08c4fd4ed4eb46d858633f05337d70e92"
|
|
"03f7ee6bec0f7003bdf6fa665ba172855a51a82da406348ba651a2f62888c30a"
|
|
"7b4e1355bb94a9ff5c458f397c9a09e5d7785b286ef83142ddad324cc74e1929"
|
|
"60ad1c34c425cdefbedcb62ca9b21ac4f3df7f5922e263cb7798de54b622ab3f"
|
|
"64a0dd6ee1e40be6ecc857e657994ecac02ccfafc9036f382d7dbdf35c903356"
|
|
"40b7c9db088143060b24f24b21c4a7c2faeb3d308e57c5a75955fd704cfe4dee"
|
|
"71a4a7d823102b90eddded795ca6eb36282d777db8cfd783e50e5c2a816ee9ed"),
|
|
wvcdm::a2b_hex(
|
|
"d5db2f50c0f5a39414ddfa5129c2c641836a8c6312b26a210c996988e0c768d5"
|
|
"9a3adff117293b52b0653c0d6e22589edda804fb8caa7442362fe4caf9053b6a"
|
|
"2a34896399259a188f0c805de54b091a7eabff098b28d54584c01dd83301e4ca"
|
|
"a01b226c4541af1592d4440e103eb55bbd08c471efb0856ec9ced43211fc3325"
|
|
"3d402dff0d15f40833dd71259a8d40d527659ef3e5f9fd0826c9471dddb17e1e"
|
|
"fab916abc957fb07d7eac4a368ac92a8fb16d995613af47303034ee57b59b1d7"
|
|
"101aa031f5586b2f6b4c74372c4d7306db02509b5924d52c46a270f427743a85"
|
|
"614f080d83f3b15cbc6600ddda43adff5d2941da13ebe49d80fd0cea5025412b"),
|
|
wvcdm::a2b_hex("964c2dfda920357c668308d52d33c652"), 0,
|
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample}};
|
|
|
|
// License duration and uncertainty window
|
|
const uint32_t kSingleEncryptedSubSampleIcpLicenseDurationExpiration = 5;
|
|
const uint32_t kSingleEncryptedSubSampleIcpLicenseExpirationWindow = 2;
|
|
|
|
struct SessionSharingSubSampleInfo {
|
|
SubSampleInfo* sub_sample;
|
|
bool session_sharing_enabled;
|
|
};
|
|
|
|
SessionSharingSubSampleInfo session_sharing_sub_samples[] = {
|
|
{&clear_sub_sample, false},
|
|
{&clear_sub_sample, true},
|
|
{&clear_sub_sample_no_key, false},
|
|
{&clear_sub_sample_no_key, true},
|
|
{&single_encrypted_sub_sample, false},
|
|
{&single_encrypted_sub_sample, true}};
|
|
|
|
struct UsageInfoSubSampleInfo {
|
|
SubSampleInfo* sub_sample;
|
|
uint32_t usage_info;
|
|
wvcdm::SecurityLevel security_level;
|
|
std::string app_id;
|
|
};
|
|
|
|
UsageInfoSubSampleInfo usage_info_sub_sample_info[] = {
|
|
{&usage_info_sub_samples_icp[0], 1, wvcdm::kLevelDefault, ""},
|
|
{&usage_info_sub_samples_icp[0], 3, wvcdm::kLevelDefault, ""},
|
|
{&usage_info_sub_samples_icp[0], 5, wvcdm::kLevelDefault, ""},
|
|
{&usage_info_sub_samples_icp[0], 3, wvcdm::kLevelDefault, "other app id"},
|
|
{&usage_info_sub_samples_icp[0], 1, wvcdm::kLevel3, ""},
|
|
{&usage_info_sub_samples_icp[0], 3, wvcdm::kLevel3, ""},
|
|
{&usage_info_sub_samples_icp[0], 5, wvcdm::kLevel3, ""},
|
|
{&usage_info_sub_samples_icp[0], 3, wvcdm::kLevel3, "other app id"}};
|
|
|
|
struct RenewWithClientIdTestConfiguration {
|
|
bool always_include_client_id;
|
|
bool specify_app_parameters;
|
|
bool enable_privacy_mode;
|
|
bool specify_service_certificate;
|
|
std::string test_description;
|
|
};
|
|
|
|
RenewWithClientIdTestConfiguration
|
|
streaming_renew_client_id_test_configuration[] = {
|
|
{false, false, false, false,
|
|
"Test: Streaming renewal without client Id"},
|
|
{true, false, false, false, "Test: Streaming renewal with client Id"},
|
|
{true, true, false, false,
|
|
"Test: Streaming renewal with app parameters"},
|
|
{true, false, true, false,
|
|
"Test: Streaming renewal fetch service cert"},
|
|
{true, false, true, true,
|
|
"Test: Streaming renewal, service cert provided"}};
|
|
|
|
// Note: Offline renewal/release with encrypted client Ids and where a service
|
|
// certificate needs to be fetched is not supported.
|
|
RenewWithClientIdTestConfiguration
|
|
offline_release_client_id_test_configuration[] = {
|
|
{false, false, false, false,
|
|
"Test: Offline renewal/release without client Id"},
|
|
{true, false, false, false,
|
|
"Test: Offline renewal/release with client Id"},
|
|
{true, true, false, false,
|
|
"Test: Offline renewal/release with app parameters"},
|
|
{true, false, true, true,
|
|
"Test: Offline renewal/release, service cert provided"}};
|
|
|
|
RenewWithClientIdTestConfiguration
|
|
usage_client_id_test_configuration[] = {
|
|
{false, false, false, false,
|
|
"Test: Usage reporting without client Id"},
|
|
{true, false, false, false,
|
|
"Test: Usage reporting with client Id"}};
|
|
|
|
// provider:"widevine_test",
|
|
// content_id":"aGxzX3NhbXBsZV9hZXNfc3RyZWFtaW5n" (hls_sample_aes_streaming)
|
|
// key_id:613db35603320eb8e7ea24bdeea3fdb8
|
|
// key:78a1dc0646119707e903514d8a00735f
|
|
const std::string kAttributeListSampleAes =
|
|
"#EXT-X-KEY:"
|
|
"METHOD=SAMPLE-AES,"
|
|
"KEYFORMAT=\"com.widevine\","
|
|
"KEYFORMATVERSIONS=\"1\","
|
|
"URI=\"data:text/"
|
|
"plain;base64,"
|
|
"ew0KICAgInByb3ZpZGVyIjoid2lkZXZpbmVfdGVzdCIsDQogICAiY29udGVudF9pZCI6ImFHeH"
|
|
"pYM05oYlhCc1pWOWhaWE5mYzNSeVpXRnRhVzVuIiwNCiAgICJrZXlfaWRzIjoNCiAgIFsNCiAg"
|
|
"ICAgICI2MTNkYjM1NjAzMzIwZWI4ZTdlYTI0YmRlZWEzZmRiOCINCiAgIF0NCn0=\","
|
|
"IV=0x9FBE45DD47DA7EBA09A3E24CBA95C9AF";
|
|
|
|
// provider:"widevine_test",
|
|
// content_id":"aGxzX2Flc18xMjhfc3RyZWFtaW5n" (hls_aes_128_streaming)
|
|
// key_id:ab6531ff6e6ea15e387b019e59c2de0a
|
|
// key:78a1dc0646119707e903514d8a00735f
|
|
const std::string kAttributeListAes128 =
|
|
"#EXT-X-KEY:"
|
|
"METHOD=AES-128,"
|
|
"KEYFORMAT=\"com.widevine\","
|
|
"KEYFORMATVERSIONS=\"1\","
|
|
"URI=\"data:text/"
|
|
"plain;base64,"
|
|
"ew0KICAgInByb3ZpZGVyIjoid2lkZXZpbmVfdGVzdCIsDQogICAiY29udGVudF9pZCI6ImFHeH"
|
|
"pYMkZsYzE4eE1qaGZjM1J5WldGdGFXNW4iLA0KICAgImtleV9pZHMiOg0KICAgWw0KICAgICAg"
|
|
"ImFiNjUzMWZmNmU2ZWExNWUzODdiMDE5ZTU5YzJkZTBhIg0KICAgXQ0KfQ==\","
|
|
"IV=0x9FBE45DD47DA7EBA09A3E24CBA95C9AF";
|
|
|
|
const std::string kAttributeListKeyFormatNonWidevine =
|
|
"#EXT-X-KEY:METHOD=SAMPLE-AES,KEYFORMAT=\"com.example\",KEYFORMATVERSIONS="
|
|
"\"1\",URI=\"data:text/"
|
|
"plain;base64,"
|
|
"eyAKICAgInByb3ZpZGVyIjoiY2FzdCIsCiAgICJjb250ZW50X2lkIjoiU0VKUElGTkJUVkJNUl"
|
|
"NBeCIsCiAgICJrZXlfaWRzIjoKICAgWwogICAgICAiZDhlMzQ0ODM1ZTM1NzA3MjUzZDU3MWYz"
|
|
"NjE0ZTdmMmYiCiAgIF0KfQ==\",IV=0x9FBE45DD47DA7EBA09A3E24CBA95C9AF";
|
|
|
|
const std::string kAttributeListKeyFormatVersionUnregonized =
|
|
"#EXT-X-KEY:METHOD=SAMPLE-AES,KEYFORMAT=\"com.widevine\",KEYFORMATVERSIONS="
|
|
"\"2\",URI=\"data:text/"
|
|
"plain;base64,"
|
|
"eyAKICAgInByb3ZpZGVyIjoiY2FzdCIsCiAgICJjb250ZW50X2lkIjoiU0VKUElGTkJUVkJNUl"
|
|
"NBeCIsCiAgICJrZXlfaWRzIjoKICAgWwogICAgICAiZDhlMzQ0ODM1ZTM1NzA3MjUzZDU3MWYz"
|
|
"NjE0ZTdmMmYiCiAgIF0KfQ==\",IV=0x9FBE45DD47DA7EBA09A3E24CBA95C9AF";
|
|
|
|
const std::string kAttributeListUnspecifiedIv =
|
|
"#EXT-X-KEY:"
|
|
"METHOD=SAMPLE-AES,"
|
|
"KEYFORMAT=\"com.widevine\","
|
|
"KEYFORMATVERSIONS=\"1\","
|
|
"URI=\"data:text/plain;base64,ew0KICAgInByb3ZpZGVyIjoid2lkZXZpbmVfdGVzdCIsD"
|
|
"QogICAiY29udGVudF9pZCI6ImFHeHpYM05oYlhCc1pWOWhaWE5mYzNSeVpXRnRhVzVuIiwNCiA"
|
|
"gICJrZXlfaWRzIjoNCiAgIFsNCiAgICAgICI3OGExZGMwNjQ2MTE5NzA3ZTkwMzUxNGQ4YTAwN"
|
|
"zM1ZiINCiAgIF0NCn0=\",";
|
|
|
|
const std::string kAttributeListUnspecifiedMethod =
|
|
"#EXT-X-KEY:"
|
|
"KEYFORMAT=\"com.widevine\","
|
|
"KEYFORMATVERSIONS=\"1\","
|
|
"URI=\"data:text/plain;base64,ew0KICAgInByb3ZpZGVyIjoid2lkZXZpbmVfdGVzdCIsD"
|
|
"QogICAiY29udGVudF9pZCI6ImFHeHpYM05oYlhCc1pWOWhaWE5mYzNSeVpXRnRhVzVuIiwNCiA"
|
|
"gICJrZXlfaWRzIjoNCiAgIFsNCiAgICAgICI3OGExZGMwNjQ2MTE5NzA3ZTkwMzUxNGQ4YTAwN"
|
|
"zM1ZiINCiAgIF0NCn0=\","
|
|
"IV=0x9FBE45DD47DA7EBA09A3E24CBA95C9AF";
|
|
|
|
struct HlsSegmentInfo {
|
|
bool start_segment;
|
|
std::string iv;
|
|
std::string clear_data;
|
|
std::string encrypted_data;
|
|
uint8_t subsample_flags;
|
|
};
|
|
|
|
HlsSegmentInfo kAes128SingleSegmentInfo[] = {
|
|
{
|
|
true, wvcdm::a2bs_hex("9FBE45DD47DA7EBA09A3E24CBA95C9AF"),
|
|
wvcdm::a2bs_hex(
|
|
"AD868A6AC55C10D564FC23B8ACFF407DAAF4ED2743520E02CDA9680D9EA88E9148"
|
|
"84604C8DA8A53CE33DB9FF8F1C5BB6BB97F37B39906BF41596555C1BCCE9ED0293"
|
|
"59C4CF5906B6AB5BF60FBB3F1A1C7C59ACFC7E4FB4AD8E623C04D503A3DDAD868A"
|
|
"6AC55C10D564FC23B8ACFF407DAAF4ED2743520E02CDA9680D9EA88E918DF21FDC"
|
|
"42F166880D97A2225CD5C9EA5E7B752F4CF81BBDBE98E542EE10E1C6595D259A1E"
|
|
"4A8B6D7744CD98C5D3F921ADC252EB7D8AF6B916044B676A574747942AC20A89FF"
|
|
"79F4C2F25FBA99D6A44618A8C0420B27D54E3DA17B77C9D43CCA217CE9BDE99BD9"
|
|
"1E9733A1A00B9B557AC3A433DC92633546156817FAE26B6E1C"),
|
|
wvcdm::a2bs_hex(
|
|
"E7C566D86E98C36D2DCA54A966E7B469B6094B9201F200932F8EB5E1A94FB0B977"
|
|
"FAB8DFDAD57C677E279615F4EAFA872CA8EFF83179E4DE2AB78E6B41A860C42203"
|
|
"4B875AC282406E03AC01F2E407A55DE38C6C35707F34B3319646FA016A01CE9056"
|
|
"E55D28C48ED72F10FA6625656ED62B758CBADA757DDC52533C9CBD54FC1A46F827"
|
|
"CC7B69BA66AE19A15D725FCBB972B23C83F95C0F00F481A7C9AC8687B3A4AD15AD"
|
|
"A2ABBB84D8E3CBEC3E8771720A35234070799173B37219127141922CBA8CB2DC48"
|
|
"EC2477832D1AE477942DCDA93C0886AF72D71E56DA3D7737E49670B024639A195B"
|
|
"7377C7F45A797C6E5DBB1BB2843DA3FC76043E33687BEF3172"),
|
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample,
|
|
},
|
|
};
|
|
|
|
HlsSegmentInfo kAes128PartialSegmentInfo[] = {
|
|
{
|
|
true, wvcdm::a2bs_hex("9FBE45DD47DA7EBA09A3E24CBA95C9AF"),
|
|
wvcdm::a2bs_hex(
|
|
"AD868A6AC55C10D564FC23B8ACFF407DAAF4ED2743520E02CDA9680D9EA88E9148"
|
|
"84604C8DA8A53CE33DB9FF8F1C5BB6BB97F37B39906BF41596555C1BCCE9ED0293"
|
|
"59C4CF5906B6AB5BF60FBB3F1A1C7C59ACFC7E4FB4AD8E623C04D503A3DDAD868A"
|
|
"6AC55C10D564FC23B8ACFF407DAAF4ED2743520E02CDA9680D9EA88E918DF21FDC"
|
|
"42F166880D97A2225CD5C9EA5E7B752F4CF81BBDBE98E542EE10E1C6595D259A1E"
|
|
"4A8B6D7744CD98C5D3F921ADC252EB7D8AF6B916044B676A574747942AC20A89FF"
|
|
"79F4C2F25FBA99D6A44618A8C0420B27D54E3DA17B77C9D43CCA217CE9BDE99BD9"
|
|
"1E9733A1A00B9B557AC3A433DC92633546156817FAE26B6E1C"),
|
|
wvcdm::a2bs_hex(
|
|
"E7C566D86E98C36D2DCA54A966E7B469B6094B9201F200932F8EB5E1A94FB0B977"
|
|
"FAB8DFDAD57C677E279615F4EAFA872CA8EFF83179E4DE2AB78E6B41A860C42203"
|
|
"4B875AC282406E03AC01F2E407A55DE38C6C35707F34B3319646FA016A01CE9056"
|
|
"E55D28C48ED72F10FA6625656ED62B758CBADA757DDC52533C9CBD54FC1A46F827"
|
|
"CC7B69BA66AE19A15D725FCBB972B23C83F95C0F00F481A7C9AC8687B3A4AD15AD"
|
|
"A2ABBB84D8E3CBEC3E8771720A35234070799173B37219127141922CBA8CB2DC48"
|
|
"EC2477832D1AE477942DCDA93C0886AF72D71E56DA3D7737E49670B024639A195B"
|
|
"7377C7F45A797C6E5DBB1BB2843DA3FC76043E33687BEF3172"),
|
|
OEMCrypto_FirstSubsample,
|
|
},
|
|
{
|
|
false, wvcdm::a2bs_hex("BB1BB2843DA3FC76043E33687BEF3172"),
|
|
wvcdm::a2bs_hex(
|
|
"64ab17b3e3dfab47245c7cce4543d4fc7a26dcf248f19f9b59f3c92601440b3617"
|
|
"c8ed0c96c656549e461f38708cd47a434066f8df28ccc28b79252eee3f9c2d7f6c"
|
|
"68ebe40141fe818fe082ca523c03d69ddaf183a93c022327fedc5582c5abca9d34"
|
|
"2b71263a67f9cb2336f12108aaaef464f17177e44e9b0c4e56e61da53c2150b440"
|
|
"5cc82d994dfd9bf4087c761956d6688a9705db4cf350381085f383c49666d4aed1"
|
|
"35c519c1f0b5cba06e287feea96ea367bf54e7368dcf998276c6e46497e0c50e20"
|
|
"fef74e42cb518fe7f22ef27202428688f86404e8278587017012c1d65537c6cbd7"
|
|
"dde04aae338d68115a9f430afc100ab83cdadf45dca39db685"),
|
|
wvcdm::a2bs_hex(
|
|
"5E61E95F918560A046682BB03CF3DBAB6E052150AEB3D46F458CF7480BF8F875E2"
|
|
"833367415656E4BA2B01421A0B18C18F802657573BF0B239173114AFE992BCD852"
|
|
"955301FAE562FC6BCC3AC89A4CA58BEC1BCCD07C89165DF77F29F42AE052858BA3"
|
|
"AC59A82652E6B432CB4993C707755C32EEF137111160A086CFC4FB15E5F76B1DAF"
|
|
"2E8217C51BDB4DE0B987288A68F88824DBD7BF4D2978147A4AE4DA019AAA2A59E9"
|
|
"94C294768D86FDADED52931E7ACEBC915C8124785E4BE9CE89BFFA631C3F5E67C4"
|
|
"EE5BA77A83B6E582DF2C1907FA572B61D656DCF9B8DEAE4B81508378732F952152"
|
|
"CF7DCAB0A3CA3EE8E5F72D24E96647EBBAAA2394BD6EC458EF"),
|
|
OEMCrypto_LastSubsample,
|
|
},
|
|
};
|
|
|
|
HlsSegmentInfo kAes128MultiSegmentInfo[] = {
|
|
{
|
|
true, wvcdm::a2bs_hex("9FBE45DD47DA7EBA09A3E24CBA95C9AF"),
|
|
wvcdm::a2bs_hex(
|
|
"AD868A6AC55C10D564FC23B8ACFF407DAAF4ED2743520E02CDA9680D9EA88E9148"
|
|
"84604C8DA8A53CE33DB9FF8F1C5BB6BB97F37B39906BF41596555C1BCCE9ED0293"
|
|
"59C4CF5906B6AB5BF60FBB3F1A1C7C59ACFC7E4FB4AD8E623C04D503A3DDAD868A"
|
|
"6AC55C10D564FC23B8ACFF407DAAF4ED2743520E02CDA9680D9EA88E918DF21FDC"
|
|
"42F166880D97A2225CD5C9EA5E7B752F4CF81BBDBE98E542EE10E1C6595D259A1E"
|
|
"4A8B6D7744CD98C5D3F921ADC252EB7D8AF6B916044B676A574747942AC20A89FF"
|
|
"79F4C2F25FBA99D6A44618A8C0420B27D54E3DA17B77C9D43CCA217CE9BDE99BD9"
|
|
"1E9733A1A00B9B557AC3A433DC92633546156817FAE26B6E1C"),
|
|
wvcdm::a2bs_hex(
|
|
"E7C566D86E98C36D2DCA54A966E7B469B6094B9201F200932F8EB5E1A94FB0B977"
|
|
"FAB8DFDAD57C677E279615F4EAFA872CA8EFF83179E4DE2AB78E6B41A860C42203"
|
|
"4B875AC282406E03AC01F2E407A55DE38C6C35707F34B3319646FA016A01CE9056"
|
|
"E55D28C48ED72F10FA6625656ED62B758CBADA757DDC52533C9CBD54FC1A46F827"
|
|
"CC7B69BA66AE19A15D725FCBB972B23C83F95C0F00F481A7C9AC8687B3A4AD15AD"
|
|
"A2ABBB84D8E3CBEC3E8771720A35234070799173B37219127141922CBA8CB2DC48"
|
|
"EC2477832D1AE477942DCDA93C0886AF72D71E56DA3D7737E49670B024639A195B"
|
|
"7377C7F45A797C6E5DBB1BB2843DA3FC76043E33687BEF3172"),
|
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample,
|
|
},
|
|
{
|
|
true, wvcdm::a2bs_hex("9FBE45DD47DA7EBA09A3E24CBA95C9AF"),
|
|
wvcdm::a2bs_hex(
|
|
"64AB17B3E3DFAB47245C7CCE4543D4FC7A26DCF248F19F9B59F3C92601440B3617"
|
|
"C8ED0C96C656549E461F38708CD47A434066F8DF28CCC28B79252EEE3F9C2D7F6C"
|
|
"68EBE40141FE818FE082CA523C03D69DDAF183A93C022327FEDC5582C5ABCA9D34"
|
|
"2B71263A67F9CB2336F12108AAAEF464F17177E44E9B0C4E56E61DA53C2150B440"
|
|
"5CC82D994DFD9BF4087C761956D6688A9705DB4CF350381085F383C49666D4AED1"
|
|
"35C519C1F0B5CBA06E287FEEA96EA367BF54E7368DCF998276C6E46497E0C50E20"
|
|
"FEF74E42CB518FE7F22EF27202428688F86404E8278587017012C1D65537C6CBD7"
|
|
"DDE04AAE338D68115A9F430AFC100AB83CDADF45DCA39DB685"),
|
|
wvcdm::a2bs_hex(
|
|
"BDA1AF662A108B3D34421B001E589A64E378CBE5386C17999F5C9E7079F52F56E3"
|
|
"EEC51C75BCD1C44FFE38709218C66B61A1CB8A7274E89F210D2D6C52905FC963DC"
|
|
"3F8D79B4EC016642AE3C8AF8D3E322A6EABE4761902D4D79FA3D2D7B827FC5797B"
|
|
"D909B5C14325643164915D528557F48A95EB3FD2437A7D553197559822AADE0A6A"
|
|
"A617729FCC58AAF581E78F7C332ED85F3470707E29AFF7BD9D8E785798311CA74C"
|
|
"C9FB1226EDF74A803B171A891DD56393FB1322D47988E1055095C5F35CF83DB5A3"
|
|
"940D329B51DDC89EC463712E9B32AEA8877AFE8C5BED67AE700FFC4CCEFFBC4021"
|
|
"0E7ECA01DFF357ADF4D73A80D2B0C46867B33A5605DFDBD06E"),
|
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample,
|
|
},
|
|
};
|
|
|
|
HlsSegmentInfo kSampleAes10ByteSegmentInfo[] = {
|
|
{
|
|
true, wvcdm::a2bs_hex("9FBE45DD47DA7EBA09A3E24CBA95C9AF"),
|
|
wvcdm::a2bs_hex("4884604C8DA8A53CE33D"),
|
|
wvcdm::a2bs_hex("4884604C8DA8A53CE33D"),
|
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample,
|
|
},
|
|
};
|
|
|
|
HlsSegmentInfo kSampleAes16ByteSegmentInfo[] = {
|
|
{
|
|
true, wvcdm::a2bs_hex("9FBE45DD47DA7EBA09A3E24CBA95C9AF"),
|
|
wvcdm::a2bs_hex("4884604C8DA8A53CE33DB9FF8F1C5BB6"),
|
|
wvcdm::a2bs_hex("8E6B884AB604495C675CA38F0425E23E"),
|
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample,
|
|
},
|
|
};
|
|
|
|
HlsSegmentInfo kSampleAes18ByteSegmentInfo[] = {
|
|
{
|
|
true, wvcdm::a2bs_hex("9FBE45DD47DA7EBA09A3E24CBA95C9AF"),
|
|
wvcdm::a2bs_hex("4884604C8DA8A53CE33DB9FF8F1C5BB6BB97"),
|
|
wvcdm::a2bs_hex("8E6B884AB604495C675CA38F0425E23EBB97"),
|
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample,
|
|
},
|
|
};
|
|
|
|
HlsSegmentInfo kSampleAes160ByteSegmentInfo[] = {
|
|
{
|
|
true, wvcdm::a2bs_hex("9FBE45DD47DA7EBA09A3E24CBA95C9AF"),
|
|
wvcdm::a2bs_hex("4884604C8DA8A53CE33DB9FF8F1C5BB6BB97F37B39906BF4159655"
|
|
"5C1BCCE9ED029359C4CF5906B6AB5BF60FBB3F1A1C7C59ACFC7E4F"
|
|
"B4AD8E623C04D503A3DDAD868A6AC55C10D564FC23B8ACFF407DAA"
|
|
"F4ED2743520E02CDA9680D9EA88E918DF21FDC42F166880D97A222"
|
|
"5CD5C9EA5E7B752F4CF81BBDBE98E542EE10E1C6595D259A1E4A8B"
|
|
"6D7744CD98C5D3F921ADC252EB7D8AF6B916044B676A574747"),
|
|
wvcdm::a2bs_hex("8E6B884AB604495C675CA38F0425E23EBB97F37B39906BF4159655"
|
|
"5C1BCCE9ED029359C4CF5906B6AB5BF60FBB3F1A1C7C59ACFC7E4F"
|
|
"B4AD8E623C04D503A3DDAD868A6AC55C10D564FC23B8ACFF407DAA"
|
|
"F4ED2743520E02CDA9680D9EA88E918DF21FDC42F166880D97A222"
|
|
"5CD5C9EA5E7B752F4CF81BBDBE98E542EE10E1C6595D259A1E4A8B"
|
|
"6D7744CD98C5D3F921ADC252EB7D8AF6B916044B676A574747"),
|
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample,
|
|
},
|
|
};
|
|
|
|
HlsSegmentInfo kSampleAes175ByteSegmentInfo[] = {
|
|
{
|
|
true, wvcdm::a2bs_hex("9FBE45DD47DA7EBA09A3E24CBA95C9AF"),
|
|
wvcdm::a2bs_hex(
|
|
"4884604C8DA8A53CE33DB9FF8F1C5BB6BB97F37B39906BF41596555C1BCC"
|
|
"E9ED029359C4CF5906B6AB5BF60FBB3F1A1C7C59ACFC7E4FB4AD8E623C04"
|
|
"D503A3DDAD868A6AC55C10D564FC23B8ACFF407DAAF4ED2743520E02CDA9"
|
|
"680D9EA88E918DF21FDC42F166880D97A2225CD5C9EA5E7B752F4CF81BBD"
|
|
"BE98E542EE10E1C6595D259A1E4A8B6D7744CD98C5D3F921ADC252EB7D8A"
|
|
"F6B916044B676A574747942AC20A89FF79F4C2F25FBA99D6A4"),
|
|
wvcdm::a2bs_hex("8E6B884AB604495C675CA38F0425E23EBB97F37B39906BF4159655"
|
|
"5C1BCCE9ED029359C4CF5906B6AB5BF60FBB3F1A1C7C59ACFC7E4F"
|
|
"B4AD8E623C04D503A3DDAD868A6AC55C10D564FC23B8ACFF407DAA"
|
|
"F4ED2743520E02CDA9680D9EA88E918DF21FDC42F166880D97A222"
|
|
"5CD5C9EA5E7B752F4CF81BBDBE98E542EE10E1C6595D259A1E4A8B"
|
|
"6D7744CD98C5D3F921ADC252EB7D8AF6B916044B676A574747942A"
|
|
"C20A89FF79F4C2F25FBA99D6A4"),
|
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample,
|
|
},
|
|
};
|
|
|
|
HlsSegmentInfo kSampleAes176ByteSegmentInfo[] = {
|
|
{
|
|
true, wvcdm::a2bs_hex("9FBE45DD47DA7EBA09A3E24CBA95C9AF"),
|
|
wvcdm::a2bs_hex(
|
|
"4884604C8DA8A53CE33DB9FF8F1C5BB6BB97F37B39906BF41596555C1BCC"
|
|
"E9ED029359C4CF5906B6AB5BF60FBB3F1A1C7C59ACFC7E4FB4AD8E623C04"
|
|
"D503A3DDAD868A6AC55C10D564FC23B8ACFF407DAAF4ED2743520E02CDA9"
|
|
"680D9EA88E918DF21FDC42F166880D97A2225CD5C9EA5E7B752F4CF81BBD"
|
|
"BE98E542EE10E1C6595D259A1E4A8B6D7744CD98C5D3F921ADC252EB7D8A"
|
|
"F6B916044B676A574747942AC20A89FF79F4C2F25FBA99D6A446"),
|
|
wvcdm::a2bs_hex("8E6B884AB604495C675CA38F0425E23EBB97F37B39906BF4159655"
|
|
"5C1BCCE9ED029359C4CF5906B6AB5BF60FBB3F1A1C7C59ACFC7E4F"
|
|
"B4AD8E623C04D503A3DDAD868A6AC55C10D564FC23B8ACFF407DAA"
|
|
"F4ED2743520E02CDA9680D9EA88E918DF21FDC42F166880D97A222"
|
|
"5CD5C9EA5E7B752F4CF81BBDBE98E542EE10E1C6595D259A1E4A8B"
|
|
"6D7744CD98C5D3F921ADC252EB7D8AF6B916044B676A574747FBDC"
|
|
"189C42C3C213A71DBCF73A05A1A1"),
|
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample,
|
|
},
|
|
};
|
|
|
|
HlsSegmentInfo kSampleAes192ByteSegmentInfo[] = {
|
|
{
|
|
true, wvcdm::a2bs_hex("9FBE45DD47DA7EBA09A3E24CBA95C9AF"),
|
|
wvcdm::a2bs_hex(
|
|
"4884604C8DA8A53CE33DB9FF8F1C5BB6BB97F37B39906BF41596555C1BCCE9ED02"
|
|
"9359C4CF5906B6AB5BF60FBB3F1A1C7C59ACFC7E4FB4AD8E623C04D503A3DDAD86"
|
|
"8A6AC55C10D564FC23B8ACFF407DAAF4ED2743520E02CDA9680D9EA88E918DF21F"
|
|
"DC42F166880D97A2225CD5C9EA5E7B752F4CF81BBDBE98E542EE10E1C6595D259A"
|
|
"1E4A8B6D7744CD98C5D3F921ADC252EB7D8AF6B916044B676A574747942AC20A89"
|
|
"FF79F4C2F25FBA99D6A44618A8C0420B27D54E3DA17B77C9D43CCA"),
|
|
wvcdm::a2bs_hex(
|
|
"8E6B884AB604495C675CA38F0425E23EBB97F37B39906BF41596555C1BCCE9ED02"
|
|
"9359C4CF5906B6AB5BF60FBB3F1A1C7C59ACFC7E4FB4AD8E623C04D503A3DDAD86"
|
|
"8A6AC55C10D564FC23B8ACFF407DAAF4ED2743520E02CDA9680D9EA88E918DF21F"
|
|
"DC42F166880D97A2225CD5C9EA5E7B752F4CF81BBDBE98E542EE10E1C6595D259A"
|
|
"1E4A8B6D7744CD98C5D3F921ADC252EB7D8AF6B916044B676A574747FBDC189C42"
|
|
"C3C213A71DBCF73A05A1A118A8C0420B27D54E3DA17B77C9D43CCA"),
|
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample,
|
|
},
|
|
};
|
|
|
|
HlsSegmentInfo kSampleAes338ByteSegmentInfo[] = {
|
|
{
|
|
true, wvcdm::a2bs_hex("9FBE45DD47DA7EBA09A3E24CBA95C9AF"),
|
|
wvcdm::a2bs_hex(
|
|
"4884604C8DA8A53CE33DB9FF8F1C5BB6BB97F37B39906BF41596555C1BCCE9ED02"
|
|
"9359C4CF5906B6AB5BF60FBB3F1A1C7C59ACFC7E4FB4AD8E623C04D503A3DDAD86"
|
|
"8A6AC55C10D564FC23B8ACFF407DAAF4ED2743520E02CDA9680D9EA88E918DF21F"
|
|
"DC42F166880D97A2225CD5C9EA5E7B752F4CF81BBDBE98E542EE10E1C6595D259A"
|
|
"1E4A8B6D7744CD98C5D3F921ADC252EB7D8AF6B916044B676A574747942AC20A89"
|
|
"FF79F4C2F25FBA99D6A44618A8C0420B27D54E3DA17B77C9D43CCA217CE9BDE99B"
|
|
"D91E9733A1A00B9B557AC3A433DC92633546156817FAE26B6E1C942AC20A89FF79"
|
|
"F4C2F25FBA99D6A44618A8C0420B27D54E3DA17B77C9D43CCAE7C566D86E98C36D"
|
|
"2DCA54A966E7B469B6094B9201F200932F8EB5E1A94FB0B977FAB8DFDAD57C677E"
|
|
"279615F4EAFA872CA8EFF83179E4DE2AB78E6B41A860C422034B875AC282406E03"
|
|
"AC01F2E407A55DE3"),
|
|
wvcdm::a2bs_hex(
|
|
"8E6B884AB604495C675CA38F0425E23EBB97F37B39906BF41596555C1BCCE9ED02"
|
|
"9359C4CF5906B6AB5BF60FBB3F1A1C7C59ACFC7E4FB4AD8E623C04D503A3DDAD86"
|
|
"8A6AC55C10D564FC23B8ACFF407DAAF4ED2743520E02CDA9680D9EA88E918DF21F"
|
|
"DC42F166880D97A2225CD5C9EA5E7B752F4CF81BBDBE98E542EE10E1C6595D259A"
|
|
"1E4A8B6D7744CD98C5D3F921ADC252EB7D8AF6B916044B676A574747FBDC189C42"
|
|
"C3C213A71DBCF73A05A1A118A8C0420B27D54E3DA17B77C9D43CCA217CE9BDE99B"
|
|
"D91E9733A1A00B9B557AC3A433DC92633546156817FAE26B6E1C942AC20A89FF79"
|
|
"F4C2F25FBA99D6A44618A8C0420B27D54E3DA17B77C9D43CCAE7C566D86E98C36D"
|
|
"2DCA54A966E7B469B6094B9201F200932F8EB5E1A94FB0B977FAB8DFDAD57C677E"
|
|
"279615F4EAFA872CA8EFF83179E4DE2AB78E6B41A860C44A27BD03EAB2D3CFCB2C"
|
|
"F4F5AA93E7025DE3"),
|
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample,
|
|
},
|
|
};
|
|
|
|
struct HlsDecryptionInfo {
|
|
bool sample_aes;
|
|
size_t number_of_segments;
|
|
HlsSegmentInfo* segment_info;
|
|
const std::string& attribute_list;
|
|
};
|
|
|
|
HlsDecryptionInfo kHlsDecryptionTestVectors[] = {
|
|
{false, 1, &kAes128SingleSegmentInfo[0], kAttributeListAes128},
|
|
{false, 2, &kAes128PartialSegmentInfo[0], kAttributeListAes128},
|
|
{false, 2, &kAes128MultiSegmentInfo[0], kAttributeListAes128},
|
|
{true, 1, &kSampleAes10ByteSegmentInfo[0], kAttributeListSampleAes},
|
|
{true, 1, &kSampleAes16ByteSegmentInfo[0], kAttributeListSampleAes},
|
|
{true, 1, &kSampleAes18ByteSegmentInfo[0], kAttributeListSampleAes},
|
|
{true, 1, &kSampleAes160ByteSegmentInfo[0], kAttributeListSampleAes},
|
|
{true, 1, &kSampleAes175ByteSegmentInfo[0], kAttributeListSampleAes},
|
|
{true, 1, &kSampleAes176ByteSegmentInfo[0], kAttributeListSampleAes},
|
|
{true, 1, &kSampleAes192ByteSegmentInfo[0], kAttributeListSampleAes},
|
|
{true, 1, &kSampleAes338ByteSegmentInfo[0], kAttributeListSampleAes},
|
|
};
|
|
|
|
const std::string kHlsPsshAes128LittleEndianFourCC = wvcdm::a2bs_hex(
|
|
"00000060" // blob size
|
|
"70737368" // "pssh"
|
|
"00000000" // flags
|
|
"edef8ba979d64acea3c827dcd51d21ed" // Widevine system id
|
|
"00000040" // pssh data size
|
|
// pssh data:
|
|
"08011210AB6531FF6E6EA15E387B019E"
|
|
"59C2DE0A1A0D7769646576696E655F74"
|
|
"6573742215686C735F6165735F313238"
|
|
"5F73747265616D696E6748E3C48D8B03");
|
|
const std::string kHlsPsshSampleAesLittleEndianFourCC = wvcdm::a2bs_hex(
|
|
"00000063" // blob size
|
|
"70737368" // "pssh"
|
|
"00000000" // flags
|
|
"edef8ba979d64acea3c827dcd51d21ed" // Widevine system id
|
|
"00000043" // pssh data size
|
|
// pssh data:
|
|
"08011210613DB35603320EB8E7EA24BD"
|
|
"EEA3FDB81A0D7769646576696E655F74"
|
|
"6573742218686C735F73616D706C655F"
|
|
"6165735F73747265616D696E6748E3C4"
|
|
"8D9B07");
|
|
const std::string kHlsPsshAes128FourCC = wvcdm::a2bs_hex(
|
|
"00000060" // blob size
|
|
"70737368" // "pssh"
|
|
"00000000" // flags
|
|
"edef8ba979d64acea3c827dcd51d21ed" // Widevine system id
|
|
"00000040" // pssh data size
|
|
// pssh data:
|
|
"08011210AB6531FF6E6EA15E387B019E"
|
|
"59C2DE0A1A0D7769646576696E655F74"
|
|
"6573742215686C735F6165735F313238"
|
|
"5F73747265616D696E6748B1C6899B06");
|
|
const std::string kHlsPsshSampleAesFourCC = wvcdm::a2bs_hex(
|
|
"00000063" // blob size
|
|
"70737368" // "pssh"
|
|
"00000000" // flags
|
|
"edef8ba979d64acea3c827dcd51d21ed" // Widevine system id
|
|
"00000043" // pssh data size
|
|
// pssh data:
|
|
"08011210613DB35603320EB8E7EA24BD"
|
|
"EEA3FDB81A0D7769646576696E655F74"
|
|
"6573742218686C735F73616D706C655F"
|
|
"6165735F73747265616D696E6748F3C6"
|
|
"899B06");
|
|
|
|
HlsDecryptionInfo kHlsFourCCBackwardCompatibilityTestVectors[] = {
|
|
{false, 2, &kAes128MultiSegmentInfo[0], kHlsPsshAes128LittleEndianFourCC},
|
|
{true, 1, &kSampleAes160ByteSegmentInfo[0],
|
|
kHlsPsshSampleAesLittleEndianFourCC},
|
|
{false, 2, &kAes128MultiSegmentInfo[0], kHlsPsshAes128FourCC},
|
|
{true, 1, &kSampleAes160ByteSegmentInfo[0], kHlsPsshSampleAesFourCC},
|
|
};
|
|
|
|
} // namespace
|
|
|
|
namespace wvcdm {
|
|
// Protobuf generated classes
|
|
using video_widevine::ClientIdentification;
|
|
using video_widevine::ClientIdentification_NameValue;
|
|
using video_widevine::SignedMessage;
|
|
|
|
class TestWvCdmClientPropertySet : public CdmClientPropertySet {
|
|
public:
|
|
TestWvCdmClientPropertySet()
|
|
: use_privacy_mode_(false),
|
|
is_session_sharing_enabled_(false),
|
|
session_sharing_id_(0) {}
|
|
virtual ~TestWvCdmClientPropertySet() {}
|
|
|
|
virtual const std::string& app_id() const { return app_id_; }
|
|
virtual const std::string& security_level() const { return security_level_; }
|
|
virtual const std::string& service_certificate() const {
|
|
return service_certificate_;
|
|
}
|
|
virtual void set_service_certificate(const std::string& cert) {
|
|
service_certificate_ = cert;
|
|
}
|
|
virtual bool use_privacy_mode() const { return use_privacy_mode_; }
|
|
virtual bool is_session_sharing_enabled() const {
|
|
return is_session_sharing_enabled_;
|
|
}
|
|
virtual uint32_t session_sharing_id() const { return session_sharing_id_; }
|
|
|
|
void set_app_id(const std::string& app_id) { app_id_ = app_id; }
|
|
void set_security_level(const std::string& security_level) {
|
|
if (!security_level.compare(QUERY_VALUE_SECURITY_LEVEL_L1) ||
|
|
!security_level.compare(QUERY_VALUE_SECURITY_LEVEL_L3)) {
|
|
security_level_ = security_level;
|
|
}
|
|
}
|
|
void set_use_privacy_mode(bool use_privacy_mode) {
|
|
use_privacy_mode_ = use_privacy_mode;
|
|
}
|
|
void set_session_sharing_mode(bool enable) {
|
|
is_session_sharing_enabled_ = enable;
|
|
}
|
|
void set_session_sharing_id(uint32_t id) { session_sharing_id_ = id; }
|
|
|
|
private:
|
|
std::string app_id_;
|
|
std::string security_level_;
|
|
std::string service_certificate_;
|
|
bool use_privacy_mode_;
|
|
bool is_session_sharing_enabled_;
|
|
uint32_t session_sharing_id_;
|
|
};
|
|
|
|
class TestWvCdmEventListener : public WvCdmEventListener {
|
|
public:
|
|
TestWvCdmEventListener() : WvCdmEventListener() {}
|
|
MOCK_METHOD1(OnSessionRenewalNeeded, void(const CdmSessionId& session_id));
|
|
MOCK_METHOD3(OnSessionKeysChange, void(const CdmSessionId& session_id,
|
|
const CdmKeyStatusMap& keys_status,
|
|
bool has_new_usable_key));
|
|
MOCK_METHOD2(OnExpirationUpdate, void(const CdmSessionId& session_id,
|
|
int64_t new_expiry_time_seconds));
|
|
};
|
|
|
|
class DecryptCallbackTester {
|
|
public:
|
|
DecryptCallbackTester(wvcdm::WvContentDecryptionModule* decryptor,
|
|
SubSampleInfo* sub_sample_info)
|
|
: decryptor_(decryptor),
|
|
sub_sample_info_(sub_sample_info) {}
|
|
|
|
void Decrypt(const CdmSessionId& session_id,
|
|
const CdmKeyStatusMap& /* keys_status */,
|
|
bool /* has_new_usable_key */) {
|
|
EXPECT_TRUE(decryptor_ != NULL);
|
|
EXPECT_TRUE(sub_sample_info_ != NULL);
|
|
|
|
std::vector<uint8_t> decrypt_buffer(sub_sample_info_->encrypt_data.size());
|
|
CdmDecryptionParameters decryption_parameters(
|
|
&sub_sample_info_->key_id, &sub_sample_info_->encrypt_data.front(),
|
|
sub_sample_info_->encrypt_data.size(), &sub_sample_info_->iv,
|
|
sub_sample_info_->block_offset, &decrypt_buffer[0]);
|
|
decryption_parameters.is_encrypted = sub_sample_info_->is_encrypted;
|
|
decryption_parameters.is_secure = sub_sample_info_->is_secure;
|
|
decryption_parameters.subsample_flags = sub_sample_info_->subsample_flags;
|
|
EXPECT_EQ(NO_ERROR, decryptor_->Decrypt(session_id,
|
|
sub_sample_info_->validate_key_id,
|
|
decryption_parameters));
|
|
|
|
}
|
|
private:
|
|
wvcdm::WvContentDecryptionModule* decryptor_;
|
|
SubSampleInfo* sub_sample_info_;
|
|
};
|
|
|
|
class TestWvCdmHlsEventListener : public WvCdmEventListener {
|
|
public:
|
|
TestWvCdmHlsEventListener() : WvCdmEventListener() {}
|
|
virtual void OnSessionRenewalNeeded(const CdmSessionId&) {}
|
|
virtual void OnSessionKeysChange(const CdmSessionId&,
|
|
const CdmKeyStatusMap& keys_status,
|
|
bool) {
|
|
key_status_map_ = keys_status;
|
|
}
|
|
|
|
virtual void OnExpirationUpdate(const CdmSessionId&,
|
|
int64_t) {}
|
|
|
|
CdmKeyStatusMap GetKeyStatusMap() { return key_status_map_; }
|
|
private:
|
|
CdmKeyStatusMap key_status_map_;
|
|
};
|
|
|
|
class WvCdmRequestLicenseTest : public WvCdmTestBase {
|
|
public:
|
|
WvCdmRequestLicenseTest() : license_type_(kLicenseTypeStreaming) {}
|
|
~WvCdmRequestLicenseTest() {}
|
|
|
|
protected:
|
|
void GetOfflineConfiguration(std::string* key_id, std::string* client_auth) {
|
|
ConfigTestEnv config(g_server_configuration_id, false);
|
|
if (g_key_id.compare(a2bs_hex(g_config->key_id())) == 0)
|
|
key_id->assign(wvcdm::a2bs_hex(config.key_id()));
|
|
else
|
|
key_id->assign(g_key_id);
|
|
|
|
if (g_client_auth.compare(g_config->client_auth()) == 0)
|
|
client_auth->assign(config.client_auth());
|
|
else
|
|
client_auth->assign(g_client_auth);
|
|
}
|
|
|
|
void GenerateKeyRequest(const std::string& init_data,
|
|
CdmLicenseType license_type) {
|
|
GenerateKeyRequest(init_data, license_type, NULL);
|
|
}
|
|
|
|
void GenerateKeyRequest(const std::string& init_data,
|
|
CdmLicenseType license_type,
|
|
CdmClientPropertySet* property_set) {
|
|
CdmAppParameterMap app_parameters;
|
|
GenerateKeyRequest(init_data, app_parameters, license_type, property_set);
|
|
}
|
|
|
|
void GenerateKeyRequest(const std::string& init_data,
|
|
CdmAppParameterMap& app_parameters,
|
|
CdmLicenseType license_type,
|
|
CdmClientPropertySet* property_set) {
|
|
std::string init_data_type = "video/mp4";
|
|
GenerateKeyRequest(wvcdm::KEY_MESSAGE, init_data_type, init_data,
|
|
app_parameters, license_type, property_set);
|
|
}
|
|
|
|
void GenerateKeyRequest(CdmResponseType expected_response,
|
|
const std::string& init_data_type,
|
|
const std::string& init_data,
|
|
CdmAppParameterMap& app_parameters,
|
|
CdmLicenseType license_type,
|
|
CdmClientPropertySet* property_set) {
|
|
CdmKeyRequest key_request;
|
|
std::string key_set_id;
|
|
license_type_ = license_type;
|
|
EXPECT_EQ(expected_response,
|
|
decryptor_.GenerateKeyRequest(
|
|
session_id_, key_set_id, init_data_type, init_data,
|
|
license_type, app_parameters, property_set,
|
|
kDefaultCdmIdentifier, &key_request));
|
|
key_msg_ = key_request.message;
|
|
EXPECT_EQ(0u, key_request.url.size());
|
|
}
|
|
|
|
void GenerateRenewalRequest(CdmLicenseType license_type,
|
|
CdmKeyMessage* key_msg, std::string* server_url) {
|
|
GenerateRenewalRequest(license_type, server_url);
|
|
*key_msg = key_msg_;
|
|
}
|
|
|
|
void GenerateRenewalRequest(CdmLicenseType license_type,
|
|
std::string* server_url) {
|
|
// TODO application makes a license request, CDM will renew the license
|
|
// when appropriate.
|
|
std::string init_data;
|
|
wvcdm::CdmAppParameterMap app_parameters;
|
|
wvcdm::CdmKeyRequestType key_request_type;
|
|
CdmKeyRequest key_request;
|
|
EXPECT_EQ(wvcdm::KEY_MESSAGE,
|
|
decryptor_.GenerateKeyRequest(
|
|
session_id_, key_set_id_, "video/mp4", init_data,
|
|
license_type, app_parameters, NULL, kDefaultCdmIdentifier,
|
|
&key_request));
|
|
key_msg_ = key_request.message;
|
|
*server_url = key_request.url;
|
|
EXPECT_EQ(kKeyRequestTypeRenewal, key_request.type);
|
|
// TODO(edwinwong, rfrias): Add tests cases for when license server url
|
|
// is empty on renewal. Need appropriate key id at the server.
|
|
EXPECT_NE(0u, key_request.url.size());
|
|
}
|
|
|
|
void GenerateKeyRelease(CdmKeySetId key_set_id) {
|
|
GenerateKeyRelease(key_set_id, NULL, NULL);
|
|
}
|
|
|
|
void GenerateKeyRelease(CdmKeySetId key_set_id,
|
|
CdmClientPropertySet* property_set,
|
|
CdmKeyMessage* key_msg) {
|
|
license_type_ = kLicenseTypeRelease;
|
|
CdmSessionId session_id;
|
|
CdmInitData init_data;
|
|
wvcdm::CdmAppParameterMap app_parameters;
|
|
CdmKeyRequest key_request;
|
|
EXPECT_EQ(wvcdm::KEY_MESSAGE,
|
|
decryptor_.GenerateKeyRequest(
|
|
session_id, key_set_id, "video/mp4", init_data,
|
|
kLicenseTypeRelease, app_parameters, property_set,
|
|
kDefaultCdmIdentifier, &key_request));
|
|
key_msg_ = key_request.message;
|
|
EXPECT_EQ(kKeyRequestTypeRelease, key_request.type);
|
|
if (key_msg) *key_msg = key_request.message;
|
|
}
|
|
|
|
void LogResponseError(const std::string& message, int http_status_code) {
|
|
LOGD("HTTP Status code = %d", http_status_code);
|
|
LOGD("HTTP response(%d): %s", message.size(), b2a_hex(message).c_str());
|
|
}
|
|
|
|
// Post a request and extract the drm message from the response
|
|
std::string GetKeyRequestResponse(const std::string& server_url,
|
|
const std::string& client_auth) {
|
|
// Use secure connection and chunk transfer coding.
|
|
UrlRequest url_request(server_url + client_auth);
|
|
EXPECT_TRUE(url_request.is_connected()) << "Fail to connect to "
|
|
<< server_url << client_auth;
|
|
url_request.PostRequest(key_msg_);
|
|
std::string message;
|
|
EXPECT_TRUE(url_request.GetResponse(&message));
|
|
|
|
int http_status_code = url_request.GetStatusCode(message);
|
|
if (kHttpOk != http_status_code) {
|
|
LogResponseError(message, http_status_code);
|
|
}
|
|
EXPECT_EQ(kHttpOk, http_status_code);
|
|
|
|
std::string drm_msg;
|
|
if (kHttpOk == http_status_code) {
|
|
LicenseRequest lic_request;
|
|
lic_request.GetDrmMessage(message, drm_msg);
|
|
LOGV("HTTP response body: (%u bytes)", drm_msg.size());
|
|
}
|
|
return drm_msg;
|
|
}
|
|
|
|
// Post a request and extract the signed provisioning message from
|
|
// the HTTP response.
|
|
std::string GetCertRequestResponse(const std::string& server_url) {
|
|
// Use secure connection and chunk transfer coding.
|
|
UrlRequest url_request(server_url);
|
|
EXPECT_TRUE(url_request.is_connected()) << "Fail to connect to "
|
|
<< server_url;
|
|
url_request.PostCertRequestInQueryString(key_msg_);
|
|
std::string message;
|
|
EXPECT_TRUE(url_request.GetResponse(&message));
|
|
|
|
int http_status_code = url_request.GetStatusCode(message);
|
|
if (kHttpOk != http_status_code) {
|
|
LogResponseError(message, http_status_code);
|
|
}
|
|
EXPECT_EQ(kHttpOk, http_status_code);
|
|
return message;
|
|
}
|
|
|
|
// Post a request and extract the signed provisioning message from
|
|
// the HTTP response.
|
|
std::string GetUsageInfoResponse(const std::string& server_url,
|
|
const std::string& client_auth,
|
|
const std::string& usage_info_request) {
|
|
// Use secure connection and chunk transfer coding.
|
|
UrlRequest url_request(server_url + client_auth);
|
|
EXPECT_TRUE(url_request.is_connected()) << "Fail to connect to "
|
|
<< server_url << client_auth;
|
|
url_request.PostRequest(usage_info_request);
|
|
std::string message;
|
|
EXPECT_TRUE(url_request.GetResponse(&message));
|
|
|
|
int http_status_code = url_request.GetStatusCode(message);
|
|
if (kHttpOk != http_status_code) {
|
|
LogResponseError(message, http_status_code);
|
|
}
|
|
EXPECT_EQ(kHttpOk, http_status_code);
|
|
|
|
std::string usage_info;
|
|
if (kHttpOk == http_status_code) {
|
|
LicenseRequest license;
|
|
license.GetDrmMessage(message, usage_info);
|
|
LOGV("HTTP response body: (%u bytes)", usage_info.size());
|
|
}
|
|
return usage_info;
|
|
}
|
|
|
|
void VerifyKeyRequestResponse(const std::string& server_url,
|
|
const std::string& client_auth) {
|
|
std::string response;
|
|
VerifyKeyRequestResponse(server_url, client_auth, false);
|
|
}
|
|
|
|
void VerifyUsageKeyRequestResponse(const std::string& server_url,
|
|
const std::string& client_auth) {
|
|
std::string response;
|
|
VerifyKeyRequestResponse(server_url, client_auth, true);
|
|
}
|
|
|
|
void VerifyKeyRequestResponse(const std::string& server_url,
|
|
const std::string& client_auth,
|
|
bool is_usage) {
|
|
std::string response;
|
|
VerifyKeyRequestResponse(server_url, client_auth, is_usage, &response);
|
|
}
|
|
|
|
void VerifyKeyRequestResponse(const std::string& server_url,
|
|
const std::string& client_auth,
|
|
bool is_usage,
|
|
std::string* response) {
|
|
*response = GetKeyRequestResponse(server_url, client_auth);
|
|
|
|
EXPECT_EQ(decryptor_.AddKey(session_id_, *response, &key_set_id_),
|
|
wvcdm::KEY_ADDED);
|
|
EXPECT_EQ(is_usage || license_type_ == kLicenseTypeOffline,
|
|
key_set_id_.size() > 0);
|
|
}
|
|
|
|
void Unprovision() {
|
|
EXPECT_EQ(NO_ERROR,
|
|
decryptor_.Unprovision(kSecurityLevelL1, kDefaultCdmIdentifier));
|
|
EXPECT_EQ(NO_ERROR,
|
|
decryptor_.Unprovision(kSecurityLevelL3, kDefaultCdmIdentifier));
|
|
}
|
|
|
|
void Provision(SecurityLevel level) {
|
|
Provision(kDefaultCdmIdentifier, level);
|
|
}
|
|
|
|
void Provision(const CdmIdentifier& identifier, SecurityLevel level) {
|
|
TestWvCdmClientPropertySet property_set_L3;
|
|
TestWvCdmClientPropertySet* property_set = NULL;
|
|
|
|
if (kLevel3 == level) {
|
|
property_set_L3.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
|
|
property_set = &property_set_L3;
|
|
}
|
|
|
|
CdmResponseType status = decryptor_.OpenSession(
|
|
g_key_system, property_set, identifier, NULL, &session_id_);
|
|
switch (status) {
|
|
case NO_ERROR:
|
|
decryptor_.CloseSession(session_id_);
|
|
return;
|
|
case NEED_PROVISIONING:
|
|
break;
|
|
default:
|
|
EXPECT_EQ(NO_ERROR, status);
|
|
return;
|
|
}
|
|
|
|
std::string provisioning_server;
|
|
CdmCertificateType cert_type = kCertificateWidevine;
|
|
std::string cert_authority, cert, wrapped_key;
|
|
|
|
status = decryptor_.GetProvisioningRequest(cert_type, cert_authority,
|
|
identifier, &key_msg_,
|
|
&provisioning_server);
|
|
EXPECT_EQ(wvcdm::NO_ERROR, status);
|
|
if (NO_ERROR != status) return;
|
|
EXPECT_EQ(provisioning_server, g_config->provisioning_server());
|
|
|
|
std::string response =
|
|
GetCertRequestResponse(g_config->provisioning_server());
|
|
EXPECT_NE(0, static_cast<int>(response.size()));
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.HandleProvisioningResponse(identifier, response,
|
|
&cert, &wrapped_key));
|
|
EXPECT_EQ(0, static_cast<int>(cert.size()));
|
|
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
|
|
decryptor_.CloseSession(session_id_);
|
|
return;
|
|
}
|
|
|
|
std::string GetSecurityLevel(TestWvCdmClientPropertySet* property_set) {
|
|
EXPECT_EQ(NO_ERROR,
|
|
decryptor_.OpenSession(g_key_system, property_set,
|
|
kDefaultCdmIdentifier, NULL,
|
|
&session_id_));
|
|
CdmQueryMap query_info;
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QuerySessionStatus(session_id_, &query_info));
|
|
CdmQueryMap::iterator itr =
|
|
query_info.find(wvcdm::QUERY_KEY_SECURITY_LEVEL);
|
|
EXPECT_TRUE(itr != query_info.end());
|
|
decryptor_.CloseSession(session_id_);
|
|
if (itr != query_info.end()) {
|
|
return itr->second;
|
|
} else {
|
|
return "ERROR";
|
|
}
|
|
}
|
|
|
|
CdmSecurityLevel GetDefaultSecurityLevel() {
|
|
std::string level = GetSecurityLevel(NULL).c_str();
|
|
CdmSecurityLevel security_level = kSecurityLevelUninitialized;
|
|
if (level.compare(wvcdm::QUERY_VALUE_SECURITY_LEVEL_L1) == 0) {
|
|
security_level = kSecurityLevelL1;
|
|
} else if (level.compare(wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3) == 0) {
|
|
security_level = kSecurityLevelL3;
|
|
} else {
|
|
EXPECT_TRUE(false) << "Default Security level is undefined: " << level;
|
|
}
|
|
return security_level;
|
|
}
|
|
|
|
uint32_t QueryStatus(SecurityLevel security_level, const std::string& key) {
|
|
std::string str;
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(security_level, key, &str));
|
|
|
|
std::istringstream ss(str);
|
|
uint32_t value;
|
|
ss >> value;
|
|
EXPECT_FALSE(ss.fail());
|
|
EXPECT_TRUE(ss.eof());
|
|
return value;
|
|
}
|
|
|
|
wvcdm::WvContentDecryptionModule decryptor_;
|
|
CdmKeyMessage key_msg_;
|
|
CdmSessionId session_id_;
|
|
CdmKeySetId key_set_id_;
|
|
CdmLicenseType license_type_;
|
|
};
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, ProvisioningTest) {
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
std::string provisioning_server;
|
|
CdmCertificateType cert_type = kCertificateWidevine;
|
|
std::string cert_authority, cert, wrapped_key;
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest(
|
|
cert_type, cert_authority,
|
|
kDefaultCdmIdentifier, &key_msg_,
|
|
&provisioning_server));
|
|
EXPECT_EQ(provisioning_server, g_config->provisioning_server());
|
|
|
|
std::string response =
|
|
GetCertRequestResponse(g_config->provisioning_server());
|
|
EXPECT_NE(0, static_cast<int>(response.size()));
|
|
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.HandleProvisioningResponse(
|
|
kDefaultCdmIdentifier, response, &cert,
|
|
&wrapped_key));
|
|
EXPECT_EQ(0, static_cast<int>(cert.size()));
|
|
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, PerOriginProvisioningTest) {
|
|
EXPECT_EQ(NO_ERROR,
|
|
decryptor_.Unprovision(kSecurityLevelL3, kExampleIdentifier));
|
|
|
|
// Verify the global identifier is provisioned.
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier,
|
|
NULL, &session_id_));
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
// The other identifier should not be provisioned.
|
|
EXPECT_EQ(
|
|
wvcdm::NEED_PROVISIONING,
|
|
decryptor_.OpenSession(g_key_system, NULL, kExampleIdentifier, NULL,
|
|
&session_id_));
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, PerOriginProvisioningSupportsOldPaths) {
|
|
// This is the current file name scheme. This test exists to ensure we do
|
|
// not break existing clients if we decide to change the naming/paths of
|
|
// certificates.
|
|
const char kOldFileName[] = "cert0LF0GfM75iqlNA_sByaQMA==.bin";
|
|
ASSERT_EQ("com.example", kExampleIdentifier.origin);
|
|
|
|
// Unprovision the device and delete all files.
|
|
EXPECT_EQ(NO_ERROR,
|
|
decryptor_.Unprovision(kSecurityLevelL3, kExampleIdentifier));
|
|
EXPECT_EQ(NO_ERROR,
|
|
decryptor_.Unprovision(kSecurityLevelL3, kDefaultCdmIdentifier));
|
|
Provision(kExampleIdentifier, kLevel3);
|
|
|
|
std::string base_path;
|
|
ASSERT_TRUE(Properties::GetDeviceFilesBasePath(kSecurityLevelL3, &base_path));
|
|
|
|
// Make sure that the cert exists.
|
|
std::vector<std::string> files;
|
|
ASSERT_TRUE(FileUtils::List(base_path, &files));
|
|
ASSERT_LE(1u, files.size());
|
|
bool found_it = false;
|
|
for(std::string file: files) {
|
|
if (file == std::string(kOldFileName)) found_it = true;
|
|
}
|
|
EXPECT_TRUE(found_it);
|
|
|
|
// Reprovision the default identifier.
|
|
Provision(kDefaultCdmIdentifier, kLevel3);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, UnprovisionTest) {
|
|
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
|
|
FileSystem file_system;
|
|
DeviceFiles handle(&file_system);
|
|
EXPECT_TRUE(handle.Init(security_level));
|
|
std::string certificate;
|
|
std::string wrapped_private_key;
|
|
std::string serial_number;
|
|
uint32_t system_id;
|
|
EXPECT_TRUE(handle.RetrieveCertificate(&certificate, &wrapped_private_key,
|
|
&serial_number, &system_id));
|
|
|
|
EXPECT_EQ(NO_ERROR,
|
|
decryptor_.Unprovision(security_level, kDefaultCdmIdentifier));
|
|
EXPECT_FALSE(handle.RetrieveCertificate(&certificate, &wrapped_private_key,
|
|
&serial_number, &system_id));
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, ProvisioningInterposedRetryTest) {
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
std::string provisioning_server;
|
|
CdmCertificateType cert_type = kCertificateWidevine;
|
|
std::string cert_authority, cert, wrapped_key;
|
|
CdmKeyMessage key_msg1, key_msg2;
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest(
|
|
cert_type, cert_authority,
|
|
kDefaultCdmIdentifier, &key_msg1,
|
|
&provisioning_server));
|
|
EXPECT_EQ(provisioning_server, g_config->provisioning_server());
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest(
|
|
cert_type, cert_authority,
|
|
kDefaultCdmIdentifier, &key_msg2,
|
|
&provisioning_server));
|
|
EXPECT_EQ(provisioning_server, g_config->provisioning_server());
|
|
|
|
key_msg_ = key_msg2;
|
|
std::string response =
|
|
GetCertRequestResponse(g_config->provisioning_server());
|
|
EXPECT_NE(0, static_cast<int>(response.size()));
|
|
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.HandleProvisioningResponse(
|
|
kDefaultCdmIdentifier, response, &cert,
|
|
&wrapped_key));
|
|
EXPECT_EQ(0, static_cast<int>(cert.size()));
|
|
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
|
|
|
|
key_msg_ = key_msg1;
|
|
response = GetCertRequestResponse(g_config->provisioning_server());
|
|
EXPECT_NE(0, static_cast<int>(response.size()));
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.HandleProvisioningResponse(kDefaultCdmIdentifier,
|
|
response, &cert,
|
|
&wrapped_key));
|
|
EXPECT_EQ(0, static_cast<int>(cert.size()));
|
|
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, ProvisioningInterspersedRetryTest) {
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
std::string provisioning_server;
|
|
CdmCertificateType cert_type = kCertificateWidevine;
|
|
std::string cert_authority, cert, wrapped_key;
|
|
std::string key_msg1, key_msg2;
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest(
|
|
cert_type, cert_authority,
|
|
kDefaultCdmIdentifier, &key_msg1,
|
|
&provisioning_server));
|
|
EXPECT_EQ(provisioning_server, g_config->provisioning_server());
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest(
|
|
cert_type, cert_authority,
|
|
kDefaultCdmIdentifier, &key_msg2,
|
|
&provisioning_server));
|
|
EXPECT_EQ(provisioning_server, g_config->provisioning_server());
|
|
|
|
key_msg_ = key_msg1;
|
|
std::string response =
|
|
GetCertRequestResponse(g_config->provisioning_server());
|
|
EXPECT_NE(0, static_cast<int>(response.size()));
|
|
EXPECT_EQ(wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_6,
|
|
decryptor_.HandleProvisioningResponse(kDefaultCdmIdentifier,
|
|
response, &cert,
|
|
&wrapped_key));
|
|
EXPECT_EQ(0, static_cast<int>(cert.size()));
|
|
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
|
|
|
|
key_msg_ = key_msg2;
|
|
response = GetCertRequestResponse(g_config->provisioning_server());
|
|
EXPECT_NE(0, static_cast<int>(response.size()));
|
|
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.HandleProvisioningResponse(
|
|
kDefaultCdmIdentifier, response, &cert,
|
|
&wrapped_key));
|
|
EXPECT_EQ(0, static_cast<int>(cert.size()));
|
|
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
|
|
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, DISABLED_X509ProvisioningTest) {
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
std::string provisioning_server;
|
|
CdmCertificateType cert_type = kCertificateX509;
|
|
// TODO(rfrias): insert appropriate CA here
|
|
std::string cert_authority = "cast.google.com";
|
|
std::string cert, wrapped_key;
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest(
|
|
cert_type, cert_authority,
|
|
kDefaultCdmIdentifier, &key_msg_,
|
|
&provisioning_server));
|
|
EXPECT_EQ(provisioning_server, g_config->provisioning_server());
|
|
|
|
std::string response =
|
|
GetCertRequestResponse(g_config->provisioning_server());
|
|
EXPECT_NE(0, static_cast<int>(response.size()));
|
|
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.HandleProvisioningResponse(
|
|
kDefaultCdmIdentifier, response, &cert,
|
|
&wrapped_key));
|
|
EXPECT_NE(0, static_cast<int>(cert.size()));
|
|
EXPECT_NE(0, static_cast<int>(wrapped_key.size()));
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, PropertySetTest) {
|
|
TestWvCdmClientPropertySet property_set_L1;
|
|
TestWvCdmClientPropertySet property_set_L3;
|
|
TestWvCdmClientPropertySet property_set_Ln;
|
|
CdmSessionId session_id_L1;
|
|
CdmSessionId session_id_L3;
|
|
CdmSessionId session_id_Ln;
|
|
|
|
property_set_L1.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L1);
|
|
property_set_L1.set_use_privacy_mode(true);
|
|
decryptor_.OpenSession(g_key_system, &property_set_L1, kDefaultCdmIdentifier,
|
|
NULL, &session_id_L1);
|
|
property_set_L3.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
|
|
property_set_L3.set_use_privacy_mode(false);
|
|
|
|
CdmResponseType sts = decryptor_.OpenSession(
|
|
g_key_system, &property_set_L3, kDefaultCdmIdentifier, NULL,
|
|
&session_id_L3);
|
|
|
|
if (NEED_PROVISIONING == sts) {
|
|
std::string provisioning_server;
|
|
CdmCertificateType cert_type = kCertificateWidevine;
|
|
std::string cert_authority, cert, wrapped_key;
|
|
EXPECT_EQ(NO_ERROR, decryptor_.GetProvisioningRequest(
|
|
cert_type, cert_authority, kDefaultCdmIdentifier,
|
|
&key_msg_, &provisioning_server));
|
|
EXPECT_EQ(provisioning_server, g_config->provisioning_server());
|
|
std::string response =
|
|
GetCertRequestResponse(g_config->provisioning_server());
|
|
EXPECT_NE(0, static_cast<int>(response.size()));
|
|
EXPECT_EQ(NO_ERROR, decryptor_.HandleProvisioningResponse(
|
|
kDefaultCdmIdentifier, response, &cert,
|
|
&wrapped_key));
|
|
EXPECT_EQ(NO_ERROR,
|
|
decryptor_.OpenSession(g_key_system, &property_set_L3,
|
|
kDefaultCdmIdentifier, NULL,
|
|
&session_id_L3));
|
|
} else {
|
|
EXPECT_EQ(NO_ERROR, sts);
|
|
}
|
|
|
|
property_set_Ln.set_security_level("");
|
|
decryptor_.OpenSession(g_key_system, &property_set_Ln, kDefaultCdmIdentifier,
|
|
NULL, &session_id_Ln);
|
|
|
|
CdmQueryMap query_info;
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QuerySessionStatus(session_id_L1, &query_info));
|
|
CdmQueryMap::iterator itr = query_info.find(wvcdm::QUERY_KEY_SECURITY_LEVEL);
|
|
EXPECT_TRUE(itr != query_info.end());
|
|
std::string security_level = itr->second;
|
|
EXPECT_TRUE(!security_level.compare(QUERY_VALUE_SECURITY_LEVEL_L1) ||
|
|
!security_level.compare(QUERY_VALUE_SECURITY_LEVEL_L3));
|
|
EXPECT_TRUE(Properties::UsePrivacyMode(session_id_L1));
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QuerySessionStatus(session_id_L3, &query_info));
|
|
itr = query_info.find(wvcdm::QUERY_KEY_SECURITY_LEVEL);
|
|
EXPECT_TRUE(itr != query_info.end());
|
|
security_level = itr->second;
|
|
EXPECT_EQ(security_level, QUERY_VALUE_SECURITY_LEVEL_L3);
|
|
EXPECT_FALSE(Properties::UsePrivacyMode(session_id_L3));
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QuerySessionStatus(session_id_Ln, &query_info));
|
|
itr = query_info.find(wvcdm::QUERY_KEY_SECURITY_LEVEL);
|
|
EXPECT_TRUE(itr != query_info.end());
|
|
security_level = itr->second;
|
|
EXPECT_TRUE(!security_level.compare(QUERY_VALUE_SECURITY_LEVEL_L1) ||
|
|
!security_level.compare(QUERY_VALUE_SECURITY_LEVEL_L3));
|
|
|
|
std::string app_id = "not empty";
|
|
EXPECT_TRUE(Properties::GetApplicationId(session_id_Ln, &app_id));
|
|
EXPECT_STREQ("", app_id.c_str());
|
|
|
|
property_set_Ln.set_app_id("com.unittest.mock.app.id");
|
|
EXPECT_TRUE(Properties::GetApplicationId(session_id_Ln, &app_id));
|
|
EXPECT_STREQ("com.unittest.mock.app.id", app_id.c_str());
|
|
|
|
decryptor_.CloseSession(session_id_L1);
|
|
decryptor_.CloseSession(session_id_L3);
|
|
decryptor_.CloseSession(session_id_Ln);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, ForceL3Test) {
|
|
TestWvCdmClientPropertySet property_set;
|
|
property_set.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
|
|
|
|
FileSystem file_system;
|
|
DeviceFiles handle(&file_system);
|
|
EXPECT_TRUE(handle.Init(kSecurityLevelL3));
|
|
EXPECT_TRUE(handle.DeleteAllFiles());
|
|
|
|
EXPECT_EQ(NEED_PROVISIONING,
|
|
decryptor_.OpenSession(g_key_system, &property_set,
|
|
kDefaultCdmIdentifier, NULL, &session_id_));
|
|
std::string provisioning_server;
|
|
CdmCertificateType cert_type = kCertificateWidevine;
|
|
std::string cert_authority, cert, wrapped_key;
|
|
EXPECT_EQ(NO_ERROR, decryptor_.GetProvisioningRequest(
|
|
cert_type, cert_authority, kDefaultCdmIdentifier,
|
|
&key_msg_, &provisioning_server));
|
|
EXPECT_EQ(provisioning_server, g_config->provisioning_server());
|
|
std::string response =
|
|
GetCertRequestResponse(g_config->provisioning_server());
|
|
EXPECT_NE(0, static_cast<int>(response.size()));
|
|
EXPECT_EQ(NO_ERROR, decryptor_.HandleProvisioningResponse(
|
|
kDefaultCdmIdentifier, response, &cert,
|
|
&wrapped_key));
|
|
|
|
EXPECT_EQ(NO_ERROR, decryptor_.OpenSession(g_key_system, &property_set,
|
|
kDefaultCdmIdentifier, NULL,
|
|
&session_id_));
|
|
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth);
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, PrivacyModeTest) {
|
|
TestWvCdmClientPropertySet property_set;
|
|
|
|
property_set.set_use_privacy_mode(true);
|
|
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
|
|
NULL, &session_id_);
|
|
|
|
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
|
|
std::string resp = GetKeyRequestResponse(g_license_server, g_client_auth);
|
|
EXPECT_EQ(decryptor_.AddKey(session_id_, resp, &key_set_id_),
|
|
wvcdm::NEED_KEY);
|
|
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth);
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, PrivacyModeWithServiceCertificateTest) {
|
|
TestWvCdmClientPropertySet property_set;
|
|
|
|
property_set.set_use_privacy_mode(true);
|
|
property_set.set_service_certificate(g_service_certificate);
|
|
// TODO: pass g_service_certificate into CdmEngine::SetServiceCertificate()
|
|
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
|
|
NULL, &session_id_);
|
|
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth);
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, BaseMessageTest) {
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
|
|
GetKeyRequestResponse(g_license_server, g_client_auth);
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, WrongMessageTest) {
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
|
|
std::string wrong_message = wvcdm::a2bs_hex(g_wrong_key_id);
|
|
GenerateKeyRequest(wrong_message, kLicenseTypeStreaming);
|
|
// We should receive a response with no license, i.e. the extracted license
|
|
// response message should be empty or an HTTP error
|
|
UrlRequest url_request(g_license_server + g_client_auth);
|
|
EXPECT_TRUE(url_request.is_connected()) << "Fail to connect to "
|
|
<< g_license_server << g_client_auth;
|
|
url_request.PostRequest(key_msg_);
|
|
std::string message;
|
|
EXPECT_TRUE(url_request.GetResponse(&message));
|
|
|
|
int http_status_code = url_request.GetStatusCode(message);
|
|
std::string drm_msg;
|
|
if (kHttpOk == http_status_code) {
|
|
LicenseRequest lic_request;
|
|
lic_request.GetDrmMessage(message, drm_msg);
|
|
LOGV("HTTP response body: (%u bytes)", drm_msg.size());
|
|
}
|
|
EXPECT_TRUE(drm_msg.empty());
|
|
EXPECT_TRUE(kHttpOk == http_status_code ||
|
|
kHttpBadRequest == http_status_code ||
|
|
kHttpInternalServerError == http_status_code);
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, AddStreamingKeyTest) {
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth);
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, AddKeyOfflineTest) {
|
|
Unprovision();
|
|
Provision(kLevelDefault);
|
|
|
|
// override default settings unless configured through the command line
|
|
std::string key_id;
|
|
std::string client_auth;
|
|
GetOfflineConfiguration(&key_id, &client_auth);
|
|
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
GenerateKeyRequest(key_id, kLicenseTypeOffline);
|
|
VerifyKeyRequestResponse(g_license_server, client_auth);
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, RestoreOfflineKeyTest) {
|
|
Unprovision();
|
|
Provision(kLevelDefault);
|
|
|
|
// override default settings unless configured through the command line
|
|
std::string key_id;
|
|
std::string client_auth;
|
|
GetOfflineConfiguration(&key_id, &client_auth);
|
|
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
GenerateKeyRequest(key_id, kLicenseTypeOffline);
|
|
VerifyKeyRequestResponse(g_license_server, client_auth);
|
|
|
|
CdmKeySetId key_set_id = key_set_id_;
|
|
EXPECT_FALSE(key_set_id_.empty());
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
session_id_.clear();
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_.RestoreKey(session_id_, key_set_id));
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, ReleaseOfflineKeyTest) {
|
|
Unprovision();
|
|
Provision(kLevelDefault);
|
|
|
|
// override default settings unless configured through the command line
|
|
std::string key_id;
|
|
std::string client_auth;
|
|
GetOfflineConfiguration(&key_id, &client_auth);
|
|
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
GenerateKeyRequest(key_id, kLicenseTypeOffline);
|
|
VerifyKeyRequestResponse(g_license_server, client_auth);
|
|
|
|
CdmKeySetId key_set_id = key_set_id_;
|
|
EXPECT_FALSE(key_set_id_.empty());
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
session_id_.clear();
|
|
key_set_id_.clear();
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_.RestoreKey(session_id_, key_set_id));
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
session_id_.clear();
|
|
key_set_id_.clear();
|
|
GenerateKeyRelease(key_set_id);
|
|
key_set_id_ = key_set_id;
|
|
VerifyKeyRequestResponse(g_license_server, client_auth);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, ReleaseOfflineKeySessionUsageDisabledTest) {
|
|
Unprovision();
|
|
Provision(kLevelDefault);
|
|
|
|
// The default offline asset "offline_clip2" has the session usage table
|
|
// entry enabled in the replay control portion of the key control block.
|
|
// To have it disabled we must use "offline_clip1", so replace the last
|
|
// char in init data with '1'
|
|
std::string key_id;
|
|
std::string client_auth;
|
|
GetOfflineConfiguration(&key_id, &client_auth);
|
|
key_id[key_id.size()-1] = '1';
|
|
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
GenerateKeyRequest(key_id, kLicenseTypeOffline);
|
|
VerifyKeyRequestResponse(g_license_server, client_auth);
|
|
|
|
CdmKeySetId key_set_id = key_set_id_;
|
|
EXPECT_FALSE(key_set_id_.empty());
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
session_id_.clear();
|
|
key_set_id_.clear();
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_.RestoreKey(session_id_, key_set_id));
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
session_id_.clear();
|
|
key_set_id_.clear();
|
|
CdmKeyMessage key_msg;
|
|
GenerateKeyRelease(key_set_id, NULL, &key_msg);
|
|
key_set_id_ = key_set_id;
|
|
VerifyKeyRequestResponse(g_license_server, client_auth);
|
|
|
|
SignedMessage signed_message;
|
|
EXPECT_TRUE(signed_message.ParseFromString(key_msg));
|
|
EXPECT_EQ(SignedMessage::LICENSE_REQUEST, signed_message.type());
|
|
EXPECT_TRUE(signed_message.has_signature());
|
|
EXPECT_TRUE(!signed_message.msg().empty());
|
|
|
|
// Verify license request
|
|
video_widevine::LicenseRequest license_renewal;
|
|
EXPECT_TRUE(license_renewal.ParseFromString(signed_message.msg()));
|
|
|
|
// Verify Content Identification
|
|
const LicenseRequest_ContentIdentification& content_id =
|
|
license_renewal.content_id();
|
|
EXPECT_FALSE(content_id.has_cenc_id_deprecated());
|
|
EXPECT_FALSE(content_id.has_webm_id_deprecated());
|
|
EXPECT_TRUE(content_id.has_existing_license());
|
|
|
|
const LicenseRequest_ContentIdentification::ExistingLicense&
|
|
existing_license = content_id.existing_license();
|
|
EXPECT_TRUE(existing_license.license_id().provider_session_token().empty());
|
|
EXPECT_TRUE(existing_license.session_usage_table_entry().empty());
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, ReleaseRetryOfflineKeyTest) {
|
|
Unprovision();
|
|
Provision(kLevelDefault);
|
|
|
|
// override default settings unless configured through the command line
|
|
std::string key_id;
|
|
std::string client_auth;
|
|
GetOfflineConfiguration(&key_id, &client_auth);
|
|
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
GenerateKeyRequest(key_id, kLicenseTypeOffline);
|
|
VerifyKeyRequestResponse(g_license_server, client_auth);
|
|
|
|
CdmKeySetId key_set_id = key_set_id_;
|
|
EXPECT_FALSE(key_set_id_.empty());
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
session_id_.clear();
|
|
key_set_id_.clear();
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_.RestoreKey(session_id_, key_set_id));
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
session_id_.clear();
|
|
key_set_id_.clear();
|
|
GenerateKeyRelease(key_set_id);
|
|
|
|
session_id_.clear();
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
EXPECT_EQ(wvcdm::GET_RELEASED_LICENSE_ERROR,
|
|
decryptor_.RestoreKey(session_id_, key_set_id));
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
session_id_.clear();
|
|
key_set_id_.clear();
|
|
GenerateKeyRelease(key_set_id);
|
|
key_set_id_ = key_set_id;
|
|
VerifyKeyRequestResponse(g_license_server, client_auth);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, ReleaseRetryL3OfflineKeyTest) {
|
|
Unprovision();
|
|
|
|
TestWvCdmClientPropertySet property_set;
|
|
property_set.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
|
|
|
|
// override default settings unless configured through the command line
|
|
std::string key_id;
|
|
std::string client_auth;
|
|
GetOfflineConfiguration(&key_id, &client_auth);
|
|
|
|
CdmResponseType sts = decryptor_.OpenSession(
|
|
g_key_system, &property_set, kDefaultCdmIdentifier, NULL, &session_id_);
|
|
|
|
if (NEED_PROVISIONING == sts) {
|
|
std::string provisioning_server;
|
|
CdmCertificateType cert_type = kCertificateWidevine;
|
|
std::string cert_authority, cert, wrapped_key;
|
|
EXPECT_EQ(NO_ERROR, decryptor_.GetProvisioningRequest(
|
|
cert_type, cert_authority, kDefaultCdmIdentifier,
|
|
&key_msg_, &provisioning_server));
|
|
EXPECT_EQ(provisioning_server, g_config->provisioning_server());
|
|
std::string response =
|
|
GetCertRequestResponse(g_config->provisioning_server());
|
|
EXPECT_NE(0, static_cast<int>(response.size()));
|
|
EXPECT_EQ(NO_ERROR, decryptor_.HandleProvisioningResponse(
|
|
kDefaultCdmIdentifier, response, &cert,
|
|
&wrapped_key));
|
|
EXPECT_EQ(NO_ERROR,
|
|
decryptor_.OpenSession(g_key_system, &property_set,
|
|
kDefaultCdmIdentifier, NULL,
|
|
&session_id_));
|
|
} else {
|
|
EXPECT_EQ(NO_ERROR, sts);
|
|
}
|
|
|
|
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
|
|
NULL, &session_id_);
|
|
GenerateKeyRequest(key_id, kLicenseTypeOffline, &property_set);
|
|
VerifyKeyRequestResponse(g_license_server, client_auth);
|
|
|
|
CdmKeySetId key_set_id = key_set_id_;
|
|
EXPECT_FALSE(key_set_id_.empty());
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
session_id_.clear();
|
|
key_set_id_.clear();
|
|
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
|
|
NULL, &session_id_);
|
|
EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_.RestoreKey(session_id_, key_set_id));
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
session_id_.clear();
|
|
key_set_id_.clear();
|
|
GenerateKeyRelease(key_set_id, &property_set, NULL);
|
|
|
|
session_id_.clear();
|
|
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
|
|
NULL, &session_id_);
|
|
EXPECT_EQ(wvcdm::GET_RELEASED_LICENSE_ERROR,
|
|
decryptor_.RestoreKey(session_id_, key_set_id));
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
session_id_.clear();
|
|
key_set_id_.clear();
|
|
GenerateKeyRelease(key_set_id, &property_set, NULL);
|
|
key_set_id_ = key_set_id;
|
|
VerifyKeyRequestResponse(g_license_server, client_auth);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest,
|
|
ReleaseRetryL3OfflineKeySessionUsageDisabledTest) {
|
|
Unprovision();
|
|
|
|
TestWvCdmClientPropertySet property_set;
|
|
property_set.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
|
|
|
|
// The default offline asset "offline_clip2" has the session usage table
|
|
// entry enabled in the replay control portion of the key control block.
|
|
// To have it disabled we must use "offline_clip1", so replace the last
|
|
// char in init data with '1'
|
|
std::string key_id;
|
|
std::string client_auth;
|
|
GetOfflineConfiguration(&key_id, &client_auth);
|
|
key_id[key_id.size()-1] = '1';
|
|
|
|
CdmResponseType sts = decryptor_.OpenSession(
|
|
g_key_system, &property_set, kDefaultCdmIdentifier, NULL, &session_id_);
|
|
|
|
if (NEED_PROVISIONING == sts) {
|
|
std::string provisioning_server_url;
|
|
CdmCertificateType cert_type = kCertificateWidevine;
|
|
std::string cert_authority, cert, wrapped_key;
|
|
EXPECT_EQ(NO_ERROR, decryptor_.GetProvisioningRequest(
|
|
cert_type, cert_authority, kDefaultCdmIdentifier,
|
|
&key_msg_, &provisioning_server_url));
|
|
EXPECT_EQ(provisioning_server_url, g_config->provisioning_server());
|
|
std::string response =
|
|
GetCertRequestResponse(g_config->provisioning_server());
|
|
EXPECT_NE(0, static_cast<int>(response.size()));
|
|
EXPECT_EQ(NO_ERROR, decryptor_.HandleProvisioningResponse(
|
|
kDefaultCdmIdentifier, response, &cert,
|
|
&wrapped_key));
|
|
EXPECT_EQ(NO_ERROR,
|
|
decryptor_.OpenSession(g_key_system, &property_set,
|
|
kDefaultCdmIdentifier, NULL,
|
|
&session_id_));
|
|
} else {
|
|
EXPECT_EQ(NO_ERROR, sts);
|
|
}
|
|
|
|
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
|
|
NULL, &session_id_);
|
|
GenerateKeyRequest(key_id, kLicenseTypeOffline, &property_set);
|
|
VerifyKeyRequestResponse(g_license_server, client_auth);
|
|
|
|
CdmKeySetId key_set_id = key_set_id_;
|
|
EXPECT_FALSE(key_set_id_.empty());
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
session_id_.clear();
|
|
key_set_id_.clear();
|
|
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
|
|
NULL, &session_id_);
|
|
EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_.RestoreKey(session_id_, key_set_id));
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
session_id_.clear();
|
|
key_set_id_.clear();
|
|
GenerateKeyRelease(key_set_id, &property_set, NULL);
|
|
|
|
session_id_.clear();
|
|
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
|
|
NULL, &session_id_);
|
|
EXPECT_EQ(wvcdm::GET_RELEASED_LICENSE_ERROR,
|
|
decryptor_.RestoreKey(session_id_, key_set_id));
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
session_id_.clear();
|
|
key_set_id_.clear();
|
|
GenerateKeyRelease(key_set_id, &property_set, NULL);
|
|
key_set_id_ = key_set_id;
|
|
VerifyKeyRequestResponse(g_license_server, client_auth);
|
|
}
|
|
|
|
// This test verifies that repeated generation of the key release message
|
|
// for the same key_set_id results in the previous session being
|
|
// deallocated (rather than leaked) and a new one allocated.
|
|
TEST_F(WvCdmRequestLicenseTest, AutomatedOfflineSessionReleaseTest) {
|
|
Unprovision();
|
|
Provision(kLevelDefault);
|
|
|
|
// override default settings unless configured through the command line
|
|
std::string key_id;
|
|
std::string client_auth;
|
|
GetOfflineConfiguration(&key_id, &client_auth);
|
|
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
GenerateKeyRequest(key_id, kLicenseTypeOffline);
|
|
VerifyKeyRequestResponse(g_license_server, client_auth);
|
|
|
|
CdmKeySetId key_set_id = key_set_id_;
|
|
EXPECT_FALSE(key_set_id_.empty());
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
session_id_.clear();
|
|
key_set_id_.clear();
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_.RestoreKey(session_id_, key_set_id));
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
uint32_t open_sessions =
|
|
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS);
|
|
|
|
session_id_.clear();
|
|
key_set_id_.clear();
|
|
GenerateKeyRelease(key_set_id);
|
|
key_set_id_ = key_set_id;
|
|
|
|
EXPECT_EQ(
|
|
++open_sessions,
|
|
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS));
|
|
|
|
session_id_.clear();
|
|
key_set_id_.clear();
|
|
GenerateKeyRelease(key_set_id);
|
|
key_set_id_ = key_set_id;
|
|
|
|
EXPECT_EQ(
|
|
open_sessions,
|
|
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS));
|
|
|
|
VerifyKeyRequestResponse(g_license_server, client_auth);
|
|
|
|
EXPECT_EQ(
|
|
--open_sessions,
|
|
QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS));
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, StreamingLicenseRenewal) {
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth);
|
|
|
|
std::string license_server;
|
|
GenerateRenewalRequest(kLicenseTypeStreaming, &license_server);
|
|
if (license_server.empty()) license_server = g_license_server;
|
|
VerifyKeyRequestResponse(license_server, g_client_auth);
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, StreamingLicenseRenewalProhibited) {
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
std::string key_id = a2bs_hex( // streaming_clip11
|
|
"000000427073736800000000" // blob size and pssh
|
|
"EDEF8BA979D64ACEA3C827DCD51D21ED00000023" // Widevine system id
|
|
"08011a0d7769646576696e655f746573" // pssh data
|
|
"74221073747265616d696e675f636c69703131");
|
|
GenerateKeyRequest(key_id, kLicenseTypeStreaming);
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth);
|
|
|
|
std::string init_data;
|
|
wvcdm::CdmAppParameterMap app_parameters;
|
|
CdmKeyRequest key_request;
|
|
EXPECT_EQ(wvcdm::LICENSE_RENEWAL_PROHIBITED,
|
|
decryptor_.GenerateKeyRequest(
|
|
session_id_, key_set_id_, "video/mp4", init_data,
|
|
kLicenseTypeStreaming, app_parameters, NULL,
|
|
kDefaultCdmIdentifier, &key_request));
|
|
key_msg_ = key_request.message;
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, OfflineLicenseRenewal) {
|
|
Unprovision();
|
|
Provision(kLevelDefault);
|
|
|
|
// override default settings unless configured through the command line
|
|
std::string key_id;
|
|
std::string client_auth;
|
|
GetOfflineConfiguration(&key_id, &client_auth);
|
|
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
GenerateKeyRequest(key_id, kLicenseTypeOffline);
|
|
VerifyKeyRequestResponse(g_license_server, client_auth);
|
|
|
|
std::string license_server;
|
|
GenerateRenewalRequest(kLicenseTypeOffline, &license_server);
|
|
if (license_server.empty()) license_server = g_license_server;
|
|
VerifyKeyRequestResponse(license_server, client_auth);
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, RemoveKeys) {
|
|
ASSERT_EQ(NO_ERROR, decryptor_.OpenSession(g_key_system, NULL,
|
|
kDefaultCdmIdentifier, NULL,
|
|
&session_id_));
|
|
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth);
|
|
ASSERT_EQ(NO_ERROR, decryptor_.RemoveKeys(session_id_));
|
|
ASSERT_EQ(NO_ERROR, decryptor_.CloseSession(session_id_));
|
|
}
|
|
|
|
class WvCdmStreamingLicenseRenewalTest
|
|
: public WvCdmRequestLicenseTest,
|
|
public ::testing::WithParamInterface<
|
|
RenewWithClientIdTestConfiguration*> {};
|
|
|
|
TEST_P(WvCdmStreamingLicenseRenewalTest, WithClientId) {
|
|
RenewWithClientIdTestConfiguration* config = GetParam();
|
|
std::string key_id;
|
|
if (config->always_include_client_id) {
|
|
key_id = a2bs_hex(
|
|
"000000427073736800000000" // blob size and pssh
|
|
"EDEF8BA979D64ACEA3C827DCD51D21ED00000022" // Widevine system id
|
|
"08011a0d7769646576696e655f74657374220f73" // pssh data
|
|
"747265616d696e675f636c697036");
|
|
} else {
|
|
key_id = g_key_id;
|
|
}
|
|
|
|
const uint32_t kNameValueParamSize = 2;
|
|
std::pair<std::string, std::string> name_value_params[kNameValueParamSize] = {
|
|
{"Name1", "Value1"}, {"Name2", "Value2"}};
|
|
wvcdm::CdmAppParameterMap app_parameters;
|
|
if (config->specify_app_parameters) {
|
|
for (uint32_t i = 0; i < kNameValueParamSize; ++i) {
|
|
app_parameters[name_value_params[i].first] = name_value_params[i].second;
|
|
}
|
|
}
|
|
|
|
TestWvCdmClientPropertySet property_set;
|
|
if (config->enable_privacy_mode) {
|
|
property_set.set_use_privacy_mode(true);
|
|
if (config->specify_service_certificate)
|
|
property_set.set_service_certificate(g_service_certificate);
|
|
}
|
|
// TODO: pass g_service_certificate into CdmEngine::SetServiceCertificate()
|
|
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
|
|
NULL, &session_id_);
|
|
GenerateKeyRequest(key_id, app_parameters, kLicenseTypeStreaming,
|
|
&property_set);
|
|
if (config->enable_privacy_mode && !config->specify_service_certificate) {
|
|
std::string resp = GetKeyRequestResponse(g_license_server, g_client_auth);
|
|
EXPECT_EQ(decryptor_.AddKey(session_id_, resp, &key_set_id_),
|
|
wvcdm::NEED_KEY);
|
|
GenerateKeyRequest(key_id, kLicenseTypeStreaming);
|
|
}
|
|
std::string key_response;
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth, false,
|
|
&key_response);
|
|
|
|
// Validate signed license
|
|
SignedMessage signed_message;
|
|
EXPECT_TRUE(signed_message.ParseFromString(key_response))
|
|
<< config->test_description;
|
|
EXPECT_EQ(SignedMessage::LICENSE, signed_message.type())
|
|
<< config->test_description;
|
|
EXPECT_TRUE(signed_message.has_signature()) << config->test_description;
|
|
EXPECT_TRUE(!signed_message.msg().empty()) << config->test_description;
|
|
|
|
// Verify license request
|
|
video_widevine::License license;
|
|
EXPECT_TRUE(license.ParseFromString(signed_message.msg()))
|
|
<< config->test_description;
|
|
|
|
// Verify always_include_client_id
|
|
EXPECT_EQ(config->always_include_client_id,
|
|
license.policy().has_always_include_client_id());
|
|
|
|
std::string license_server;
|
|
CdmKeyMessage key_msg;
|
|
GenerateRenewalRequest(kLicenseTypeStreaming, &key_msg, &license_server);
|
|
if (license_server.empty()) license_server = g_license_server;
|
|
|
|
// Validate signed renewal request
|
|
EXPECT_TRUE(signed_message.ParseFromString(key_msg))
|
|
<< config->test_description;
|
|
EXPECT_EQ(SignedMessage::LICENSE_REQUEST, signed_message.type())
|
|
<< config->test_description;
|
|
EXPECT_TRUE(signed_message.has_signature()) << config->test_description;
|
|
EXPECT_TRUE(!signed_message.msg().empty()) << config->test_description;
|
|
|
|
// Verify license request
|
|
video_widevine::LicenseRequest license_renewal;
|
|
EXPECT_TRUE(license_renewal.ParseFromString(signed_message.msg()))
|
|
<< config->test_description;
|
|
|
|
// Verify ClientId
|
|
EXPECT_EQ(config->always_include_client_id && !config->enable_privacy_mode,
|
|
license_renewal.has_client_id())
|
|
<< config->test_description;
|
|
|
|
if (config->specify_app_parameters) {
|
|
for (uint32_t i = 0; i < kNameValueParamSize; ++i) {
|
|
bool found = false;
|
|
for (int j = 0; j < license_renewal.client_id().client_info_size(); ++j) {
|
|
ClientIdentification_NameValue client_info =
|
|
license_renewal.client_id().client_info(i);
|
|
if (name_value_params[i].first.compare(client_info.name()) == 0 &&
|
|
name_value_params[i].second.compare(client_info.value()) == 0) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(found) << config->test_description;
|
|
}
|
|
}
|
|
|
|
if (config->enable_privacy_mode) {
|
|
EXPECT_EQ(config->always_include_client_id,
|
|
license_renewal.has_encrypted_client_id())
|
|
<< config->test_description;
|
|
EXPECT_NE(
|
|
0u, license_renewal.encrypted_client_id().encrypted_client_id().size());
|
|
}
|
|
|
|
VerifyKeyRequestResponse(license_server, g_client_auth);
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
INSTANTIATE_TEST_CASE_P(
|
|
Cdm, WvCdmStreamingLicenseRenewalTest,
|
|
::testing::Range(&streaming_renew_client_id_test_configuration[0],
|
|
&streaming_renew_client_id_test_configuration[5]));
|
|
|
|
class WvCdmOfflineLicenseReleaseTest
|
|
: public WvCdmRequestLicenseTest,
|
|
public ::testing::WithParamInterface<
|
|
RenewWithClientIdTestConfiguration*> {};
|
|
|
|
TEST_P(WvCdmOfflineLicenseReleaseTest, WithClientId) {
|
|
Unprovision();
|
|
Provision(kLevelDefault);
|
|
|
|
RenewWithClientIdTestConfiguration* config = GetParam();
|
|
std::string key_id;
|
|
std::string client_auth;
|
|
GetOfflineConfiguration(&key_id, &client_auth);
|
|
|
|
if (config->always_include_client_id) {
|
|
key_id = a2bs_hex(
|
|
"00000040" // blob size
|
|
"70737368" // "pssh"
|
|
"00000000" // flags
|
|
"edef8ba979d64acea3c827dcd51d21ed" // Widevine system id
|
|
"00000020" // pssh data size
|
|
// pssh data:
|
|
"08011a0d7769646576696e655f746573"
|
|
"74220d6f66666c696e655f636c697033");
|
|
}
|
|
|
|
const uint32_t kNameValueParamSize = 2;
|
|
std::pair<std::string, std::string> name_value_params[kNameValueParamSize] = {
|
|
{"Name1", "Value1"}, {"Name2", "Value2"}};
|
|
wvcdm::CdmAppParameterMap app_parameters;
|
|
if (config->specify_app_parameters) {
|
|
for (uint32_t i = 0; i < kNameValueParamSize; ++i) {
|
|
app_parameters[name_value_params[i].first] = name_value_params[i].second;
|
|
}
|
|
}
|
|
|
|
TestWvCdmClientPropertySet property_set;
|
|
if (config->enable_privacy_mode) {
|
|
property_set.set_use_privacy_mode(true);
|
|
if (config->specify_service_certificate)
|
|
property_set.set_service_certificate(g_service_certificate);
|
|
}
|
|
// TODO: pass g_service_certificate into CdmEngine::SetServiceCertificate()
|
|
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
|
|
NULL, &session_id_);
|
|
GenerateKeyRequest(key_id, app_parameters, kLicenseTypeOffline, NULL);
|
|
if (config->enable_privacy_mode && !config->specify_service_certificate) {
|
|
std::string resp = GetKeyRequestResponse(g_license_server, client_auth);
|
|
EXPECT_EQ(decryptor_.AddKey(session_id_, resp, &key_set_id_),
|
|
wvcdm::NEED_KEY);
|
|
GenerateKeyRequest(key_id, kLicenseTypeOffline);
|
|
}
|
|
std::string key_response;
|
|
VerifyKeyRequestResponse(g_license_server, client_auth, false, &key_response);
|
|
|
|
// Validate signed license
|
|
SignedMessage signed_message;
|
|
EXPECT_TRUE(signed_message.ParseFromString(key_response))
|
|
<< config->test_description;
|
|
EXPECT_EQ(SignedMessage::LICENSE, signed_message.type())
|
|
<< config->test_description;
|
|
EXPECT_TRUE(signed_message.has_signature()) << config->test_description;
|
|
EXPECT_TRUE(!signed_message.msg().empty()) << config->test_description;
|
|
|
|
// Verify license request
|
|
video_widevine::License license;
|
|
EXPECT_TRUE(license.ParseFromString(signed_message.msg()))
|
|
<< config->test_description;
|
|
|
|
// Verify always_include_client_id
|
|
EXPECT_EQ(config->always_include_client_id,
|
|
license.policy().has_always_include_client_id());
|
|
|
|
CdmKeySetId key_set_id = key_set_id_;
|
|
EXPECT_TRUE(key_set_id_.size() > 0);
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
session_id_.clear();
|
|
key_set_id_.clear();
|
|
|
|
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
|
|
NULL, &session_id_);
|
|
EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_.RestoreKey(session_id_, key_set_id));
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
session_id_.clear();
|
|
key_set_id_.clear();
|
|
CdmKeyMessage key_msg;
|
|
GenerateKeyRelease(key_set_id, &property_set, &key_msg);
|
|
key_set_id_ = key_set_id;
|
|
|
|
// Validate signed renewal request
|
|
EXPECT_TRUE(signed_message.ParseFromString(key_msg))
|
|
<< config->test_description;
|
|
EXPECT_EQ(SignedMessage::LICENSE_REQUEST, signed_message.type())
|
|
<< config->test_description;
|
|
EXPECT_TRUE(signed_message.has_signature()) << config->test_description;
|
|
EXPECT_TRUE(!signed_message.msg().empty()) << config->test_description;
|
|
|
|
// Verify license request
|
|
video_widevine::LicenseRequest license_release;
|
|
EXPECT_TRUE(license_release.ParseFromString(signed_message.msg()))
|
|
<< config->test_description;
|
|
|
|
// Verify ClientId
|
|
EXPECT_EQ(config->always_include_client_id && !config->enable_privacy_mode,
|
|
license_release.has_client_id())
|
|
<< config->test_description;
|
|
|
|
if (config->specify_app_parameters) {
|
|
for (uint32_t i = 0; i < kNameValueParamSize; ++i) {
|
|
bool found = false;
|
|
for (int j = 0; j < license_release.client_id().client_info_size(); ++j) {
|
|
ClientIdentification_NameValue client_info =
|
|
license_release.client_id().client_info(i);
|
|
if (name_value_params[i].first.compare(client_info.name()) == 0 &&
|
|
name_value_params[i].second.compare(client_info.value()) == 0) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
EXPECT_TRUE(found) << config->test_description;
|
|
}
|
|
}
|
|
|
|
if (config->enable_privacy_mode) {
|
|
EXPECT_EQ(config->always_include_client_id,
|
|
license_release.has_encrypted_client_id())
|
|
<< config->test_description;
|
|
EXPECT_NE(
|
|
0u, license_release.encrypted_client_id().encrypted_client_id().size());
|
|
}
|
|
|
|
VerifyKeyRequestResponse(g_license_server, client_auth);
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
INSTANTIATE_TEST_CASE_P(
|
|
Cdm, WvCdmOfflineLicenseReleaseTest,
|
|
::testing::Range(&offline_release_client_id_test_configuration[0],
|
|
&offline_release_client_id_test_configuration[4]));
|
|
|
|
class WvCdmUsageTest
|
|
: public WvCdmRequestLicenseTest,
|
|
public ::testing::WithParamInterface<
|
|
RenewWithClientIdTestConfiguration*> {};
|
|
|
|
TEST_P(WvCdmUsageTest, WithClientId) {
|
|
Unprovision();
|
|
Provision(kLevelDefault);
|
|
|
|
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
|
|
std::string app_id = "";
|
|
FileSystem file_system;
|
|
DeviceFiles handle(&file_system);
|
|
EXPECT_TRUE(handle.Init(security_level));
|
|
std::vector<std::string> psts;
|
|
EXPECT_TRUE(handle.DeleteAllUsageInfoForApp(
|
|
DeviceFiles::GetUsageInfoFileName(app_id),
|
|
&psts));
|
|
|
|
RenewWithClientIdTestConfiguration* config = GetParam();
|
|
std::string key_id;
|
|
|
|
if (config->always_include_client_id) {
|
|
key_id = a2bs_hex( // streaming_clip20
|
|
"000000427073736800000000" // blob size and pssh
|
|
"EDEF8BA979D64ACEA3C827DCD51D21ED00000023" // Widevine system id
|
|
"08011a0d7769646576696e655f746573" // pssh data
|
|
"74221073747265616d696e675f636c69703230");
|
|
} else {
|
|
key_id = a2bs_hex( // streaming_clip3
|
|
"000000427073736800000000" // blob size and pssh
|
|
"EDEF8BA979D64ACEA3C827DCD51D21ED00000022" // Widevine system id
|
|
"08011a0d7769646576696e655f746573" // pssh data
|
|
"74220f73747265616d696e675f636c697033");
|
|
}
|
|
wvcdm::CdmAppParameterMap app_parameters;
|
|
TestWvCdmClientPropertySet property_set;
|
|
|
|
SubSampleInfo* data = &usage_info_sub_samples_icp[0];
|
|
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
|
|
NULL, &session_id_);
|
|
|
|
GenerateKeyRequest(key_id, app_parameters, kLicenseTypeStreaming,
|
|
&property_set);
|
|
|
|
std::string key_response;
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth, true,
|
|
&key_response);
|
|
|
|
// Validate signed license
|
|
SignedMessage signed_message;
|
|
EXPECT_TRUE(signed_message.ParseFromString(key_response))
|
|
<< config->test_description;
|
|
EXPECT_EQ(SignedMessage::LICENSE, signed_message.type())
|
|
<< config->test_description;
|
|
EXPECT_TRUE(signed_message.has_signature()) << config->test_description;
|
|
EXPECT_TRUE(!signed_message.msg().empty()) << config->test_description;
|
|
|
|
// Verify license request
|
|
video_widevine::License license;
|
|
EXPECT_TRUE(license.ParseFromString(signed_message.msg()))
|
|
<< config->test_description;
|
|
|
|
// Verify always_include_client_id
|
|
EXPECT_EQ(config->always_include_client_id,
|
|
license.policy().has_always_include_client_id());
|
|
|
|
EXPECT_FALSE(license.id().provider_session_token().empty());
|
|
|
|
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
|
|
CdmDecryptionParameters decryption_parameters(
|
|
&data->key_id, &data->encrypt_data.front(), data->encrypt_data.size(),
|
|
&data->iv, data->block_offset, &decrypt_buffer[0]);
|
|
decryption_parameters.is_encrypted = data->is_encrypted;
|
|
decryption_parameters.is_secure = data->is_secure;
|
|
decryption_parameters.subsample_flags = data->subsample_flags;
|
|
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_, data->validate_key_id,
|
|
decryption_parameters));
|
|
|
|
EXPECT_TRUE(std::equal(data->decrypt_data.begin(), data->decrypt_data.end(),
|
|
decrypt_buffer.begin()));
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
uint32_t num_usage_info = 0;
|
|
CdmUsageInfo usage_info;
|
|
CdmUsageInfoReleaseMessage release_msg;
|
|
CdmResponseType status = decryptor_.GetUsageInfo(
|
|
app_id, kDefaultCdmIdentifier, &usage_info);
|
|
EXPECT_EQ(usage_info.empty() ? NO_ERROR : KEY_MESSAGE, status);
|
|
|
|
// Validate signed renewal request
|
|
EXPECT_TRUE(signed_message.ParseFromString(usage_info[0]))
|
|
<< config->test_description;
|
|
EXPECT_EQ(SignedMessage::LICENSE_REQUEST, signed_message.type())
|
|
<< config->test_description;
|
|
EXPECT_TRUE(signed_message.has_signature()) << config->test_description;
|
|
EXPECT_TRUE(!signed_message.msg().empty()) << config->test_description;
|
|
|
|
// Verify license request
|
|
video_widevine::LicenseRequest license_renewal;
|
|
EXPECT_TRUE(license_renewal.ParseFromString(signed_message.msg()))
|
|
<< config->test_description;
|
|
|
|
// Verify ClientId
|
|
EXPECT_EQ(config->always_include_client_id && !config->enable_privacy_mode,
|
|
license_renewal.has_client_id())
|
|
<< config->test_description;
|
|
|
|
if (config->enable_privacy_mode) {
|
|
EXPECT_EQ(config->always_include_client_id,
|
|
license_renewal.has_encrypted_client_id())
|
|
<< config->test_description;
|
|
EXPECT_NE(
|
|
0u, license_renewal.encrypted_client_id().encrypted_client_id().size());
|
|
}
|
|
|
|
release_msg =
|
|
GetUsageInfoResponse(g_license_server, g_client_auth, usage_info[0]);
|
|
EXPECT_EQ(NO_ERROR, decryptor_.ReleaseUsageInfo(release_msg,
|
|
kDefaultCdmIdentifier));
|
|
}
|
|
|
|
INSTANTIATE_TEST_CASE_P(
|
|
Cdm, WvCdmUsageTest,
|
|
::testing::Range(&usage_client_id_test_configuration[0],
|
|
&usage_client_id_test_configuration[2]));
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, UsageInfoRetryTest) {
|
|
Unprovision();
|
|
Provision(kLevelDefault);
|
|
|
|
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
|
|
std::string app_id = "";
|
|
FileSystem file_system;
|
|
DeviceFiles handle(&file_system);
|
|
EXPECT_TRUE(handle.Init(security_level));
|
|
std::vector<std::string> psts;
|
|
EXPECT_TRUE(handle.DeleteAllUsageInfoForApp(
|
|
DeviceFiles::GetUsageInfoFileName(app_id),
|
|
&psts));
|
|
|
|
SubSampleInfo* data = &usage_info_sub_samples_icp[0];
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
std::string key_id = a2bs_hex(
|
|
"000000427073736800000000" // blob size and pssh
|
|
"EDEF8BA979D64ACEA3C827DCD51D21ED00000022" // Widevine system id
|
|
"08011a0d7769646576696e655f74657374220f73" // pssh data
|
|
"747265616d696e675f636c697033");
|
|
|
|
GenerateKeyRequest(key_id, kLicenseTypeStreaming, NULL);
|
|
VerifyUsageKeyRequestResponse(g_license_server, g_client_auth);
|
|
|
|
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
|
|
CdmDecryptionParameters decryption_parameters(
|
|
&data->key_id, &data->encrypt_data.front(), data->encrypt_data.size(),
|
|
&data->iv, data->block_offset, &decrypt_buffer[0]);
|
|
decryption_parameters.is_encrypted = data->is_encrypted;
|
|
decryption_parameters.is_secure = data->is_secure;
|
|
decryption_parameters.subsample_flags = data->subsample_flags;
|
|
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_, data->validate_key_id,
|
|
decryption_parameters));
|
|
|
|
EXPECT_TRUE(std::equal(data->decrypt_data.begin(), data->decrypt_data.end(),
|
|
decrypt_buffer.begin()));
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
uint32_t num_usage_info = 0;
|
|
CdmUsageInfo usage_info;
|
|
CdmUsageInfoReleaseMessage release_msg;
|
|
CdmResponseType status = decryptor_.GetUsageInfo(
|
|
app_id, kDefaultCdmIdentifier, &usage_info);
|
|
EXPECT_EQ(usage_info.empty() ? NO_ERROR : KEY_MESSAGE, status);
|
|
|
|
// Discard and retry to verify usage reports can be generated multiple times
|
|
// before release.
|
|
status = decryptor_.GetUsageInfo(app_id, kDefaultCdmIdentifier, &usage_info);
|
|
EXPECT_EQ(usage_info.empty() ? NO_ERROR : KEY_MESSAGE, status);
|
|
while (usage_info.size() > 0) {
|
|
for (size_t i = 0; i < usage_info.size(); ++i) {
|
|
release_msg =
|
|
GetUsageInfoResponse(g_license_server, g_client_auth, usage_info[i]);
|
|
EXPECT_EQ(NO_ERROR, decryptor_.ReleaseUsageInfo(release_msg,
|
|
kDefaultCdmIdentifier));
|
|
}
|
|
status = decryptor_.GetUsageInfo(
|
|
app_id, kDefaultCdmIdentifier, &usage_info);
|
|
switch (status) {
|
|
case KEY_MESSAGE:
|
|
EXPECT_FALSE(usage_info.empty());
|
|
break;
|
|
case NO_ERROR:
|
|
EXPECT_TRUE(usage_info.empty());
|
|
break;
|
|
default:
|
|
FAIL() << "GetUsageInfo failed with error " << static_cast<int>(status);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
class WvCdmUsageInfoTest
|
|
: public WvCdmRequestLicenseTest,
|
|
public ::testing::WithParamInterface<UsageInfoSubSampleInfo*> {};
|
|
|
|
TEST_P(WvCdmUsageInfoTest, UsageInfo) {
|
|
Unprovision();
|
|
|
|
UsageInfoSubSampleInfo* usage_info_data = GetParam();
|
|
TestWvCdmClientPropertySet client_property_set;
|
|
TestWvCdmClientPropertySet* property_set = NULL;
|
|
if (kLevel3 == usage_info_data->security_level) {
|
|
client_property_set.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
|
|
property_set = &client_property_set;
|
|
Provision(kLevel3);
|
|
Provision(kLevelDefault);
|
|
} else {
|
|
Provision(kLevelDefault);
|
|
}
|
|
|
|
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
|
|
FileSystem file_system;
|
|
DeviceFiles handle(&file_system);
|
|
EXPECT_TRUE(handle.Init(security_level));
|
|
std::vector<std::string> psts;
|
|
EXPECT_TRUE(handle.DeleteAllUsageInfoForApp(
|
|
DeviceFiles::GetUsageInfoFileName(usage_info_data->app_id),
|
|
&psts));
|
|
|
|
for (size_t i = 0; i < usage_info_data->usage_info; ++i) {
|
|
SubSampleInfo* data = usage_info_data->sub_sample + i;
|
|
decryptor_.OpenSession(g_key_system, property_set, kDefaultCdmIdentifier,
|
|
NULL, &session_id_);
|
|
std::string key_id = a2bs_hex(
|
|
"000000427073736800000000" // blob size and pssh
|
|
"EDEF8BA979D64ACEA3C827DCD51D21ED00000022" // Widevine system id
|
|
"08011a0d7769646576696e655f74657374220f73" // pssh data
|
|
"747265616d696e675f636c6970");
|
|
|
|
char ch = 0x33 + i;
|
|
key_id.append(1, ch);
|
|
|
|
GenerateKeyRequest(key_id, kLicenseTypeStreaming, property_set);
|
|
|
|
// TODO(rfrias): streaming_clip6 is a streaming license without a pst
|
|
if (ch == '6')
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
|
|
else
|
|
VerifyUsageKeyRequestResponse(g_license_server, g_client_auth);
|
|
|
|
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
|
|
CdmDecryptionParameters decryption_parameters(
|
|
&data->key_id, &data->encrypt_data.front(), data->encrypt_data.size(),
|
|
&data->iv, data->block_offset, &decrypt_buffer[0]);
|
|
decryption_parameters.is_encrypted = data->is_encrypted;
|
|
decryption_parameters.is_secure = data->is_secure;
|
|
decryption_parameters.subsample_flags = data->subsample_flags;
|
|
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_, data->validate_key_id,
|
|
decryption_parameters));
|
|
|
|
EXPECT_TRUE(std::equal(data->decrypt_data.begin(), data->decrypt_data.end(),
|
|
decrypt_buffer.begin()));
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
uint32_t num_usage_info = 0;
|
|
CdmUsageInfo usage_info;
|
|
CdmUsageInfoReleaseMessage release_msg;
|
|
CdmResponseType status =
|
|
decryptor_.GetUsageInfo(usage_info_data->app_id, kDefaultCdmIdentifier,
|
|
&usage_info);
|
|
EXPECT_EQ(usage_info.empty() ? NO_ERROR : KEY_MESSAGE, status);
|
|
while (usage_info.size() > 0) {
|
|
for (size_t i = 0; i < usage_info.size(); ++i) {
|
|
release_msg =
|
|
GetUsageInfoResponse(g_license_server, g_client_auth, usage_info[i]);
|
|
EXPECT_EQ(
|
|
NO_ERROR,
|
|
decryptor_.ReleaseUsageInfo(release_msg, kDefaultCdmIdentifier));
|
|
}
|
|
status = decryptor_.GetUsageInfo(usage_info_data->app_id,
|
|
kDefaultCdmIdentifier, &usage_info);
|
|
EXPECT_EQ(usage_info.empty() ? NO_ERROR : KEY_MESSAGE, status);
|
|
}
|
|
}
|
|
|
|
INSTANTIATE_TEST_CASE_P(Cdm, WvCdmUsageInfoTest,
|
|
::testing::Values(&usage_info_sub_sample_info[0],
|
|
&usage_info_sub_sample_info[1],
|
|
&usage_info_sub_sample_info[2],
|
|
&usage_info_sub_sample_info[3],
|
|
&usage_info_sub_sample_info[4],
|
|
&usage_info_sub_sample_info[5],
|
|
&usage_info_sub_sample_info[6],
|
|
&usage_info_sub_sample_info[7]));
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, UsageReleaseAllTest) {
|
|
Unprovision();
|
|
|
|
std::string app_id_empty = "";
|
|
std::string app_id_not_empty = "not empty";
|
|
|
|
TestWvCdmClientPropertySet property_set;
|
|
Provision(kLevelDefault);
|
|
|
|
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
|
|
FileSystem file_system;
|
|
DeviceFiles handle(&file_system);
|
|
EXPECT_TRUE(handle.Init(security_level));
|
|
std::vector<std::string> psts;
|
|
EXPECT_TRUE(handle.DeleteAllUsageInfoForApp(
|
|
DeviceFiles::GetUsageInfoFileName(""), &psts));
|
|
|
|
for (size_t i = 0; i < N_ELEM(usage_info_sub_samples_icp); ++i) {
|
|
SubSampleInfo* data = usage_info_sub_samples_icp + i;
|
|
property_set.set_app_id(i % 2 == 0 ? app_id_empty : app_id_not_empty);
|
|
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
|
|
NULL, &session_id_);
|
|
std::string key_id = a2bs_hex(
|
|
"000000427073736800000000" // blob size and pssh
|
|
"EDEF8BA979D64ACEA3C827DCD51D21ED00000022" // Widevine system id
|
|
"08011a0d7769646576696e655f74657374220f73" // pssh data
|
|
"747265616d696e675f636c6970");
|
|
|
|
char ch = 0x33 + i;
|
|
key_id.append(1, ch);
|
|
|
|
GenerateKeyRequest(key_id, kLicenseTypeStreaming, &property_set);
|
|
|
|
// TODO(rfrias): streaming_clip6 is a streaming license without a pst
|
|
if (ch == '6')
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
|
|
else
|
|
VerifyUsageKeyRequestResponse(g_license_server, g_client_auth);
|
|
|
|
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
|
|
CdmDecryptionParameters decryption_parameters(
|
|
&data->key_id, &data->encrypt_data.front(), data->encrypt_data.size(),
|
|
&data->iv, data->block_offset, &decrypt_buffer[0]);
|
|
decryption_parameters.is_encrypted = data->is_encrypted;
|
|
decryption_parameters.is_secure = data->is_secure;
|
|
decryption_parameters.subsample_flags = data->subsample_flags;
|
|
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_, data->validate_key_id,
|
|
decryption_parameters));
|
|
|
|
EXPECT_TRUE(std::equal(data->decrypt_data.begin(), data->decrypt_data.end(),
|
|
decrypt_buffer.begin()));
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
CdmUsageInfo usage_info;
|
|
EXPECT_EQ(
|
|
KEY_MESSAGE,
|
|
decryptor_.GetUsageInfo(app_id_empty, kDefaultCdmIdentifier,
|
|
&usage_info));
|
|
EXPECT_TRUE(usage_info.size() > 0);
|
|
EXPECT_EQ(
|
|
KEY_MESSAGE,
|
|
decryptor_.GetUsageInfo(app_id_not_empty, kDefaultCdmIdentifier,
|
|
&usage_info));
|
|
EXPECT_TRUE(usage_info.size() > 0);
|
|
|
|
|
|
EXPECT_EQ(
|
|
NO_ERROR,
|
|
decryptor_.ReleaseAllUsageInfo(app_id_not_empty, kDefaultCdmIdentifier));
|
|
|
|
EXPECT_EQ(
|
|
NO_ERROR,
|
|
decryptor_.GetUsageInfo(app_id_not_empty, kDefaultCdmIdentifier,
|
|
&usage_info));
|
|
EXPECT_TRUE(usage_info.empty());
|
|
EXPECT_EQ(
|
|
KEY_MESSAGE,
|
|
decryptor_.GetUsageInfo(app_id_empty, kDefaultCdmIdentifier,
|
|
&usage_info));
|
|
EXPECT_TRUE(usage_info.size() > 0);
|
|
|
|
EXPECT_EQ(
|
|
NO_ERROR,
|
|
decryptor_.ReleaseAllUsageInfo(app_id_empty, kDefaultCdmIdentifier));
|
|
|
|
EXPECT_EQ(
|
|
NO_ERROR,
|
|
decryptor_.GetUsageInfo(app_id_not_empty, kDefaultCdmIdentifier,
|
|
&usage_info));
|
|
EXPECT_TRUE(usage_info.empty());
|
|
EXPECT_EQ(
|
|
NO_ERROR,
|
|
decryptor_.GetUsageInfo(app_id_empty, kDefaultCdmIdentifier,
|
|
&usage_info));
|
|
EXPECT_TRUE(usage_info.empty());
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, QueryUnmodifiedSessionStatus) {
|
|
// Test that the global value is returned when no properties are modifying it.
|
|
std::string security_level;
|
|
ASSERT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(kLevelDefault,
|
|
wvcdm::QUERY_KEY_SECURITY_LEVEL,
|
|
&security_level));
|
|
EXPECT_EQ(GetSecurityLevel(NULL), security_level);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, QueryModifiedSessionStatus) {
|
|
// Test that L3 is returned when properties downgrade security.
|
|
Unprovision();
|
|
Provision(kLevel3);
|
|
TestWvCdmClientPropertySet property_set_L3;
|
|
property_set_L3.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
|
|
|
|
EXPECT_EQ(QUERY_VALUE_SECURITY_LEVEL_L3, GetSecurityLevel(&property_set_L3));
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, QueryKeyStatus) {
|
|
Unprovision();
|
|
Provision(kLevelDefault);
|
|
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth);
|
|
|
|
CdmQueryMap query_info;
|
|
CdmQueryMap::iterator itr;
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QueryKeyStatus(session_id_, &query_info));
|
|
|
|
itr = query_info.find(wvcdm::QUERY_KEY_LICENSE_TYPE);
|
|
ASSERT_TRUE(itr != query_info.end());
|
|
EXPECT_EQ(wvcdm::QUERY_VALUE_STREAMING, itr->second);
|
|
itr = query_info.find(wvcdm::QUERY_KEY_PLAY_ALLOWED);
|
|
ASSERT_TRUE(itr != query_info.end());
|
|
EXPECT_EQ(wvcdm::QUERY_VALUE_TRUE, itr->second);
|
|
itr = query_info.find(wvcdm::QUERY_KEY_PERSIST_ALLOWED);
|
|
ASSERT_TRUE(itr != query_info.end());
|
|
EXPECT_EQ(wvcdm::QUERY_VALUE_FALSE, itr->second);
|
|
itr = query_info.find(wvcdm::QUERY_KEY_RENEW_ALLOWED);
|
|
ASSERT_TRUE(itr != query_info.end());
|
|
EXPECT_EQ(wvcdm::QUERY_VALUE_TRUE, itr->second);
|
|
|
|
int64_t remaining_time;
|
|
std::istringstream ss;
|
|
itr = query_info.find(wvcdm::QUERY_KEY_LICENSE_DURATION_REMAINING);
|
|
ASSERT_TRUE(itr != query_info.end());
|
|
ss.str(itr->second);
|
|
ss >> remaining_time;
|
|
ASSERT_FALSE(ss.fail());
|
|
EXPECT_LT(0, remaining_time);
|
|
itr = query_info.find(wvcdm::QUERY_KEY_PLAYBACK_DURATION_REMAINING);
|
|
ASSERT_TRUE(itr != query_info.end());
|
|
ss.clear();
|
|
ss.str(itr->second);
|
|
ss >> remaining_time;
|
|
ASSERT_FALSE(ss.fail());
|
|
EXPECT_LT(0, remaining_time);
|
|
|
|
itr = query_info.find(wvcdm::QUERY_KEY_RENEWAL_SERVER_URL);
|
|
ASSERT_TRUE(itr != query_info.end());
|
|
EXPECT_LT(0u, itr->second.size());
|
|
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, QueryStatus) {
|
|
std::string value;
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(kLevelDefault,
|
|
wvcdm::QUERY_KEY_SECURITY_LEVEL, &value));
|
|
|
|
EXPECT_EQ(2u, value.size());
|
|
EXPECT_TRUE(wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3 == value ||
|
|
wvcdm::QUERY_VALUE_SECURITY_LEVEL_L1 == value);
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_DEVICE_ID,
|
|
&value));
|
|
EXPECT_LT(0u, value.size());
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_SYSTEM_ID,
|
|
&value));
|
|
std::istringstream ss(value);
|
|
uint32_t system_id;
|
|
ss >> system_id;
|
|
ASSERT_FALSE(ss.fail());
|
|
EXPECT_TRUE(ss.eof());
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(kLevelDefault,
|
|
wvcdm::QUERY_KEY_PROVISIONING_ID, &value));
|
|
EXPECT_EQ(16u, value.size());
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(
|
|
kLevelDefault, wvcdm::QUERY_KEY_CURRENT_HDCP_LEVEL, &value));
|
|
EXPECT_TRUE(
|
|
value == QUERY_VALUE_UNPROTECTED || value == QUERY_VALUE_HDCP_V1 ||
|
|
value == QUERY_VALUE_HDCP_V2_0 || value == QUERY_VALUE_HDCP_V2_1 ||
|
|
value == QUERY_VALUE_HDCP_V2_2 || value == QUERY_VALUE_DISCONNECTED);
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(kLevelDefault,
|
|
wvcdm::QUERY_KEY_MAX_HDCP_LEVEL, &value));
|
|
EXPECT_TRUE(
|
|
value == QUERY_VALUE_UNPROTECTED || value == QUERY_VALUE_HDCP_V1 ||
|
|
value == QUERY_VALUE_HDCP_V2_0 || value == QUERY_VALUE_HDCP_V2_1 ||
|
|
value == QUERY_VALUE_HDCP_V2_2 || value == QUERY_VALUE_DISCONNECTED);
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(kLevelDefault,
|
|
wvcdm::QUERY_KEY_USAGE_SUPPORT, &value));
|
|
EXPECT_TRUE(value == QUERY_VALUE_TRUE || value == QUERY_VALUE_FALSE);
|
|
|
|
EXPECT_EQ(
|
|
wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(kLevelDefault,
|
|
wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS, &value));
|
|
ss.clear();
|
|
ss.str(value);
|
|
uint32_t open_sessions;
|
|
ss >> open_sessions;
|
|
ASSERT_FALSE(ss.fail());
|
|
EXPECT_TRUE(ss.eof());
|
|
|
|
EXPECT_EQ(
|
|
wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(kLevelDefault,
|
|
wvcdm::QUERY_KEY_MAX_NUMBER_OF_SESSIONS, &value));
|
|
ss.clear();
|
|
ss.str(value);
|
|
uint32_t max_sessions;
|
|
ss >> max_sessions;
|
|
ASSERT_FALSE(ss.fail());
|
|
EXPECT_TRUE(ss.eof());
|
|
EXPECT_LE(open_sessions, max_sessions);
|
|
EXPECT_LE(8u, max_sessions);
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(
|
|
kLevelDefault, wvcdm::QUERY_KEY_OEMCRYPTO_API_VERSION, &value));
|
|
ss.clear();
|
|
ss.str(value);
|
|
uint32_t api_version;
|
|
ss >> api_version;
|
|
ASSERT_FALSE(ss.fail());
|
|
EXPECT_TRUE(ss.eof());
|
|
EXPECT_LE(10u, api_version);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, QueryStatusL3) {
|
|
std::string value;
|
|
EXPECT_EQ(
|
|
wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(kLevel3, wvcdm::QUERY_KEY_SECURITY_LEVEL, &value));
|
|
EXPECT_EQ(wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3, value);
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.QueryStatus(
|
|
kLevel3, wvcdm::QUERY_KEY_DEVICE_ID, &value));
|
|
EXPECT_LT(0u, value.size());
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_SYSTEM_ID,
|
|
&value));
|
|
std::istringstream ss(value);
|
|
uint32_t default_system_id;
|
|
ss >> default_system_id;
|
|
ASSERT_FALSE(ss.fail());
|
|
EXPECT_TRUE(ss.eof());
|
|
|
|
std::string default_security_level;
|
|
EXPECT_EQ(
|
|
wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_SECURITY_LEVEL,
|
|
&default_security_level));
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.QueryStatus(
|
|
kLevel3, wvcdm::QUERY_KEY_SYSTEM_ID, &value));
|
|
ss.clear();
|
|
ss.str(value);
|
|
uint32_t system_id;
|
|
ss >> system_id;
|
|
ASSERT_FALSE(ss.fail());
|
|
EXPECT_TRUE(ss.eof());
|
|
if (default_security_level != wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3) {
|
|
EXPECT_NE(default_system_id, system_id);
|
|
}
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(kLevel3, wvcdm::QUERY_KEY_PROVISIONING_ID,
|
|
&value));
|
|
EXPECT_EQ(16u, value.size());
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(kLevel3, wvcdm::QUERY_KEY_CURRENT_HDCP_LEVEL,
|
|
&value));
|
|
EXPECT_TRUE(
|
|
value == QUERY_VALUE_UNPROTECTED || value == QUERY_VALUE_HDCP_V1 ||
|
|
value == QUERY_VALUE_HDCP_V2_0 || value == QUERY_VALUE_HDCP_V2_1 ||
|
|
value == QUERY_VALUE_HDCP_V2_2 || value == QUERY_VALUE_DISCONNECTED);
|
|
|
|
EXPECT_EQ(
|
|
wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(kLevel3, wvcdm::QUERY_KEY_MAX_HDCP_LEVEL, &value));
|
|
EXPECT_TRUE(
|
|
value == QUERY_VALUE_UNPROTECTED || value == QUERY_VALUE_HDCP_V1 ||
|
|
value == QUERY_VALUE_HDCP_V2_0 || value == QUERY_VALUE_HDCP_V2_1 ||
|
|
value == QUERY_VALUE_HDCP_V2_2 || value == QUERY_VALUE_DISCONNECTED);
|
|
|
|
EXPECT_EQ(
|
|
wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(kLevel3, wvcdm::QUERY_KEY_USAGE_SUPPORT, &value));
|
|
EXPECT_TRUE(value == QUERY_VALUE_TRUE || value == QUERY_VALUE_FALSE);
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(
|
|
kLevel3, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS, &value));
|
|
ss.clear();
|
|
ss.str(value);
|
|
uint32_t open_sessions;
|
|
ss >> open_sessions;
|
|
ASSERT_FALSE(ss.fail());
|
|
EXPECT_TRUE(ss.eof());
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(
|
|
kLevel3, wvcdm::QUERY_KEY_MAX_NUMBER_OF_SESSIONS, &value));
|
|
ss.clear();
|
|
ss.str(value);
|
|
uint32_t max_sessions;
|
|
ss >> max_sessions;
|
|
ASSERT_FALSE(ss.fail());
|
|
EXPECT_TRUE(ss.eof());
|
|
EXPECT_LE(open_sessions, max_sessions);
|
|
EXPECT_LE(8u, max_sessions);
|
|
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(
|
|
kLevel3, wvcdm::QUERY_KEY_OEMCRYPTO_API_VERSION, &value));
|
|
ss.clear();
|
|
ss.str(value);
|
|
uint32_t api_version;
|
|
ss >> api_version;
|
|
ASSERT_FALSE(ss.fail());
|
|
EXPECT_TRUE(ss.eof());
|
|
EXPECT_LE(10u, api_version);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, QueryOemCryptoSessionId) {
|
|
Unprovision();
|
|
Provision(kLevelDefault);
|
|
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth);
|
|
|
|
CdmQueryMap query_info;
|
|
CdmQueryMap::iterator itr;
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QueryOemCryptoSessionId(session_id_, &query_info));
|
|
|
|
uint32_t oem_crypto_session_id;
|
|
itr = query_info.find(wvcdm::QUERY_KEY_OEMCRYPTO_SESSION_ID);
|
|
ASSERT_TRUE(itr != query_info.end());
|
|
std::istringstream ss;
|
|
ss.str(itr->second);
|
|
ss >> oem_crypto_session_id;
|
|
ASSERT_FALSE(ss.fail());
|
|
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, SecurityLevelPathBackwardCompatibility) {
|
|
Unprovision();
|
|
Provision(kLevelDefault);
|
|
|
|
// override default settings unless configured through the command line
|
|
std::string key_id;
|
|
std::string client_auth;
|
|
|
|
GetOfflineConfiguration(&key_id, &client_auth);
|
|
|
|
std::string level;
|
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
|
decryptor_.QueryStatus(kLevelDefault,
|
|
wvcdm::QUERY_KEY_SECURITY_LEVEL,
|
|
&level));
|
|
EXPECT_TRUE(wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3 == level ||
|
|
wvcdm::QUERY_VALUE_SECURITY_LEVEL_L1 == level);
|
|
|
|
CdmSecurityLevel security_level =
|
|
wvcdm::QUERY_VALUE_SECURITY_LEVEL_L1 == level
|
|
? kSecurityLevelL1
|
|
: kSecurityLevelL3;
|
|
|
|
std::string base_path;
|
|
EXPECT_TRUE(Properties::GetDeviceFilesBasePath(security_level, &base_path));
|
|
|
|
std::vector<std::string> security_dirs;
|
|
EXPECT_TRUE(Properties::GetSecurityLevelDirectories(&security_dirs));
|
|
size_t pos = std::string::npos;
|
|
for (size_t i = 0; i < security_dirs.size(); i++) {
|
|
pos = base_path.rfind(security_dirs[i]);
|
|
if (std::string::npos != pos) break;
|
|
}
|
|
|
|
// Delete any old files.
|
|
EXPECT_NE(std::string::npos, pos);
|
|
std::string old_base_path(base_path, 0, pos);
|
|
FileSystem file_system;
|
|
for (size_t i = 0; i < security_dirs.size(); i++) {
|
|
std::string path = old_base_path + kPathDelimiter + security_dirs[i];
|
|
file_system.Remove(path);
|
|
}
|
|
|
|
// Provision the device to create any required files.
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
std::string provisioning_server;
|
|
CdmCertificateType cert_type = kCertificateWidevine;
|
|
std::string cert_authority, cert, wrapped_key;
|
|
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest(
|
|
cert_type, cert_authority,
|
|
kDefaultCdmIdentifier, &key_msg_,
|
|
&provisioning_server));
|
|
EXPECT_EQ(provisioning_server, g_config->provisioning_server());
|
|
std::string response =
|
|
GetCertRequestResponse(g_config->provisioning_server());
|
|
EXPECT_NE(0, static_cast<int>(response.size()));
|
|
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.HandleProvisioningResponse(
|
|
kDefaultCdmIdentifier, response, &cert,
|
|
&wrapped_key));
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
std::vector<std::string> files;
|
|
EXPECT_TRUE(FileUtils::List(base_path, &files));
|
|
size_t number_of_files = files.size();
|
|
|
|
// Create an offline license to create license files.
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
GenerateKeyRequest(key_id, kLicenseTypeOffline);
|
|
VerifyKeyRequestResponse(g_license_server, client_auth);
|
|
CdmKeySetId key_set_id = key_set_id_;
|
|
EXPECT_FALSE(key_set_id_.empty());
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
EXPECT_TRUE(FileUtils::List(base_path, &files));
|
|
int number_of_new_files = files.size() - number_of_files;
|
|
// There should be a new license file, and maybe a new usage table
|
|
// file.
|
|
EXPECT_LE(1, number_of_new_files);
|
|
EXPECT_GE(2, number_of_new_files);
|
|
|
|
// Move files to the old location.
|
|
for (size_t i = 0; i < files.size(); ++i) {
|
|
std::string from = base_path + files[i];
|
|
if (FileUtils::IsRegularFile(from)) {
|
|
std::string to = old_base_path + files[i];
|
|
EXPECT_TRUE(FileUtils::Copy(from, to));
|
|
}
|
|
}
|
|
EXPECT_TRUE(file_system.Remove(base_path));
|
|
|
|
//// Setup complete to earlier version (non-security level based) path.
|
|
|
|
// Create a new file system. This will cause the files to be moved over.
|
|
// Normally this will happen when the plugin is created, but since we are
|
|
// reusing the same decryptor, we need it to update here.
|
|
FileSystem dummy_file_system;
|
|
|
|
// Restore persistent license, retrieve L1, L3 streaming licenses to verify
|
|
session_id_.clear();
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_.RestoreKey(session_id_, key_set_id));
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
|
|
VerifyKeyRequestResponse(g_license_server, client_auth);
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
if (security_level != kSecurityLevelL1) return;
|
|
|
|
TestWvCdmClientPropertySet property_set;
|
|
property_set.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
|
|
|
|
EXPECT_EQ(wvcdm::NEED_PROVISIONING,
|
|
decryptor_.OpenSession(g_key_system, &property_set,
|
|
kDefaultCdmIdentifier, NULL, &session_id_));
|
|
EXPECT_EQ(NO_ERROR, decryptor_.GetProvisioningRequest(
|
|
cert_type, cert_authority, kDefaultCdmIdentifier,
|
|
&key_msg_, &provisioning_server));
|
|
EXPECT_EQ(provisioning_server, g_config->provisioning_server());
|
|
response = GetCertRequestResponse(g_config->provisioning_server());
|
|
EXPECT_NE(0, static_cast<int>(response.size()));
|
|
EXPECT_EQ(NO_ERROR, decryptor_.HandleProvisioningResponse(
|
|
kDefaultCdmIdentifier, response, &cert,
|
|
&wrapped_key));
|
|
|
|
EXPECT_EQ(NO_ERROR, decryptor_.OpenSession(g_key_system, &property_set,
|
|
kDefaultCdmIdentifier, NULL,
|
|
&session_id_));
|
|
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
|
|
VerifyKeyRequestResponse(g_license_server, client_auth);
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, DISABLED_OfflineLicenseDecryptionTest) {
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
GenerateKeyRequest(g_key_id, kLicenseTypeOffline);
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth);
|
|
|
|
/*
|
|
// key 1, encrypted, 256b
|
|
DecryptionData data;
|
|
data.is_encrypted = true;
|
|
data.is_secure = false;
|
|
data.key_id = wvcdm::a2bs_hex("30313233343536373839414243444546");
|
|
data.encrypt_data = wvcdm::a2b_hex(
|
|
"b6d7d2430aa82b1cb8bd32f02e1f3b2a8d84f9eddf935ced5a6a98022cbb4561"
|
|
"8346a749fdb336858a64d7169fd0aa898a32891d14c24bed17fdc17fd62b8771"
|
|
"a8e22e9f093fa0f2aacd293d471b8e886d5ed8d0998ab2fde2d908580ff88c93"
|
|
"c0f0bbc14867267b3a3955bb6e7d05fca734a3aec3463d786d555cad83536ebe"
|
|
"4496d934d40df2aba5aea98c1145a2890879568ae31bb8a85d74714a4ad75785"
|
|
"7488523e697f5fd370eac746d56990a81cc76a178e3d6d65743520cdbc669412"
|
|
"9e73b86214256c67430cf78662346cab3e2bdd6f095dddf75b7fb3868c5ff5ff"
|
|
"3e1bbf08d456532ffa9df6e21a8bb2664c2d2a6d47ee78f9a6d53b2f2c8c087c");
|
|
data.iv = wvcdm::a2b_hex("86856b9409743ca107b043e82068c7b6");
|
|
data.block_offset = 0;
|
|
data.decrypt_data = wvcdm::a2b_hex(
|
|
"cc4a7fed8c5ac6e316e45317805c43e6d62a383ad738219c65e7a259dc12b46a"
|
|
"d50a3f8ce2facec8eeadff9cfa6b649212b88602b41f6d4c510c05af07fd523a"
|
|
"e7032634d9f8db5dd652d35f776376c5fc56e7031ed7cb28b72427fd4b367b6d"
|
|
"8c4eb6e46ed1249de5d24a61aeb08ebd60984c10581042ca8b0ef6bc44ec34a0"
|
|
"d4a77d68125c9bb1ace6f650e8716540f5b20d6482f7cfdf1b57a9ee9802160c"
|
|
"a632ce42934347410abc61bb78fba11b093498572de38bca96101ecece455e3b"
|
|
"5fef6805c44a2609cf97ce0dac7f15695c8058c590eda517f845108b90dfb29c"
|
|
"e73f3656000399f2fd196bc6fc225f3a7b8f578237751fd485ff070b5289e5cf");
|
|
|
|
std::vector<uint8_t> decrypt_buffer;
|
|
size_t encrypt_length = data.encrypt_data.size();
|
|
decrypt_buffer.resize(encrypt_length);
|
|
|
|
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_,
|
|
data.is_encrypted,
|
|
data.is_secure,
|
|
data.key_id,
|
|
&data.encrypt_data.front(),
|
|
encrypt_length,
|
|
data.iv,
|
|
data.block_offset,
|
|
&decrypt_buffer.front(),
|
|
0));
|
|
|
|
EXPECT_TRUE(std::equal(data.decrypt_data.begin(), data.decrypt_data.end(),
|
|
decrypt_buffer.begin()));
|
|
*/
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, DISABLED_RestoreOfflineLicenseDecryptionTest) {
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
GenerateKeyRequest(g_key_id, kLicenseTypeOffline);
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth);
|
|
CdmKeySetId key_set_id = key_set_id_;
|
|
EXPECT_FALSE(key_set_id_.empty());
|
|
decryptor_.CloseSession(session_id_);
|
|
|
|
session_id_.clear();
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_.RestoreKey(session_id_, key_set_id));
|
|
/*
|
|
// key 1, encrypted, 256b
|
|
DecryptionData data;
|
|
data.is_encrypted = true;
|
|
data.is_secure = false;
|
|
data.key_id = wvcdm::a2bs_hex("30313233343536373839414243444546");
|
|
data.encrypt_data = wvcdm::a2b_hex(
|
|
"b6d7d2430aa82b1cb8bd32f02e1f3b2a8d84f9eddf935ced5a6a98022cbb4561"
|
|
"8346a749fdb336858a64d7169fd0aa898a32891d14c24bed17fdc17fd62b8771"
|
|
"a8e22e9f093fa0f2aacd293d471b8e886d5ed8d0998ab2fde2d908580ff88c93"
|
|
"c0f0bbc14867267b3a3955bb6e7d05fca734a3aec3463d786d555cad83536ebe"
|
|
"4496d934d40df2aba5aea98c1145a2890879568ae31bb8a85d74714a4ad75785"
|
|
"7488523e697f5fd370eac746d56990a81cc76a178e3d6d65743520cdbc669412"
|
|
"9e73b86214256c67430cf78662346cab3e2bdd6f095dddf75b7fb3868c5ff5ff"
|
|
"3e1bbf08d456532ffa9df6e21a8bb2664c2d2a6d47ee78f9a6d53b2f2c8c087c");
|
|
data.iv = wvcdm::a2b_hex("86856b9409743ca107b043e82068c7b6");
|
|
data.block_offset = 0;
|
|
data.decrypt_data = wvcdm::a2b_hex(
|
|
"cc4a7fed8c5ac6e316e45317805c43e6d62a383ad738219c65e7a259dc12b46a"
|
|
"d50a3f8ce2facec8eeadff9cfa6b649212b88602b41f6d4c510c05af07fd523a"
|
|
"e7032634d9f8db5dd652d35f776376c5fc56e7031ed7cb28b72427fd4b367b6d"
|
|
"8c4eb6e46ed1249de5d24a61aeb08ebd60984c10581042ca8b0ef6bc44ec34a0"
|
|
"d4a77d68125c9bb1ace6f650e8716540f5b20d6482f7cfdf1b57a9ee9802160c"
|
|
"a632ce42934347410abc61bb78fba11b093498572de38bca96101ecece455e3b"
|
|
"5fef6805c44a2609cf97ce0dac7f15695c8058c590eda517f845108b90dfb29c"
|
|
"e73f3656000399f2fd196bc6fc225f3a7b8f578237751fd485ff070b5289e5cf");
|
|
|
|
std::vector<uint8_t> decrypt_buffer;
|
|
size_t encrypt_length = data.encrypt_data.size();
|
|
decrypt_buffer.resize(encrypt_length);
|
|
|
|
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_,
|
|
data.is_encrypted,
|
|
data.is_secure,
|
|
data.key_id,
|
|
&data.encrypt_data.front(),
|
|
encrypt_length,
|
|
data.iv,
|
|
data.block_offset,
|
|
&decrypt_buffer.front(),
|
|
0));
|
|
|
|
EXPECT_TRUE(std::equal(data.decrypt_data.begin(), data.decrypt_data.end(),
|
|
decrypt_buffer.begin()));
|
|
*/
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
// TODO(rfrias, edwinwong): pending L1 OEMCrypto due to key block handling
|
|
/*
|
|
TEST_F(WvCdmRequestLicenseTest, KeyControlBlockDecryptionTest) {
|
|
decryptor_.OpenSession(g_key_system, &session_id_);
|
|
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth);
|
|
|
|
DecryptionData data;
|
|
|
|
// block 4, key 2, encrypted
|
|
data.is_encrypted = true;
|
|
data.is_secure = false;
|
|
data.key_id = wvcdm::a2bs_hex("0915007CAA9B5931B76A3A85F046523E");
|
|
data.encrypt_data = wvcdm::a2b_hex(
|
|
"6758ac1c6ccf5d08479e3bfc62bbc0fd154aff4415aa7ed53d89e3983248d117"
|
|
"ab5137ae7cedd9f9d7321d4cf35a7013237afbcc2d893d1d928efa94e9f7e2ed"
|
|
"1855463cf75ff07ecc0246b90d0734f42d98aeea6a0a6d2618a8339bd0aca368"
|
|
"4fb4a4670c0385e5bd5de9e2d8b9226851b8f8955adfbab968793b46fd152f5e"
|
|
"e608467bb2695836f8f76c32731f5e208176d05e4b07020d58f6282c477f3840"
|
|
"b8079c02e8bd1d03191d190cc505ddfbb2e9bacc794534c91fe409d62f5389b9"
|
|
"35ed66134bd30f09f8da9dbfe6b8cf53d13cae34dae6e89109216e3a02233d5c"
|
|
"2f66aef74313aae4a99b654b485b5cc207b2dc8d44a8b99a4dc196a9820eccef");
|
|
data.iv = wvcdm::a2b_hex("c8f2d133ec357fe727cd233b3bfa755f");
|
|
data.block_offset = 0;
|
|
data.decrypt_data = wvcdm::a2b_hex(
|
|
"34bab89185f1be990dfc454410c7c9093d008bc783908838b02a65b26db28759"
|
|
"dca9dc5f117b3c8c3898358722d1b4c490e5a5d168ba0f9f8a3d4371b8fd1057"
|
|
"2d6dd65f3f9d1850de8d76dc71bd6dc6c23da4e1223fcc3e47162033a6f82890"
|
|
"e2bd6e9d6ddbe453830afc89064ed18078c786f8f746fcbafd88e83e7160cce5"
|
|
"62fa7a7d699ef8421bda020d242ae4f61a786213b707c3b17b83d77510f9a07e"
|
|
"d9d7e47d8f8fa2aff86eb26d61ddf384a27513e3facf6b1f5fe6c0d063b8856c"
|
|
"c486d930393ea79ba73ba293eda39059e2ce9ee7bd5d31ab11f35e55dc35dfe0"
|
|
"ea5e2ec684014852add6e29ce7d88a1595641ae4c0dd10155526b5a87560ec9d");
|
|
|
|
std::vector<uint8_t> decrypt_buffer;
|
|
size_t encrypt_length = data[i].encrypt_data.size();
|
|
decrypt_buffer.resize(encrypt_length);
|
|
|
|
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_,
|
|
data.is_encrypted,
|
|
data.is_secure,
|
|
data.key_id,
|
|
&data.encrypt_data.front(),
|
|
encrypt_length,
|
|
data.iv,
|
|
data.block_offset,
|
|
&decrypt_buffer.front()));
|
|
|
|
EXPECT_TRUE(std::equal(data.decrypt_data.begin(),
|
|
data.decrypt_data.end(),
|
|
decrypt_buffer.begin()));
|
|
}
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
*/
|
|
|
|
class WvCdmSessionSharingTest
|
|
: public WvCdmRequestLicenseTest,
|
|
public ::testing::WithParamInterface<SessionSharingSubSampleInfo*> {};
|
|
|
|
TEST_P(WvCdmSessionSharingTest, SessionSharingTest) {
|
|
SessionSharingSubSampleInfo* session_sharing_info = GetParam();
|
|
|
|
TestWvCdmClientPropertySet property_set;
|
|
property_set.set_session_sharing_mode(
|
|
session_sharing_info->session_sharing_enabled);
|
|
|
|
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
|
|
NULL, &session_id_);
|
|
CdmSessionId gp_session_id_1 = session_id_;
|
|
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth);
|
|
|
|
// TODO(rfrias): Move content information to ConfigTestEnv
|
|
std::string gp_client_auth2 =
|
|
"?source=YOUTUBE&video_id=z3S_NhwueaM&oauth=ya.gtsqawidevine";
|
|
std::string gp_key_id2 = wvcdm::a2bs_hex(
|
|
"000000347073736800000000" // blob size and pssh
|
|
"edef8ba979d64acea3c827dcd51d21ed00000014" // Widevine system id
|
|
"08011210bdf1cb4fffc6506b8b7945b0bd2917fb"); // pssh data
|
|
|
|
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
|
|
NULL, &session_id_);
|
|
CdmSessionId gp_session_id_2 = session_id_;
|
|
GenerateKeyRequest(gp_key_id2, kLicenseTypeStreaming);
|
|
VerifyKeyRequestResponse(g_license_server, gp_client_auth2);
|
|
|
|
SubSampleInfo* data = session_sharing_info->sub_sample;
|
|
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
|
|
CdmDecryptionParameters decryption_parameters(
|
|
&data->key_id, &data->encrypt_data.front(), data->encrypt_data.size(),
|
|
&data->iv, data->block_offset, &decrypt_buffer[0]);
|
|
decryption_parameters.is_encrypted = data->is_encrypted;
|
|
decryption_parameters.is_secure = data->is_secure;
|
|
decryption_parameters.subsample_flags = data->subsample_flags;
|
|
|
|
if (session_sharing_info->session_sharing_enabled || !data->is_encrypted) {
|
|
EXPECT_EQ(NO_ERROR,
|
|
decryptor_.Decrypt(gp_session_id_2, data->validate_key_id,
|
|
decryption_parameters));
|
|
EXPECT_TRUE(std::equal(data->decrypt_data.begin(), data->decrypt_data.end(),
|
|
decrypt_buffer.begin()));
|
|
} else {
|
|
EXPECT_EQ(NEED_KEY,
|
|
decryptor_.Decrypt(gp_session_id_2, data->validate_key_id,
|
|
decryption_parameters));
|
|
}
|
|
|
|
decryptor_.CloseSession(gp_session_id_1);
|
|
decryptor_.CloseSession(gp_session_id_2);
|
|
}
|
|
|
|
INSTANTIATE_TEST_CASE_P(Cdm, WvCdmSessionSharingTest,
|
|
::testing::Range(&session_sharing_sub_samples[0],
|
|
&session_sharing_sub_samples[6]));
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, SessionSharingTest) {
|
|
TestWvCdmClientPropertySet property_set;
|
|
property_set.set_session_sharing_mode(true);
|
|
|
|
// TODO(rfrias): Move content information to ConfigTestEnv
|
|
const std::string init_data1 = a2bs_hex(
|
|
"000000347073736800000000" // blob size and pssh
|
|
"EDEF8BA979D64ACEA3C827DCD51D21ED00000014" // Widevine system id
|
|
"0801121030313233343536373839616263646566"); // pssh data
|
|
|
|
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
|
|
NULL, &session_id_);
|
|
CdmSessionId session_id1 = session_id_;
|
|
GenerateKeyRequest(init_data1, kLicenseTypeStreaming);
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth);
|
|
|
|
// TODO(rfrias): Move content information to ConfigTestEnv
|
|
std::string gp_client_auth2 =
|
|
"?source=YOUTUBE&video_id=z3S_NhwueaM&oauth=ya.gtsqawidevine";
|
|
std::string init_data2 = a2bs_hex(
|
|
"000000347073736800000000" // blob size and pssh
|
|
"edef8ba979d64acea3c827dcd51d21ed00000014" // Widevine system id
|
|
"08011210bdf1cb4fffc6506b8b7945b0bd2917fb"); // pssh data
|
|
|
|
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
|
|
NULL, &session_id_);
|
|
CdmSessionId session_id2 = session_id_;
|
|
GenerateKeyRequest(init_data2, kLicenseTypeStreaming);
|
|
VerifyKeyRequestResponse(g_license_server, gp_client_auth2);
|
|
|
|
SubSampleInfo* data = &single_encrypted_sub_sample_short_expiry;
|
|
|
|
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
|
|
CdmDecryptionParameters decryption_parameters(
|
|
&data->key_id, &data->encrypt_data.front(), data->encrypt_data.size(),
|
|
&data->iv, data->block_offset, &decrypt_buffer[0]);
|
|
decryption_parameters.is_encrypted = data->is_encrypted;
|
|
decryption_parameters.is_secure = data->is_secure;
|
|
decryption_parameters.subsample_flags = data->subsample_flags;
|
|
|
|
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id1, data->validate_key_id,
|
|
decryption_parameters));
|
|
|
|
sleep(kSingleEncryptedSubSampleIcpLicenseDurationExpiration -
|
|
kSingleEncryptedSubSampleIcpLicenseExpirationWindow);
|
|
|
|
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
|
|
NULL, &session_id_);
|
|
CdmSessionId session_id3 = session_id_;
|
|
GenerateKeyRequest(init_data1, kLicenseTypeStreaming);
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth);
|
|
|
|
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id1, data->validate_key_id,
|
|
decryption_parameters));
|
|
|
|
sleep(kSingleEncryptedSubSampleIcpLicenseExpirationWindow);
|
|
// session 1 will be expired, shared session 3 will be used to decrypt
|
|
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id1, data->validate_key_id,
|
|
decryption_parameters));
|
|
|
|
decryptor_.CloseSession(session_id1);
|
|
decryptor_.CloseSession(session_id2);
|
|
decryptor_.CloseSession(session_id3);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, DecryptionKeyExpiredTest) {
|
|
const std::string kCpKeyId = a2bs_hex(
|
|
"000000347073736800000000" // blob size and pssh
|
|
"EDEF8BA979D64ACEA3C827DCD51D21ED00000014" // Widevine system id
|
|
"0801121030313233343536373839616263646566"); // pssh data
|
|
SubSampleInfo* data = &single_encrypted_sub_sample_short_expiry;
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
if (data->retrieve_key) {
|
|
GenerateKeyRequest(kCpKeyId, kLicenseTypeStreaming);
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth);
|
|
}
|
|
|
|
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
|
|
CdmDecryptionParameters decryption_parameters(
|
|
&data->key_id, &data->encrypt_data.front(), data->encrypt_data.size(),
|
|
&data->iv, data->block_offset, &decrypt_buffer[0]);
|
|
decryption_parameters.is_encrypted = data->is_encrypted;
|
|
decryption_parameters.is_secure = data->is_secure;
|
|
decryption_parameters.subsample_flags = data->subsample_flags;
|
|
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_, data->validate_key_id,
|
|
decryption_parameters));
|
|
sleep(kSingleEncryptedSubSampleIcpLicenseDurationExpiration +
|
|
kSingleEncryptedSubSampleIcpLicenseExpirationWindow);
|
|
EXPECT_EQ(NEED_KEY, decryptor_.Decrypt(session_id_, data->validate_key_id,
|
|
decryption_parameters));
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, SessionKeyChangeNotificationTest) {
|
|
StrictMock<TestWvCdmEventListener> listener;
|
|
DecryptCallbackTester decrypt_callback(
|
|
&decryptor_,
|
|
&single_encrypted_sub_sample_short_expiry);
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, &listener,
|
|
&session_id_);
|
|
EXPECT_CALL(
|
|
listener,
|
|
OnSessionKeysChange(
|
|
session_id_,
|
|
AllOf(Each(Pair(_, kKeyStatusUsable)), Not(IsEmpty())), true))
|
|
.WillOnce(Invoke(&decrypt_callback, &DecryptCallbackTester::Decrypt));
|
|
;
|
|
EXPECT_CALL(listener, OnExpirationUpdate(session_id_, _));
|
|
|
|
const std::string kCpKeyId = a2bs_hex(
|
|
"000000347073736800000000" // blob size and pssh
|
|
"EDEF8BA979D64ACEA3C827DCD51D21ED00000014" // Widevine system id
|
|
"0801121030313233343536373839616263646566"); // pssh data
|
|
|
|
GenerateKeyRequest(kCpKeyId, kLicenseTypeStreaming);
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth);
|
|
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
class WvCdmDecryptionTest
|
|
: public WvCdmRequestLicenseTest,
|
|
public ::testing::WithParamInterface<SubSampleInfo*> {};
|
|
|
|
TEST_P(WvCdmDecryptionTest, DecryptionTest) {
|
|
SubSampleInfo* data = GetParam();
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
if (data->retrieve_key) {
|
|
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
|
|
VerifyKeyRequestResponse(g_license_server, g_client_auth);
|
|
}
|
|
|
|
uint32_t decrypt_sample_buffer_size = 0;
|
|
uint32_t decrypt_buffer_offset = 0;
|
|
for (size_t i = 0; i < data->num_of_subsamples; i++)
|
|
decrypt_sample_buffer_size += (data + i)->encrypt_data.size();
|
|
|
|
std::vector<uint8_t> decrypt_buffer(decrypt_sample_buffer_size);
|
|
std::vector<uint8_t> expected_decrypt_data;
|
|
|
|
for (size_t i = 0; i < data->num_of_subsamples; i++) {
|
|
CdmDecryptionParameters decryption_parameters(
|
|
&(data + i)->key_id, &(data + i)->encrypt_data.front(),
|
|
(data + i)->encrypt_data.size(), &(data + i)->iv,
|
|
(data + i)->block_offset, &decrypt_buffer[0]);
|
|
decryption_parameters.is_encrypted = (data + i)->is_encrypted;
|
|
decryption_parameters.is_secure = (data + i)->is_secure;
|
|
decryption_parameters.subsample_flags = (data + i)->subsample_flags;
|
|
decryption_parameters.decrypt_buffer_length = decrypt_sample_buffer_size;
|
|
decryption_parameters.decrypt_buffer_offset = decrypt_buffer_offset;
|
|
expected_decrypt_data.insert(expected_decrypt_data.end(),
|
|
(data+i)->decrypt_data.begin(),
|
|
(data+i)->decrypt_data.end());
|
|
EXPECT_EQ(NO_ERROR,
|
|
decryptor_.Decrypt(session_id_, (data + i)->validate_key_id,
|
|
decryption_parameters));
|
|
|
|
decrypt_buffer_offset += (data +i)->encrypt_data.size();
|
|
}
|
|
EXPECT_TRUE(std::equal(expected_decrypt_data.begin(),
|
|
expected_decrypt_data.end(),
|
|
decrypt_buffer.begin()));
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
INSTANTIATE_TEST_CASE_P(Cdm, WvCdmDecryptionTest,
|
|
::testing::Values(&clear_sub_sample,
|
|
&clear_sub_sample_no_key,
|
|
&single_encrypted_sub_sample,
|
|
&switch_key_encrypted_sub_samples[0],
|
|
&partial_encrypted_sub_samples[0]));
|
|
|
|
class WvCdmSessionSharingNoKeyTest
|
|
: public WvCdmRequestLicenseTest,
|
|
public ::testing::WithParamInterface<SubSampleInfo*> {};
|
|
|
|
TEST_P(WvCdmSessionSharingNoKeyTest, DecryptionTest) {
|
|
SubSampleInfo* data = GetParam();
|
|
|
|
TestWvCdmClientPropertySet property_set;
|
|
property_set.set_session_sharing_mode(true);
|
|
|
|
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
|
|
NULL, &session_id_);
|
|
CdmSessionId gp_session_id_1 = session_id_;
|
|
GenerateKeyRequest(g_key_id, kLicenseTypeStreaming);
|
|
|
|
// TODO(rfrias): Move content information to ConfigTestEnv
|
|
std::string gp_client_auth2 =
|
|
"?source=YOUTUBE&video_id=z3S_NhwueaM&oauth=ya.gtsqawidevine";
|
|
std::string gp_key_id2 = wvcdm::a2bs_hex(
|
|
"000000347073736800000000" // blob size and pssh
|
|
"edef8ba979d64acea3c827dcd51d21ed00000014" // Widevine system id
|
|
"08011210bdf1cb4fffc6506b8b7945b0bd2917fb"); // pssh data
|
|
|
|
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
|
|
NULL, &session_id_);
|
|
CdmSessionId gp_session_id_2 = session_id_;
|
|
GenerateKeyRequest(gp_key_id2, kLicenseTypeStreaming);
|
|
|
|
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
|
|
CdmDecryptionParameters decryption_parameters(
|
|
&data->key_id, &data->encrypt_data.front(), data->encrypt_data.size(),
|
|
&data->iv, data->block_offset, &decrypt_buffer[0]);
|
|
decryption_parameters.is_encrypted = data->is_encrypted;
|
|
decryption_parameters.is_secure = data->is_secure;
|
|
decryption_parameters.subsample_flags = data->subsample_flags;
|
|
|
|
EXPECT_EQ(data->is_encrypted ? KEY_NOT_FOUND_IN_SESSION : NO_ERROR,
|
|
decryptor_.Decrypt(gp_session_id_2, data->validate_key_id,
|
|
decryption_parameters));
|
|
if (!data->is_encrypted) {
|
|
EXPECT_TRUE(std::equal(data->decrypt_data.begin(), data->decrypt_data.end(),
|
|
decrypt_buffer.begin()));
|
|
}
|
|
|
|
decryptor_.CloseSession(gp_session_id_1);
|
|
decryptor_.CloseSession(gp_session_id_2);
|
|
}
|
|
|
|
INSTANTIATE_TEST_CASE_P(Cdm, WvCdmSessionSharingNoKeyTest,
|
|
::testing::Values(&clear_sub_sample,
|
|
&clear_sub_sample_no_key,
|
|
&single_encrypted_sub_sample));
|
|
|
|
TEST(VersionNumberTest, VersionNumberChangeCanary) {
|
|
char release_number[PROPERTY_VALUE_MAX];
|
|
ASSERT_GT(property_get("ro.build.version.release", release_number, "Unknown"),
|
|
0);
|
|
EXPECT_STREQ("8.1.0", release_number)
|
|
<< "The Android version number has changed. You need to update this test "
|
|
"and also possibly update the Widevine version number in "
|
|
"properties_android.cpp.";
|
|
|
|
std::string widevine_version;
|
|
ASSERT_TRUE(Properties::GetWVCdmVersion(&widevine_version));
|
|
EXPECT_EQ("v5.1.0-android", widevine_version)
|
|
<< "The Widevine CDM version number has changed. Did you forget to "
|
|
"update this test after changing it?";
|
|
}
|
|
|
|
TEST_F(WvCdmRequestLicenseTest, AddHlsStreamingKeyTest) {
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
CdmAppParameterMap app_parameters;
|
|
GenerateKeyRequest(wvcdm::KEY_MESSAGE, HLS_INIT_DATA_FORMAT,
|
|
kAttributeListSampleAes, app_parameters,
|
|
kLicenseTypeStreaming, NULL);
|
|
//TODO(rfrias): Remove once we switch to git-on-borg
|
|
std::string license_server = "https://proxy.uat.widevine.com/proxy";
|
|
VerifyKeyRequestResponse(license_server, g_client_auth);
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
class WvHlsInitDataTest
|
|
: public WvCdmRequestLicenseTest,
|
|
public ::testing::WithParamInterface<std::string> {};
|
|
|
|
TEST_P(WvHlsInitDataTest, InvalidHlsFormatTest) {
|
|
decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL,
|
|
&session_id_);
|
|
CdmAppParameterMap app_parameters;
|
|
std::string init_data = GetParam();
|
|
GenerateKeyRequest(wvcdm::INIT_DATA_NOT_FOUND, HLS_INIT_DATA_FORMAT,
|
|
init_data, app_parameters, kLicenseTypeStreaming, NULL);
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
INSTANTIATE_TEST_CASE_P(Cdm, WvHlsInitDataTest,
|
|
::testing::Values(
|
|
kAttributeListKeyFormatNonWidevine,
|
|
kAttributeListKeyFormatVersionUnregonized,
|
|
kAttributeListUnspecifiedIv,
|
|
kAttributeListUnspecifiedMethod));
|
|
|
|
class WvHlsDecryptionTest
|
|
: public WvCdmRequestLicenseTest,
|
|
public ::testing::WithParamInterface<HlsDecryptionInfo*> {};
|
|
|
|
TEST_P(WvHlsDecryptionTest, HlsDecryptionTest) {
|
|
Provision(kLevel3);
|
|
TestWvCdmClientPropertySet client_property_set;
|
|
client_property_set.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
|
|
HlsDecryptionInfo* info = GetParam();
|
|
|
|
TestWvCdmHlsEventListener listener;
|
|
decryptor_.OpenSession(g_key_system, &client_property_set,
|
|
kDefaultCdmIdentifier, &listener, &session_id_);
|
|
CdmAppParameterMap app_parameters;
|
|
GenerateKeyRequest(wvcdm::KEY_MESSAGE, HLS_INIT_DATA_FORMAT,
|
|
info->attribute_list, app_parameters,
|
|
kLicenseTypeStreaming, NULL);
|
|
//TODO(rfrias): Remove once we switch to git-on-borg
|
|
std::string license_server = "https://proxy.uat.widevine.com/proxy";
|
|
VerifyKeyRequestResponse(license_server, g_client_auth);
|
|
CdmKeyStatusMap key_status_map = listener.GetKeyStatusMap();
|
|
EXPECT_EQ(1u, key_status_map.size());
|
|
KeyId key_id = key_status_map.begin()->first;
|
|
EXPECT_EQ(KEY_ID_SIZE, key_id.size());
|
|
|
|
for (size_t i = 0; i < info->number_of_segments; ++i) {
|
|
HlsSegmentInfo* data = info->segment_info + i;
|
|
std::vector<uint8_t> output_buffer(data->encrypted_data.size(), 0);
|
|
std::vector<uint8_t> iv(data->iv.begin(), data->iv.end());
|
|
CdmDecryptionParameters decryption_parameters(
|
|
&key_id, reinterpret_cast<const uint8_t*>(data->encrypted_data.c_str()),
|
|
data->encrypted_data.size(), &iv, 0, &output_buffer[0]);
|
|
decryption_parameters.is_encrypted = true;
|
|
decryption_parameters.is_secure = false;
|
|
decryption_parameters.cipher_mode = kCipherModeCbc;
|
|
if (info->sample_aes) {
|
|
decryption_parameters.pattern_descriptor.encrypt_blocks = 1;
|
|
decryption_parameters.pattern_descriptor.skip_blocks = 9;
|
|
}
|
|
decryption_parameters.subsample_flags = data->subsample_flags;
|
|
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_, false,
|
|
decryption_parameters));
|
|
EXPECT_EQ(data->clear_data,
|
|
std::string(reinterpret_cast<const char*>(&output_buffer[0]),
|
|
output_buffer.size()));
|
|
}
|
|
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
INSTANTIATE_TEST_CASE_P(Cdm, WvHlsDecryptionTest,
|
|
::testing::Range(&kHlsDecryptionTestVectors[0],
|
|
&kHlsDecryptionTestVectors[11]));
|
|
|
|
class WvHlsFourCCBackwardCompatibilityTest
|
|
: public WvCdmRequestLicenseTest,
|
|
public ::testing::WithParamInterface<HlsDecryptionInfo*> {};
|
|
|
|
TEST_P(WvHlsFourCCBackwardCompatibilityTest, HlsDecryptionTest) {
|
|
Provision(kLevel3);
|
|
TestWvCdmClientPropertySet client_property_set;
|
|
client_property_set.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
|
|
HlsDecryptionInfo* info = GetParam();
|
|
|
|
TestWvCdmHlsEventListener listener;
|
|
decryptor_.OpenSession(g_key_system, &client_property_set,
|
|
kDefaultCdmIdentifier, &listener, &session_id_);
|
|
CdmAppParameterMap app_parameters;
|
|
GenerateKeyRequest(wvcdm::KEY_MESSAGE, ISO_BMFF_VIDEO_MIME_TYPE,
|
|
info->attribute_list, app_parameters,
|
|
kLicenseTypeStreaming, NULL);
|
|
//TODO(rfrias): Remove once we switch to git-on-borg
|
|
std::string license_server = "https://proxy.uat.widevine.com/proxy";
|
|
VerifyKeyRequestResponse(license_server, g_client_auth);
|
|
CdmKeyStatusMap key_status_map = listener.GetKeyStatusMap();
|
|
EXPECT_EQ(1u, key_status_map.size());
|
|
KeyId key_id = key_status_map.begin()->first;
|
|
EXPECT_EQ(KEY_ID_SIZE, key_id.size());
|
|
|
|
for (size_t i = 0; i < info->number_of_segments; ++i) {
|
|
HlsSegmentInfo* data = info->segment_info + i;
|
|
std::vector<uint8_t> output_buffer(data->encrypted_data.size(), 0);
|
|
std::vector<uint8_t> iv(data->iv.begin(), data->iv.end());
|
|
CdmDecryptionParameters decryption_parameters(
|
|
&key_id, reinterpret_cast<const uint8_t*>(data->encrypted_data.c_str()),
|
|
data->encrypted_data.size(), &iv, 0, &output_buffer[0]);
|
|
decryption_parameters.is_encrypted = true;
|
|
decryption_parameters.is_secure = false;
|
|
decryption_parameters.cipher_mode = kCipherModeCbc;
|
|
if (info->sample_aes) {
|
|
decryption_parameters.pattern_descriptor.encrypt_blocks = 1;
|
|
decryption_parameters.pattern_descriptor.skip_blocks = 9;
|
|
}
|
|
decryption_parameters.subsample_flags = data->subsample_flags;
|
|
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_, false,
|
|
decryption_parameters));
|
|
EXPECT_EQ(data->clear_data,
|
|
std::string(reinterpret_cast<const char*>(&output_buffer[0]),
|
|
output_buffer.size()));
|
|
}
|
|
|
|
decryptor_.CloseSession(session_id_);
|
|
}
|
|
|
|
INSTANTIATE_TEST_CASE_P(
|
|
Cdm, WvHlsFourCCBackwardCompatibilityTest,
|
|
::testing::Range(&kHlsFourCCBackwardCompatibilityTestVectors[0],
|
|
&kHlsFourCCBackwardCompatibilityTestVectors[4]));
|
|
|
|
} // namespace wvcdm
|
|
|
|
void show_menu(char* prog_name) {
|
|
std::cout << std::endl;
|
|
std::cout << "usage: " << prog_name << " [options]" << std::endl << std::endl;
|
|
std::cout << " enclose multiple arguments in '' when using adb shell"
|
|
<< std::endl;
|
|
std::cout << " e.g. adb shell '" << prog_name << " --server=\"url\"'"
|
|
<< std::endl;
|
|
std::cout << " or adb shell '" << prog_name << " -u\"url\"'" << std::endl
|
|
<< std::endl;
|
|
|
|
std::cout << " -i/--license_server_id=<gp/cp/st>" << std::endl;
|
|
std::cout << " specifies which default server settings to use: "
|
|
<< std::endl;
|
|
std::cout << " gp for GooglePlay server" << std::endl;
|
|
std::cout << " cp for Content Protection UAT server" << std::endl;
|
|
std::cout << " st for Content Protection Staging server" << std::endl
|
|
<< std::endl;
|
|
|
|
std::cout << " -k/--keyid=<key_id>" << std::endl;
|
|
std::cout << " configure the key id or pssh, in hex format" << std::endl
|
|
<< std::endl;
|
|
|
|
std::cout << " -s/--cert=<service_certificate>" << std::endl;
|
|
std::cout << " configure the signed service certificate" << std::endl;
|
|
std::cout << " Specify the SignedDeviceCertificate (from "
|
|
<< "device_certificate.proto) " << std::endl;
|
|
std::cout << " in hex format." << std::endl;
|
|
std::cout << " Due to the length of the argument use, " << std::endl;
|
|
std::cout << " echo \"/system/bin/request_license_test -s \\\""
|
|
<< "0ABF02...A29914\\\"\" \\" << std::endl;
|
|
std::cout << " > run_request_license_test.sh" << std::endl;
|
|
std::cout << " chmod +x run_request_license_test.sh" << std::endl;
|
|
std::cout << " adb push run_request_license_test.sh /system/bin"
|
|
<< std::endl;
|
|
std::cout << " adb shell sh /system/bin/run_request_license_test.sh"
|
|
<< std::endl
|
|
<< std::endl;
|
|
|
|
std::cout << " -u/--server=<server_url>" << std::endl;
|
|
std::cout << " configure the license server url, please include http[s]"
|
|
<< " in the url" << std::endl
|
|
<< std::endl;
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
|
|
bool show_usage = false;
|
|
static const struct option long_options[] = {
|
|
{"keyid", required_argument, NULL, 'k'},
|
|
{"license_server_id", required_argument, NULL, 'i'},
|
|
{"service_certificate", required_argument, NULL, 's'},
|
|
{"license_server_url", required_argument, NULL, 'u'},
|
|
{NULL, 0, NULL, '\0'}};
|
|
|
|
int option_index = 0;
|
|
int opt = 0;
|
|
while ((opt = getopt_long(argc, argv, "i:k:s:u:", long_options,
|
|
&option_index)) != -1) {
|
|
switch (opt) {
|
|
case 'i': {
|
|
std::string license_id(optarg);
|
|
if (!license_id.compare("gp")) {
|
|
g_server_configuration_id = wvcdm::kGooglePlayServer;
|
|
} else if (!license_id.compare("cp")) {
|
|
g_server_configuration_id = wvcdm::kContentProtectionUatServer;
|
|
} else if (!license_id.compare("st")) {
|
|
g_server_configuration_id =
|
|
wvcdm::kContentProtectionStagingServer;
|
|
} else {
|
|
std::cout << "Invalid license server id" << optarg << std::endl;
|
|
show_usage = true;
|
|
}
|
|
break;
|
|
}
|
|
case 'k': {
|
|
g_key_id.clear();
|
|
g_key_id.assign(optarg);
|
|
break;
|
|
}
|
|
case 's': {
|
|
g_service_certificate.clear();
|
|
g_service_certificate.assign(wvcdm::a2bs_hex(optarg));
|
|
break;
|
|
}
|
|
case 'u': {
|
|
g_license_server.clear();
|
|
g_license_server.assign(optarg);
|
|
break;
|
|
}
|
|
case '?': {
|
|
show_usage = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (show_usage) {
|
|
show_menu(argv[0]);
|
|
return 0;
|
|
}
|
|
|
|
g_config = new wvcdm::ConfigTestEnv(g_server_configuration_id);
|
|
g_client_auth.assign(g_config->client_auth());
|
|
g_key_system.assign(g_config->key_system());
|
|
g_wrong_key_id.assign(g_config->wrong_key_id());
|
|
|
|
// The following variables are configurable through command line
|
|
// options. If the command line arguments are absent, use the settings
|
|
// in kLicenseServers[] pointed to by g_config.
|
|
if (g_key_id.empty()) {
|
|
g_key_id.assign(g_config->key_id());
|
|
}
|
|
if (g_service_certificate.empty()) {
|
|
g_service_certificate.assign(g_config->license_service_certificate());
|
|
}
|
|
if (g_license_server.empty()) {
|
|
g_license_server.assign(g_config->license_server());
|
|
}
|
|
|
|
// Displays server url, port and key Id being used
|
|
std::cout << std::endl;
|
|
std::cout << "Server: " << g_license_server << std::endl;
|
|
std::cout << "KeyID: " << g_key_id << std::endl << std::endl;
|
|
|
|
g_key_id = wvcdm::a2bs_hex(g_key_id);
|
|
g_config->set_license_server(g_license_server);
|
|
|
|
int status = RUN_ALL_TESTS();
|
|
delete g_config;
|
|
return status;
|
|
}
|