Source release 18.6.0

This commit is contained in:
Alex Dale
2024-06-27 12:54:34 -07:00
parent 28ec8548c6
commit 20c0587dcb
56 changed files with 1191 additions and 35538 deletions

View File

@@ -144,8 +144,10 @@
'include',
],
'dependencies': [
'../cdm/cdm.gyp:device_files',
'../third_party/googletest.gyp:gmock',
'../third_party/googletest.gyp:gtest',
'<(device_files_target)',
],
'conditions': [
['OS=="linux"', {

View File

@@ -10,7 +10,7 @@
# define CDM_VERSION_MAJOR 18
#endif
#ifndef CDM_VERSION_MINOR
# define CDM_VERSION_MINOR 5
# define CDM_VERSION_MINOR 6
#endif
#ifndef CDM_VERSION_PATCH
# define CDM_VERSION_PATCH 0

View File

@@ -0,0 +1,70 @@
# Copyright 2024 Google LLC. All Rights Reserved. This file and proprietary
# source code may only be used and distributed under the Widevine License
# Agreement.
#
# Any top-level targets in this file (and their dependencies) will be built by
# the CE CDM's ./build.py build system. Refer to the distribution package's
# README for details.
{
'includes': [
'platform_properties.gypi',
],
'variables': {
},
'targets': [{
'toolsets' : [ 'target' ],
'target_name': 'install_prov30_oem_cert_tool',
'type': 'executable',
'sources': [
'../oemcrypto/test/install_prov30_oem_cert_tool.cpp',
],
'include_dirs': [
'../cdm/include',
'../core/include',
'../metrics/include',
'../oemcrypto/include',
'../oemcrypto/test',
'../util/include',
],
'dependencies': [
'cdm.gyp:widevine_ce_cdm_static',
],
'msvs_settings': {
'VCLinkerTool': {
# Additionally, since they are loaded locally, suppress these
# warnings.
'AdditionalOptions': [
'/IGNORE:4049',
'/IGNORE:4217',
],
},
},
'conditions': [
['OS=="ios"', {
'type': 'loadable_module',
'mac_xctest_bundle': '1',
'defines': [
'GTEST_FILTER="<(gtest_filter)"',
],
'dependencies': [
'cdm_unittests.gyp:dummy_app',
],
'sources': [
'test/gtest_xctest_wrapper.mm',
],
'xcode_settings': {
'BUNDLE_LOADER': '$(TEST_HOST)',
'TEST_HOST': '<(PRODUCT_DIR)/dummy_app.app/dummy_app',
'WRAPPER_EXTENSION': 'xctest',
},
}, {
'type': 'executable',
}],
['oemcrypto_lib=="target"', {
'dependencies': [
'<(oemcrypto_gyp_path)',
],
}],
],
}],
}

View File

@@ -38,11 +38,6 @@
namespace widevine {
#ifdef HAS_EMBEDDED_CERT
extern const uint8_t kDeviceCert[];
extern const size_t kDeviceCertSize;
#endif
using namespace wvcdm;
using namespace wvutil;
@@ -1700,27 +1695,6 @@ class FileImpl final : public File {
const bool truncate_;
};
#ifdef HAS_EMBEDDED_CERT
class FileCertImpl final : public File {
public:
// This Read method only gives correct results for the first call.
ssize_t Read(char* buffer, size_t bytes) override {
if (!buffer) {
LOGW("File::Read: buffer is empty");
return -1;
}
size_t to_copy = std::min(bytes, kDeviceCertSize);
memcpy(buffer, kDeviceCert, to_copy);
return to_copy;
}
ssize_t Write(const char* buffer, size_t bytes) override {
LOGW("File::Write: device cert is read-only.");
return -1;
}
};
#endif
class FileSystem::Impl {
public:
Impl(widevine::Cdm::IStorage* storage) : storage_(storage) {
@@ -1740,12 +1714,6 @@ FileSystem::~FileSystem() {}
std::unique_ptr<File> FileSystem::Open(const std::string& file_path,
int flags) {
#ifdef HAS_EMBEDDED_CERT
if (file_path == kLegacyCertificateFileName) {
return std::unique_ptr<File>(new FileCertImpl);
}
#endif
if (!(flags & kCreate) && !impl_->storage_->exists(file_path)) {
return nullptr;
}
@@ -1762,39 +1730,20 @@ bool FileSystem::Exists(const std::string& file_path, int* errno_value) {
}
bool FileSystem::Exists(const std::string& file_path) {
#ifdef HAS_EMBEDDED_CERT
if (file_path == kLegacyCertificateFileName) return true;
#endif
return !file_path.empty() && impl_->storage_->exists(file_path);
}
bool FileSystem::Remove(const std::string& file_path) {
#ifdef HAS_EMBEDDED_CERT
if (file_path == kLegacyCertificateFileName) {
LOGE("Cannot remove device cert when embedded.");
return false;
}
#endif
return impl_->storage_->remove(file_path);
}
ssize_t FileSystem::FileSize(const std::string& file_path) {
#ifdef HAS_EMBEDDED_CERT
if (file_path == kLegacyCertificateFileName) {
return kDeviceCertSize;
}
#endif
return impl_->storage_->size(file_path);
}
bool FileSystem::List(const std::string&,
std::vector<std::string>* file_names) {
const bool ret = file_names && impl_->storage_->list(file_names);
#ifdef HAS_EMBEDDED_CERT
if (ret) {
file_names->emplace_back(kLegacyCertificateFileName);
}
#endif
return ret;
}

View File

@@ -15,6 +15,7 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <openssl/aes.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
@@ -40,7 +41,7 @@
#include "test_sleep.h"
#include "url_request.h"
using namespace testing;
using namespace testing;
using namespace wvcdm;
using namespace wvutil;
@@ -185,12 +186,33 @@ const std::vector<uint8_t> kKeyIdCtr =
// kHlsInitData.
const std::vector<uint8_t> kKeyIdCbc =
a2b_hex("9b759040321a408a5c7768b4511287a6");
// This Key ID must match a key embedded in kCencEntitlementInitData1.
const std::vector<uint8_t> kKeyIdEntitlement1 =
a2b_hex("c8326486bb5d5c4a958f00b1111afc81");
// This Key ID must match a key embedded in kCencEntitlementInitData2.
const std::vector<uint8_t> kKeyIdEntitlement2 =
a2b_hex("f8488775a99855ff94b93ec5bd499356");
const std::string kEntitlementContentId = "CDM_Entitlement";
// This entitlement key id has to match the key id in the license data for
// content id "CDM_Entitlement" as seen in the integration console. And it
// also has to match the key id derived by UAT for the content id
// CDM_Entitlement, for the AUDIO track. When running backwards compatibility
// tests, the SDK servers use the data in the integration console, and UAT
// derives key data.
const std::string kKeyIdEntitlement =
a2bs_hex("972F75C583835AABA6778E2565948825");
// The key id and encrypted key are made up. The decrypted key is golden data
// from a working system. This is TEST_ONLY data, so we may include it in source
// code in the clear.
const std::string kKeyIdEntitlement1 = // Key ID for entitled key 1.
a2bs_hex("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
const std::string kEncEntitledKey1 = // Encrypted key data for entitled key 1.
a2bs_hex("11111111111111111111111111111111");
// Clear key data for entitled key 1, used to encrypt test data.
const std::vector<uint8_t> kEntitledKey1 =
a2b_hex("AD789E1309DD67E55965679E72CE2328");
const std::string kKeyIdEntitlement2 = // Key ID for entitled key 2.
a2bs_hex("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB");
const std::string kEncEntitledKey2 = // Encrypted key data for entitled key 2.
a2bs_hex("22222222222222222222222222222222");
// Clear key data for entitled key 2, used to encrypt test data.
const std::vector<uint8_t> kEntitledKey2 =
a2b_hex("EA1E37D89066BF0B6FEF181DD5373580");
// A default pattern object disables patterns during decryption.
const Cdm::Pattern kPatternNone;
@@ -235,15 +257,6 @@ class CdmTest : public WvCdmTestBase, public Cdm::IEventListener {
protected:
void SetUp() override {
// TODO: b/305093063 - Remove when Drm Reprovisioning server is implemented.
// Many of these tests call EnsureProvisioned which tries to provision the
// test device using a provisioning server. Until support is added for Drm
// Reprovisioning on the server, skip these tests to avoid test failures.
if (wvoec::global_features.provisioning_method ==
OEMCrypto_DrmReprovisioning) {
GTEST_SKIP()
<< "Skipping until Drm Reprovisioning server support is implemented.";
}
WvCdmTestBase::SetUp();
// Clear anything stored, load default device cert.
@@ -1470,13 +1483,6 @@ TEST_F(CdmTest, GetExpiration) {
TEST_P(CdmTestWithRemoveParam, Remove) {
const bool intermediate_close = GetParam();
// TODO: b/305093063 - Remove when Drm Reprovisioning server is implemented.
if (wvoec::global_features.provisioning_method ==
OEMCrypto_DrmReprovisioning) {
GTEST_SKIP()
<< "Skipping until Drm Reprovisioning server support is implemented.";
}
EnsureProvisioned();
std::string session_id;
ASSERT_NO_FATAL_FAILURE(
@@ -1949,6 +1955,38 @@ TEST_F(CdmTest, GetStatusForHdcpResolution) {
}
}
// Make some init data for an entitled license. The entitled key information is
// in this PSSH, and the entitlement key information is in the license data on
// UAT.
std::string MakeEntitledData(const std::string& content_key_id,
const std::string& encrypted_content_key) {
video_widevine::WidevinePsshData pssh;
pssh.set_content_id(kEntitlementContentId);
const uint32_t kFourCcCenc = 0x63656e63;
pssh.set_protection_scheme(kFourCcCenc);
pssh.set_type(video_widevine::WidevinePsshData_Type_ENTITLED_KEY);
pssh.set_crypto_period_index(20);
pssh.set_crypto_period_seconds(2);
video_widevine::WidevinePsshData_EntitledKey* key = pssh.add_entitled_keys();
// The key id for the entitlement id. This id is in the license, too.
key->set_entitlement_key_id(kKeyIdEntitlement);
key->set_key_id(content_key_id); // Entitled content key id.
key->set_key(encrypted_content_key); // encrypted entitled content key.
key->set_iv(a2bs_hex("1234567890abcdef1234567890abcdef"));
for (int i = 0; i < 3; i++) {
// The other key ids are just to pad out the init data. Only the first one
// is used.
key = pssh.add_entitled_keys();
char x = 'G' + static_cast<char>(i);
key->set_entitlement_key_id(std::string(AES_BLOCK_SIZE, x));
key->set_key_id(std::string(AES_BLOCK_SIZE, x));
key->set_key(std::string(AES_BLOCK_SIZE, x));
key->set_iv(std::string(AES_BLOCK_SIZE, x));
}
return MakePSSH(pssh);
}
TEST_F(CdmTest, HandlesKeyRotationWithOnlyOneLicenseRequest) {
EnsureProvisioned();
std::string session_id;
@@ -1960,13 +1998,14 @@ TEST_F(CdmTest, HandlesKeyRotationWithOnlyOneLicenseRequest) {
ASSERT_EQ(Cdm::kSuccess, cdm_->createSession(Cdm::kTemporary, &session_id));
// Generate a license request for the 1st entitlement init data.
const std::string init_data_string1 =
MakeEntitledData(kKeyIdEntitlement1, kEncEntitledKey1);
std::string license_request;
{
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _, _))
.WillOnce(SaveArg<2>(&license_request));
ASSERT_EQ(Cdm::kSuccess,
generateRequestWithRetry(session_id, Cdm::kCenc,
kCencEntitlementInitData1));
ASSERT_EQ(Cdm::kSuccess, generateRequestWithRetry(session_id, Cdm::kCenc,
init_data_string1));
Mock::VerifyAndClear(this);
}
@@ -1981,13 +2020,22 @@ TEST_F(CdmTest, HandlesKeyRotationWithOnlyOneLicenseRequest) {
Mock::VerifyAndClear(this);
}
// Set up input and expected output.
std::vector<uint8_t> input(12345u);
for (size_t i = 0; i < input.size(); i++) input[i] = i % 256;
const std::vector<uint8_t> test_iv1(AES_BLOCK_SIZE, 42);
const std::vector<uint8_t> test_iv2(AES_BLOCK_SIZE, 74);
const std::vector<uint8_t> expected_output1 =
Aes128CtrEncrypt(kEntitledKey1, test_iv1, input);
const std::vector<uint8_t> expected_output2 =
Aes128CtrEncrypt(kEntitledKey2, test_iv2, input);
// Set up subsample
Cdm::Subsample subsample;
subsample.protected_bytes = kInputSize;
subsample.protected_bytes = static_cast<uint32_t>(input.size());
// Set up sample
Cdm::Sample sample;
sample.input.data = kInput;
sample.input.data = input.data();
sample.input.data_length = subsample.protected_bytes;
sample.input.subsamples = &subsample;
sample.input.subsamples_length = 1;
@@ -2002,42 +2050,40 @@ TEST_F(CdmTest, HandlesKeyRotationWithOnlyOneLicenseRequest) {
batch.encryption_scheme = Cdm::kAesCtr;
// Attempt multiple decrypts with a key from the first license.
batch.key_id = kKeyIdEntitlement1.data();
batch.key_id = reinterpret_cast<const uint8_t*>(kKeyIdEntitlement1.c_str());
batch.key_id_length = static_cast<uint32_t>(kKeyIdEntitlement1.size());
sample.input.iv = kIvEntitlement1;
sample.input.iv_length = kIvEntitlement1Size;
sample.input.iv = test_iv1.data();
sample.input.iv_length = static_cast<uint32_t>(test_iv1.size());
ASSERT_EQ(Cdm::kSuccess, cdm_->decrypt(batch));
const std::vector<uint8_t> expected_output1(
kOutputEntitlement1, kOutputEntitlement1 + kOutputEntitlement1Size);
EXPECT_EQ(expected_output1, output_buffer);
memset(&(output_buffer[0]), 0, output_buffer.size());
ASSERT_EQ(Cdm::kSuccess, cdm_->decrypt(batch));
EXPECT_EQ(expected_output1, output_buffer);
// Load the second entitlement license using the first. This should not
// Load the second entitled license using the first. This should not
// require any server roundtrip.
ASSERT_EQ(Cdm::kSuccess, cdm_->loadEmbeddedKeys(session_id, Cdm::kCenc,
kCencEntitlementInitData2));
const std::string init_data_string2 =
MakeEntitledData(kKeyIdEntitlement2, kEncEntitledKey2);
ASSERT_EQ(Cdm::kSuccess,
cdm_->loadEmbeddedKeys(session_id, Cdm::kCenc, init_data_string2));
// Attempt multiple decrypts with a key from the second license.
batch.key_id = kKeyIdEntitlement2.data();
batch.key_id = reinterpret_cast<const uint8_t*>(kKeyIdEntitlement2.c_str());
batch.key_id_length = static_cast<uint32_t>(kKeyIdEntitlement2.size());
sample.input.iv = kIvEntitlement2;
sample.input.iv_length = kIvEntitlement2Size;
sample.input.iv = test_iv2.data();
sample.input.iv_length = static_cast<uint32_t>(test_iv2.size());
memset(&(output_buffer[0]), 0, output_buffer.size());
ASSERT_EQ(Cdm::kSuccess, cdm_->decrypt(batch));
const std::vector<uint8_t> expected_output2(
kOutputEntitlement2, kOutputEntitlement2 + kOutputEntitlement2Size);
EXPECT_EQ(expected_output2, output_buffer);
memset(&(output_buffer[0]), 0, output_buffer.size());
ASSERT_EQ(Cdm::kSuccess, cdm_->decrypt(batch));
EXPECT_EQ(expected_output2, output_buffer);
// Attempt multiple decrypts with a key from the first license again.
batch.key_id = kKeyIdEntitlement1.data();
batch.key_id = reinterpret_cast<const uint8_t*>(kKeyIdEntitlement1.c_str());
batch.key_id_length = static_cast<uint32_t>(kKeyIdEntitlement1.size());
sample.input.iv = kIvEntitlement1;
sample.input.iv_length = kIvEntitlement1Size;
sample.input.iv = test_iv1.data();
sample.input.iv_length = static_cast<uint32_t>(test_iv1.size());
memset(&(output_buffer[0]), 0, output_buffer.size());
ASSERT_EQ(Cdm::kSuccess, cdm_->decrypt(batch));
EXPECT_EQ(expected_output1, output_buffer);
@@ -2172,12 +2218,6 @@ TEST_F(CdmTest, GetMetrics) {
}
TEST_P(CdmTestWithDecryptParam, DecryptToClearBuffer) {
// TODO: b/305093063 - Remove when Drm Reprovisioning server is implemented.
if (wvoec::global_features.provisioning_method ==
OEMCrypto_DrmReprovisioning) {
GTEST_SKIP()
<< "Skipping until Drm Reprovisioning server support is implemented.";
}
EnsureProvisioned();
DecryptParam param = GetParam();

View File

@@ -6,6 +6,7 @@
#include "test_host.h"
wvutil::FileSystem* CreateTestFileSystem() {
return new wvutil::FileSystem("", &g_host->per_origin_storage());
std::unique_ptr<wvutil::FileSystem> CreateTestFileSystem() {
return std::make_unique<wvutil::FileSystem>("",
&g_host->per_origin_storage());
}

File diff suppressed because it is too large Load Diff