A new set of license data was created on UAT so that we could have keys that match those in the license returned by a License SDK and by those generated by UAT. It should be more clear now which data is just made up, and which data has to match some golden values based on the made up data. Bug: 338323091 Test: WVTS Change-Id: Ic112b4594afb99c6f43e011f59ee7592d4809189
640 lines
26 KiB
C++
640 lines
26 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 "message_dumper.h"
|
|
#include "oec_device_features.h"
|
|
#include "oec_test_data.h"
|
|
#include "platform.h"
|
|
#include "properties.h"
|
|
#include "provisioning_holder.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 << " --dump_golden_data" << std::endl;
|
|
std::cout << " Dump the license request and response from the server."
|
|
<< std::endl
|
|
<< std::endl;
|
|
|
|
std::cout << " --skip-slow-tests" << std::endl;
|
|
std::cout << " Skips tests that are known to be slow." << std::endl;
|
|
std::cout << " --skip-sleepy-tests" << std::endl;
|
|
std::cout << " Skips tests that sleep a lot." << std::endl;
|
|
std::cout << " --run-sleepy-tests" << std::endl;
|
|
std::cout << " Allow tests that sleep a lot (used with --skip-slow-tests)"
|
|
<< std::endl;
|
|
std::cout << " --skip-decryption-stress-tests" << std::endl;
|
|
std::cout << " Skips decryption stress tests." << std::endl;
|
|
std::cout << " --run-decryption-stress-tests" << std::endl;
|
|
std::cout << " Allow decryption stress tests (used with "
|
|
<< "--skip-slow-tests)" << std::endl;
|
|
std::cout << " --skip-request-flood-tests" << std::endl;
|
|
std::cout << " Skips tests that generate a lot of requests." << std::endl;
|
|
std::cout << " --run-request-flood-tests" << std::endl;
|
|
std::cout << " Allow tests that generate a lot of requests (used with "
|
|
<< "--skip-slow-tests)" << std::endl;
|
|
std::cout << " --skip-multi-thread-stress-tests" << std::endl;
|
|
std::cout << " Skips tests that stress thread protections." << std::endl;
|
|
std::cout << " --run-multi-thread-stress-tests" << std::endl;
|
|
std::cout << " Allow tests that stress thread protections (used with "
|
|
<< "--skip-slow-tests)" << std::endl;
|
|
std::cout << " --skip-usage-table-stress-tests" << std::endl;
|
|
std::cout << " Skips tests that stess the usage table." << std::endl;
|
|
std::cout << " --run-usage-table-stress-tests" << std::endl;
|
|
std::cout << " Allow tests that stess the usage table (used with "
|
|
<< "--skip-slow-tests)" << std::endl
|
|
<< std::endl;
|
|
|
|
std::cout << extra_help_text << std::endl;
|
|
}
|
|
|
|
enum OptionalBool {
|
|
kBoolUnset,
|
|
kBoolFalse,
|
|
kBoolTrue,
|
|
};
|
|
|
|
bool UnwrapOptionalBool(OptionalBool value, bool default_value) {
|
|
return (value == kBoolUnset) ? default_value : (value == kBoolTrue);
|
|
}
|
|
|
|
// Increment counter for AES-CTR. The CENC spec specifies we increment only
|
|
// the low 64 bits of the IV counter, and leave the high 64 bits alone. This
|
|
// is different from the BoringSSL implementation, so we implement the CTR loop
|
|
// ourselves.
|
|
void ctr128_inc64(int64_t increaseBy, std::vector<uint8_t>& iv) {
|
|
uint64_t* counterBuffer = reinterpret_cast<uint64_t*>(&(iv[8]));
|
|
(*counterBuffer) =
|
|
wvutil::htonll64(wvutil::ntohll64(*counterBuffer) + increaseBy);
|
|
}
|
|
} // namespace
|
|
|
|
// Static WvCdmTestBase variables.
|
|
std::unique_ptr<ConfigTestEnv> WvCdmTestBase::default_config_;
|
|
bool WvCdmTestBase::use_qa_test_keybox_ = false;
|
|
bool WvCdmTestBase::skip_sleepy_tests_ = false;
|
|
bool WvCdmTestBase::skip_decryption_stress_tests_ = false;
|
|
bool WvCdmTestBase::skip_request_flood_tests_ = false;
|
|
bool WvCdmTestBase::skip_multi_thread_stress_tests_ = false;
|
|
bool WvCdmTestBase::skip_usage_table_stress_tests_ = 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;
|
|
}
|
|
}
|
|
|
|
// Encrypt a block of data using CTR mode.
|
|
std::vector<uint8_t> WvCdmTestBase::Aes128CtrEncrypt(
|
|
const std::vector<uint8_t>& key, const std::vector<uint8_t>& starting_iv,
|
|
const std::vector<uint8_t>& in_buffer) {
|
|
AES_KEY aes_key;
|
|
AES_set_encrypt_key(key.data(), AES_BLOCK_SIZE * 8, &aes_key);
|
|
std::vector<uint8_t> out_buffer(in_buffer.size());
|
|
std::vector<uint8_t> iv = starting_iv;
|
|
size_t l = 0; // byte index into encrypted subsample.
|
|
while (l < in_buffer.size()) {
|
|
uint8_t aes_output[AES_BLOCK_SIZE];
|
|
AES_encrypt(iv.data(), aes_output, &aes_key);
|
|
for (size_t n = 0; n < AES_BLOCK_SIZE && l < in_buffer.size(); n++, l++) {
|
|
out_buffer[l] = aes_output[n] ^ in_buffer[l];
|
|
}
|
|
ctr128_inc64(1, iv);
|
|
}
|
|
return out_buffer;
|
|
}
|
|
|
|
std::string WvCdmTestBase::Aes128CbcEncrypt(std::vector<uint8_t> key,
|
|
const std::vector<uint8_t>& clear,
|
|
std::vector<uint8_t> iv) {
|
|
std::vector<uint8_t> encrypted(clear.size());
|
|
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[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,
|
|
std::vector<uint8_t> iv) {
|
|
std::vector<uint8_t> encrypted(clear.size());
|
|
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[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()) {
|
|
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") == 0) {
|
|
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_) {
|
|
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() {
|
|
const CdmCertificateType cert_type = kCertificateWidevine;
|
|
std::unique_ptr<wvutil::FileSystem> file_system(CreateTestFileSystem());
|
|
TestCdmEngine cdm_engine(file_system.get(),
|
|
std::make_shared<EngineMetrics>());
|
|
ProvisioningHolder provisioner(&cdm_engine, config_);
|
|
provisioner.Provision(cert_type, binary_provisioning_);
|
|
}
|
|
|
|
void WvCdmTestBase::EnsureProvisioned() {
|
|
// 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.";
|
|
}
|
|
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::make_shared<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 show_usage = false;
|
|
int verbosity = 0;
|
|
|
|
bool skip_slow_tests = false;
|
|
OptionalBool skip_sleepy_tests = kBoolUnset;
|
|
OptionalBool skip_decryption_stress_tests = kBoolUnset;
|
|
OptionalBool skip_request_flood_tests = kBoolUnset;
|
|
OptionalBool skip_multi_thread_stress_tests = kBoolUnset;
|
|
OptionalBool skip_usage_table_stress_tests = kBoolUnset;
|
|
|
|
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 == "--help" || arg == "-h") {
|
|
show_usage = true;
|
|
} else if (arg == "--verbose" || arg == "-v") {
|
|
++verbosity;
|
|
} 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 if (arg == "--dump_golden_data") {
|
|
default_config_->set_dump_golden_data(true);
|
|
testing::AddGlobalTestEnvironment(new MessageDumper);
|
|
} else if (arg == "--skip-slow-tests") {
|
|
skip_slow_tests = true;
|
|
} else if (arg == "--skip-sleepy-tests") {
|
|
skip_sleepy_tests = kBoolTrue;
|
|
} else if (arg == "--run-sleepy-tests") {
|
|
skip_sleepy_tests = kBoolFalse;
|
|
} else if (arg == "--skip-decryption-stress-tests") {
|
|
skip_decryption_stress_tests = kBoolTrue;
|
|
} else if (arg == "--run-decryption-stress-tests") {
|
|
skip_decryption_stress_tests = kBoolFalse;
|
|
} else if (arg == "--skip-request-flood-tests") {
|
|
skip_request_flood_tests = kBoolTrue;
|
|
} else if (arg == "--run-request-flood-tests") {
|
|
skip_request_flood_tests = kBoolFalse;
|
|
} else if (arg == "--skip-multi-thread-stress-tests") {
|
|
skip_multi_thread_stress_tests = kBoolTrue;
|
|
} else if (arg == "--run-multi-thread-stress-tests") {
|
|
skip_multi_thread_stress_tests = kBoolFalse;
|
|
} else if (arg == "--skip-usage-table-stress-tests") {
|
|
skip_usage_table_stress_tests = kBoolTrue;
|
|
} else if (arg == "--run-usage-table-stress-tests") {
|
|
skip_usage_table_stress_tests = kBoolFalse;
|
|
} 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);
|
|
}
|
|
|
|
skip_sleepy_tests_ = UnwrapOptionalBool(skip_sleepy_tests, skip_slow_tests);
|
|
skip_decryption_stress_tests_ =
|
|
UnwrapOptionalBool(skip_decryption_stress_tests, skip_slow_tests);
|
|
skip_request_flood_tests_ =
|
|
UnwrapOptionalBool(skip_request_flood_tests, skip_slow_tests);
|
|
skip_multi_thread_stress_tests_ =
|
|
UnwrapOptionalBool(skip_multi_thread_stress_tests, skip_slow_tests);
|
|
skip_usage_table_stress_tests_ =
|
|
UnwrapOptionalBool(skip_usage_table_stress_tests, skip_slow_tests);
|
|
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
|