Files
android/libwvdrmengine/cdm/core/test/test_base.cpp
Fred Gylys-Colwell d7ee89bab0 Filter Cast Reciver tests
Merge from Widevine repo of http://go/wvgerrit/169070

This turns on the cast receiver tests for any device that
claims to support this feature. Previously, we had to
explicitly request these tests on the command line.

But since they do not pass for Prov 4.0, we fitler them out
in this case and reference a bug tracking that work.

We also switch to using GTEST_SKIP to skip the tests instead
of modifying the GTEST_FILTER.

Bug: 251240681
Bug: 269310676
Bug: 259455058
Bug: 259454969
Merged from https://widevine-internal-review.googlesource.com/166497

Change-Id: I1bcd749243a474b3f638547aa43c2805e86731af
2023-03-28 20:30:22 +00:00

719 lines
29 KiB
C++

// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
#include "test_base.h"
#include <openssl/aes.h>
#include <openssl/bio.h>
#include <openssl/cmac.h>
#include <openssl/hmac.h>
#include <stdlib.h>
#include <chrono>
#include <string>
#include <thread>
#include <vector>
#include "cdm_engine.h"
#include "clock.h"
#include "crypto_session.h"
#include "fake_provisioning_server.h"
#include "file_store.h"
#include "license.h"
#include "log.h"
#include "oec_device_features.h"
#include "oec_test_data.h"
#include "platform.h"
#include "properties.h"
#include "test_printers.h"
#include "test_sleep.h"
#include "url_request.h"
using wvcdm::metrics::EngineMetrics;
namespace wvcdm {
namespace {
void show_menu(const char* prog_name, const std::string& extra_help_text) {
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 << " --verbose or -v" << std::endl;
std::cout << " increase logging verbosity (may be repeated)" << std::endl
<< std::endl;
std::cout << " --no_filter" << std::endl;
std::cout << " Do not filter out inappropriate tests" << std::endl
<< std::endl;
std::cout << " --cast" << std::endl;
std::cout << " Run tests appropriate for a Cast Receiver" << std::endl
<< std::endl;
std::cout << " --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 << " --keyid=<key_id>" << std::endl;
std::cout << " configure the key id or pssh, in hex format" << std::endl
<< std::endl;
std::cout << " --service_certificate=<cert>" << std::endl;
std::cout << " configure the signed license 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 << " --provisioning_certificate=<cert>" << std::endl;
std::cout << " configure the signed provisioning service certificate"
<< std::endl
<< " in hex" << std::endl
<< std::endl;
std::cout << " --license_server_url=<url>" << std::endl;
std::cout << " configure the license server url, please include http[s]"
<< " in the url" << std::endl
<< std::endl;
std::cout << " --renewal_server_url=<url>" << std::endl;
std::cout << " configure the renewal server url, please include http[s] "
"in the url"
<< std::endl
<< " If not set, this defaults to be the same url used by the "
"license server."
<< std::endl
<< " Some tests, such as LicenseRenewalSpecifiedServer, will "
"ignore this setting. "
<< std::endl
<< " See comments in the code for an explanation." << std::endl
<< std::endl;
std::cout << " --provisioning_server_url=<url>" << std::endl;
std::cout
<< " configure the provisioning server url, please include http[s]"
<< " in the url" << std::endl
<< std::endl;
std::cout << " --server_version=N" << std::endl;
std::cout << " specify the server version. Tests that are not expected "
<< "to pass" << std::endl
<< " on this server version will be skipped." << std::endl
<< std::endl;
std::cout << " --qa_provisioning" << std::endl;
std::cout << " use the QA provisioning cert and QA test keybox"
<< std::endl
<< std::endl;
std::cout << " --fake_sleep" << std::endl;
std::cout << " Use a fake clock to sleep for duration tests. This cannot"
<< " be used with a real OEMCrypto." << std::endl
<< std::endl;
std::cout << " --initial_time=<time>" << std::endl;
std::cout << " Set the initial time on the fake clock. This is ignored"
<< " if fake_sleep was not set." << std::endl
<< std::endl;
std::cout << " --pass=<N>" << std::endl;
std::cout << " Run test pass N. This is used for reboot tests that "
<< "require several passes." << std::endl
<< std::endl;
std::cout << " --test_data_path=<path>" << std::endl;
std::cout << " Where to store test data for reboot tests." << std::endl;
std::cout << extra_help_text << std::endl;
}
/*
* Locate the portion of the server's response message that is between
* the strings jason_start_substr and json_end_substr. Returns the string
* through *result. If the start substring match fails, assume the entire
* string represents a serialized protobuf mesaage and return true with
* the entire string. If the end_substring match fails, return false with
* an empty *result.
*/
bool ExtractSignedMessage(const std::string& response,
const std::string& json_start_substr,
const std::string& json_end_substr,
std::string* result) {
std::string response_string;
size_t start = response.find(json_start_substr);
if (start == response.npos) {
// Assume serialized protobuf message.
result->assign(response);
} else {
// Assume JSON-wrapped protobuf.
size_t end =
response.find(json_end_substr, start + json_start_substr.length());
if (end == response.npos) {
LOGE("ExtractSignedMessage cannot locate end substring");
result->clear();
return false;
}
size_t result_string_size = end - start - json_start_substr.length();
result->assign(response, start + json_start_substr.length(),
result_string_size);
}
if (result->empty()) {
LOGE("ExtractSignedMessage: Response message is empty");
return false;
}
return true;
}
// TODO(b/242744857): This extra debugging may not be needed in all cases. When
// provisioning fails, this dumps the cert and other information.
std::string DumpProvAttempt(const std::string& url, const std::string& request,
const std::string& http_message,
CdmEngine* cdm_engine) {
std::stringstream info;
info << "Provisioning url: " << url << "\n";
info << "Request: " << wvutil::unlimited_b2a_hex(request) << "\n";
info << "http_message: " << wvutil::unlimited_b2a_hex(http_message) << "\n";
std::string system_id;
cdm_engine->QueryStatus(kLevelDefault, QUERY_KEY_SYSTEM_ID, &system_id);
info << "system id: " << system_id << "\n";
if (wvoec::global_features.derive_key_method ==
wvoec::DeviceFeatures::TEST_PROVISION_30) {
std::vector<uint8_t> cert;
size_t cert_length = 0;
OEMCryptoResult result = OEMCrypto_GetOEMPublicCertificate(
cert.data(), &cert_length, kLevelDefault);
if (result == OEMCrypto_ERROR_SHORT_BUFFER) {
cert.resize(cert_length);
result = OEMCrypto_GetOEMPublicCertificate(cert.data(), &cert_length,
kLevelDefault);
}
if (result != OEMCrypto_SUCCESS) {
info << "--- ERROR GETTING CERT. result=" << result;
} else {
info << "OEM Cert = (len=" << cert_length << ") "
<< wvutil::unlimited_b2a_hex(cert);
}
}
if (wvoec::global_features.derive_key_method ==
wvoec::DeviceFeatures::TEST_PROVISION_40) {
std::vector<uint8_t> bcc;
size_t bcc_length = 0;
std::vector<uint8_t> signature;
size_t signature_length = 0;
OEMCryptoResult result = OEMCrypto_GetBootCertificateChain(
bcc.data(), &bcc_length, signature.data(), &signature_length);
if (result == OEMCrypto_ERROR_SHORT_BUFFER) {
bcc.resize(bcc_length);
signature.resize(signature_length);
result = OEMCrypto_GetBootCertificateChain(
bcc.data(), &bcc_length, signature.data(), &signature_length);
}
if (result != OEMCrypto_SUCCESS) {
info << "--- ERROR GETTING BCC. result=" << result;
} else {
info << "BCC = (len=" << bcc_length << ") "
<< wvutil::unlimited_b2a_hex(bcc) << "\n"
<< "Additional Sig = (len=" << signature_length << ") "
<< wvutil::unlimited_b2a_hex(signature) << "\n";
}
}
return info.str();
}
} // namespace
std::unique_ptr<ConfigTestEnv> WvCdmTestBase::default_config_;
bool WvCdmTestBase::use_qa_test_keybox_ = false;
void WvCdmTestBase::StripeBuffer(std::vector<uint8_t>* buffer, size_t size,
uint8_t init) {
buffer->assign(size, 0);
for (size_t i = 0; i < size; i++) {
(*buffer)[i] = init + i % 250;
}
}
std::string WvCdmTestBase::Aes128CbcEncrypt(std::vector<uint8_t> key,
const std::vector<uint8_t>& clear,
const std::vector<uint8_t> iv) {
std::vector<uint8_t> encrypted(clear.size());
std::vector<uint8_t> iv_mod(iv.begin(), iv.end());
AES_KEY aes_key;
AES_set_encrypt_key(&key[0], 128, &aes_key);
AES_cbc_encrypt(&clear[0], &encrypted[0], clear.size(), &aes_key, &iv_mod[0],
AES_ENCRYPT);
return std::string(encrypted.begin(), encrypted.end());
}
std::string WvCdmTestBase::Aes128CbcDecrypt(std::vector<uint8_t> key,
const std::vector<uint8_t>& clear,
const std::vector<uint8_t> iv) {
std::vector<uint8_t> encrypted(clear.size());
std::vector<uint8_t> iv_mod(iv.begin(), iv.end());
AES_KEY aes_key;
AES_set_decrypt_key(&key[0], 128, &aes_key);
AES_cbc_encrypt(&clear[0], &encrypted[0], clear.size(), &aes_key, &iv_mod[0],
AES_DECRYPT);
return std::string(encrypted.begin(), encrypted.end());
}
std::string WvCdmTestBase::SignHMAC(const std::string& message,
const std::vector<uint8_t>& key) {
uint8_t signature[SHA256_DIGEST_LENGTH];
unsigned int md_len = SHA256_DIGEST_LENGTH;
HMAC(EVP_sha256(), &key[0], static_cast<int>(key.size()),
reinterpret_cast<const uint8_t*>(message.data()), message.size(),
signature, &md_len);
std::string result(signature, signature + SHA256_DIGEST_LENGTH);
return result;
}
TestCryptoSession::TestCryptoSession(metrics::CryptoMetrics* crypto_metrics)
: CryptoSession(crypto_metrics) {
MaybeInstallTestKeybox();
}
TestCryptoSession::TestCryptoSession(metrics::CryptoMetrics* crypto_metrics,
const TestCryptoSessionConfig* config)
: CryptoSession(crypto_metrics), config_(config) {
MaybeInstallTestKeybox();
}
void TestCryptoSession::MaybeInstallTestKeybox() {
if (IsTestKeyboxNeeded()) {
CryptoSession::SetAllowTestKeybox(true);
ReinitializeForTest();
WvCdmTestBase::InstallTestRootOfTrust();
}
}
bool TestCryptoSession::IsTestKeyboxNeeded() {
// The first CryptoSession should have initialized OEMCrypto. This is right
// after that.
if (session_count() != 1) return false;
// If config is not available, assume keybox is required.
if (config_ == nullptr) return true;
// Unless disabled, test keybox is required.
return !config_->disable_test_keybox;
}
CdmResponseType TestCryptoSession::GenerateNonce(uint32_t* nonce) {
CdmResponseType status = CryptoSession::GenerateNonce(nonce);
for (int i = 0; status != NO_ERROR; i++) {
LOGV("Recovering from nonce flood.");
if (i > 2) return status;
wvutil::TestSleep::Sleep(1);
status = CryptoSession::GenerateNonce(nonce);
}
return CdmResponseType(NO_ERROR);
}
class TestCryptoSessionFactory : public CryptoSessionFactory {
public:
CryptoSession* MakeCryptoSession(
metrics::CryptoMetrics* crypto_metrics) override {
// We need to add extra locking here because we need to make sure that there
// are no other OEMCrypto calls between OEMCrypto_Initialize and
// InstallTestRootOfTrust. OEMCrypto_Initialize is called in the production
// CryptoSession::Init and is wrapped in crypto_lock_, but
// InstallTestRootOfTrust is only called in the constructor of the
// TestCryptoSession, above.
std::unique_lock<std::mutex> auto_lock(init_lock_);
return new TestCryptoSession(crypto_metrics, &session_config_);
}
void SetDisableTestKeybox(bool disable) {
std::unique_lock<std::mutex> auto_lock(init_lock_);
session_config_.disable_test_keybox = disable;
}
private:
std::mutex init_lock_;
// Shared with all TestCryptoSession instances created by this factory.
TestCryptoSessionConfig session_config_;
};
void WvCdmTestBase::SetUp() {
::testing::Test::SetUp();
Properties::Init();
Properties::set_provisioning_messages_are_binary(binary_provisioning_);
// Log the current test name, to help with debugging when the log and stdout
// are not the same.
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
LOGD("Running test %s.%s", test_info->test_case_name(), test_info->name());
// Some test environments allow the model name of the device to be set
// dynamically using an environment variable. The model name will show up in
// the license server logs as the part of the device idenfication as
// "model_name".
std::string model_name =
std::string(test_info->test_case_name()) + "." + test_info->name();
int overwrite = 1; // Set value even if already set.
setenv("MODEL_NAME", model_name.c_str(), overwrite);
TestCryptoSessionFactory* factory = new TestCryptoSessionFactory();
CryptoSession::SetCryptoSessionFactory(factory);
const char* const disable_test_keybox_flag = getenv("DISABLE_TEST_KEYBOX");
if (disable_test_keybox_flag != nullptr &&
!strcmp(disable_test_keybox_flag, "yes")) {
factory->SetDisableTestKeybox(true);
}
// TODO(fredgc): Add a test version of DeviceFiles.
}
void WvCdmTestBase::InstallTestRootOfTrust() {
const wvoec::WidevineKeybox& test_keybox =
use_qa_test_keybox_ ? wvoec::kQATestKeybox : wvoec::kTestKeybox;
switch (wvoec::global_features.derive_key_method) {
case wvoec::DeviceFeatures::LOAD_TEST_KEYBOX:
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_LoadTestKeybox(
reinterpret_cast<const uint8_t*>(&test_keybox),
sizeof(test_keybox)));
break;
case wvoec::DeviceFeatures::LOAD_TEST_RSA_KEY:
// Rare case: used by devices with baked in DRM cert.
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestRSAKey());
break;
case wvoec::DeviceFeatures::TEST_PROVISION_30:
// Can use oem certificate to install test rsa key.
break;
case wvoec::DeviceFeatures::TEST_PROVISION_40:
// OEM certificate is retrieved from the server.
break;
default:
FAIL() << "Cannot run test without test keybox or RSA key installed.";
}
}
WvCdmTestBase::WvCdmTestBase()
: config_(*default_config_), binary_provisioning_(false) {
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
LOGD("Running test %s.%s", test_info->test_case_name(), test_info->name());
}
void WvCdmTestBase::Provision() {
CdmProvisioningRequest prov_request;
std::string provisioning_server_url;
CdmCertificateType cert_type = kCertificateWidevine;
std::string cert_authority;
std::string cert, wrapped_key;
CdmSessionId session_id;
std::unique_ptr<wvutil::FileSystem> file_system(CreateTestFileSystem());
if (config_.provisioning_server() == "fake") {
LOGD("Using fake provisioning server.");
TestCdmEngine cdm_engine(file_system.get(),
std::shared_ptr<EngineMetrics>(new EngineMetrics));
FakeProvisioningServer server;
CdmResponseType result = cdm_engine.GetProvisioningRequest(
cert_type, cert_authority, server.service_certificate(), kLevelDefault,
&prov_request, &provisioning_server_url);
ASSERT_EQ(NO_ERROR, result);
if (!binary_provisioning_) {
std::vector<uint8_t> prov_request_v =
wvutil::Base64SafeDecode(prov_request);
prov_request = std::string(prov_request_v.begin(), prov_request_v.end());
}
std::string response;
ASSERT_TRUE(server.MakeResponse(prov_request, &response))
<< "Fake provisioning server could not provision";
result = cdm_engine.HandleProvisioningResponse(response, kLevelDefault,
&cert, &wrapped_key);
EXPECT_EQ(NO_ERROR, result);
} else {
// TODO(fredgc): provision for different SPOIDs.
TestCdmEngine cdm_engine(file_system.get(),
std::shared_ptr<EngineMetrics>(new EngineMetrics));
CdmResponseType result = cdm_engine.GetProvisioningRequest(
cert_type, cert_authority, config_.provisioning_service_certificate(),
kLevelDefault, &prov_request, &provisioning_server_url);
ASSERT_EQ(NO_ERROR, result);
if (binary_provisioning_) {
prov_request = wvutil::Base64SafeEncodeNoPad(prov_request);
}
LOGV("Provisioning request: req = %s", prov_request.c_str());
// Ignore URL provided by CdmEngine. Use ours, as configured
// for test vs. production server.
provisioning_server_url.assign(config_.provisioning_server());
// Make request.
UrlRequest url_request(provisioning_server_url);
if (!url_request.is_connected()) {
LOGE("Failed to connect to provisioning server: url = %s",
provisioning_server_url.c_str());
}
url_request.PostCertRequestInQueryString(prov_request);
// Receive and parse response.
std::string http_message;
ASSERT_NO_FATAL_FAILURE(url_request.AssertOkResponse(&http_message))
<< "Failed to fetch provisioning response. "
<< DumpProvAttempt(provisioning_server_url, prov_request, http_message,
&cdm_engine);
if (binary_provisioning_) {
// extract provisioning response from received message
// Extracts signed response from JSON string, result is serialized
// protobuf.
static const std::string kMessageStart = "\"signedResponse\": \"";
static const std::string kMessageEnd = "\"";
std::string protobuf_response;
const bool extract_ok = ExtractSignedMessage(
http_message, kMessageStart, kMessageEnd, &protobuf_response);
ASSERT_TRUE(extract_ok) << "Failed to extract signed serialized "
"response from JSON response";
LOGV("Extracted response message: \n%s\n", protobuf_response.c_str());
ASSERT_FALSE(protobuf_response.empty())
<< "Protobuf response is unexpectedly empty";
// base64 decode response to yield binary protobuf
const std::vector<uint8_t> response_vec(
wvutil::Base64SafeDecode(protobuf_response));
ASSERT_FALSE(response_vec.empty())
<< "Failed to decode base64 of response: response = "
<< protobuf_response;
const std::string binary_protobuf_response(response_vec.begin(),
response_vec.end());
ASSERT_EQ(NO_ERROR, cdm_engine.HandleProvisioningResponse(
binary_protobuf_response, kLevelDefault, &cert,
&wrapped_key))
<< "Binary provisioning failed. "
<< DumpProvAttempt(provisioning_server_url, prov_request,
http_message, &cdm_engine);
} else {
ASSERT_EQ(NO_ERROR, cdm_engine.HandleProvisioningResponse(
http_message, kLevelDefault, &cert, &wrapped_key))
<< "Non-binary provisioning failed. "
<< DumpProvAttempt(provisioning_server_url, prov_request,
http_message, &cdm_engine);
}
}
}
// TODO(fredgc): Replace this with a pre-defined DRM certificate. We could do
// that because either the device is using a known test keybox with a known
// device key, or the device is using an OEM certificate, and we can extract
// that certificate from the provisioning request.
void WvCdmTestBase::EnsureProvisioned() {
CdmSessionId session_id;
std::unique_ptr<wvutil::FileSystem> file_system(CreateTestFileSystem());
// OpenSession will check if a DRM certificate exists, while
// GenerateKeyRequest will actually load the wrapped private key.
// Either may return a NEED_PROVISIONING error, so both have to be checked.
TestCdmEngine cdm_engine(file_system.get(),
std::shared_ptr<EngineMetrics>(new EngineMetrics));
CdmResponseType status = cdm_engine.OpenSession(config_.key_system(), nullptr,
nullptr, &session_id);
CdmAppParameterMap app_parameters;
CdmKeySetId key_set_id;
InitializationData init_data(ISO_BMFF_VIDEO_MIME_TYPE, binary_key_id());
CdmKeyRequest key_request;
if (status == NO_ERROR) {
status = cdm_engine.GenerateKeyRequest(session_id, key_set_id, init_data,
kLicenseTypeStreaming,
app_parameters, &key_request);
}
// There are situations where we need two provisioning steps.
for (int count = 0; count < 2 && status == NEED_PROVISIONING; count++) {
Provision();
status = cdm_engine.OpenSession(config_.key_system(), nullptr, nullptr,
&session_id);
if (status == NEED_PROVISIONING) {
continue;
}
ASSERT_EQ(NO_ERROR, status);
status = cdm_engine.GenerateKeyRequest(session_id, key_set_id, init_data,
kLicenseTypeStreaming,
app_parameters, &key_request);
}
ASSERT_EQ(KEY_MESSAGE, status);
ASSERT_NE("", session_id) << "Could not open CDM session.";
ASSERT_TRUE(cdm_engine.IsOpenSession(session_id));
ASSERT_EQ(NO_ERROR, cdm_engine.CloseSession(session_id));
}
bool WvCdmTestBase::Initialize(int argc, const char* const argv[],
const std::string& extra_help_text) {
Properties::Init();
bool is_cast_receiver = false;
bool filter_tests = true;
bool show_usage = false;
int verbosity = 0;
default_config_.reset(new ConfigTestEnv(kContentProtectionUatServer));
// Skip the first element, which is the program name.
const std::vector<std::string> args(argv + 1, argv + argc);
for (const std::string& arg : args) {
if (arg == "--verbose" || arg == "-v") {
++verbosity;
} else if (arg == "--no_filter") {
filter_tests = false;
} else if (arg == "--cast") {
is_cast_receiver = true;
} else if (arg == "--fake_sleep") {
wvutil::TestSleep::set_real_sleep(false);
} else if (arg == "--qa_provisioning") {
use_qa_test_keybox_ = true;
default_config_->set_provisioning_service_certificate(
default_config_->QAProvisioningServiceCertificate());
} else if (arg.find("--gtest") == 0) {
// gtest arguments will be passed to gtest by the main program.
continue;
} else {
const auto index = arg.find('=');
if (index == std::string::npos) {
std::cerr << "Argument values need to be specified using --arg=foo"
<< std::endl;
show_usage = true;
break;
}
const std::string arg_prefix = arg.substr(0, index);
const std::string arg_value = arg.substr(index + 1);
if (arg_prefix == "--license_server_id") {
if (arg_value == "gp") {
default_config_.reset(new ConfigTestEnv(kGooglePlayServer));
} else if (arg_value == "cp") {
default_config_.reset(new ConfigTestEnv(kContentProtectionUatServer));
} else if (arg_value == "st") {
default_config_.reset(
new ConfigTestEnv(kContentProtectionStagingServer));
} else {
std::cerr << "Invalid license server id: " << arg_value << std::endl;
show_usage = true;
break;
}
} else if (arg_prefix == "--keyid") {
default_config_->set_key_id(arg_value);
} else if (arg_prefix == "--service_certificate") {
const std::string certificate(wvutil::a2bs_hex(arg_value));
default_config_->set_license_service_certificate(certificate);
} else if (arg_prefix == "--provisioning_certificate") {
const std::string certificate(wvutil::a2bs_hex(arg_value));
default_config_->set_provisioning_service_certificate(certificate);
} else if (arg_prefix == "--license_server_url") {
default_config_->set_license_server(arg_value);
} else if (arg_prefix == "--renewal_server_url") {
default_config_->set_renewal_server(arg_value);
} else if (arg_prefix == "--provisioning_server_url") {
default_config_->set_provisioning_server(arg_value);
} else if (arg_prefix == "--pass") {
default_config_->set_test_pass(std::stoi(arg_value));
std::cout << "Running test pass " << default_config_->test_pass()
<< std::endl;
} else if (arg_prefix == "--initial_time") {
if (wvutil::TestSleep::real_sleep()) {
LOGD("Ignoring initial time %s because using a real clock",
arg_value.c_str());
} else {
LOGE("Setting initial fake clock time to %s", arg_value.c_str());
wvutil::TestSleep::SetFakeClock(stol(arg_value));
}
} else if (arg_prefix == "--test_data_path") {
default_config_->set_test_data_path(arg_value);
} else if (arg_prefix == "--server_version") {
default_config_->set_server_version(atoi(arg_value.c_str()));
} else {
std::cerr << "Unknown argument " << arg_prefix << std::endl;
show_usage = true;
break;
}
}
}
if (show_usage) {
show_menu(argv[0], extra_help_text);
return false;
}
wvutil::g_cutoff = static_cast<wvutil::LogPriority>(verbosity);
// Displays server url, port and key Id being used
std::cout << std::endl;
std::cout << "Default Provisioning Server: "
<< default_config_->provisioning_server() << std::endl;
std::cout << "Default License Server: " << default_config_->license_server()
<< std::endl;
std::cout << "Default Renewal Server: " << default_config_->renewal_server()
<< std::endl;
std::cout << "Default KeyID: " << default_config_->key_id() << std::endl;
if (default_config_->server_version() != 0) {
std::cout << "Server Version: " << default_config_->server_version()
<< std::endl;
}
std::cout << std::endl;
// Figure out which tests are appropriate for OEMCrypto, based on features
// supported.
wvoec::global_features.Initialize();
if (is_cast_receiver) {
// Turn it on if passed in on the command line. Do not turn these tests off
// automtically -- instead, we'll let the caller filter them out if they
// need to. These tests will normally only run if the device claims to
// support being a cast receiver.
wvoec::global_features.set_cast_receiver(is_cast_receiver);
}
// If the user requests --no_filter, we don't change the filter, otherwise, we
// filter out features that are not supported.
if (filter_tests) {
::testing::GTEST_FLAG(filter) =
wvoec::global_features.RestrictFilter(::testing::GTEST_FLAG(filter));
}
return true;
}
std::string MakePSSH(const video_widevine::WidevinePsshData& header) {
std::string data;
header.SerializeToString(&data);
return MakePSSH(data);
}
std::string MakePSSH(const std::string& serialized_header) {
const uint32_t version = 0;
const std::string system_id = InitializationData::WidevineSystemID();
size_t system_id_size = system_id.size();
size_t data_size = serialized_header.size();
size_t atom_size = data_size + system_id_size + 4 * 4;
std::string pssh = wvutil::EncodeUint32(static_cast<uint32_t>(atom_size));
pssh.append("pssh");
pssh.append(wvutil::EncodeUint32(version));
pssh.append(system_id);
pssh.append(wvutil::EncodeUint32(static_cast<uint32_t>(data_size)));
pssh.append(serialized_header);
return pssh;
}
} // namespace wvcdm