Source release v3.3.0

This commit is contained in:
Gene Morgan
2017-05-04 14:01:27 -07:00
parent baa7b133d3
commit 8082775924
678 changed files with 51264 additions and 14200 deletions

View File

@@ -8,7 +8,7 @@
{
'variables': {
# Override if you intend to link against a different OEMCrypto API version.
'oemcrypto_version%': 11,
'oemcrypto_version%': 12,
# Override if you can't depend on OpenSSL for privacy features.
# If set to 'dummy', privacy mode in the CDM will fail.
@@ -101,6 +101,7 @@
'../core/include/cdm_client_property_set.h',
'../core/include/cdm_engine.h',
'../core/include/cdm_session.h',
'../core/include/cdm_session_map.h',
'../core/include/certificate_provisioning.h',
'../core/include/clock.h',
'../core/include/crypto_key.h',
@@ -125,6 +126,7 @@
'../core/src/buffer_reader.cpp',
'../core/src/cdm_engine.cpp',
'../core/src/cdm_session.cpp',
'../core/src/cdm_session_map.cpp',
'../core/src/certificate_provisioning.cpp',
'../core/src/crypto_session.cpp',
'../core/src/device_files.cpp',

View File

@@ -9,7 +9,7 @@
'../core/test/cdm_session_unittest.cpp',
'../core/test/config_test_env.cpp',
'../core/test/device_files_unittest.cpp',
'../core/test/generic_crypto_unittest.cpp',
# '../core/test/generic_crypto_unittest.cpp', # currently keybox only
'../core/test/http_socket.cpp',
'../core/test/initialization_data_unittest.cpp',
'../core/test/license_request.cpp',

View File

@@ -63,21 +63,31 @@ class CDM_EXPORT Cdm : public ITimerClient {
// is used instead of App-Assisted
} MessageType;
// Status codes returned by CDM functions.
//
typedef enum {
// These are defined by Widevine:
kSuccess = 0,
kNeedsDeviceCertificate = 1,
kSessionNotFound = 2,
kDecryptError = 3,
kNoKey = 4,
// These are analogous to the errors used by EME:
kTypeError = 5,
kInvalidAccess = kTypeError, // deprecated name from June 1 draft
kNotSupported = 6,
kInvalidState = 7,
kQuotaExceeded = 8,
kRangeError = 9,
// These are analogous to the exceptions defined in the EME specification.
// Client implementations that support the EME API should pass these
// directly to the client application.
// Note: kTypeError replaced kInvalidAccess in the 6/1/2015 EME spec.
kTypeError = 1,
kNotSupported = 2,
kInvalidState = 3,
kQuotaExceeded = 4,
// These are additional codes defined by Widevine. In client implementations
// that support the EME API, these codes should be handled in the system
// layer. If it is necessary to notify the client application of one of
// these statuses, it should be mapped to one of the exception codes defined
// in the EME specification.
kNeedsDeviceCertificate = 101,
kSessionNotFound = 102,
kDecryptError = 103,
kNoKey = 104,
kKeyUsageBlockedByPolicy = 105,
kRangeError = 106,
// The action could not be completed yet but has been scheduled to be done
// later. A call to |event_listener.onDeferredComplete| will be made once
@@ -341,6 +351,24 @@ class CDM_EXPORT Cdm : public ITimerClient {
// as a preliminary step in the license request.
virtual Status setServiceCertificate(const std::string& certificate) = 0;
// Create a Service Certificate Request message.
// This is used to fetch a service certificate from the license server.
// It is needed in cases where the system or application does not have
// a service certificate for the license server.
// The service certificate holds the RSA public key for the server and
// other fields needed for provisioning. It is also needed for privacy mode.
virtual Status getServiceCertificateRequest(std::string* message) = 0;
// Parse a Service Certificate Response message and extract the certificate.
// This is used when fetching a service certificate from the license server.
// The response input is the string returned by the license server
// (see getServiceCertificateRequest()). The service certificate is installed
// if no error is returned. The returned certificate string may be used in
// future sessions as the input to setServiceCertificate(), avoiding extra
// calls to the license server.
virtual Status parseServiceCertificateResponse(const std::string& response,
std::string* certificate) = 0;
// Determine if the device has a Device Certificate (for the current origin).
// The Device Certificate is origin-specific, and the origin is
// dertermined by the CDM's current IStorage object.
@@ -360,6 +388,22 @@ class CDM_EXPORT Cdm : public ITimerClient {
// CDM's current IStorage object.
virtual Status listStoredLicenses(std::vector<std::string>* key_set_ids) = 0;
// Get the current list of secure-stop licenses on the system.
// License storage is origin-specific, and the origin is determined by the
// CDM's current IStorage object. ksids receives list of KSIDs representing
// usage records or secure-stop licenses.
virtual Status listUsageRecords(std::vector<std::string>* ksids) = 0;
// Delete the usage record for the given key_set_id.
// Usage info storage is origin-specific, and the origin is determined by the
// CDM's current IStorage object.
virtual Status deleteUsageRecord(const std::string& key_set_id) = 0;
// Delete all usage records for the current origin.
// Usage info storage is origin-specific, and the origin is determined by the
// CDM's current IStorage object.
virtual Status deleteAllUsageRecords() = 0;
// Creates a new session.
// Do not use this to load an existing persistent session (use load()).
// If successful, the session_id is returned via |sessionId|.

View File

@@ -1,2 +1,2 @@
// Widevine CE CDM Version
#define CDM_VERSION "v3.2.0-0-g565f4378-ce"
#define CDM_VERSION "v3.3.0-0-gffcfda19-ce"

View File

@@ -14,6 +14,7 @@ class PropertiesCE {
public:
static Cdm::ClientInfo GetClientInfo();
static Cdm::SecureOutputType GetSecureOutputType();
static void SetProvisioningMessagesAreBinary(bool bin_prov);
private:
static void SetSecureOutputType(Cdm::SecureOutputType secure_output_type);

View File

@@ -88,7 +88,7 @@ class PropertySet : public CdmClientPropertySet {
return 1;
}
virtual void set_session_sharing_id(uint32_t id) OVERRIDE {
virtual void set_session_sharing_id(uint32_t) OVERRIDE {
// Unused on CE platforms.
return;
}
@@ -117,6 +117,11 @@ class CdmImpl : public Cdm,
// Cdm:
virtual Status setServiceCertificate(const std::string& certificate) OVERRIDE;
virtual Status getServiceCertificateRequest(std::string* message) OVERRIDE;
virtual Status parseServiceCertificateResponse(
const std::string& response, std::string* certificate) OVERRIDE;
virtual bool isProvisioned() OVERRIDE;
virtual Status removeProvisioning() OVERRIDE;
@@ -126,6 +131,12 @@ class CdmImpl : public Cdm,
virtual Status listStoredLicenses(
std::vector<std::string>* key_set_ids) OVERRIDE;
virtual Status listUsageRecords(std::vector<std::string>* ksids) OVERRIDE;
virtual Status deleteUsageRecord(const std::string& key_set_id) OVERRIDE;
virtual Status deleteAllUsageRecords() OVERRIDE;
virtual Status createSession(SessionType session_type,
std::string* session_id) OVERRIDE;
@@ -266,7 +277,8 @@ CdmImpl::~CdmImpl() {
Cdm::Status CdmImpl::setServiceCertificate(const std::string& certificate) {
if (certificate.empty()) {
LOGW("An empty licensing service certificate may be invalid.");
LOGE("Service certificate string is empty.");
return kTypeError;
}
// Check for properly signed and well-formed certificate.
@@ -279,6 +291,37 @@ Cdm::Status CdmImpl::setServiceCertificate(const std::string& certificate) {
return kSuccess;
}
Cdm::Status CdmImpl::getServiceCertificateRequest(std::string* message) {
if (!message) {
LOGE("Unable to return service certificate request - "
"string return parameter not supplied");
return kTypeError;
}
CdmKeyMessage request_message;
if (!cdm_engine_.GetServiceCertificateRequest(message)) {
LOGE("Unable to return service certificate request!");
message->clear();
return kTypeError;
}
return kSuccess;
}
Cdm::Status CdmImpl::parseServiceCertificateResponse(
const std::string& response, std::string* certificate) {
if (!certificate) {
LOGE("Unable to return service certificate - "
"string return parameter not supplied");
return kTypeError;
}
if (cdm_engine_.ParseServiceCertificateResponse(response, certificate) !=
NO_ERROR) {
LOGE("Failure parsing service certificate response!");
certificate->clear();
return kTypeError;
}
return kSuccess;
}
bool CdmImpl::isProvisioned() {
return cdm_engine_.IsProvisioned(kSecurityLevelL1);
}
@@ -309,6 +352,34 @@ Cdm::Status CdmImpl::listStoredLicenses(std::vector<std::string>* key_set_ids) {
return kSuccess;
}
Cdm::Status CdmImpl::listUsageRecords(std::vector<std::string>* ksids) {
if (ksids == NULL) {
LOGE("Missing vector parameter to receive KSIDs.");
return kTypeError;
}
if (cdm_engine_.ListUsageRecords(
property_set_.app_id(), kSecurityLevelL1, ksids) != NO_ERROR) {
return kUnexpectedError;
}
return kSuccess;
}
Cdm::Status CdmImpl::deleteUsageRecord(const std::string& key_set_id) {
if (cdm_engine_.DeleteUsageRecord(
property_set_.app_id(), kSecurityLevelL1, key_set_id) != NO_ERROR) {
return kUnexpectedError;
}
return kSuccess;
}
Cdm::Status CdmImpl::deleteAllUsageRecords() {
if (cdm_engine_.ReleaseAllUsageInfo(
property_set_.app_id(), kSecurityLevelL1) != NO_ERROR) {
return kUnexpectedError;
}
return kSuccess;
}
Cdm::Status CdmImpl::createSession(SessionType session_type,
std::string* session_id) {
if (session_id == NULL) {
@@ -871,12 +942,19 @@ Cdm::Status CdmImpl::decrypt(const InputBuffer& input,
CdmSessionId empty_session_id;
CdmResponseType result = cdm_engine_.Decrypt(empty_session_id, parameters);
if (result == NO_ERROR) {
return kSuccess;
}
if (result == NEED_KEY || result == SESSION_NOT_FOUND_FOR_DECRYPT) {
LOGE("Key not available.");
return kNoKey;
}
if (result == NO_ERROR) {
return kSuccess;
if (result == INSUFFICIENT_OUTPUT_PROTECTION) {
LOGE("Key usage blocked due to HDCP or display resolution constraints.");
return kKeyUsageBlockedByPolicy;
}
LOGE("Decrypt error: %d", result);
@@ -1037,8 +1115,7 @@ void CdmImpl::OnSessionRenewalNeeded(const CdmSessionId& session_id) {
}
void CdmImpl::OnSessionKeysChange(const CdmSessionId& session_id,
const CdmKeyStatusMap& keys_status,
bool has_new_usable_key) {
const CdmKeyStatusMap& keys_status, bool) {
KeyStatusMap& map = sessions_[session_id].key_statuses;
CdmKeyStatusMap::const_iterator it;

View File

@@ -12,6 +12,7 @@ namespace {
bool use_secure_buffers_ = false;
bool use_fifo_ = false;
bool use_userspace_buffers_ = true;
bool set_provisioning_messages_to_binary_ = false;
widevine::Cdm::SecureOutputType secure_output_type_ =
widevine::Cdm::kNoSecureOutput;
@@ -69,6 +70,11 @@ Cdm::ClientInfo PropertiesCE::GetClientInfo() {
return client_info_;
}
// static
void PropertiesCE::SetProvisioningMessagesAreBinary(bool new_setting) {
set_provisioning_messages_to_binary_ = new_setting;
}
} // namespace widevine
namespace wvcdm {
@@ -79,6 +85,7 @@ void Properties::Init() {
oem_crypto_use_fifo_ = use_fifo_;
oem_crypto_use_userspace_buffers_ = use_userspace_buffers_;
use_certificates_as_identification_ = true;
provisioning_messages_are_binary_ = set_provisioning_messages_to_binary_;
security_level_path_backward_compatibility_support_ = false;
session_property_set_.reset(new CdmClientPropertySetMap());
}
@@ -119,7 +126,7 @@ bool Properties::GetWVCdmVersion(std::string* version) {
}
// static
bool Properties::GetDeviceFilesBasePath(CdmSecurityLevel security_level,
bool Properties::GetDeviceFilesBasePath(CdmSecurityLevel,
std::string* base_path) {
// A no-op, but successful.
base_path->clear();
@@ -127,13 +134,13 @@ bool Properties::GetDeviceFilesBasePath(CdmSecurityLevel security_level,
}
// static
bool Properties::GetFactoryKeyboxPath(std::string* keybox) {
bool Properties::GetFactoryKeyboxPath(std::string*) {
// Unused on CE devices.
return false;
}
// static
bool Properties::GetOEMCryptoPath(std::string* library_name) {
bool Properties::GetOEMCryptoPath(std::string*) {
// Unused on CE devices.
return false;
}

View File

@@ -8,8 +8,8 @@
#include "cdm.h"
#include "cdm_test_printers.h"
#include "config_test_env.h"
#include "decryption_test_data.h"
#include "default_service_certificate.h"
#include "license_request.h"
#include "log.h"
#include "OEMCryptoCENC.h"
@@ -37,14 +37,10 @@ const Cdm::SessionType kBogusSessionType = static_cast<Cdm::SessionType>(-1);
const Cdm::InitDataType kBogusInitDataType = static_cast<Cdm::InitDataType>(-1);
const std::string kBogusSessionId = "asdf";
const std::string kProvisioningServerUrl =
"https://www.googleapis.com/"
"certificateprovisioning/v1/devicecertificates/create"
"?key=AIzaSyB-5OLKTx2iU5mko18DfdwK5611JIjbUhE";
const std::string kLicenseServerAppspot =
"http://widevine-proxy.appspot.com/proxy";
const std::string kLicenseServerUat = "https://proxy.uat.widevine.com/proxy";
std::string g_provisioning_server;
std::string g_provisioning_service_certificate;
std::string g_license_server;
std::string g_license_service_certificate;
const std::string kCencInitData = a2bs_hex(
"00000042" // blob size
@@ -85,11 +81,11 @@ const std::string kHlsInitData =
"yI6IFsNCiAgICAgICI5Yjc1OTA0MDMyMWE0MDhhNWM3NzY4YjQ1MTEyODdhNiINCiAgIF0NCn0"
"=\",IV=0x75537a79fa41abc7b598ea72aba0c26f";
// This Key ID must match the key retrieved from kLicenseServerAppspot by
// This Key ID must match the key retrieved from the license server by
// kCencInitData.
const std::vector<uint8_t> kKeyIdCtr = a2b_hex(
"371ea35e1a985d75d198a7f41020dc23");
// This Key ID must match the key retrieved from kLicenseServerUat by
// This Key ID must match the key retrieved from the license server by
// kHlsInitData.
const std::vector<uint8_t> kKeyIdCbc = a2b_hex(
"9b759040321a408a5c7768b4511287a6");
@@ -133,6 +129,15 @@ class CdmTest : public Test, public Cdm::IEventListener {
protected:
virtual void SetUp() OVERRIDE {
ConfigTestEnv config(kContentProtectionStagingPlusProv30);
g_provisioning_service_certificate.assign(
config.provisioning_service_certificate());
g_license_service_certificate.assign(config.license_service_certificate());
g_provisioning_server.assign(config.provisioning_server());
g_license_server.assign(config.license_server());
// Clear anything stored, load default device cert.
g_host->Reset();
@@ -162,9 +167,14 @@ class CdmTest : public Test, public Cdm::IEventListener {
usleep(500 * 1000);
}
virtual void Provision() {
cdm_->removeProvisioning();
cdm_->setServiceCertificate(g_provisioning_service_certificate);
}
void RecreateCdm(bool privacy_mode) {
CreateAdditionalCdm(privacy_mode, &cdm_);
cdm_->setServiceCertificate(kDefaultServiceCertificate);
cdm_->setServiceCertificate(g_license_service_certificate);
}
void CreateAdditionalCdm(bool privacy_mode, scoped_ptr<Cdm>* cdm) {
@@ -203,7 +213,11 @@ class CdmTest : public Test, public Cdm::IEventListener {
} else {
*response = http_response;
}
LOGV("Reply body: %s", b2a_hex(*response).c_str());
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;
}
@@ -228,7 +242,7 @@ class CdmTest : public Test, public Cdm::IEventListener {
void FetchLicenseFailure(const std::string& message,
int expected_status_code) {
int status_code;
bool ok = Fetch(kLicenseServerAppspot, message, NULL, &status_code);
bool ok = Fetch(g_license_server, message, NULL, &status_code);
ASSERT_TRUE(ok);
if (ok) ASSERT_EQ(expected_status_code, status_code);
}
@@ -238,7 +252,7 @@ class CdmTest : public Test, public Cdm::IEventListener {
std::string* session_id,
std::string* message) {
Cdm::Status status;
status = cdm_->setServiceCertificate(kDefaultServiceCertificate);
status = cdm_->setServiceCertificate(g_license_service_certificate);
ASSERT_EQ(Cdm::kSuccess, status);
status = cdm_->createSession(session_type, session_id);
@@ -276,9 +290,9 @@ class CdmTest : public Test, public Cdm::IEventListener {
std::string license_server;
if (init_data_type == Cdm::kCenc) {
license_server = kLicenseServerAppspot;
license_server = g_license_server;
} else if (init_data_type == Cdm::kHls) {
license_server = kLicenseServerUat;
license_server = g_license_server;
}
ASSERT_FALSE(license_server.empty());
FetchLicense(license_server, message, response);
@@ -301,7 +315,7 @@ class CdmTest : public Test, public Cdm::IEventListener {
// Acquire a license.
std::string response;
ASSERT_NO_FATAL_FAILURE(FetchLicense(
kLicenseServerAppspot, message, &response));
g_license_server, message, &response));
// This license should be accepted, but the keys are not expected to change.
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
@@ -465,19 +479,24 @@ TEST_F(CdmTest, Initialize) {
EXPECT_EQ(Cdm::kSuccess, status);
}
TEST_F(CdmTest, GetServiceCertificateRequest) {
// Set a server certificate with privacy mode disabled - should work.
ASSERT_NO_FATAL_FAILURE(RecreateCdm(false /* privacy_mode */));
std::string message;
Cdm::Status status = cdm_->getServiceCertificateRequest(&message);
EXPECT_EQ(Cdm::kSuccess, status);
}
TEST_F(CdmTest, SetServiceCertificate) {
// Set a server certificate with privacy mode disabled - should work.
ASSERT_NO_FATAL_FAILURE(RecreateCdm(false /* privacy_mode */));
Cdm::Status status = cdm_->setServiceCertificate(kDefaultServiceCertificate);
Cdm::Status status =
cdm_->setServiceCertificate(g_license_service_certificate);
EXPECT_EQ(Cdm::kSuccess, status);
// Can set a server certificate if privacy mode is enabled.
ASSERT_NO_FATAL_FAILURE(RecreateCdm(true /* privacy_mode */));
status = cdm_->setServiceCertificate(kDefaultServiceCertificate);
EXPECT_EQ(Cdm::kSuccess, status);
// Setting an empty cert is allowed.
status = cdm_->setServiceCertificate("");
status = cdm_->setServiceCertificate(g_license_service_certificate);
EXPECT_EQ(Cdm::kSuccess, status);
// It is invalid to set a malformed cert.
@@ -515,7 +534,7 @@ TEST_F(CdmTest, CreateSession) {
TEST_F(CdmTest, GenerateRequest) {
std::string session_id;
Cdm::Status status;
status = cdm_->setServiceCertificate(kDefaultServiceCertificate);
status = cdm_->setServiceCertificate(g_license_service_certificate);
ASSERT_EQ(Cdm::kSuccess, status);
status = cdm_->createSession(Cdm::kTemporary, &session_id);
@@ -608,7 +627,7 @@ TEST_F(CdmTest, Update) {
std::string session_id;
std::string message;
Cdm::Status status;
status = cdm_->setServiceCertificate(kDefaultServiceCertificate);
status = cdm_->setServiceCertificate(g_license_service_certificate);
ASSERT_EQ(Cdm::kSuccess, status);
ASSERT_NO_FATAL_FAILURE(CreateSessionAndGenerateRequest(
@@ -617,7 +636,7 @@ TEST_F(CdmTest, Update) {
// Acquire a license.
std::string response;
ASSERT_NO_FATAL_FAILURE(FetchLicense(
kLicenseServerAppspot, message, &response));
g_license_server, message, &response));
// Update the session.
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
@@ -669,7 +688,7 @@ TEST_F(CdmTest, LoadTemporary) {
std::string session_id;
std::string response;
Cdm::Status status;
status = cdm_->setServiceCertificate(kDefaultServiceCertificate);
status = cdm_->setServiceCertificate(g_license_service_certificate);
ASSERT_EQ(Cdm::kSuccess, status);
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
@@ -772,7 +791,7 @@ TEST_F(CdmTest, PerOriginLoadPersistent) {
scoped_ptr<Cdm> other_cdm(
Cdm::create(this, &other_host, /* privacy_mode */ true));
ASSERT_TRUE(other_cdm.get());
status = other_cdm->setServiceCertificate(kDefaultServiceCertificate);
status = other_cdm->setServiceCertificate(g_license_service_certificate);
ASSERT_EQ(Cdm::kSuccess, status);
// Should not be able to load from another origin.
@@ -785,6 +804,7 @@ TEST_F(CdmTest, PerOriginLoadPersistent) {
TEST_F(CdmTest, LoadUsageRecord) {
std::string session_id;
std::string response;
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
Cdm::kPersistentUsageRecord, Cdm::kCenc, &session_id, &response));
@@ -824,6 +844,114 @@ TEST_F(CdmTest, LoadUsageRecord) {
Mock::VerifyAndClear(this);
}
TEST_F(CdmTest, DestroyUsageRecord) {
std::string session_id;
std::string response;
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
Cdm::kPersistentUsageRecord, Cdm::kCenc, &session_id, &response));
// Update the session.
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
Cdm::Status status = cdm_->update(session_id, response);
ASSERT_EQ(Cdm::kSuccess, status);
Mock::VerifyAndClear(this);
// Should be able to load the session again after closing it.
status = cdm_->close(session_id);
ASSERT_EQ(Cdm::kSuccess, status);
// There should be no usable keys after loading this session.
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
status = cdm_->load(session_id);
EXPECT_EQ(Cdm::kSuccess, status);
Mock::VerifyAndClear(this);
// Should be able to load the session again after recreating the CDM.
ASSERT_NO_FATAL_FAILURE(RecreateCdm(true /* privacy_mode */));
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
status = cdm_->deleteUsageRecord(session_id);
EXPECT_EQ(Cdm::kSuccess, status);
status = cdm_->load(session_id);
EXPECT_EQ(Cdm::kSessionNotFound, status);
Mock::VerifyAndClear(this);
}
TEST_F(CdmTest, DestroyAllUsageRecords) {
std::string session_id;
std::string response;
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
Cdm::kPersistentUsageRecord, Cdm::kCenc, &session_id, &response));
// Update the session.
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
Cdm::Status status = cdm_->update(session_id, response);
ASSERT_EQ(Cdm::kSuccess, status);
Mock::VerifyAndClear(this);
// Should be able to load the session again after closing it.
status = cdm_->close(session_id);
ASSERT_EQ(Cdm::kSuccess, status);
// There should be no usable keys after loading this session.
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
status = cdm_->load(session_id);
EXPECT_EQ(Cdm::kSuccess, status);
Mock::VerifyAndClear(this);
// Should be able to load the session again after recreating the CDM.
ASSERT_NO_FATAL_FAILURE(RecreateCdm(true /* privacy_mode */));
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
status = cdm_->deleteAllUsageRecords();
EXPECT_EQ(Cdm::kSuccess, status);
status = cdm_->load(session_id);
EXPECT_EQ(Cdm::kSessionNotFound, status);
Mock::VerifyAndClear(this);
}
TEST_F(CdmTest, ListUsageRecords) {
std::string session_id;
std::string response;
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
Cdm::kPersistentUsageRecord, Cdm::kCenc, &session_id, &response));
// Update the session.
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
Cdm::Status status = cdm_->update(session_id, response);
ASSERT_EQ(Cdm::kSuccess, status);
Mock::VerifyAndClear(this);
// Should be able to load the session again after closing it.
status = cdm_->close(session_id);
ASSERT_EQ(Cdm::kSuccess, status);
// There should be no usable keys after loading this session.
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
status = cdm_->load(session_id);
EXPECT_EQ(Cdm::kSuccess, status);
Mock::VerifyAndClear(this);
// Should be able to load the session again after recreating the CDM.
ASSERT_NO_FATAL_FAILURE(RecreateCdm(true /* privacy_mode */));
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
std::vector<std::string> ksids;
status = cdm_->listUsageRecords(&ksids);
EXPECT_EQ(Cdm::kSuccess, status);
EXPECT_EQ(ksids.size(), 1UL);
if (ksids.size() > 0UL) {
EXPECT_TRUE(ksids[0] == session_id);
}
status = cdm_->load(session_id);
EXPECT_EQ(Cdm::kSuccess, status);
Mock::VerifyAndClear(this);
}
TEST_F(CdmTest, LoadBogus) {
EXPECT_CALL(*this, onKeyStatusesChange(_)).Times(0);
Cdm::Status status = cdm_->load(kBogusSessionId);
@@ -921,7 +1049,7 @@ TEST_F(CdmTest, Remove) {
// Post the release message to the license server.
std::string response;
ASSERT_NO_FATAL_FAILURE(FetchLicense(
kLicenseServerAppspot, message, &response));
g_license_server, message, &response));
// Update the session.
EXPECT_CALL(*this, onRemoveComplete(session_id));
@@ -975,7 +1103,7 @@ TEST_F(CdmTest, RemoveUsageRecord) {
// Post the release message to the license server.
std::string response;
ASSERT_NO_FATAL_FAILURE(FetchLicense(
kLicenseServerAppspot, message, &response));
g_license_server, message, &response));
// Update the session.
EXPECT_CALL(*this, onRemoveComplete(session_id));
@@ -1037,7 +1165,7 @@ TEST_F(CdmTest, RemoveIncomplete) {
// Post the release message to the license server.
std::string response;
ASSERT_NO_FATAL_FAILURE(FetchLicense(
kLicenseServerAppspot, message, &response));
g_license_server, message, &response));
// Update the session.
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
@@ -1108,7 +1236,7 @@ TEST_F(CdmTest, RemoveUsageRecordIncomplete) {
// Post the release message to the license server.
std::string response;
ASSERT_NO_FATAL_FAILURE(FetchLicense(
kLicenseServerAppspot, message, &response));
g_license_server, message, &response));
// Update the session.
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
@@ -1141,7 +1269,7 @@ TEST_F(CdmTest, RequestPersistentLicenseWithWrongInitData) {
// persistent content init data.
std::string session_id;
Cdm::Status status;
status = cdm_->setServiceCertificate(kDefaultServiceCertificate);
status = cdm_->setServiceCertificate(g_license_service_certificate);
ASSERT_EQ(Cdm::kSuccess, status);
status = cdm_->createSession(Cdm::kPersistentLicense, &session_id);
ASSERT_EQ(Cdm::kSuccess, status);
@@ -1161,7 +1289,7 @@ TEST_F(CdmTest, RequestTemporaryLicenseWithWrongInitData) {
// Generate a request for a temporary license using persistent init data.
std::string session_id;
Cdm::Status status;
status = cdm_->setServiceCertificate(kDefaultServiceCertificate);
status = cdm_->setServiceCertificate(g_license_service_certificate);
ASSERT_EQ(Cdm::kSuccess, status);
status = cdm_->createSession(Cdm::kTemporary, &session_id);
ASSERT_EQ(Cdm::kSuccess, status);
@@ -1177,7 +1305,7 @@ TEST_F(CdmTest, RequestTemporaryLicenseWithWrongInitData) {
// Acquire a license.
std::string response;
ASSERT_NO_FATAL_FAILURE(FetchLicense(
kLicenseServerAppspot, message, &response));
g_license_server, message, &response));
// This license should not be accepted.
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
@@ -1408,11 +1536,19 @@ class CdmIndividualizationTest : public CdmTest {
std::string GetProvisioningResponse(const std::string& message) {
std::string reply;
std::string uri = kProvisioningServerUrl;
std::string uri = g_provisioning_server;
LOGV("GetProvisioningResponse: URI: %s", uri.c_str());
LOGV("GetProvisioningResponse: message:\n%s\n", message.c_str());
uri += "&signedRequest=" + message;
FetchCertificate(uri, &reply);
if (HasFatalFailure())
if (HasFatalFailure()) {
LOGE("GetProvisioningResponse: Failed.");
return "";
}
LOGV("GetProvisioningResponse: response:\n%s\n", reply.c_str());
return reply;
}
};
@@ -1426,7 +1562,7 @@ TEST_F(CdmIndividualizationTest, BasicFlow) {
// Creating a session should succeed.
std::string session_id;
Cdm::Status status;
status = cdm_->setServiceCertificate(kDefaultServiceCertificate);
status = cdm_->setServiceCertificate(g_license_service_certificate);
EXPECT_EQ(Cdm::kSuccess, status);
status = cdm_->createSession(Cdm::kTemporary, &session_id);
EXPECT_EQ(Cdm::kSuccess, status);
@@ -1454,7 +1590,7 @@ TEST_F(CdmIndividualizationTest, BasicFlow) {
// Acquire a license and update the session.
ASSERT_NO_FATAL_FAILURE(FetchLicense(
kLicenseServerAppspot, message, &reply));
g_license_server, message, &reply));
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
status = cdm_->update(session_id, reply);
EXPECT_EQ(Cdm::kSuccess, status);

View File

@@ -36,8 +36,8 @@ 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