Source release 16.2.0

This commit is contained in:
John W. Bruce
2020-04-10 16:13:07 -07:00
parent 1ff9f8588a
commit b830b1d1fb
883 changed files with 509706 additions and 143739 deletions

View File

@@ -10,14 +10,15 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "OEMCryptoCENC.h"
#include "cdm.h"
#include "cdm_test_printers.h"
#include "config_test_env.h"
#include "decryption_test_data.h"
#include "license_protocol.pb.h"
#include "license_request.h"
#include "log.h"
#include "oec_device_features.h"
#include "OEMCryptoCENC.h"
#include "platform.h"
#include "properties_ce.h"
#include "service_certificate.h"
@@ -32,6 +33,9 @@ using namespace wvcdm;
namespace widevine {
using video_widevine::LicenseError;
using video_widevine::SignedMessage;
namespace {
const int kHttpOk = 200;
@@ -56,7 +60,7 @@ const std::string kCencInitData = a2bs_hex(
// pssh data:
"08011a0d7769646576696e655f746573"
"74220f73747265616d696e675f636c69"
"7031");
"7039");
const std::string kCencPersistentInitData = a2bs_hex(
"00000040" // blob size
"70737368" // "pssh"
@@ -65,11 +69,11 @@ const std::string kCencPersistentInitData = a2bs_hex(
"00000020" // pssh data size
// pssh data:
"08011a0d7769646576696e655f746573"
"74220d6f66666c696e655f636c697032");
"74220d6f66666c696e655f636c697036");
const std::string kInvalidCencInitData = a2bs_hex(
"0000000c" // blob size
"61736466" // "asdf" (wrong box type)
"01020304"); // nonsense
"0000000c" // blob size
"61736466" // "asdf" (wrong box type)
"01020304"); // nonsense
const std::string kNonWidevineCencInitData = a2bs_hex(
"00000020" // blob size
"70737368" // "pssh"
@@ -203,8 +207,6 @@ class CdmTest : public WvCdmTestBase, public Cdm::IEventListener {
MOCK_METHOD2(onKeyStatusesChange,
void(const std::string& session_id, bool has_new_usable_key));
MOCK_METHOD1(onRemoveComplete, void(const std::string& session_id));
MOCK_METHOD2(onDeferredComplete,
void(const std::string& session_id, Cdm::Status error_code));
protected:
void SetUp() override {
@@ -326,12 +328,7 @@ class CdmTest : public WvCdmTestBase, public Cdm::IEventListener {
Cdm::InitDataType init_data_type,
std::string* session_id,
std::string* message) {
Cdm::Status status;
status = cdm_->setServiceCertificate(Cdm::kLicensingService,
config_.license_service_certificate());
ASSERT_EQ(Cdm::kSuccess, status);
status = cdm_->createSession(session_type, session_id);
Cdm::Status status = cdm_->createSession(session_type, session_id);
ASSERT_EQ(Cdm::kSuccess, status);
std::string init_data;
@@ -400,21 +397,27 @@ class CdmTest : public WvCdmTestBase, public Cdm::IEventListener {
Mock::VerifyAndClear(this);
}
std::string GetProvisioningResponse(const std::string& message) {
std::string reply;
std::string GetProvisioningResponse(const std::string& message,
size_t max_attempts = 10) {
std::string uri = config_.provisioning_server();
LOGV("GetProvisioningResponse: URI: %s", uri.c_str());
LOGV("GetProvisioningResponse: message:\n%s\n", b2a_hex(message).c_str());
std::string reply;
uri += "&signedRequest=" + message;
FetchCertificate(uri, &reply);
if (HasFatalFailure()) {
LOGE("GetProvisioningResponse: Failed.");
return "";
// TODO(b/139361531): Remove loop once provisioning service is stable.
for (size_t attempt = 1; attempt <= max_attempts; attempt++) {
FetchCertificate(uri, &reply);
if (HasFatalFailure()) {
LOGE("Failed to get provisioning response: attempt = %zu", attempt);
reply.clear();
continue;
} else {
LOGV("GetProvisioningResponse: response:\n%s\n", reply.c_str());
break;
}
}
LOGV("GetProvisioningResponse: response:\n%s\n", reply.c_str());
return reply;
}
@@ -458,19 +461,14 @@ class CdmTest : public WvCdmTestBase, public Cdm::IEventListener {
struct DecryptParam {
public:
DecryptParam(
const std::string& short_name_param,
Cdm::InitDataType init_data_type_param,
const std::vector<uint8_t>& key_id_param,
const uint8_t* iv_param,
size_t iv_size_param,
Cdm::EncryptionScheme scheme_param,
const Cdm::Pattern& pattern_param,
const uint8_t* input_param,
size_t input_size_param,
const uint8_t* output_param,
size_t output_size_param)
DecryptParam(const std::string& short_name_param,
Cdm::InitDataType init_data_type_param,
const std::vector<uint8_t>& key_id_param,
const uint8_t* iv_param, size_t iv_size_param,
Cdm::EncryptionScheme scheme_param,
const Cdm::Pattern& pattern_param, const uint8_t* input_param,
size_t input_size_param, const uint8_t* output_param,
size_t output_size_param)
: short_name(short_name_param),
init_data_type(init_data_type_param),
key_id(&key_id_param),
@@ -827,12 +825,7 @@ TEST_F(CdmTest, CreateSession) {
TEST_F(CdmTest, GenerateRequest) {
EnsureProvisioned();
std::string session_id;
Cdm::Status status;
status = cdm_->setServiceCertificate(Cdm::kLicensingService,
config_.license_service_certificate());
ASSERT_EQ(Cdm::kSuccess, status);
status = cdm_->createSession(Cdm::kTemporary, &session_id);
Cdm::Status status = cdm_->createSession(Cdm::kTemporary, &session_id);
ASSERT_EQ(Cdm::kSuccess, status);
// Generate a license request for CENC.
@@ -923,11 +916,6 @@ TEST_F(CdmTest, Update) {
EnsureProvisioned();
std::string session_id;
std::string message;
Cdm::Status status;
status = cdm_->setServiceCertificate(Cdm::kLicensingService,
config_.license_service_certificate());
ASSERT_EQ(Cdm::kSuccess, status);
ASSERT_NO_FATAL_FAILURE(CreateSessionAndGenerateRequest(
Cdm::kTemporary, Cdm::kCenc, &session_id, &message));
@@ -938,7 +926,7 @@ TEST_F(CdmTest, Update) {
// Update the session.
EXPECT_CALL(*this, onKeyStatusesChange(session_id, true));
status = updateWithRetry(session_id, response);
Cdm::Status status = updateWithRetry(session_id, response);
EXPECT_EQ(Cdm::kSuccess, status);
Mock::VerifyAndClear(this);
@@ -950,6 +938,35 @@ TEST_F(CdmTest, Update) {
status = updateWithRetry(session_id, "");
EXPECT_EQ(Cdm::kTypeError, status);
// Try updating with a rejected device certificate.
{
EXPECT_CALL(*this, onKeyStatusesChange(session_id, true)).Times(0);
LicenseError license_error;
std::string error_msg;
SignedMessage signed_message;
signed_message.set_type(SignedMessage::ERROR_RESPONSE);
std::string error_response;
// Invalid device certificate
license_error.set_error_code(LicenseError::INVALID_DRM_DEVICE_CERTIFICATE);
license_error.SerializeToString(&error_msg);
signed_message.set_msg(error_msg);
signed_message.SerializeToString(&error_response);
status = updateWithRetry(session_id, error_response);
EXPECT_EQ(Cdm::kNeedsDeviceCertificate, status);
// Revoked device certificate
license_error.set_error_code(LicenseError::REVOKED_DRM_DEVICE_CERTIFICATE);
license_error.SerializeToString(&error_msg);
signed_message.set_msg(error_msg);
signed_message.SerializeToString(&error_response);
status = updateWithRetry(session_id, error_response);
EXPECT_EQ(Cdm::kUnexpectedError, status);
Mock::VerifyAndClear(this);
}
// Create a new session and try updating before generating a request.
status = cdm_->createSession(Cdm::kTemporary, &session_id);
ASSERT_EQ(Cdm::kSuccess, status);
@@ -987,17 +1004,12 @@ TEST_F(CdmTest, LoadTemporary) {
EnsureProvisioned();
std::string session_id;
std::string response;
Cdm::Status status;
status = cdm_->setServiceCertificate(Cdm::kLicensingService,
config_.license_service_certificate());
ASSERT_EQ(Cdm::kSuccess, status);
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
Cdm::kTemporary, Cdm::kCenc, &session_id, &response));
// Update the temporary session.
EXPECT_CALL(*this, onKeyStatusesChange(session_id, true));
status = updateWithRetry(session_id, response);
Cdm::Status status = updateWithRetry(session_id, response);
ASSERT_EQ(Cdm::kSuccess, status);
Mock::VerifyAndClear(this);
@@ -1014,14 +1026,13 @@ TEST_F(CdmTest, LoadPersistent) {
EnsureProvisioned();
std::string session_id;
std::string response;
Cdm::Status status;
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
Cdm::kPersistentLicense, Cdm::kCenc, &session_id, &response));
// Update the persistent session.
EXPECT_CALL(*this, onKeyStatusesChange(session_id, true));
status = updateWithRetry(session_id, response);
Cdm::Status status = updateWithRetry(session_id, response);
ASSERT_EQ(Cdm::kSuccess, status);
Mock::VerifyAndClear(this);
@@ -1786,11 +1797,8 @@ TEST_F(CdmTest, RequestPersistentLicenseWithWrongInitData) {
// Generate a request for a persistent license without using the correct
// persistent content init data.
std::string session_id;
Cdm::Status status;
status = cdm_->setServiceCertificate(Cdm::kLicensingService,
config_.license_service_certificate());
ASSERT_EQ(Cdm::kSuccess, status);
status = cdm_->createSession(Cdm::kPersistentLicense, &session_id);
Cdm::Status status =
cdm_->createSession(Cdm::kPersistentLicense, &session_id);
ASSERT_EQ(Cdm::kSuccess, status);
std::string message;
@@ -1809,11 +1817,7 @@ TEST_F(CdmTest, DISABLED_RequestTemporaryLicenseWithWrongInitData) {
EnsureProvisioned();
// Generate a request for a temporary license using persistent init data.
std::string session_id;
Cdm::Status status;
status = cdm_->setServiceCertificate(Cdm::kLicensingService,
config_.license_service_certificate());
ASSERT_EQ(Cdm::kSuccess, status);
status = cdm_->createSession(Cdm::kTemporary, &session_id);
Cdm::Status status = cdm_->createSession(Cdm::kTemporary, &session_id);
ASSERT_EQ(Cdm::kSuccess, status);
std::string message;
@@ -2022,9 +2026,6 @@ TEST_F(CdmTest, HandlesKeyRotationWithOnlyOneLicenseRequest) {
// The CreateSessionAndX helpers need to be reworked so this function can use
// them.
ASSERT_EQ(Cdm::kSuccess,
cdm_->setServiceCertificate(Cdm::kLicensingService,
config_.license_service_certificate()));
ASSERT_EQ(Cdm::kSuccess, cdm_->createSession(Cdm::kTemporary, &session_id));
// Generate a license request for the 1st entitlement init data.
@@ -2049,77 +2050,92 @@ TEST_F(CdmTest, HandlesKeyRotationWithOnlyOneLicenseRequest) {
Mock::VerifyAndClear(this);
}
// Set up decrypt input and output.
Cdm::InputBuffer input;
input.data = kInput;
input.data_length = kInputSize;
input.encryption_scheme = Cdm::kAesCtr;
input.pattern = kPatternNone;
// Set up subsample
Cdm::Subsample subsample;
subsample.protected_bytes = kInputSize;
Cdm::OutputBuffer output;
std::vector<uint8_t> output_buffer(input.data_length);
output.data = &(output_buffer[0]);
output.data_length = output_buffer.size();
// Set up sample
Cdm::Sample sample;
sample.input.data = kInput;
sample.input.data_length = subsample.protected_bytes;
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 = output_buffer.size();
// Set up batch to decrypt
Cdm::DecryptionBatch batch;
batch.samples = &sample;
batch.samples_length = 1;
batch.encryption_scheme = Cdm::kAesCtr;
// Attempt multiple decrypts with a key from the first license.
input.key_id = kKeyIdEntitlement1.data();
input.key_id_length = kKeyIdEntitlement1.size();
input.iv = kIvEntitlement1;
input.iv_length = kIvEntitlement1Size;
ASSERT_EQ(Cdm::kSuccess, cdm_->decrypt(input, output));
batch.key_id = kKeyIdEntitlement1.data();
batch.key_id_length = kKeyIdEntitlement1.size();
sample.input.iv = kIvEntitlement1;
sample.input.iv_length = kIvEntitlement1Size;
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(input, output));
ASSERT_EQ(Cdm::kSuccess, cdm_->decrypt(batch));
EXPECT_EQ(expected_output1, output_buffer);
// Load the second entitlement license using the first. This should not
// require any server roundtrip.
ASSERT_EQ(Cdm::kSuccess,
cdm_->loadEmbeddedKeys(session_id, Cdm::kCenc,
kCencEntitlementInitData2));
ASSERT_EQ(Cdm::kSuccess, cdm_->loadEmbeddedKeys(session_id, Cdm::kCenc,
kCencEntitlementInitData2));
// Attempt multiple decrypts with a key from the second license.
input.key_id = kKeyIdEntitlement2.data();
input.key_id_length = kKeyIdEntitlement2.size();
input.iv = kIvEntitlement2;
input.iv_length = kIvEntitlement2Size;
batch.key_id = kKeyIdEntitlement2.data();
batch.key_id_length = kKeyIdEntitlement2.size();
sample.input.iv = kIvEntitlement2;
sample.input.iv_length = kIvEntitlement2Size;
memset(&(output_buffer[0]), 0, output_buffer.size());
ASSERT_EQ(Cdm::kSuccess, cdm_->decrypt(input, output));
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(input, output));
ASSERT_EQ(Cdm::kSuccess, cdm_->decrypt(batch));
EXPECT_EQ(expected_output2, output_buffer);
// Attempt multiple decrypts with a key from the first license again.
input.key_id = kKeyIdEntitlement1.data();
input.key_id_length = kKeyIdEntitlement1.size();
input.iv = kIvEntitlement1;
input.iv_length = kIvEntitlement1Size;
batch.key_id = kKeyIdEntitlement1.data();
batch.key_id_length = kKeyIdEntitlement1.size();
sample.input.iv = kIvEntitlement1;
sample.input.iv_length = kIvEntitlement1Size;
memset(&(output_buffer[0]), 0, output_buffer.size());
ASSERT_EQ(Cdm::kSuccess, cdm_->decrypt(input, output));
ASSERT_EQ(Cdm::kSuccess, cdm_->decrypt(batch));
EXPECT_EQ(expected_output1, output_buffer);
memset(&(output_buffer[0]), 0, output_buffer.size());
ASSERT_EQ(Cdm::kSuccess, cdm_->decrypt(input, output));
ASSERT_EQ(Cdm::kSuccess, cdm_->decrypt(batch));
EXPECT_EQ(expected_output1, output_buffer);
}
TEST_F(CdmTest, ClearPlaybackWithoutAKeyId) {
TEST_F(CdmTest, ClearPlaybackWithoutAKeyIdOrIv) {
EnsureProvisioned();
Cdm::InputBuffer input;
Cdm::OutputBuffer output;
// Set up subsample
Cdm::Subsample subsample;
subsample.clear_bytes = kInputSize;
input.data = kInput;
input.data_length = kInputSize;
input.encryption_scheme = Cdm::kClear;
// Set up sample
Cdm::Sample sample;
sample.input.data = kInput;
sample.input.data_length = subsample.clear_bytes;
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 = output_buffer.size();
std::vector<uint8_t> output_buffer(input.data_length);
output.data = &(output_buffer[0]);
output.data_length = output_buffer.size();
// Set up batch to decrypt
Cdm::DecryptionBatch batch;
batch.samples = &sample;
batch.samples_length = 1;
// Note that the use of kInput for the expected output is not an error. This
// is clear playback, so the data should pass through unchanged.
@@ -2130,70 +2146,111 @@ TEST_F(CdmTest, ClearPlaybackWithoutAKeyId) {
cdm_->createSession(Cdm::kTemporary, &session_id);
// Decrypt without specifying a session or key ID should fail.
Cdm::Status status = cdm_->decrypt(input, output);
Cdm::Status status = cdm_->decrypt(batch);
EXPECT_EQ(Cdm::kNoKey, status);
// Decrypt with a known session should succeed.
status = cdm_->decrypt(session_id, input, output);
status = cdm_->decrypt(session_id, batch);
EXPECT_EQ(Cdm::kSuccess, status);
}
TEST_F(CdmTest, EncryptedPlaybackWithoutALicense) {
EnsureProvisioned();
Cdm::InputBuffer input;
Cdm::OutputBuffer output;
// Set up subsample
Cdm::Subsample subsample;
subsample.protected_bytes = kInputSize;
input.key_id = kKeyIdCtr.data();
input.key_id_length = kKeyIdCtr.size();
input.iv = kIvCenc;
input.iv_length = kIvCencSize;
input.data = kInput;
input.data_length = kInputSize;
input.encryption_scheme = Cdm::kAesCtr;
// Set up sample
Cdm::Sample sample;
sample.input.iv = kIvCenc;
sample.input.iv_length = kIvCencSize;
sample.input.data = kInput;
sample.input.data_length = subsample.protected_bytes;
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 = output_buffer.size();
std::vector<uint8_t> output_buffer(input.data_length);
output.data = &(output_buffer[0]);
output.data_length = 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 = kKeyIdCtr.size();
batch.encryption_scheme = Cdm::kAesCtr;
// Create a session.
std::string session_id;
cdm_->createSession(Cdm::kTemporary, &session_id);
// Decrypt without specifying a session should fail.
Cdm::Status status = cdm_->decrypt(input, output);
Cdm::Status status = cdm_->decrypt(batch);
EXPECT_EQ(Cdm::kNoKey, status);
// Decrypt with a known session should fail.
status = cdm_->decrypt(session_id, input, output);
status = cdm_->decrypt(session_id, batch);
EXPECT_EQ(Cdm::kNoKey, status);
}
TEST_F(CdmTest, GetEmptyMetrics) {
std::string metrics;
Cdm::Status status = cdm_->getMetrics(&metrics);
EXPECT_EQ(status, Cdm::kSuccess);
EXPECT_NE(metrics.length(), 0u);
}
TEST_F(CdmTest, GetMetrics) {
EnsureProvisioned();
std::string ignored;
ASSERT_NO_FATAL_FAILURE(
CreateSessionAndUpdate(Cdm::kTemporary, Cdm::kCenc, &ignored));
std::string metrics;
Cdm::Status status = cdm_->getMetrics(&metrics);
EXPECT_EQ(status, Cdm::kSuccess);
EXPECT_NE(metrics.length(), 0u);
}
TEST_P(CdmTestWithDecryptParam, DecryptToClearBuffer) {
EnsureProvisioned();
DecryptParam param = GetParam();
Cdm::InputBuffer input;
Cdm::OutputBuffer output;
// Set up subsample
Cdm::Subsample subsample;
if (param.scheme == Cdm::kClear) {
subsample.clear_bytes = param.input_size;
} else {
subsample.protected_bytes = param.input_size;
}
input.key_id = param.key_id->data();
input.key_id_length = param.key_id->size();
input.iv = param.iv;
input.iv_length = param.iv_size;
input.data = param.input;
input.data_length = param.input_size;
input.encryption_scheme = param.scheme;
input.pattern = *param.pattern;
// Set up sample
Cdm::Sample sample;
sample.input.iv = param.iv;
sample.input.iv_length = param.iv_size;
sample.input.data = param.input;
sample.input.data_length = param.input_size;
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 = output_buffer.size();
std::vector<uint8_t> output_buffer(input.data_length);
output.data = &(output_buffer[0]);
output.data_length = output_buffer.size();
// Set up batch to decrypt
Cdm::DecryptionBatch batch;
batch.samples = &sample;
batch.samples_length = 1;
batch.key_id = param.key_id->data();
batch.key_id_length = param.key_id->size();
batch.pattern = *param.pattern;
batch.encryption_scheme = param.scheme;
std::vector<uint8_t> expected_output(
param.output, param.output + param.output_size);
std::vector<uint8_t> expected_output(param.output,
param.output + param.output_size);
// Decrypt without keys loaded should fail.
Cdm::Status status = cdm_->decrypt(input, output);
Cdm::Status status = cdm_->decrypt(batch);
ASSERT_EQ(Cdm::kNoKey, status);
// Create a session with the right keys.
@@ -2202,39 +2259,31 @@ TEST_P(CdmTestWithDecryptParam, DecryptToClearBuffer) {
Cdm::kTemporary, param.init_data_type, &session_id));
// Decrypt should now succeed.
status = cdm_->decrypt(session_id, input, output);
status = cdm_->decrypt(session_id, batch);
ASSERT_EQ(Cdm::kSuccess, status);
EXPECT_EQ(expected_output, output_buffer);
// Decrypt should succeed even without specifying the session ID.
status = cdm_->decrypt(input, output);
status = cdm_->decrypt(batch);
ASSERT_EQ(Cdm::kSuccess, status);
EXPECT_EQ(expected_output, output_buffer);
}
INSTANTIATE_TEST_CASE_P(CdmDecryptTest, CdmTestWithDecryptParam, Values(
DecryptParam("CENC 3.0 cenc Mode",
Cdm::kCenc, kKeyIdCtr, kIvCenc, kIvCencSize, Cdm::kAesCtr,
kPatternNone, kInput, kInputSize, kOutputCenc, kOutputCencSize),
DecryptParam("CENC 3.0 cens Mode",
Cdm::kCenc, kKeyIdCtr, kIvCens, kIvCensSize, Cdm::kAesCtr,
kPatternRecommended, kInput, kInputSize, kOutputCens,
kOutputCensSize),
DecryptParam("CENC 3.0 cbc1 Mode",
Cdm::kHls, kKeyIdCbc, kIvCbc1, kIvCbc1Size, Cdm::kAesCbc,
kPatternNone, kInput, kInputSize, kOutputCbc1, kOutputCbc1Size),
DecryptParam("CENC 3.0 cbcs Mode",
Cdm::kHls, kKeyIdCbc, kIvCbcs, kIvCbcsSize, Cdm::kAesCbc,
kPatternRecommended, kInput, kInputSize, kOutputCbcs,
kOutputCbcsSize),
DecryptParam("HLS Audio (CENC 3.0 cbcs Mode Without a Pattern)",
Cdm::kHls, kKeyIdCbc, kIvCbc1, kIvCbc1Size, Cdm::kAesCbc,
kPatternHlsAudio, kInput, kInputSize, kOutputCbc1,
kOutputCbc1Size),
DecryptParam("Clear Data w/ Known Key ID",
Cdm::kCenc, kKeyIdCtr, kIvCenc, kIvCencSize, Cdm::kClear,
kPatternNone, kInput, kInputSize, kInput, kInputSize)
));
INSTANTIATE_TEST_CASE_P(
CdmDecryptTest, CdmTestWithDecryptParam,
Values(DecryptParam("CENC 3.0 cenc Mode", Cdm::kCenc, kKeyIdCtr, kIvCenc,
kIvCencSize, Cdm::kAesCtr, kPatternNone, kInput,
kInputSize, kOutputCenc, kOutputCencSize),
DecryptParam("CENC 3.0 cbcs Mode", Cdm::kHls, kKeyIdCbc, kIvCbcs,
kIvCbcsSize, Cdm::kAesCbc, kPatternRecommended, kInput,
kInputSize, kOutputCbcs, kOutputCbcsSize),
DecryptParam("HLS Audio (CENC 3.0 cbcs Mode Without a Pattern)",
Cdm::kHls, kKeyIdCbc, kIvCbc1, kIvCbc1Size,
Cdm::kAesCbc, kPatternHlsAudio, kInput, kInputSize,
kOutputCbc1, kOutputCbc1Size),
DecryptParam("Clear Data w/ Known Key ID", Cdm::kCenc, kKeyIdCtr,
kIvCenc, kIvCencSize, Cdm::kClear, kPatternNone, kInput,
kInputSize, kInput, kInputSize)));
// TODO (b/119200745):
// add infrastructure to test secure buffer decrypt for some platforms
@@ -2276,11 +2325,8 @@ TEST_F(CdmIndividualizationTest, BasicFlow) {
g_host->remove(kDeviceCertFileName);
// Provision the device
Cdm::Status status = cdm_->setServiceCertificate(
Cdm::kProvisioningService, config_.provisioning_service_certificate());
EXPECT_EQ(Cdm::kSuccess, status);
std::string message;
status = cdm_->getProvisioningRequest(&message);
Cdm::Status status = cdm_->getProvisioningRequest(&message);
EXPECT_EQ(Cdm::kSuccess, status);
std::string reply = GetProvisioningResponse(message);
ASSERT_FALSE(reply.empty());
@@ -2289,9 +2335,6 @@ TEST_F(CdmIndividualizationTest, BasicFlow) {
// We should now be able to create a session and generate a request.
std::string session_id;
status = cdm_->setServiceCertificate(Cdm::kLicensingService,
config_.license_service_certificate());
EXPECT_EQ(Cdm::kSuccess, status);
ASSERT_NO_FATAL_FAILURE(CreateSessionAndGenerateRequest(
Cdm::kTemporary, Cdm::kCenc, &session_id, &message));
@@ -2313,11 +2356,8 @@ TEST_F(CdmIndividualizationTest, IsProvisioned) {
EXPECT_FALSE(cdm_->isProvisioned());
// Provision the device
Cdm::Status status = cdm_->setServiceCertificate(
Cdm::kProvisioningService, config_.provisioning_service_certificate());
EXPECT_EQ(Cdm::kSuccess, status);
std::string message;
status = cdm_->getProvisioningRequest(&message);
Cdm::Status status = cdm_->getProvisioningRequest(&message);
EXPECT_EQ(Cdm::kSuccess, status);
std::string reply = GetProvisioningResponse(message);
ASSERT_FALSE(reply.empty());
@@ -2336,11 +2376,8 @@ TEST_F(CdmIndividualizationTest, RemoveProvisioning) {
EXPECT_FALSE(cdm_->isProvisioned());
// Provision the device
Cdm::Status status = cdm_->setServiceCertificate(
Cdm::kProvisioningService, config_.provisioning_service_certificate());
EXPECT_EQ(Cdm::kSuccess, status);
std::string message;
status = cdm_->getProvisioningRequest(&message);
Cdm::Status status = cdm_->getProvisioningRequest(&message);
EXPECT_EQ(Cdm::kSuccess, status);
std::string reply = GetProvisioningResponse(message);
ASSERT_FALSE(reply.empty());
@@ -2363,7 +2400,7 @@ TEST_F(CdmIndividualizationTest, NoCreateSessionWithoutProvisioning) {
std::string session_id;
EXPECT_EQ(Cdm::kNeedsDeviceCertificate,
cdm_->createSession(Cdm::kTemporary, &session_id));
cdm_->createSession(Cdm::kTemporary, &session_id));
EXPECT_THAT(session_id, IsEmpty());
}

View File

@@ -11,7 +11,7 @@
#include <vector>
#if defined(__linux__)
#include <sys/utsname.h>
# include <sys/utsname.h>
#endif
#include "cdm.h"
@@ -37,9 +37,6 @@ constexpr const char kExtraHelpText[] =
} // namespace
int main(int argc, char** argv) {
// Init gtest and let it consume arguments.
::testing::InitGoogleTest(&argc, argv);
// Find and filter out the Sandbox ID, if any.
std::vector<std::string> args(argv, argv + argc);
auto sandbox_id_iter = std::find_if(std::begin(args) + 1, std::end(args),
@@ -90,5 +87,8 @@ int main(int argc, char** argv) {
return 0;
}
// Init gtest after oemcrypto and cdm host have been initialized.
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -17515,8 +17515,8 @@ const size_t kInputSize = sizeof(kInput) / sizeof(kInput[0]);
// Dummy decrypted output using the CENC 3.0 "cenc" mode. Decrypted using the
// key matching kKeyIdCtr.
const uint8_t kIvCenc[] = {
0xf6, 0xf4, 0xb1, 0xe6, 0x00, 0xa5, 0xb6, 0x78, 0x13, 0xed, 0x2b, 0xde,
0xd9, 0x13, 0xba, 0x9f,
0xf6, 0xf4, 0xb1, 0xe6, 0x00, 0xa5, 0xb6, 0x78,
0x13, 0xed, 0x2b, 0xde, 0xd9, 0x13, 0xba, 0x9f,
};
const size_t kIvCencSize = sizeof(kIvCenc) / sizeof(kIvCenc[0]);
const uint8_t kOutputCenc[] = {
@@ -35026,8 +35026,8 @@ const size_t kOutputCencSize = sizeof(kOutputCenc) / sizeof(kOutputCenc[0]);
// Dummy decrypted output using the CENC 3.0 "cens" mode. Decrypted using the
// key matching kKeyIdCtr.
const uint8_t kIvCens[] = {
0xa8, 0x91, 0xb8, 0x00, 0x0a, 0xf5, 0x30, 0x49, 0xd7, 0xb2, 0x4b, 0xdc,
0x19, 0x07, 0x48, 0x39,
0xa8, 0x91, 0xb8, 0x00, 0x0a, 0xf5, 0x30, 0x49,
0xd7, 0xb2, 0x4b, 0xdc, 0x19, 0x07, 0x48, 0x39,
};
const size_t kIvCensSize = sizeof(kIvCens) / sizeof(kIvCens[0]);
const uint8_t kOutputCens[] = {
@@ -52537,8 +52537,8 @@ const size_t kOutputCensSize = sizeof(kOutputCens) / sizeof(kOutputCens[0]);
// Dummy decrypted output using the CENC 3.0 "cbc1" mode. Decrypted using the
// key matching kKeyIdCbc.
const uint8_t kIvCbc1[] = {
0x01, 0x11, 0x32, 0x13, 0x22, 0x79, 0x3b, 0x04, 0xf8, 0x71, 0xaa, 0xb2,
0x8f, 0x6b, 0x06, 0x6e,
0x01, 0x11, 0x32, 0x13, 0x22, 0x79, 0x3b, 0x04,
0xf8, 0x71, 0xaa, 0xb2, 0x8f, 0x6b, 0x06, 0x6e,
};
const size_t kIvCbc1Size = sizeof(kIvCbc1) / sizeof(kIvCbc1[0]);
const uint8_t kOutputCbc1[] = {
@@ -70048,8 +70048,8 @@ const size_t kOutputCbc1Size = sizeof(kOutputCbc1) / sizeof(kOutputCbc1[0]);
// Dummy decrypted output using the CENC 3.0 "cbcs" mode. Decrypted using the
// key matching kKeyIdCbc.
const uint8_t kIvCbcs[] = {
0x8e, 0x26, 0x1c, 0x96, 0x60, 0xf5, 0x93, 0x0e, 0xbe, 0x17, 0x34, 0x51,
0x0c, 0xb9, 0xbc, 0x23,
0x8e, 0x26, 0x1c, 0x96, 0x60, 0xf5, 0x93, 0x0e,
0xbe, 0x17, 0x34, 0x51, 0x0c, 0xb9, 0xbc, 0x23,
};
const size_t kIvCbcsSize = sizeof(kIvCbcs) / sizeof(kIvCbcs[0]);
const uint8_t kOutputCbcs[] = {
@@ -87559,8 +87559,8 @@ const size_t kOutputCbcsSize = sizeof(kOutputCbcs) / sizeof(kOutputCbcs[0]);
// Dummy decrypted output for Entitlement License tests. Decrypted using the
// key matching kKeyIdEntitlement1.
const uint8_t kIvEntitlement1[] = {
0xa5, 0xd0, 0x34, 0x63, 0xe3, 0x9c, 0x61, 0x27, 0x18, 0x41, 0xf7, 0x77,
0x0b, 0x54, 0x91, 0xfe,
0xa5, 0xd0, 0x34, 0x63, 0xe3, 0x9c, 0x61, 0x27,
0x18, 0x41, 0xf7, 0x77, 0x0b, 0x54, 0x91, 0xfe,
};
const size_t kIvEntitlement1Size =
sizeof(kIvEntitlement1) / sizeof(kIvEntitlement1[0]);
@@ -105072,8 +105072,8 @@ const size_t kOutputEntitlement1Size =
// Dummy decrypted output for Entitlement License tests. Decrypted using the
// key matching kKeyIdEntitlement2.
const uint8_t kIvEntitlement2[] = {
0xfa, 0x98, 0x28, 0x28, 0x01, 0x71, 0x08, 0x5e, 0x84, 0x03, 0x7f, 0x5c,
0xd3, 0x9d, 0x7d, 0x4e,
0xfa, 0x98, 0x28, 0x28, 0x01, 0x71, 0x08, 0x5e,
0x84, 0x03, 0x7f, 0x5c, 0xd3, 0x9d, 0x7d, 0x4e,
};
const size_t kIvEntitlement2Size =
sizeof(kIvEntitlement2) / sizeof(kIvEntitlement2[0]);

View File

@@ -21,11 +21,11 @@ class OEMCrypto_Level3CETestFileSystem : public OEMCrypto_Level3FileSystem {
public:
OEMCrypto_Level3CETestFileSystem() {}
~OEMCrypto_Level3CETestFileSystem() override {}
ssize_t Read(const char *filename, void *buffer, size_t size) override;
ssize_t Write(const char *filename, const void *buffer, size_t size) override;
bool Exists(const char *filename) override;
ssize_t FileSize(const char *filename) override;
bool Remove(const char *filename) override;
ssize_t Read(const char* filename, void* buffer, size_t size) override;
ssize_t Write(const char* filename, const void* buffer, size_t size) override;
bool Exists(const char* filename) override;
ssize_t FileSize(const char* filename) override;
bool Remove(const char* filename) override;
private:
static std::map<std::string, std::string> files_;

View File

@@ -18,10 +18,12 @@ const std::string kCertificateFilename = "cert.bin";
} // namespace
TestHost::TestHost() { Reset(); }
TestHost::~TestHost() { wvcdm::TestSleep::set_callback(nullptr); }
void TestHost::Reset() {
auto now = std::chrono::steady_clock().now();
now_ = now.time_since_epoch() / std::chrono::milliseconds(1);
wvcdm::TestSleep::set_callback(this);
save_device_cert_ = false;
@@ -57,14 +59,14 @@ int TestHost::NumTimers() const { return timers_.size(); }
bool TestHost::read(const std::string& name, std::string* data) {
StorageMap::iterator it = files_.find(name);
bool ok = it != files_.end();
LOGD("read file: %s: %s", name.c_str(), ok ? "ok" : "fail");
LOGV("read file: %s: %s", name.c_str(), ok ? "ok" : "fail");
if (!ok) return false;
*data = it->second;
return true;
}
bool TestHost::write(const std::string& name, const std::string& data) {
LOGD("write file: %s", name.c_str());
LOGV("write file: %s", name.c_str());
files_[name] = data;
if (save_device_cert_ && kCertificateFilename.compare(name) == 0) {
device_cert_ = data;
@@ -76,12 +78,12 @@ bool TestHost::write(const std::string& name, const std::string& data) {
bool TestHost::exists(const std::string& name) {
StorageMap::iterator it = files_.find(name);
bool ok = it != files_.end();
LOGD("exists? %s: %s", name.c_str(), ok ? "true" : "false");
LOGV("exists? %s: %s", name.c_str(), ok ? "true" : "false");
return ok;
}
bool TestHost::remove(const std::string& name) {
LOGD("remove: %s", name.c_str());
LOGV("remove: %s", name.c_str());
if (name.empty()) {
// If no name, delete all files (see DeviceFiles::DeleteAllFiles())
files_.clear();

View File

@@ -8,15 +8,18 @@
#include <vector>
#include "cdm.h"
#include "test_sleep.h"
class TestHost : public widevine::Cdm::IStorage,
public widevine::Cdm::IClock,
public widevine::Cdm::ITimer {
public widevine::Cdm::ITimer,
public wvcdm::TestSleep::CallBack {
public:
TestHost();
~TestHost();
void Reset();
void ElapseTime(int64_t milliseconds);
void ElapseTime(int64_t milliseconds) override;
int NumTimers() const;
void SaveProvisioningInformation() { save_device_cert_ = true; }