Source release 19.3.0

This commit is contained in:
John W. Bruce
2024-09-05 07:02:36 +00:00
parent cd8256726f
commit 11c108a8da
122 changed files with 2259 additions and 1082 deletions

View File

@@ -8,6 +8,7 @@
#include <time.h>
#include <chrono>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <memory>
@@ -2219,6 +2220,208 @@ TEST_F(CdmTest, GetMetrics) {
EXPECT_NE(metrics.length(), 0u);
}
// These test reverse-compatibility of offline licenses. These tests are
// disabled by default as they require multiple runs using different builds.
// First run the *Setup* test with the old build to save the files into the test
// data path. Then copy the *.dat files into the new build directory. Finally
// run the remaining tests on the new build.
// You can set GTEST_ALSO_RUN_DISABLED_TESTS variable to run these tests too.
class OfflineReverseCompatTest : public CdmTest {
public:
void SaveToFiles(const std::string& session_id) {
auto save = [](const std::string& data, const std::string& path) {
std::ofstream os(path);
os.write(data.data(), data.size());
ASSERT_TRUE(os);
};
ASSERT_NO_FATAL_FAILURE(save(session_id, kSessionIdFile));
std::string data;
ASSERT_TRUE(g_host->global_storage().SaveToString(&data));
ASSERT_NO_FATAL_FAILURE(save(data, kGlobalStorageFile));
ASSERT_TRUE(g_host->per_origin_storage().SaveToString(&data));
ASSERT_NO_FATAL_FAILURE(save(data, kPerOriginStorageFile));
}
void LoadFromFiles(std::string* session_id) {
auto load = [](const std::string& path, std::string* data) {
std::ifstream file(path);
ASSERT_TRUE(file);
data->assign(std::istreambuf_iterator<char>(file),
std::istreambuf_iterator<char>());
};
ASSERT_NO_FATAL_FAILURE(load(kSessionIdFile, session_id));
std::string data;
ASSERT_NO_FATAL_FAILURE(load(kGlobalStorageFile, &data));
ASSERT_TRUE(g_host->global_storage().LoadFromString(data));
ASSERT_NO_FATAL_FAILURE(load(kPerOriginStorageFile, &data));
ASSERT_TRUE(g_host->per_origin_storage().LoadFromString(data));
}
private:
static constexpr const char* kSessionIdFile = "session_id.dat";
static constexpr const char* kGlobalStorageFile = "global.dat";
static constexpr const char* kPerOriginStorageFile = "per_origin.dat";
};
TEST_F(OfflineReverseCompatTest, DISABLED_Setup) {
constexpr const size_t kNumSessions = 20;
std::string first_session_id;
std::string session_id;
std::string response;
EnsureProvisioned();
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
Cdm::kPersistentLicense, Cdm::kCenc, &first_session_id, &response));
ASSERT_EQ(Cdm::kSuccess, updateWithRetry(first_session_id, response));
ASSERT_EQ(Cdm::kSuccess, cdm_->close(first_session_id));
for (size_t i = 0; i < kNumSessions; i++) {
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
Cdm::kPersistentLicense, Cdm::kCenc, &session_id, &response));
ASSERT_EQ(Cdm::kSuccess, updateWithRetry(session_id, response));
ASSERT_EQ(Cdm::kSuccess, cdm_->close(session_id));
}
ASSERT_NO_FATAL_FAILURE(SaveToFiles(first_session_id));
}
TEST_F(OfflineReverseCompatTest, DISABLED_LoadAndDecrypt) {
std::string session_id;
ASSERT_NO_FATAL_FAILURE(LoadFromFiles(&session_id));
ASSERT_EQ(cdm_->getProvisioningStatus(), Cdm::kProvisioned);
Cdm::Status status = cdm_->load(session_id);
ASSERT_EQ(Cdm::kSuccess, status);
Cdm::Subsample subsample;
subsample.protected_bytes = kInputSize;
// Set up sample
Cdm::Sample sample;
sample.input.iv = kIvCenc;
sample.input.iv_length = kIvCencSize;
sample.input.data = kInput;
sample.input.data_length = kInputSize;
sample.input.subsamples = &subsample;
sample.input.subsamples_length = 1;
std::vector<uint8_t> output_buffer(sample.input.data_length);
sample.output.data = output_buffer.data();
sample.output.data_length = static_cast<uint32_t>(output_buffer.size());
// Set up batch to decrypt
Cdm::DecryptionBatch batch;
batch.samples = &sample;
batch.samples_length = 1;
batch.key_id = kKeyIdCtr.data();
batch.key_id_length = static_cast<uint32_t>(kKeyIdCtr.size());
batch.pattern = kPatternNone;
batch.encryption_scheme = Cdm::kAesCtr;
std::vector<uint8_t> expected_output(kOutputCenc,
kOutputCenc + kOutputCencSize);
status = cdm_->decrypt(session_id, batch);
ASSERT_EQ(Cdm::kSuccess, status);
EXPECT_EQ(expected_output, output_buffer);
}
TEST_F(OfflineReverseCompatTest, DISABLED_CreateSessionThenLoad) {
std::string session_id;
ASSERT_NO_FATAL_FAILURE(LoadFromFiles(&session_id));
ASSERT_EQ(cdm_->getProvisioningStatus(), Cdm::kProvisioned);
// This will cause us to re-provision.
EnsureProvisioned();
// Create a new streaming license to use the new CDM/OEMCrypto.
std::string new_session_id;
std::string response;
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
Cdm::kTemporary, Cdm::kCenc, &new_session_id, &response));
EXPECT_CALL(*this, onKeyStatusesChange(new_session_id, true));
Cdm::Status status = updateWithRetry(new_session_id, response);
ASSERT_EQ(Cdm::kSuccess, status);
Mock::VerifyAndClear(this);
// Loading the offline license should still succeed.
status = cdm_->load(session_id);
ASSERT_EQ(Cdm::kSuccess, status);
}
TEST_F(OfflineReverseCompatTest, DISABLED_LoadThenCreateSession) {
std::string session_id;
ASSERT_NO_FATAL_FAILURE(LoadFromFiles(&session_id));
ASSERT_EQ(cdm_->getProvisioningStatus(), Cdm::kProvisioned);
// Loading the offline license should not break new sessions.
Cdm::Status status = cdm_->load(session_id);
ASSERT_EQ(Cdm::kSuccess, status);
ASSERT_EQ(cdm_->close(session_id), Cdm::kSuccess);
// This will cause us to re-provision.
EnsureProvisioned();
std::string new_session_id;
std::string response;
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
Cdm::kTemporary, Cdm::kCenc, &new_session_id, &response));
EXPECT_CALL(*this, onKeyStatusesChange(new_session_id, true));
status = updateWithRetry(new_session_id, response);
ASSERT_EQ(Cdm::kSuccess, status);
Mock::VerifyAndClear(this);
}
TEST_F(OfflineReverseCompatTest, DISABLED_LoadThenCreateOfflineSession) {
std::string session_id;
ASSERT_NO_FATAL_FAILURE(LoadFromFiles(&session_id));
ASSERT_EQ(cdm_->getProvisioningStatus(), Cdm::kProvisioned);
// Loading the offline license should not break new sessions.
Cdm::Status status = cdm_->load(session_id);
ASSERT_EQ(Cdm::kSuccess, status);
ASSERT_EQ(cdm_->close(session_id), Cdm::kSuccess);
// This will cause us to re-provision.
EnsureProvisioned();
std::string new_session_id;
std::string response;
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
Cdm::kPersistentLicense, Cdm::kCenc, &new_session_id, &response));
EXPECT_CALL(*this, onKeyStatusesChange(new_session_id, true));
status = updateWithRetry(new_session_id, response);
ASSERT_EQ(Cdm::kSuccess, status);
Mock::VerifyAndClear(this);
}
TEST_F(OfflineReverseCompatTest, DISABLED_NewCdmInstance) {
std::string session_id;
ASSERT_NO_FATAL_FAILURE(LoadFromFiles(&session_id));
ASSERT_EQ(cdm_->getProvisioningStatus(), Cdm::kProvisioned);
// This will cause us to re-provision.
EnsureProvisioned();
std::string new_session_id;
std::string response;
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
Cdm::kTemporary, Cdm::kCenc, &new_session_id, &response));
EXPECT_CALL(*this, onKeyStatusesChange(new_session_id, true));
Cdm::Status status = updateWithRetry(new_session_id, response);
ASSERT_EQ(Cdm::kSuccess, status);
Mock::VerifyAndClear(this);
// Loading should still work with an entirely new CDM instance.
ASSERT_NO_FATAL_FAILURE(RecreateCdm(true /* privacy_mode */));
EnsureProvisioned();
status = cdm_->load(session_id);
ASSERT_EQ(Cdm::kSuccess, status);
}
TEST_P(CdmTestWithDecryptParam, DecryptToClearBuffer) {
EnsureProvisioned();
DecryptParam param = GetParam();