Source release v3.5.0

This commit is contained in:
Gene Morgan
2017-11-28 17:42:16 -08:00
parent 501c22890d
commit 31381a1311
155 changed files with 16680 additions and 3816 deletions

View File

@@ -16,6 +16,7 @@
#include "override.h"
#include "properties_ce.h"
#include "scoped_ptr.h"
#include "service_certificate.h"
#include "string_conversions.h"
#include "test_host.h"
#include "url_request.h"
@@ -130,7 +131,7 @@ class CdmTest : public Test, public Cdm::IEventListener {
protected:
virtual void SetUp() OVERRIDE {
ConfigTestEnv config(kContentProtectionStagingPlusProv30);
ConfigTestEnv config(kContentProtectionUatServer);
g_provisioning_service_certificate.assign(
config.provisioning_service_certificate());
@@ -143,7 +144,7 @@ class CdmTest : public Test, public Cdm::IEventListener {
// Clear anything stored by OEMCrypto.
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize());
int result = OEMCrypto_DeleteUsageTable();
int result = OEMCrypto_DeleteOldUsageTable(); // TODO(fredgc): update this.
// Don't fault OEMCrypto implementations without usage tables:
if (result != OEMCrypto_ERROR_NOT_IMPLEMENTED) {
EXPECT_EQ(OEMCrypto_SUCCESS, result);
@@ -227,7 +228,28 @@ class CdmTest : public Test, public Cdm::IEventListener {
int status_code;
bool ok = Fetch(url, "", response, &status_code);
ASSERT_TRUE(ok);
if (ok) ASSERT_EQ(kHttpOk, status_code);
if (ok) ASSERT_EQ(kHttpOk, status_code)
<< "Error response: " << *response << "\n"
<< "url: " << url;
}
bool FetchServiceCertificate(const std::string& url,
std::string* response) {
std::string request;
int status;
if (!ServiceCertificate::GetRequest(&request)) {
LOGE("FAILED to generate service certificate request.");
return false;
}
if (!Fetch (url, request, response, &status)) {
LOGE("FAILED to get service certificate response: sts=%d", status);
return false;
}
LOGV("Reply body(hex): \n%s\n", b2a_hex(*response).c_str());
LOGV("Reply body(b64): \n%s\n",
Base64SafeEncode(std::vector<uint8_t>(response->begin(),
response->end())).c_str());
return true;
}
void FetchLicense(const std::string& license_server,
@@ -236,7 +258,9 @@ class CdmTest : public Test, public Cdm::IEventListener {
int status_code;
bool ok = Fetch(license_server, message, response, &status_code);
ASSERT_TRUE(ok);
if (ok) ASSERT_EQ(kHttpOk, status_code);
if (ok) ASSERT_EQ(kHttpOk, status_code)
<< "Error response: " << *response << "\n"
<< "license_server: " << license_server;
}
void FetchLicenseFailure(const std::string& message,
@@ -324,6 +348,24 @@ class CdmTest : public Test, public Cdm::IEventListener {
Mock::VerifyAndClear(this);
}
std::string GetProvisioningResponse(const std::string& message) {
std::string reply;
std::string uri = g_provisioning_server;
LOGV("GetProvisioningResponse: URI: %s", uri.c_str());
LOGV("GetProvisioningResponse: message:\n%s\n", b2a_hex(message).c_str());
uri += "&signedRequest=" + message;
FetchCertificate(uri, &reply);
if (HasFatalFailure()) {
LOGE("GetProvisioningResponse: Failed.");
return "";
}
LOGV("GetProvisioningResponse: response:\n%s\n", reply.c_str());
return reply;
}
scoped_ptr<Cdm> cdm_;
};
@@ -487,6 +529,51 @@ TEST_F(CdmTest, GetServiceCertificateRequest) {
EXPECT_EQ(Cdm::kSuccess, status);
}
TEST_F(CdmTest, ServiceCertificateRequestResponseUat) {
ConfigTestEnv uat_config(kContentProtectionUatServer);
std::string response;
ASSERT_TRUE(FetchServiceCertificate(uat_config.license_server(), &response));
LOGV("response size=%d", response.size());
#if 0 // enable to extract the service certificate in byte form
size_t done = 0;
while (done < response.size()) {
for (int i = 0; i < 12; i++) {
if (done >= response.size()) {
break;
}
uint32_t x = static_cast<uint8_t>(response.data()[done]);
printf("0x%02x, ", x);
done++;
}
printf ("\n");
}
#endif
}
TEST_F(CdmTest, ServiceCertificateRequestResponseStaging) {
ConfigTestEnv staging_config(kContentProtectionStagingServer);
std::string response;
ASSERT_TRUE(FetchServiceCertificate(staging_config.license_server(),
&response));
LOGV("response size=%d", response.size());
#if 0 // enable to extract the service certificate in byte form
size_t done = 0;
while (done < response.size()) {
for (int i = 0; i < 12; i++) {
if (done >= response.size()) {
break;
}
uint32_t x = static_cast<uint8_t>(response.data()[done]);
printf("0x%02x, ", x);
done++;
}
printf ("\n");
}
#endif
}
TEST_F(CdmTest, SetServiceCertificate) {
// Set a server certificate with privacy mode disabled - should work.
ASSERT_NO_FATAL_FAILURE(RecreateCdm(false /* privacy_mode */));
@@ -504,6 +591,37 @@ TEST_F(CdmTest, SetServiceCertificate) {
EXPECT_EQ(Cdm::kTypeError, status);
}
TEST_F(CdmTest, Provision) {
// Clear any existing certificates.
g_host->remove("cert.bin");
g_host->SaveProvisioningInformation();
// Creating a session should succeed.
std::string session_id;
Cdm::Status status;
status = cdm_->setServiceCertificate(g_license_service_certificate);
EXPECT_EQ(Cdm::kSuccess, status);
status = cdm_->createSession(Cdm::kTemporary, &session_id);
EXPECT_EQ(Cdm::kSuccess, status);
// Should get an individualization request when we generate request.
std::string message;
EXPECT_CALL(*this, onDirectIndividualizationRequest(session_id, _))
.WillOnce(SaveArg<1>(&message));
status = cdm_->generateRequest(session_id, Cdm::kCenc, kCencInitData);
EXPECT_EQ(Cdm::kSuccess, status);
Mock::VerifyAndClear(this);
// Complete the provisioning request.
std::string reply = GetProvisioningResponse(message);
ASSERT_FALSE(reply.empty());
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _)).Times(1);
EXPECT_CALL(*this, onDeferredComplete(_, _)).Times(0);
status = cdm_->update(session_id, reply);
ASSERT_EQ(Cdm::kSuccess, status);
Mock::VerifyAndClear(this);
}
TEST_F(CdmTest, CreateSession) {
// Create a temporary session.
std::string session_id;
@@ -709,7 +827,8 @@ TEST_F(CdmTest, LoadTemporary) {
EXPECT_EQ(Cdm::kSessionNotFound, status);
}
TEST_F(CdmTest, LoadPersistent) {
// TODO(fredgc,rfrias): turn this on after big usage tables work.
TEST_F(CdmTest, DISABLED_LoadPersistent) {
std::string session_id;
std::string response;
Cdm::Status status;
@@ -748,7 +867,8 @@ TEST_F(CdmTest, LoadPersistent) {
Mock::VerifyAndClear(this);
}
TEST_F(CdmTest, LoadWillFireExpiration) {
// TODO(fredgc,rfrias): turn this on after big usage tables work.
TEST_F(CdmTest, DISABLED_LoadWillFireExpiration) {
// There was a bug where calling load() would not start the PolicyEngine timer
// because it was only started in update().
std::string session_id;
@@ -769,7 +889,8 @@ TEST_F(CdmTest, LoadWillFireExpiration) {
Mock::VerifyAndClear(this);
}
TEST_F(CdmTest, PerOriginLoadPersistent) {
// TODO(fredgc,rfrias): turn this on after big usage tables work.
TEST_F(CdmTest, DISABLED_PerOriginLoadPersistent) {
std::string session_id;
std::string response;
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
@@ -801,7 +922,8 @@ TEST_F(CdmTest, PerOriginLoadPersistent) {
Mock::VerifyAndClear(this);
}
TEST_F(CdmTest, LoadUsageRecord) {
// TODO(fredgc,rfrias): turn this on after big usage tables work.
TEST_F(CdmTest, DISABLED_LoadUsageRecord) {
std::string session_id;
std::string response;
@@ -844,7 +966,8 @@ TEST_F(CdmTest, LoadUsageRecord) {
Mock::VerifyAndClear(this);
}
TEST_F(CdmTest, DestroyUsageRecord) {
// TODO(gmorgan): temporarily disabled - pending cdm_partner_3.2 merges
TEST_F(CdmTest, DISABLED_DestroyUsageRecord) {
std::string session_id;
std::string response;
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
@@ -878,7 +1001,8 @@ TEST_F(CdmTest, DestroyUsageRecord) {
Mock::VerifyAndClear(this);
}
TEST_F(CdmTest, DestroyAllUsageRecords) {
// TODO(gmorgan): temporarily disabled - pending cdm_partner_3.2 merges
TEST_F(CdmTest, DISABLED_DestroyAllUsageRecords) {
std::string session_id;
std::string response;
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
@@ -912,7 +1036,8 @@ TEST_F(CdmTest, DestroyAllUsageRecords) {
Mock::VerifyAndClear(this);
}
TEST_F(CdmTest, ListUsageRecords) {
// TODO(gmorgan): temporarily disabled - pending cdm_partner_3.2 merges
TEST_F(CdmTest, DISABLED_ListUsageRecords) {
std::string session_id;
std::string response;
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
@@ -1026,7 +1151,8 @@ TEST_F(CdmTest, GetExpiration) {
ASSERT_EQ(Cdm::kSessionNotFound, status);
}
TEST_F(CdmTest, Remove) {
// TODO(fredgc,rfrias): turn this on after big usage tables work.
TEST_F(CdmTest, DISABLED_Remove) {
std::string session_id;
ASSERT_NO_FATAL_FAILURE(CreateSessionAndUpdate(
Cdm::kPersistentLicense, Cdm::kCenc, &session_id));
@@ -1080,7 +1206,8 @@ TEST_F(CdmTest, Remove) {
EXPECT_EQ(Cdm::kRangeError, status);
}
TEST_F(CdmTest, RemoveUsageRecord) {
// TODO(fredgc,rfrias): turn this on after big usage tables work.
TEST_F(CdmTest, DISABLED_RemoveUsageRecord) {
std::string session_id;
ASSERT_NO_FATAL_FAILURE(CreateSessionAndUpdate(
Cdm::kPersistentUsageRecord, Cdm::kCenc, &session_id));
@@ -1116,7 +1243,8 @@ TEST_F(CdmTest, RemoveUsageRecord) {
ASSERT_EQ(Cdm::kSessionNotFound, status);
}
TEST_F(CdmTest, RemoveIncomplete) {
// TODO(fredgc,rfrias): turn this on after big usage tables work.
TEST_F(CdmTest, DISABLED_RemoveIncomplete) {
std::string session_id;
ASSERT_NO_FATAL_FAILURE(CreateSessionAndUpdate(
Cdm::kPersistentLicense, Cdm::kCenc, &session_id));
@@ -1179,15 +1307,8 @@ TEST_F(CdmTest, RemoveIncomplete) {
ASSERT_EQ(Cdm::kSessionNotFound, status);
}
TEST_F(CdmTest, RemoveUsageTable) {
Cdm::Status status;
status = cdm_->removeUsageTable();
ASSERT_EQ(Cdm::kSuccess, status);
status = cdm_->removeUsageTable();
ASSERT_EQ(Cdm::kSuccess, status);
}
TEST_F(CdmTest, RemoveUsageRecordIncomplete) {
// TODO(fredgc,rfrias): turn this on after big usage tables work.
TEST_F(CdmTest, DISABLED_RemoveUsageRecordIncomplete) {
std::string session_id;
ASSERT_NO_FATAL_FAILURE(CreateSessionAndUpdate(
Cdm::kPersistentUsageRecord, Cdm::kCenc, &session_id));
@@ -1250,7 +1371,8 @@ TEST_F(CdmTest, RemoveUsageRecordIncomplete) {
ASSERT_EQ(Cdm::kSessionNotFound, status);
}
TEST_F(CdmTest, RemoveNotLoaded) {
// TODO(fredgc,rfrias): turn this on after big usage tables work.
TEST_F(CdmTest, DISABLED_RemoveNotLoaded) {
// Create a persistent session and then close it.
std::string session_id;
ASSERT_NO_FATAL_FAILURE(CreateSessionAndUpdate(
@@ -1285,7 +1407,8 @@ TEST_F(CdmTest, RequestPersistentLicenseWithWrongInitData) {
FetchLicenseFailure(message, 500);
}
TEST_F(CdmTest, RequestTemporaryLicenseWithWrongInitData) {
// TODO(fredgc,rfrias): turn this on after big usage tables work.
TEST_F(CdmTest, DISABLED_RequestTemporaryLicenseWithWrongInitData) {
// Generate a request for a temporary license using persistent init data.
std::string session_id;
Cdm::Status status;
@@ -1460,6 +1583,7 @@ TEST_F(CdmTest, SetVideoResolutionOverflow) {
cdm_->close(session_id);
}
// TODO(http://b/37286053): Fix this test.
TEST_P(CdmTestWithDecryptParam, DecryptToClearBuffer) {
DecryptParam param = GetParam();
@@ -1630,6 +1754,7 @@ TEST_F(CdmIndividualizationTest, IsProvisioned) {
EXPECT_TRUE(cdm_->isProvisioned());
}
// TODO(fredgc,rfrias): turn this on after big usage tables work.
TEST_F(CdmIndividualizationTest, RemoveProvisioning) {
if (!CheckProvisioningSupport()) return;
@@ -1810,7 +1935,8 @@ TEST_F(CdmIndividualizationTest, OnlyPropagatesErrorsForThisSession) {
Mock::VerifyAndClear(this);
}
TEST_F(CdmIndividualizationTest, WorksWithLoad) {
// TODO(fredgc,rfrias): turn this on after big usage tables work.
TEST_F(CdmIndividualizationTest, DISABLED_WorksWithLoad) {
if (!CheckProvisioningSupport()) return;
// Create an offline session to load.

View File

@@ -4,6 +4,7 @@
#include <getopt.h>
#include <gtest/gtest.h>
#include <time.h>
#include <stdio.h>
#if defined(__linux__)
#include <sys/utsname.h>
@@ -13,6 +14,7 @@
#include "device_cert.h"
#include "override.h"
#include "test_host.h"
#include "test_keybox.h"
#if defined(OEMCRYPTO_TESTS)
# include "oec_device_features.h"
@@ -45,6 +47,23 @@ int main(int argc, char** argv) {
return 0;
}
{
FILE* outfile;
outfile = fopen("danger_do_not_use.bin", "w");
if (outfile == NULL) { return 0; }
if (fwrite(wvcdm_test_auth::kKeybox, 1,
wvcdm_test_auth::kKeyboxSize, outfile) != 128) {
fclose(outfile);
return 0;
}
if (fwrite(wvcdm_test_auth::kKeyboxValid02, 1,
wvcdm_test_auth::kKeyboxSize, outfile) != 128) {
fclose(outfile);
return 0;
}
fclose(outfile);
}
// Set up a Host so that tests and initialize the library. This makes these
// services available to the tests. We would do this in the test suite
// itself, but the core & OEMCrypto tests don't know they depend on this
@@ -76,7 +95,6 @@ int main(int argc, char** argv) {
#if defined(OEMCRYPTO_TESTS)
// Set up the OEMCrypto test harness.
// NOTE: This creates a temporary OEMCrypto "instance".
wvoec::global_features.Initialize(false /* is_cast_receiver */,
false /* force_load_test_keybox */);
::testing::GTEST_FLAG(filter)

View File

@@ -0,0 +1,44 @@
#include <algorithm>
#include <cstring>
#include <map>
#include <string>
#include "level3_file_system_ce_test.h"
namespace wvoec3 {
std::map<std::string, std::string> OEMCrypto_Level3CETestFileSystem::files_;
ssize_t OEMCrypto_Level3CETestFileSystem::Read(const char *filename,
void *buffer, size_t size) {
if (!Exists(filename)) return 0;
std::string data = files_[std::string(filename)];
size_t bytes_read = std::min(size, data.size());
memcpy(buffer, data.data(), bytes_read);
return bytes_read;
}
ssize_t OEMCrypto_Level3CETestFileSystem::Write(const char *filename,
const void *buffer,
size_t size) {
std::string data(static_cast<const char*>(buffer), size);
files_[std::string(filename)] = data;
return size;
}
bool OEMCrypto_Level3CETestFileSystem::Exists(const char *filename) {
return files_.find(std::string(filename)) != files_.end();
}
ssize_t OEMCrypto_Level3CETestFileSystem::FileSize(const char *filename) {
if (!Exists(filename)) return -1;
return files_[std::string(filename)].size();
}
bool OEMCrypto_Level3CETestFileSystem::Remove(const char *filename) {
if (!Exists(filename)) return false;
files_.erase(std::string(filename));
return true;
}
} // namespace wvoec3

View File

@@ -0,0 +1,34 @@
// Copyright 2017 Google Inc. All Rights Reserved
/*********************************************************************
* level3_file_system_ce_test.h
*
* Test file system for CE CDM for OEMCrypto Level3 File Operations.
*********************************************************************/
#ifndef LEVEL3_FILE_SYSTEM_CE_TEST_H_
#define LEVEL3_FILE_SYSTEM_CE_TEST_H_
#include "cdm.h"
#include "file_store.h"
#include "level3_file_system.h"
namespace wvoec3 {
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;
private:
static std::map<std::string, std::string> files_;
};
} // namespace wvoec3
#endif

View File

@@ -0,0 +1,16 @@
#include "level3_file_system_ce_test.h"
#include "level3_file_system_factory.h"
namespace wvoec3 {
OEMCrypto_Level3FileSystem* createLevel3FileSystem() {
return new OEMCrypto_Level3CETestFileSystem();
}
void deleteLevel3FileSystem(OEMCrypto_Level3FileSystem* file_system) {
if (file_system) {
delete file_system;
}
}
}

View File

@@ -9,6 +9,10 @@
using namespace widevine;
namespace {
const std::string kCertificateFilename = "cert.bin";
} // namespace
TestHost::TestHost() {
Reset();
}
@@ -19,14 +23,17 @@ void TestHost::Reset() {
gettimeofday(&tv, NULL);
now_ = (tv.tv_sec * 1000LL) + (tv.tv_usec / 1000LL);
save_device_cert_ = false;
// Surprisingly, std::priority_queue has no clear().
while (!timers_.empty()) {
timers_.pop();
}
files_.clear();
files_["cert.bin"] =
std::string((const char*)kDeviceCert, kDeviceCertSize);
files_[kCertificateFilename.c_str()] = (device_cert_.size() > 0)
? device_cert_
: std::string((const char*)kDeviceCert, kDeviceCertSize);
}
void TestHost::ElapseTime(int64_t milliseconds) {
@@ -37,9 +44,9 @@ void TestHost::ElapseTime(int64_t milliseconds) {
} else {
Timer t = timers_.top();
timers_.pop();
ASSERT_GE(t.expiry_time, now_);
now_ = t.expiry_time;
t.client->onTimerExpired(t.context);
ASSERT_GE(t.expiry_time(), now_);
now_ = t.expiry_time();
t.client()->onTimerExpired(t.context());
}
}
}
@@ -60,6 +67,10 @@ bool TestHost::write(const std::string& name,
const std::string& data) {
LOGD("write file: %s", name.c_str());
files_[name] = data;
if (save_device_cert_ && kCertificateFilename.compare(name) == 0) {
device_cert_ = data;
save_device_cert_ = false;
}
return true;
}
@@ -114,7 +125,7 @@ void TestHost::cancel(IClient* client) {
Timer t = timers_.top();
timers_.pop();
if (t.client != client) {
if (t.client() != client) {
others.push(t);
}
}

View File

@@ -18,6 +18,8 @@ class TestHost : public widevine::Cdm::IStorage,
void ElapseTime(int64_t milliseconds);
int NumTimers() const;
void SaveProvisioningInformation() { save_device_cert_ = true; }
virtual bool read(const std::string& name,
std::string* data) OVERRIDE;
virtual bool write(const std::string& name,
@@ -36,23 +38,31 @@ class TestHost : public widevine::Cdm::IStorage,
private:
struct Timer {
Timer(int64_t expiry_time_, IClient* client_, void* context_)
: expiry_time(expiry_time_), client(client_), context(context_) {}
Timer(int64_t expiry_time, IClient* client, void* context)
: expiry_time_(expiry_time), client_(client), context_(context) {}
bool operator<(const Timer& other) const {
// We want to reverse the order so that the smallest expiry times go to
// the top of the priority queue.
return expiry_time > other.expiry_time;
return expiry_time_ > other.expiry_time_;
}
int64_t expiry_time;
IClient* client;
void* context;
int64_t expiry_time() { return expiry_time_; }
IClient* client() { return client_; }
void* context() { return context_; }
private:
int64_t expiry_time_;
IClient* client_;
void* context_;
};
int64_t now_;
std::priority_queue<Timer> timers_;
std::string device_cert_;
bool save_device_cert_;
typedef std::map<std::string, std::string> StorageMap;
StorageMap files_;
};