Source release v3.3.0
This commit is contained in:
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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|.
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user