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

@@ -1,8 +1,6 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
// This file adds some print methods so that when unit tests fail, the
// will print the name of an enumeration instead of the numeric value.
#include "test_base.h"
@@ -11,11 +9,15 @@
#include <openssl/cmac.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"
@@ -24,6 +26,7 @@
#include "platform.h"
#include "properties.h"
#include "test_printers.h"
#include "test_sleep.h"
#include "url_request.h"
using wvcdm::metrics::EngineMetrics;
@@ -63,7 +66,8 @@ void show_menu(const char* prog_name, const std::string& extra_help_text) {
<< std::endl;
std::cout << " --service_certificate=<cert>" << std::endl;
std::cout << " configure the signed license service certificate" << 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;
@@ -75,11 +79,14 @@ void show_menu(const char* prog_name, const std::string& extra_help_text) {
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::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 << " 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]"
@@ -87,8 +94,14 @@ void show_menu(const char* prog_name, const std::string& extra_help_text) {
<< 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::cout
<< " configure the provisioning server url, please include http[s]"
<< " in the url" << 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 << extra_help_text << std::endl;
@@ -194,7 +207,7 @@ CdmResponseType TestCryptoSession::GenerateNonce(uint32_t* nonce) {
for (int i = 0; status != NO_ERROR; i++) {
LOGV("Recovering from nonce flood.");
if (i > 2) return status;
sleep(1);
TestSleep::Sleep(1);
status = CryptoSession::GenerateNonce(nonce);
}
return NO_ERROR;
@@ -255,6 +268,14 @@ void WvCdmTestBase::InstallTestRootOfTrust() {
}
}
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;
CdmProvisioningRequest binary_prov_request;
@@ -266,60 +287,126 @@ void WvCdmTestBase::Provision() {
CdmSessionId session_id;
FileSystem file_system;
// TODO(fredgc): provision for different SPOIDs.
CdmEngine cdm_engine(&file_system,
std::shared_ptr<EngineMetrics>(new EngineMetrics));
if (config_.provisioning_server() == "fake") {
LOGD("Using fake provisioning server.");
CdmResponseType result = cdm_engine.GetProvisioningRequest(
cert_type, cert_authority, config_.provisioning_service_certificate(),
&prov_request, &provisioning_server_url);
ASSERT_EQ(NO_ERROR, result);
if (binary_provisioning_) {
binary_prov_request = prov_request;
prov_request = std::string(Base64SafeEncodeNoPad(std::vector<uint8_t>(
binary_prov_request.begin(), binary_prov_request.end())));
}
LOGV("WvCdmTestBase::Provision: 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());
UrlRequest url_request(provisioning_server_url);
EXPECT_TRUE(url_request.is_connected());
url_request.PostCertRequestInQueryString(prov_request);
std::string http_message;
bool ok = url_request.GetResponse(&http_message);
EXPECT_TRUE(ok) << http_message;
LOGV("WvCdmTestBase::Provision: http_message: \n%s\n", http_message.c_str());
if (binary_provisioning_) {
// extract provisioning response from received message
// Extracts signed response from JSON string, result is serialized protobuf.
const std::string kMessageStart = "\"signedResponse\": \"";
const std::string kMessageEnd = "\"";
std::string protobuf_response;
EXPECT_TRUE(ExtractSignedMessage(http_message, kMessageStart, kMessageEnd,
&protobuf_response))
<< "Failed to extract signed serialized response from JSON response";
LOGV("WvCdmEnginePreProvTest::Provision: extracted response message: \n"
"%s\n", protobuf_response.c_str());
// base64 decode response to yield binary protobuf
std::vector<uint8_t> response_vec(Base64SafeDecode(
std::string(protobuf_response.begin(), protobuf_response.end())));
std::string binary_protobuf_response(response_vec.begin(),
response_vec.end());
ASSERT_EQ(NO_ERROR, cdm_engine.HandleProvisioningResponse(
binary_protobuf_response, &cert, &wrapped_key))
<< "message = " << http_message;
CdmEngine cdm_engine(&file_system,
std::shared_ptr<EngineMetrics>(new EngineMetrics));
FakeProvisioningServer server;
CdmResponseType result = cdm_engine.GetProvisioningRequest(
cert_type, cert_authority, server.service_certificate(), &prov_request,
&provisioning_server_url);
ASSERT_EQ(NO_ERROR, result);
if (!binary_provisioning_) {
std::vector<uint8_t> prov_request_v = 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, &cert, &wrapped_key);
EXPECT_EQ(NO_ERROR, result);
} else {
ASSERT_EQ(NO_ERROR, cdm_engine.HandleProvisioningResponse(
http_message, &cert, &wrapped_key))
<< "message = " << http_message;
// TODO(fredgc): provision for different SPOIDs.
CdmEngine cdm_engine(&file_system,
std::shared_ptr<EngineMetrics>(new EngineMetrics));
CdmResponseType result = cdm_engine.GetProvisioningRequest(
cert_type, cert_authority, config_.provisioning_service_certificate(),
&prov_request, &provisioning_server_url);
ASSERT_EQ(NO_ERROR, result);
if (binary_provisioning_) {
binary_prov_request = prov_request;
prov_request = std::string(Base64SafeEncodeNoPad(std::vector<uint8_t>(
binary_prov_request.begin(), binary_prov_request.end())));
}
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());
// TODO(b/139361531): Remove loop once provisioning service is stable.
std::string http_message;
size_t attempt_num = 0;
bool provision_success = false;
do {
if (attempt_num > 0) {
// Sleep between attempts.
std::this_thread::sleep_for(std::chrono::seconds(1));
}
++attempt_num;
// 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());
continue;
}
url_request.PostCertRequestInQueryString(prov_request);
// Receive and parse response.
if (!url_request.GetResponse(&http_message)) {
LOGE("Failed to get provisioning response");
continue;
}
LOGV("http_message: \n%s\n", http_message.c_str());
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;
if (!ExtractSignedMessage(http_message, kMessageStart, kMessageEnd,
&protobuf_response)) {
LOGE(
"Failed to extract signed serialized response from JSON "
"response");
continue;
}
LOGV("Extracted response message: \n%s\n", protobuf_response.c_str());
// base64 decode response to yield binary protobuf
std::vector<uint8_t> response_vec(Base64SafeDecode(protobuf_response));
if (response_vec.empty() && !protobuf_response.empty()) {
LOGE("Failed to decode base64 of response: response = %s",
protobuf_response.c_str());
continue;
}
std::string binary_protobuf_response(response_vec.begin(),
response_vec.end());
if (cdm_engine.HandleProvisioningResponse(
binary_protobuf_response, &cert, &wrapped_key) != NO_ERROR) {
LOGE("Failed to handle provisioning response");
continue;
}
} else {
if (cdm_engine.HandleProvisioningResponse(http_message, &cert,
&wrapped_key) != NO_ERROR) {
LOGE("Failed to handle binary provisioning response");
continue;
}
}
provision_success = true;
} while (attempt_num <= kDefaultMaxProvisioningAttempts &&
!provision_success);
if (attempt_num > 1) {
LOGW("Provisioning request failed at least once: attempts = %zu",
attempt_num);
}
ASSERT_TRUE(provision_success)
<< "Failed to provision: message = " << http_message;
}
}
@@ -332,12 +419,12 @@ void WvCdmTestBase::EnsureProvisioned() {
FileSystem file_system;
CdmEngine cdm_engine(&file_system,
std::shared_ptr<EngineMetrics>(new EngineMetrics));
CdmResponseType status =
cdm_engine.OpenSession(config_.key_system(), NULL, NULL, &session_id);
CdmResponseType status = cdm_engine.OpenSession(config_.key_system(), nullptr,
nullptr, &session_id);
if (status == NEED_PROVISIONING) {
Provision();
status =
cdm_engine.OpenSession(config_.key_system(), NULL, NULL, &session_id);
status = cdm_engine.OpenSession(config_.key_system(), nullptr, nullptr,
&session_id);
}
ASSERT_EQ(NO_ERROR, status);
ASSERT_NE("", session_id) << "Could not open CDM session.";
@@ -349,7 +436,6 @@ bool WvCdmTestBase::Initialize(int argc, const char* const argv[],
const std::string& extra_help_text) {
Properties::Init();
bool is_cast_receiver = false;
bool force_load_test_keybox = false; // TODO(fredgc): obsolete. remove.
bool filter_tests = true;
bool show_usage = false;
int verbosity = 0;
@@ -363,10 +449,16 @@ bool WvCdmTestBase::Initialize(int argc, const char* const argv[],
filter_tests = false;
} else if (arg == "--cast") {
is_cast_receiver = true;
} else if (arg == "--fake_sleep") {
wvcdm::TestSleep::set_real_sleep(false);
} 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;
std::cerr << "Argument values need to be specified using --arg=foo"
<< std::endl;
show_usage = true;
break;
}
@@ -414,14 +506,17 @@ bool WvCdmTestBase::Initialize(int argc, const char* const argv[],
// Displays server url, port and key Id being used
std::cout << std::endl;
std::cout << "Default Server: " << default_config_.license_server()
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 KeyID: " << default_config_.key_id() << std::endl
<< std::endl;
// Figure out which tests are appropriate for OEMCrypto, based on features
// supported.
wvoec::global_features.Initialize(is_cast_receiver, force_load_test_keybox);
wvoec::global_features.Initialize();
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) {
@@ -442,13 +537,11 @@ TestLicenseHolder::TestLicenseHolder(CdmEngine* cdm_engine)
enc_key_(CONTENT_KEY_SIZE, 'e'),
session_key_(CONTENT_KEY_SIZE, 'f') {}
TestLicenseHolder::~TestLicenseHolder() {
CloseSession();
}
TestLicenseHolder::~TestLicenseHolder() { CloseSession(); }
void TestLicenseHolder::OpenSession(const std::string& key_system) {
CdmResponseType status =
cdm_engine_->OpenSession(key_system, NULL, NULL, &session_id_);
cdm_engine_->OpenSession(key_system, nullptr, nullptr, &session_id_);
ASSERT_EQ(status, NO_ERROR);
ASSERT_NE("", session_id_) << "Could not open CDM session.";
ASSERT_TRUE(cdm_engine_->IsOpenSession(session_id_));
@@ -595,9 +688,8 @@ void TestLicenseHolder::SignAndLoadLicense() {
CdmKeySetId key_set_id;
CdmLicenseType license_type; // Required for AddKey. Result value ignored.
EXPECT_EQ(KEY_ADDED,
cdm_engine_->AddKey(session_id_, response_data,
&license_type, &key_set_id));
EXPECT_EQ(KEY_ADDED, cdm_engine_->AddKey(session_id_, response_data,
&license_type, &key_set_id));
}
void TestLicenseHolder::DeriveKeysFromSessionKey() {
@@ -627,7 +719,7 @@ void TestLicenseHolder::DeriveKeysFromSessionKey() {
bool TestLicenseHolder::DeriveKey(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& context,
int counter, std::vector<uint8_t>* out) {
if (key.empty() || counter > 4 || context.empty() || out == NULL) {
if (key.empty() || counter > 4 || context.empty() || out == nullptr) {
LOGE("DeriveKey(): bad context");
return false;
}
@@ -667,4 +759,26 @@ bool TestLicenseHolder::DeriveKey(const std::vector<uint8_t>& key,
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 = EncodeUint32(atom_size);
pssh.append("pssh");
pssh.append(EncodeUint32(version));
pssh.append(system_id);
pssh.append(EncodeUint32(data_size));
pssh.append(serialized_header);
return pssh;
}
} // namespace wvcdm