Enable usage reporting

[ Merge from Widevine CDM repo of
  https://widevine-internal-review.googlesource.com/#/c/10171/ and
  https://widevine-internal-review.googlesource.com/#/c/10172/ ]

Updated license_protocol.proto from constituent protos in google3

These changes make use of OEMCrypto v9 changes to support usage reporting.
Usage reporting may be enabled for streaming (by means of secure stops) and
offline playback by a provider session token specified in the license.

Changes include periodically updating usage information for relevant
sessions and reporting and releasing usage information as needed.

The CDM has removed all references to Secure Stops. This change
updates the Android API implementation to comply.

b/11987015

Change-Id: Ibb6f2ced4ef20ee349ca1ae6412ce686b2b5d085
This commit is contained in:
Rahul Frias
2014-05-17 09:31:41 -07:00
parent d68e1f8307
commit e56e58fbf5
20 changed files with 1573 additions and 261 deletions

View File

@@ -88,10 +88,9 @@ class CdmEngine {
std::string* cert, std::string* cert,
std::string* wrapped_key); std::string* wrapped_key);
// Secure stop related methods // Usage related methods for streaming licenses
CdmResponseType GetSecureStops(CdmSecureStops* secure_stops); CdmResponseType GetUsageInfo(CdmUsageInfo* usage_info);
CdmResponseType ReleaseSecureStops( CdmResponseType ReleaseUsageInfo(const CdmUsageInfoReleaseMessage& message);
const CdmSecureStopReleaseMessage& message);
// Decryption and key related methods // Decryption and key related methods
// Accept encrypted buffer and return decrypted data. // Accept encrypted buffer and return decrypted data.
@@ -126,6 +125,9 @@ class CdmEngine {
CdmReleaseKeySetMap release_key_sets_; CdmReleaseKeySetMap release_key_sets_;
CertificateProvisioning cert_provisioning_; CertificateProvisioning cert_provisioning_;
SecurityLevel cert_provisioning_requested_security_level_; SecurityLevel cert_provisioning_requested_security_level_;
CdmSession* usage_session_;
int64_t last_usage_information_update_time;
CORE_DISALLOW_COPY_AND_ASSIGN(CdmEngine); CORE_DISALLOW_COPY_AND_ASSIGN(CdmEngine);
}; };

View File

@@ -28,6 +28,8 @@ class CdmSession {
CdmResponseType RestoreOfflineSession(const CdmKeySetId& key_set_id, CdmResponseType RestoreOfflineSession(const CdmKeySetId& key_set_id,
const CdmLicenseType license_type); const CdmLicenseType license_type);
CdmResponseType RestoreUsageSession(const CdmKeyMessage& key_request,
const CdmKeyResponse& key_response);
void set_key_system(const CdmKeySystem& ksystem) { key_system_ = ksystem; } void set_key_system(const CdmKeySystem& ksystem) { key_system_ = ksystem; }
const CdmKeySystem& key_system() { return key_system_; } const CdmKeySystem& key_system() { return key_system_; }
@@ -89,6 +91,12 @@ class CdmSession {
void OnKeyReleaseEvent(const CdmKeySetId& key_set_id); void OnKeyReleaseEvent(const CdmKeySetId& key_set_id);
SecurityLevel GetRequestedSecurityLevel(); SecurityLevel GetRequestedSecurityLevel();
CdmSecurityLevel GetSecurityLevel();
CdmResponseType UpdateUsageInformation();
bool is_usage_update_needed() { return is_usage_update_needed_; }
void reset_is_usage_update_needed() { is_usage_update_needed_ = false; }
private: private:
@@ -96,7 +104,9 @@ class CdmSession {
CdmSessionId GenerateSessionId(); CdmSessionId GenerateSessionId();
bool GenerateKeySetId(CdmKeySetId* key_set_id); bool GenerateKeySetId(CdmKeySetId* key_set_id);
CdmResponseType StoreLicense();
bool StoreLicense(DeviceFiles::LicenseState state); bool StoreLicense(DeviceFiles::LicenseState state);
bool DeleteLicense();
// instance variables // instance variables
const CdmSessionId session_id_; const CdmSessionId session_id_;
@@ -106,13 +116,16 @@ class CdmSession {
PolicyEngine policy_engine_; PolicyEngine policy_engine_;
bool license_received_; bool license_received_;
bool reinitialize_session_; bool reinitialize_session_;
bool is_offline_;
bool is_release_;
bool is_usage_update_needed_;
CdmLicenseType license_type_; // information useful for offline and usage scenarios
CdmKeyMessage key_request_;
CdmKeyResponse key_response_;
// license type offline related information // license type offline related information
CdmInitData offline_init_data_; CdmInitData offline_init_data_;
CdmKeyMessage offline_key_request_;
CdmKeyResponse offline_key_response_;
CdmKeyMessage offline_key_renewal_request_; CdmKeyMessage offline_key_renewal_request_;
CdmKeyResponse offline_key_renewal_response_; CdmKeyResponse offline_key_renewal_response_;
std::string offline_release_server_url_; std::string offline_release_server_url_;

View File

@@ -45,7 +45,8 @@ class CryptoSession {
const std::string& signature, const std::string& signature,
const std::string& mac_key_iv, const std::string& mac_key_iv,
const std::string& mac_key, const std::string& mac_key,
int num_keys, const CryptoKey* key_array); const std::vector<CryptoKey>& key_array,
const std::string& provider_session_token);
bool LoadCertificatePrivateKey(std::string& wrapped_key); bool LoadCertificatePrivateKey(std::string& wrapped_key);
bool RefreshKeys(const std::string& message, const std::string& signature, bool RefreshKeys(const std::string& message, const std::string& signature,
int num_keys, const CryptoKey* key_array); int num_keys, const CryptoKey* key_array);
@@ -63,6 +64,15 @@ class CryptoSession {
// Media data path // Media data path
CdmResponseType Decrypt(const CdmDecryptionParameters& parameters); CdmResponseType Decrypt(const CdmDecryptionParameters& parameters);
CdmResponseType UpdateUsageInformation();
CdmResponseType GenerateUsageReport(
const std::string& provider_session_token,
std::string* usage_report);
CdmResponseType ReleaseUsageInformation(
const std::string& message,
const std::string& signature,
const std::string& provider_session_token);
bool GetRandom(size_t data_length, uint8_t* random_data); bool GetRandom(size_t data_length, uint8_t* random_data);
private: private:

View File

@@ -18,10 +18,10 @@ class DeviceFiles {
} LicenseState; } LicenseState;
DeviceFiles(): file_(NULL), security_level_(kSecurityLevelUninitialized), DeviceFiles(): file_(NULL), security_level_(kSecurityLevelUninitialized),
initialized_(false) {} initialized_(false), test_file_(false) {}
virtual ~DeviceFiles() {} virtual ~DeviceFiles();
virtual bool Init(const File* handle, CdmSecurityLevel security_level); virtual bool Init(CdmSecurityLevel security_level);
virtual bool StoreCertificate(const std::string& certificate, virtual bool StoreCertificate(const std::string& certificate,
const std::string& wrapped_private_key); const std::string& wrapped_private_key);
@@ -49,14 +49,24 @@ class DeviceFiles {
virtual bool DeleteAllLicenses(); virtual bool DeleteAllLicenses();
virtual bool LicenseExists(const std::string& key_set_id); virtual bool LicenseExists(const std::string& key_set_id);
virtual bool StoreUsageInfo(const std::string& provider_session_token,
const CdmKeyMessage& key_request,
const CdmKeyResponse& key_response);
virtual bool DeleteUsageInfo(const std::string& provider_session_token);
virtual bool DeleteUsageInfo();
virtual bool RetrieveUsageInfo(
std::vector<std::pair<CdmKeyMessage, CdmKeyResponse> >* usage_info);
// For testing only // For testing only
static std::string GetCertificateFileName(); static std::string GetCertificateFileName();
static std::string GetLicenseFileNameExtension(); static std::string GetLicenseFileNameExtension();
static std::string GetUsageInfoFileName();
void SetTestFile(File* file);
protected: protected:
bool Hash(const std::string& data, std::string* hash); bool Hash(const std::string& data, std::string* hash);
bool StoreFile(const char* name, const std::string& data); bool StoreFile(const char* name, const std::string& serialized_file);
bool RetrieveFile(const char* name, std::string* data); bool RetrieveFile(const char* name, std::string* serialized_file);
private: private:
// Certificate and offline licenses are now stored in security // Certificate and offline licenses are now stored in security
@@ -68,6 +78,8 @@ class DeviceFiles {
CdmSecurityLevel security_level_; CdmSecurityLevel security_level_;
bool initialized_; bool initialized_;
bool test_file_;
CORE_DISALLOW_COPY_AND_ASSIGN(DeviceFiles); CORE_DISALLOW_COPY_AND_ASSIGN(DeviceFiles);
}; };

View File

@@ -40,12 +40,16 @@ class CdmLicense {
CdmResponseType HandleKeyUpdateResponse( CdmResponseType HandleKeyUpdateResponse(
bool is_renewal, const CdmKeyResponse& license_response); bool is_renewal, const CdmKeyResponse& license_response);
bool RestoreOfflineLicense(CdmKeyMessage& license_request, bool RestoreOfflineLicense(const CdmKeyMessage& license_request,
CdmKeyResponse& license_response, const CdmKeyResponse& license_response,
CdmKeyResponse& license_renewal_response); const CdmKeyResponse& license_renewal_response);
bool RestoreUsageLicense(const CdmKeyMessage& license_request,
const CdmKeyResponse& license_response);
bool HasInitData() { return !stored_init_data_.empty(); } bool HasInitData() { return !stored_init_data_.empty(); }
bool IsKeyLoaded(const KeyId& key_id); bool IsKeyLoaded(const KeyId& key_id);
std::string provider_session_token() { return provider_session_token_; }
private: private:
bool PrepareServiceCertificateRequest(CdmKeyMessage* signed_request, bool PrepareServiceCertificateRequest(CdmKeyMessage* signed_request,
std::string* server_url); std::string* server_url);
@@ -67,6 +71,7 @@ class CdmLicense {
std::string stored_init_data_; std::string stored_init_data_;
bool initialized_; bool initialized_;
std::set<KeyId> loaded_keys_; std::set<KeyId> loaded_keys_;
std::string provider_session_token_;
// Used for certificate based licensing // Used for certificate based licensing
CdmKeyMessage key_request_; CdmKeyMessage key_request_;

View File

@@ -23,8 +23,8 @@ typedef uint32_t CryptoSessionId;
typedef std::string CryptoKeyId; typedef std::string CryptoKeyId;
typedef std::map<std::string, std::string> CdmAppParameterMap; typedef std::map<std::string, std::string> CdmAppParameterMap;
typedef std::map<std::string, std::string> CdmQueryMap; typedef std::map<std::string, std::string> CdmQueryMap;
typedef std::vector<std::string> CdmSecureStops; typedef std::vector<std::string> CdmUsageInfo;
typedef std::vector<uint8_t> CdmSecureStopReleaseMessage; typedef std::string CdmUsageInfoReleaseMessage;
typedef std::string CdmProvisioningRequest; typedef std::string CdmProvisioningRequest;
typedef std::string CdmProvisioningResponse; typedef std::string CdmProvisioningResponse;

View File

@@ -6,6 +6,8 @@
#include <sstream> #include <sstream>
#include "cdm_session.h" #include "cdm_session.h"
#include "clock.h"
#include "device_files.h"
#include "license_protocol.pb.h" #include "license_protocol.pb.h"
#include "log.h" #include "log.h"
#include "properties.h" #include "properties.h"
@@ -14,16 +16,26 @@
#include "wv_cdm_constants.h" #include "wv_cdm_constants.h"
#include "wv_cdm_event_listener.h" #include "wv_cdm_event_listener.h"
namespace {
const uint32_t kUpdateUsageInformationPeriod = 60; // seconds
const size_t kMinNoncesPerSession = 4;
} // unnamed namespace
namespace wvcdm { namespace wvcdm {
CdmEngine::CdmEngine() CdmEngine::CdmEngine()
: cert_provisioning_requested_security_level_(kLevelDefault) { : cert_provisioning_requested_security_level_(kLevelDefault),
usage_session_(NULL),
last_usage_information_update_time(0) {
Properties::Init(); Properties::Init();
} }
CdmEngine::~CdmEngine() { CdmEngine::~CdmEngine() {
CancelSessions(); CancelSessions();
if (NULL != usage_session_)
delete usage_session_;
CdmSessionMap::iterator i(sessions_.begin()); CdmSessionMap::iterator i(sessions_.begin());
for (; i != sessions_.end(); ++i) for (; i != sessions_.end(); ++i)
delete i->second; delete i->second;
@@ -482,15 +494,73 @@ CdmResponseType CdmEngine::HandleProvisioningResponse(
wrapped_key); wrapped_key);
} }
CdmResponseType CdmEngine::GetSecureStops( CdmResponseType CdmEngine::GetUsageInfo(CdmUsageInfo* usage_info) {
CdmSecureStops* secure_stops) { if (NULL == usage_session_) {
// TODO(edwinwong, rfrias): add implementation usage_session_ = new CdmSession(NULL);
}
CdmResponseType status = usage_session_->Init();
if (NO_ERROR != status) {
LOGE("CdmEngine::GetUsageInfo: session init error");
return status;
}
DeviceFiles handle;
if (!handle.Init(usage_session_->GetSecurityLevel())) {
LOGE("CdmEngine::GetUsageInfo: unable to initialize device files");
return status;
}
std::vector<std::pair<CdmKeyMessage, CdmKeyResponse> > license_info;
if (!handle.RetrieveUsageInfo(&license_info)) {
LOGE("CdmEngine::GetUsageInfo: unable to read usage information");
return UNKNOWN_ERROR;
}
if (0 == license_info.size()) {
usage_info->resize(0);
return NO_ERROR; return NO_ERROR;
} }
CdmResponseType CdmEngine::ReleaseSecureStops( std::string server_url;
const CdmSecureStopReleaseMessage& message) { // rate limit secure stop messages based on minimum nonce
// TODO(edwinwong, rfrias): add implementation // table size per session
usage_info->resize(license_info.size() >= kMinNoncesPerSession - 1
? kMinNoncesPerSession - 1
: license_info.size());
for (size_t i = 0; i < usage_info->size(); ++i) {
status = usage_session_->RestoreUsageSession(license_info[i].first,
license_info[i].second);
if (KEY_ADDED != status) {
LOGE("CdmEngine::GetUsageInfo: restore usage session error: %ld",
status);
usage_info->clear();
return status;
}
status = usage_session_->GenerateReleaseRequest(&(*usage_info)[i],
&server_url);
if (KEY_MESSAGE != status) {
LOGE("CdmEngine::GetUsageInfo: generate release request error: %ld",
status);
usage_info->clear();
return status;
}
}
return KEY_MESSAGE;
}
CdmResponseType CdmEngine::ReleaseUsageInfo(
const CdmUsageInfoReleaseMessage& message) {
if (NULL == usage_session_) {
LOGE("CdmEngine::ReleaseUsageInfo: cdm session not initialized");
return UNKNOWN_ERROR;
}
CdmResponseType status = usage_session_->ReleaseKey(message);
if (NO_ERROR != status) {
LOGE("CdmEngine::ReleaseUsageInfo: release key error: %ld", status);
return UNKNOWN_ERROR;
}
return NO_ERROR; return NO_ERROR;
} }
@@ -615,9 +685,31 @@ bool CdmEngine::CancelSessions() {
} }
void CdmEngine::OnTimerEvent() { void CdmEngine::OnTimerEvent() {
Clock clock;
uint64_t current_time = clock.GetCurrentTime();
bool update_usage_information = false;
if (current_time - last_usage_information_update_time >
kUpdateUsageInformationPeriod) {
update_usage_information = true;
last_usage_information_update_time = current_time;
}
for (CdmSessionMap::iterator iter = sessions_.begin(); for (CdmSessionMap::iterator iter = sessions_.begin();
iter != sessions_.end(); ++iter) { iter != sessions_.end(); ++iter) {
iter->second->OnTimerEvent(); iter->second->OnTimerEvent();
if (update_usage_information && iter->second->is_usage_update_needed()) {
// usage is updated for all sessions so this needs to be
// called only once per update usage information period
CdmResponseType status = iter->second->UpdateUsageInformation();
if (NO_ERROR != status) {
LOGW("Update usage information failed: %u", status);
} else {
update_usage_information = false;
}
}
iter->second->reset_is_usage_update_needed();
} }
} }

View File

@@ -31,7 +31,9 @@ CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set)
crypto_session_(NULL), crypto_session_(NULL),
license_received_(false), license_received_(false),
reinitialize_session_(false), reinitialize_session_(false),
license_type_(kLicenseTypeStreaming), is_offline_(false),
is_release_(false),
is_usage_update_needed_(false),
is_certificate_loaded_(false) { is_certificate_loaded_(false) {
if (cdm_client_property_set) { if (cdm_client_property_set) {
Properties::AddSessionPropertySet(session_id_, cdm_client_property_set); Properties::AddSessionPropertySet(session_id_, cdm_client_property_set);
@@ -48,9 +50,8 @@ CdmResponseType CdmSession::Init() {
std::string token; std::string token;
if (Properties::use_certificates_as_identification()) { if (Properties::use_certificates_as_identification()) {
File file;
DeviceFiles handle; DeviceFiles handle;
if (!handle.Init(&file, session.get()->GetSecurityLevel()) || if (!handle.Init(session.get()->GetSecurityLevel()) ||
!handle.RetrieveCertificate(&token, &wrapped_key_)) { !handle.RetrieveCertificate(&token, &wrapped_key_)) {
return NEED_PROVISIONING; return NEED_PROVISIONING;
} }
@@ -72,15 +73,14 @@ CdmResponseType CdmSession::RestoreOfflineSession(
key_set_id_ = key_set_id; key_set_id_ = key_set_id;
// Retrieve license information from persistent store // Retrieve license information from persistent store
File file;
DeviceFiles handle; DeviceFiles handle;
if (!handle.Init(&file, crypto_session_->GetSecurityLevel())) if (!handle.Init(crypto_session_->GetSecurityLevel()))
return UNKNOWN_ERROR; return UNKNOWN_ERROR;
DeviceFiles::LicenseState license_state; DeviceFiles::LicenseState license_state;
if (!handle.RetrieveLicense(key_set_id, &license_state, &offline_init_data_, if (!handle.RetrieveLicense(key_set_id, &license_state, &offline_init_data_,
&offline_key_request_, &offline_key_response_, &key_request_, &key_response_,
&offline_key_renewal_request_, &offline_key_renewal_request_,
&offline_key_renewal_response_, &offline_key_renewal_response_,
&offline_release_server_url_)) { &offline_release_server_url_)) {
@@ -103,14 +103,39 @@ CdmResponseType CdmSession::RestoreOfflineSession(
} }
} }
if (!license_parser_.RestoreOfflineLicense(offline_key_request_, if (!license_parser_.RestoreOfflineLicense(key_request_, key_response_,
offline_key_response_,
offline_key_renewal_response_)) { offline_key_renewal_response_)) {
return UNKNOWN_ERROR; return UNKNOWN_ERROR;
} }
license_received_ = true; license_received_ = true;
license_type_ = license_type; is_offline_ = true;
is_release_ = license_type == kLicenseTypeRelease;
return KEY_ADDED;
}
CdmResponseType CdmSession::RestoreUsageSession(
const CdmKeyMessage& key_request,
const CdmKeyResponse& key_response) {
key_request_ = key_request;
key_response_ = key_response;
if (Properties::use_certificates_as_identification()) {
if (is_certificate_loaded_ ||
crypto_session_->LoadCertificatePrivateKey(wrapped_key_)) {
is_certificate_loaded_ = true;
} else {
return NEED_PROVISIONING;
}
}
if (!license_parser_.RestoreUsageLicense(key_request_, key_response_)) {
return UNKNOWN_ERROR;
}
license_received_ = true;
is_offline_ = false;
is_release_ = true;
return KEY_ADDED; return KEY_ADDED;
} }
@@ -143,9 +168,17 @@ CdmResponseType CdmSession::GenerateKeyRequest(
return UNKNOWN_ERROR; return UNKNOWN_ERROR;
} }
license_type_ = license_type; switch (license_type) {
case kLicenseTypeStreaming: is_offline_ = false; break;
case kLicenseTypeOffline: is_offline_ = true; break;
case kLicenseTypeRelease: is_release_ = true; break;
default:
LOGE("CdmSession::GenerateKeyRequest: unrecognized license type: %ld",
license_type);
return UNKNOWN_ERROR;
}
if (license_type_ == kLicenseTypeRelease) { if (is_release_) {
return GenerateReleaseRequest(key_request, server_url); return GenerateReleaseRequest(key_request, server_url);
} else if (license_received_) { // renewal } else if (license_received_) { // renewal
return Properties::require_explicit_renew_request() return Properties::require_explicit_renew_request()
@@ -178,9 +211,9 @@ CdmResponseType CdmSession::GenerateKeyRequest(
return KEY_ERROR; return KEY_ERROR;
} }
if (license_type_ == kLicenseTypeOffline) { key_request_ = *key_request;
if (is_offline_) {
offline_init_data_ = init_data.data(); offline_init_data_ = init_data.data();
offline_key_request_ = *key_request;
offline_release_server_url_ = *server_url; offline_release_server_url_ = *server_url;
} }
@@ -201,7 +234,7 @@ CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response,
return UNKNOWN_ERROR; return UNKNOWN_ERROR;
} }
if (license_type_ == kLicenseTypeRelease) { if (is_release_) {
return ReleaseKey(key_response); return ReleaseKey(key_response);
} else if (license_received_) { // renewal } else if (license_received_) { // renewal
return Properties::require_explicit_renew_request() return Properties::require_explicit_renew_request()
@@ -213,25 +246,11 @@ CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response,
if (sts != KEY_ADDED) return sts; if (sts != KEY_ADDED) return sts;
license_received_ = true; license_received_ = true;
key_response_ = key_response;
if (license_type_ == kLicenseTypeOffline) { if (is_offline_ || !license_parser_.provider_session_token().empty()) {
offline_key_response_ = key_response; sts = StoreLicense();
if (!GenerateKeySetId(&key_set_id_)) { if (sts != NO_ERROR) return sts;
LOGE("CdmSession::AddKey: Unable to generate key set Id");
return UNKNOWN_ERROR;
}
if (!StoreLicense(DeviceFiles::kLicenseStateActive)) {
LOGE("CdmSession::AddKey: Unable to store license");
CdmResponseType sts = Init();
if (sts != NO_ERROR) {
LOGW("CdmSession::AddKey: Reinitialization failed");
return sts;
}
key_set_id_.clear();
return UNKNOWN_ERROR;
}
} }
*key_set_id = key_set_id_; *key_set_id = key_set_id_;
@@ -314,6 +333,14 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
return NEED_KEY; return NEED_KEY;
} }
} }
if (NO_ERROR == status) {
if (!is_usage_update_needed_) {
is_usage_update_needed_ =
!license_parser_.provider_session_token().empty();
}
}
return status; return status;
} }
@@ -327,7 +354,7 @@ CdmResponseType CdmSession::GenerateRenewalRequest(CdmKeyMessage* key_request,
return KEY_ERROR; return KEY_ERROR;
} }
if (license_type_ == kLicenseTypeOffline) { if (is_offline_) {
offline_key_renewal_request_ = *key_request; offline_key_renewal_request_ = *key_request;
} }
return KEY_MESSAGE; return KEY_MESSAGE;
@@ -339,7 +366,7 @@ CdmResponseType CdmSession::RenewKey(const CdmKeyResponse& key_response) {
license_parser_.HandleKeyUpdateResponse(true, key_response); license_parser_.HandleKeyUpdateResponse(true, key_response);
if (sts != KEY_ADDED) return sts; if (sts != KEY_ADDED) return sts;
if (license_type_ == kLicenseTypeOffline) { if (is_offline_) {
offline_key_renewal_response_ = key_response; offline_key_renewal_response_ = key_response;
if (!StoreLicense(DeviceFiles::kLicenseStateActive)) return UNKNOWN_ERROR; if (!StoreLicense(DeviceFiles::kLicenseStateActive)) return UNKNOWN_ERROR;
} }
@@ -348,23 +375,28 @@ CdmResponseType CdmSession::RenewKey(const CdmKeyResponse& key_response) {
CdmResponseType CdmSession::GenerateReleaseRequest(CdmKeyMessage* key_request, CdmResponseType CdmSession::GenerateReleaseRequest(CdmKeyMessage* key_request,
std::string* server_url) { std::string* server_url) {
if (license_parser_.PrepareKeyUpdateRequest(false, key_request, server_url)) { is_release_ = true;
// Mark license as being released if (!license_parser_.PrepareKeyUpdateRequest(false, key_request, server_url))
if (StoreLicense(DeviceFiles::kLicenseStateReleasing)) return KEY_MESSAGE;
}
return UNKNOWN_ERROR; return UNKNOWN_ERROR;
if (is_offline_) { // Mark license as being released
if (!StoreLicense(DeviceFiles::kLicenseStateReleasing))
return UNKNOWN_ERROR;
}
return KEY_MESSAGE;
} }
// ReleaseKey() - Accept release response and release license. // ReleaseKey() - Accept release response and release license.
CdmResponseType CdmSession::ReleaseKey(const CdmKeyResponse& key_response) { CdmResponseType CdmSession::ReleaseKey(const CdmKeyResponse& key_response) {
CdmResponseType sts = CdmResponseType sts = license_parser_.HandleKeyUpdateResponse(false,
license_parser_.HandleKeyUpdateResponse(false, key_response); key_response);
File file; if (NO_ERROR != sts)
DeviceFiles handle;
if (handle.Init(&file, crypto_session_->GetSecurityLevel()))
handle.DeleteLicense(key_set_id_);
return sts; return sts;
if (is_offline_ || !license_parser_.provider_session_token().empty()) {
DeleteLicense();
}
return NO_ERROR;
} }
bool CdmSession::IsKeyLoaded(const KeyId& key_id) { bool CdmSession::IsKeyLoaded(const KeyId& key_id) {
@@ -387,9 +419,8 @@ bool CdmSession::GenerateKeySetId(CdmKeySetId* key_set_id) {
std::vector<uint8_t> random_data( std::vector<uint8_t> random_data(
(kKeySetIdLength - sizeof(KEY_SET_ID_PREFIX)) / 2, 0); (kKeySetIdLength - sizeof(KEY_SET_ID_PREFIX)) / 2, 0);
File file;
DeviceFiles handle; DeviceFiles handle;
if (!handle.Init(&file, crypto_session_->GetSecurityLevel())) if (!handle.Init(crypto_session_->GetSecurityLevel()))
return false; return false;
while (key_set_id->empty()) { while (key_set_id->empty()) {
@@ -406,18 +437,75 @@ bool CdmSession::GenerateKeySetId(CdmKeySetId* key_set_id) {
return true; return true;
} }
bool CdmSession::StoreLicense(DeviceFiles::LicenseState state) { CdmResponseType CdmSession::StoreLicense() {
File file; if (is_offline_) {
if (!GenerateKeySetId(&key_set_id_)) {
LOGE("CdmSession::StoreLicense: Unable to generate key set Id");
return UNKNOWN_ERROR;
}
if (!StoreLicense(DeviceFiles::kLicenseStateActive)) {
LOGE("CdmSession::StoreLicense: Unable to store license");
CdmResponseType sts = Init();
if (sts != NO_ERROR) {
LOGW("CdmSession::StoreLicense: Reinitialization failed");
return sts;
}
key_set_id_.clear();
return UNKNOWN_ERROR;
}
return NO_ERROR;
}
std::string provider_session_token = license_parser_.provider_session_token();
if (provider_session_token.empty()) {
LOGE("CdmSession::StoreLicense: No provider session token and not offline");
return UNKNOWN_ERROR;
}
DeviceFiles handle; DeviceFiles handle;
if (!handle.Init(&file, crypto_session_->GetSecurityLevel())) if (!handle.Init(crypto_session_->GetSecurityLevel())) {
LOGE("CdmSession::StoreLicense: Unable to initialize device files");
return UNKNOWN_ERROR;
}
if (!handle.StoreUsageInfo(provider_session_token, key_request_,
key_response_)) {
LOGE("CdmSession::StoreLicense: Unable to store usage info");
return UNKNOWN_ERROR;
}
return NO_ERROR;
}
bool CdmSession::StoreLicense(DeviceFiles::LicenseState state) {
DeviceFiles handle;
if (!handle.Init(crypto_session_->GetSecurityLevel()))
return false; return false;
return handle.StoreLicense( return handle.StoreLicense(
key_set_id_, state, offline_init_data_, offline_key_request_, key_set_id_, state, offline_init_data_, key_request_,
offline_key_response_, offline_key_renewal_request_, key_response_, offline_key_renewal_request_,
offline_key_renewal_response_, offline_release_server_url_); offline_key_renewal_response_, offline_release_server_url_);
} }
bool CdmSession::DeleteLicense() {
if (!is_offline_ && license_parser_.provider_session_token().empty())
return false;
DeviceFiles handle;
if (!handle.Init(crypto_session_->GetSecurityLevel())) {
LOGE("CdmSession::DeleteLicense: Unable to initialize device files");
return false;
}
if (is_offline_)
return handle.DeleteLicense(key_set_id_);
else
return handle.DeleteUsageInfo(
license_parser_.provider_session_token());
}
bool CdmSession::AttachEventListener(WvCdmEventListener* listener) { bool CdmSession::AttachEventListener(WvCdmEventListener* listener) {
std::pair<CdmEventListenerIter, bool> result = listeners_.insert(listener); std::pair<CdmEventListenerIter, bool> result = listeners_.insert(listener);
return result.second; return result.second;
@@ -459,4 +547,15 @@ SecurityLevel CdmSession::GetRequestedSecurityLevel() {
return kLevelDefault; return kLevelDefault;
} }
CdmSecurityLevel CdmSession::GetSecurityLevel() {
if (NULL == crypto_session_.get())
return kSecurityLevelUninitialized;
return crypto_session_.get()->GetSecurityLevel();
}
CdmResponseType CdmSession::UpdateUsageInformation() {
return crypto_session_->UpdateUsageInformation();
}
} // namespace wvcdm } // namespace wvcdm

View File

@@ -103,7 +103,8 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequest(
switch (cert_type) { switch (cert_type) {
case kCertificateWidevine: case kCertificateWidevine:
options->set_certificate_type( options->set_certificate_type(
video_widevine_server::sdk::ProvisioningOptions_CertificateType_RSA_WIDEVINE); video_widevine_server::sdk::
ProvisioningOptions_CertificateType_WIDEVINE_DRM);
break; break;
case kCertificateX509: case kCertificateX509:
options->set_certificate_type( options->set_certificate_type(
@@ -262,9 +263,8 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
const std::string& device_certificate = const std::string& device_certificate =
provisioning_response.device_certificate(); provisioning_response.device_certificate();
File file;
DeviceFiles handle; DeviceFiles handle;
if (!handle.Init(&file, crypto_session_.GetSecurityLevel())) { if (!handle.Init(crypto_session_.GetSecurityLevel())) {
LOGE("HandleProvisioningResponse: failed to init DeviceFiles"); LOGE("HandleProvisioningResponse: failed to init DeviceFiles");
return UNKNOWN_ERROR; return UNKNOWN_ERROR;
} }

View File

@@ -340,12 +340,11 @@ size_t CryptoSession::GetOffset(std::string message, std::string field) {
return pos; return pos;
} }
CdmResponseType CryptoSession::LoadKeys(const std::string& message, CdmResponseType CryptoSession::LoadKeys(
const std::string& signature, const std::string& message, const std::string& signature,
const std::string& mac_key_iv, const std::string& mac_key_iv, const std::string& mac_key,
const std::string& mac_key, const std::vector<CryptoKey>& keys,
int num_keys, const std::string& provider_session_token) {
const CryptoKey* key_array) {
LOGV("CryptoSession::LoadKeys: Lock"); LOGV("CryptoSession::LoadKeys: Lock");
AutoLock auto_lock(crypto_lock_); AutoLock auto_lock(crypto_lock_);
@@ -358,10 +357,10 @@ CdmResponseType CryptoSession::LoadKeys(const std::string& message,
} else { } else {
LOGV("CryptoSession::LoadKeys: enc_mac_key not set"); LOGV("CryptoSession::LoadKeys: enc_mac_key not set");
} }
std::vector<OEMCrypto_KeyObject> load_key_array(num_keys); std::vector<OEMCrypto_KeyObject> load_keys(keys.size());
for (int i = 0; i < num_keys; ++i) { for (size_t i = 0; i < keys.size(); ++i) {
const CryptoKey* ki = &key_array[i]; const CryptoKey* ki = &keys[i];
OEMCrypto_KeyObject* ko = &load_key_array[i]; OEMCrypto_KeyObject* ko = &load_keys[i];
ko->key_id = msg + GetOffset(message, ki->key_id()); ko->key_id = msg + GetOffset(message, ki->key_id());
ko->key_id_length = ki->key_id().length(); ko->key_id_length = ki->key_id().length();
ko->key_data_iv = msg + GetOffset(message, ki->key_data_iv()); ko->key_data_iv = msg + GetOffset(message, ki->key_data_iv());
@@ -377,11 +376,17 @@ CdmResponseType CryptoSession::LoadKeys(const std::string& message,
ko->key_control = NULL; ko->key_control = NULL;
} }
} }
uint8_t* pst = NULL;
if (!provider_session_token.empty()) {
pst =
const_cast<uint8_t*>(msg) + GetOffset(message, provider_session_token);
}
LOGV("LoadKeys: id=%ld", (uint32_t)oec_session_id_); LOGV("LoadKeys: id=%ld", (uint32_t)oec_session_id_);
OEMCryptoResult sts = OEMCrypto_LoadKeys( OEMCryptoResult sts = OEMCrypto_LoadKeys(
oec_session_id_, msg, message.size(), oec_session_id_, msg, message.size(),
reinterpret_cast<const uint8_t*>(signature.data()), signature.size(), reinterpret_cast<const uint8_t*>(signature.data()), signature.size(),
enc_mac_key_iv, enc_mac_key, num_keys, &load_key_array[0], NULL, 0); enc_mac_key_iv, enc_mac_key, keys.size(), &load_keys[0], pst,
provider_session_token.length());
if (OEMCrypto_SUCCESS == sts) { if (OEMCrypto_SUCCESS == sts) {
return KEY_ADDED; return KEY_ADDED;
@@ -613,6 +618,84 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) {
} }
} }
CdmResponseType CryptoSession::UpdateUsageInformation() {
return (OEMCrypto_UpdateUsageTable() == OEMCrypto_SUCCESS) ? NO_ERROR
: UNKNOWN_ERROR;
}
CdmResponseType CryptoSession::GenerateUsageReport(
const std::string& provider_session_token, std::string* usage_report) {
LOGV("GenerateUsageReport: id=%ld", (uint32_t)oec_session_id_);
if (NULL == usage_report) {
LOGE("usage_report parameter is null");
return UNKNOWN_ERROR;
}
AutoLock auto_lock(crypto_lock_);
uint8_t* pst = reinterpret_cast<uint8_t*>(
const_cast<char*>(provider_session_token.data()));
OEMCryptoResult status =
OEMCrypto_DeactivateUsageEntry(pst, provider_session_token.length());
if (OEMCrypto_SUCCESS != status) {
LOGE("CryptoSession::GenerateUsageReport: Deactivate Usage Entry error=%ld",
status);
return UNKNOWN_ERROR;
}
size_t usage_length = 0;
status = OEMCrypto_ReportUsage(oec_session_id_, pst,
provider_session_token.length(), NULL,
&usage_length);
if (OEMCrypto_ERROR_SHORT_BUFFER != status) {
LOGE("CryptoSession::GenerateUsageReport: Report Usage error=%ld", status);
return UNKNOWN_ERROR;
}
usage_report->resize(usage_length);
OEMCrypto_PST_Report* report = reinterpret_cast<OEMCrypto_PST_Report*>(
const_cast<char*>(usage_report->data()));
status = OEMCrypto_ReportUsage(oec_session_id_, pst,
provider_session_token.length(), report,
&usage_length);
if (OEMCrypto_SUCCESS != status) {
LOGE("CryptoSession::GenerateUsageReport: Report Usage error=%ld", status);
return UNKNOWN_ERROR;
}
if (usage_length < usage_report->length()) {
usage_report->resize(usage_length);
}
return NO_ERROR;
}
CdmResponseType CryptoSession::ReleaseUsageInformation(
const std::string& message, const std::string& signature,
const std::string& provider_session_token) {
LOGV("ReleaseUsageInformation: id=%ld", (uint32_t)oec_session_id_);
AutoLock auto_lock(crypto_lock_);
const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data());
const uint8_t* sig = reinterpret_cast<const uint8_t*>(signature.data());
const uint8_t* pst = msg + GetOffset(message, provider_session_token);
OEMCryptoResult status = OEMCrypto_DeleteUsageEntry(
oec_session_id_, pst, provider_session_token.length(), msg,
message.length(), sig, signature.length());
if (OEMCrypto_SUCCESS != status) {
LOGE("CryptoSession::ReleaseUsageInformation: Report Usage error=%ld",
status);
return UNKNOWN_ERROR;
}
return NO_ERROR;
}
bool CryptoSession::GenerateNonce(uint32_t* nonce) { bool CryptoSession::GenerateNonce(uint32_t* nonce) {
if (!nonce) { if (!nonce) {
LOGE("input parameter is null"); LOGE("input parameter is null");

View File

@@ -10,6 +10,7 @@
#include "log.h" #include "log.h"
#include "openssl/sha.h" #include "openssl/sha.h"
#include "properties.h" #include "properties.h"
#include "string_conversions.h"
// Protobuf generated classes. // Protobuf generated classes.
using video_widevine_client::sdk::DeviceCertificate; using video_widevine_client::sdk::DeviceCertificate;
@@ -17,9 +18,12 @@ using video_widevine_client::sdk::HashedFile;
using video_widevine_client::sdk::License; using video_widevine_client::sdk::License;
using video_widevine_client::sdk::License_LicenseState_ACTIVE; using video_widevine_client::sdk::License_LicenseState_ACTIVE;
using video_widevine_client::sdk::License_LicenseState_RELEASING; using video_widevine_client::sdk::License_LicenseState_RELEASING;
using video_widevine_client::sdk::UsageInfo;
using video_widevine_client::sdk::UsageInfo_ProviderSession;
namespace { namespace {
const char kCertificateFileName[] = "cert.bin"; const char kCertificateFileName[] = "cert.bin";
const char kUsageInfoFileName[] = "usage.bin";
const char kLicenseFileNameExt[] = ".lic"; const char kLicenseFileNameExt[] = ".lic";
const char kWildcard[] = "*"; const char kWildcard[] = "*";
const char kDirectoryDelimiter = '/'; const char kDirectoryDelimiter = '/';
@@ -27,15 +31,15 @@ const char* kSecurityLevelPathCompatibilityExclusionList[] = {"ay64.dat"};
size_t kSecurityLevelPathCompatibilityExclusionListSize = size_t kSecurityLevelPathCompatibilityExclusionListSize =
sizeof(kSecurityLevelPathCompatibilityExclusionList) / sizeof(kSecurityLevelPathCompatibilityExclusionList) /
sizeof(*kSecurityLevelPathCompatibilityExclusionList); sizeof(*kSecurityLevelPathCompatibilityExclusionList);
} // namespace } // unnamed namespace
namespace wvcdm { namespace wvcdm {
bool DeviceFiles::Init(const File* handle, CdmSecurityLevel security_level) { DeviceFiles::~DeviceFiles() {
if (handle == NULL) { if (!file_ && !test_file_) delete file_;
LOGW("DeviceFiles::Init: Invalid file handle parameter");
return false;
} }
bool DeviceFiles::Init(CdmSecurityLevel security_level) {
switch (security_level) { switch (security_level) {
case kSecurityLevelL1: case kSecurityLevelL1:
case kSecurityLevelL2: case kSecurityLevelL2:
@@ -45,7 +49,7 @@ bool DeviceFiles::Init(const File* handle, CdmSecurityLevel security_level) {
LOGW("DeviceFiles::Init: Unsupported security level %d", security_level); LOGW("DeviceFiles::Init: Unsupported security level %d", security_level);
return false; return false;
} }
file_ = const_cast<File*>(handle); file_ = new File();
security_level_ = security_level; security_level_ = security_level;
initialized_ = true; initialized_ = true;
return true; return true;
@@ -68,24 +72,10 @@ bool DeviceFiles::StoreCertificate(const std::string& certificate,
device_certificate->set_certificate(certificate); device_certificate->set_certificate(certificate);
device_certificate->set_wrapped_private_key(wrapped_private_key); device_certificate->set_wrapped_private_key(wrapped_private_key);
std::string serialized_string; std::string serialized_file;
file.SerializeToString(&serialized_string); file.SerializeToString(&serialized_file);
// calculate SHA hash return StoreFile(kCertificateFileName, serialized_file);
std::string hash;
if (!Hash(serialized_string, &hash)) {
LOGW("DeviceFiles::StoreCertificate: Hash computation failed");
return false;
}
// Fill in hashed file data
HashedFile hashed_file;
hashed_file.set_file(serialized_string);
hashed_file.set_hash(hash);
hashed_file.SerializeToString(&serialized_string);
return StoreFile(kCertificateFileName, serialized_string);
} }
bool DeviceFiles::RetrieveCertificate(std::string* certificate, bool DeviceFiles::RetrieveCertificate(std::string* certificate,
@@ -99,29 +89,12 @@ bool DeviceFiles::RetrieveCertificate(std::string* certificate,
SecurityLevelPathBackwardCompatibility(); SecurityLevelPathBackwardCompatibility();
} }
std::string serialized_hashed_file; std::string serialized_file;
if (!RetrieveFile(kCertificateFileName, &serialized_hashed_file)) if (!RetrieveFile(kCertificateFileName, &serialized_file))
return false; return false;
HashedFile hashed_file;
if (!hashed_file.ParseFromString(serialized_hashed_file)) {
LOGW("DeviceFiles::RetrieveCertificate: Unable to parse hash file");
return false;
}
std::string hash;
if (!Hash(hashed_file.file(), &hash)) {
LOGW("DeviceFiles::RetrieveCertificate: Hash computation failed");
return false;
}
if (hash.compare(hashed_file.hash())) {
LOGW("DeviceFiles::RetrieveCertificate: Hash mismatch");
return false;
}
video_widevine_client::sdk::File file; video_widevine_client::sdk::File file;
if (!file.ParseFromString(hashed_file.file())) { if (!file.ParseFromString(serialized_file)) {
LOGW("DeviceFiles::RetrieveCertificate: Unable to parse file"); LOGW("DeviceFiles::RetrieveCertificate: Unable to parse file");
return false; return false;
} }
@@ -187,25 +160,11 @@ bool DeviceFiles::StoreLicense(const std::string& key_set_id,
license->set_renewal(license_renewal); license->set_renewal(license_renewal);
license->set_release_server_url(release_server_url); license->set_release_server_url(release_server_url);
std::string serialized_string; std::string serialized_file;
file.SerializeToString(&serialized_string); file.SerializeToString(&serialized_file);
// calculate SHA hash
std::string hash;
if (!Hash(serialized_string, &hash)) {
LOGW("DeviceFiles::StoreLicense: Hash computation failed");
return false;
}
// File in hashed file data
HashedFile hashed_file;
hashed_file.set_file(serialized_string);
hashed_file.set_hash(hash);
hashed_file.SerializeToString(&serialized_string);
std::string file_name = key_set_id + kLicenseFileNameExt; std::string file_name = key_set_id + kLicenseFileNameExt;
return StoreFile(file_name.c_str(), serialized_string); return StoreFile(file_name.c_str(), serialized_file);
} }
bool DeviceFiles::RetrieveLicense(const std::string& key_set_id, bool DeviceFiles::RetrieveLicense(const std::string& key_set_id,
@@ -220,29 +179,12 @@ bool DeviceFiles::RetrieveLicense(const std::string& key_set_id,
return false; return false;
} }
std::string serialized_hashed_file; std::string serialized_file;
std::string file_name = key_set_id + kLicenseFileNameExt; std::string file_name = key_set_id + kLicenseFileNameExt;
if (!RetrieveFile(file_name.c_str(), &serialized_hashed_file)) return false; if (!RetrieveFile(file_name.c_str(), &serialized_file)) return false;
HashedFile hashed_file;
if (!hashed_file.ParseFromString(serialized_hashed_file)) {
LOGW("DeviceFiles::RetrieveLicense: Unable to parse hash file");
return false;
}
std::string hash;
if (!Hash(hashed_file.file(), &hash)) {
LOGW("DeviceFiles::RetrieveLicense: Hash computation failed");
return false;
}
if (hash.compare(hashed_file.hash())) {
LOGW("DeviceFiles::RetrieveLicense: Hash mismatch");
return false;
}
video_widevine_client::sdk::File file; video_widevine_client::sdk::File file;
if (!file.ParseFromString(hashed_file.file())) { if (!file.ParseFromString(serialized_file)) {
LOGW("DeviceFiles::RetrieveLicense: Unable to parse file"); LOGW("DeviceFiles::RetrieveLicense: Unable to parse file");
return false; return false;
} }
@@ -352,6 +294,142 @@ bool DeviceFiles::LicenseExists(const std::string& key_set_id) {
return file_->Exists(path); return file_->Exists(path);
} }
bool DeviceFiles::StoreUsageInfo(const std::string& provider_session_token,
const CdmKeyMessage& key_request,
const CdmKeyResponse& key_response) {
if (!initialized_) {
LOGW("DeviceFiles::StoreUsageInfo: not initialized");
return false;
}
std::string serialized_file;
video_widevine_client::sdk::File file;
if (!RetrieveFile(kUsageInfoFileName, &serialized_file)) {
file.set_type(video_widevine_client::sdk::File::USAGE_INFO);
file.set_version(video_widevine_client::sdk::File::VERSION_1);
} else {
if (!file.ParseFromString(serialized_file)) {
LOGW("DeviceFiles::StoreUsageInfo: Unable to parse file");
return false;
}
}
UsageInfo* usage_info = file.mutable_usage_info();
UsageInfo_ProviderSession* provider_session = usage_info->add_sessions();
provider_session->set_token(provider_session_token.data(),
provider_session_token.size());
provider_session->set_license_request(key_request.data(),
key_request.size());
provider_session->set_license(key_response.data(),
key_response.size());
file.SerializeToString(&serialized_file);
return StoreFile(kUsageInfoFileName, serialized_file);
}
bool DeviceFiles::DeleteUsageInfo(const std::string& provider_session_token) {
if (!initialized_) {
LOGW("DeviceFiles::DeleteUsageInfo: not initialized");
return false;
}
std::string serialized_file;
if (!RetrieveFile(kUsageInfoFileName, &serialized_file)) return false;
video_widevine_client::sdk::File file;
if (!file.ParseFromString(serialized_file)) {
LOGW("DeviceFiles::DeleteUsageInfo: Unable to parse file");
return false;
}
UsageInfo* updated_info = file.mutable_usage_info();
UsageInfo info(*(const_cast<const UsageInfo*>(updated_info)));
updated_info->clear_sessions();
bool found = false;
for (int i = 0; i < info.sessions_size(); ++i) {
if (info.sessions(i).token().compare(provider_session_token) == 0) {
found = true;
} else {
updated_info->add_sessions()->set_token(info.sessions(i).token());
updated_info->add_sessions()->set_license_request(
info.sessions(i).license_request());
updated_info->add_sessions()->set_license(info.sessions(i).license());
}
}
if (!found) {
LOGW("DeviceFiles::DeleteUsageInfo: Unable to find provider session "
"token: %s", b2a_hex(provider_session_token).c_str());
return false;
}
file.SerializeToString(&serialized_file);
return StoreFile(kUsageInfoFileName, serialized_file);
}
bool DeviceFiles::DeleteUsageInfo() {
if (!initialized_) {
LOGW("DeviceFiles::DeleteUsageInfo: not initialized");
return false;
}
std::string path;
if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) {
LOGW("DeviceFiles::DeleteUsageInfo: Unable to get base path");
return false;
}
path.append(kUsageInfoFileName);
return file_->Remove(path);
}
bool DeviceFiles::RetrieveUsageInfo(std::vector<
std::pair<CdmKeyMessage, CdmKeyResponse> >* usage_info) {
if (!initialized_) {
LOGW("DeviceFiles::RetrieveUsageInfo: not initialized");
return false;
}
if (NULL == usage_info) {
LOGW("DeviceFiles::RetrieveUsageInfo: license destination not "
"provided");
return false;
}
std::string serialized_file;
if (!RetrieveFile(kUsageInfoFileName, &serialized_file)) {
std::string path;
if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) {
return false;
}
path += kUsageInfoFileName;
if (!file_->Exists(path) || 0 == file_->FileSize(path)) {
usage_info->resize(0);
return true;
}
return false;
}
video_widevine_client::sdk::File file;
if (!file.ParseFromString(serialized_file)) {
LOGW("DeviceFiles::RetrieveUsageInfo: Unable to parse file");
return false;
}
usage_info->resize(file.usage_info().sessions_size());
for (int i = 0; i < file.usage_info().sessions_size(); ++i) {
(*usage_info)[i] =
std::make_pair(file.usage_info().sessions(i).license_request(),
file.usage_info().sessions(i).license());
}
return true;
}
bool DeviceFiles::Hash(const std::string& data, std::string* hash) { bool DeviceFiles::Hash(const std::string& data, std::string* hash) {
if (!hash) return false; if (!hash) return false;
@@ -363,7 +441,8 @@ bool DeviceFiles::Hash(const std::string& data, std::string* hash) {
return true; return true;
} }
bool DeviceFiles::StoreFile(const char* name, const std::string& data) { bool DeviceFiles::StoreFile(const char* name,
const std::string& serialized_file) {
if (!file_) { if (!file_) {
LOGW("DeviceFiles::StoreFile: Invalid file handle"); LOGW("DeviceFiles::StoreFile: Invalid file handle");
return false; return false;
@@ -374,6 +453,21 @@ bool DeviceFiles::StoreFile(const char* name, const std::string& data) {
return false; return false;
} }
// calculate SHA hash
std::string hash;
if (!Hash(serialized_file, &hash)) {
LOGW("DeviceFiles::StoreFile: Hash computation failed");
return false;
}
// Fill in hashed file data
HashedFile hash_file;
hash_file.set_file(serialized_file);
hash_file.set_hash(hash);
std::string serialized_hash_file;
hash_file.SerializeToString(&serialized_hash_file);
std::string path; std::string path;
if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) { if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) {
LOGW("DeviceFiles::StoreFile: Unable to get base path"); LOGW("DeviceFiles::StoreFile: Unable to get base path");
@@ -391,19 +485,24 @@ bool DeviceFiles::StoreFile(const char* name, const std::string& data) {
return false; return false;
} }
ssize_t bytes = file_->Write(data.data(), data.size()); ssize_t bytes = file_->Write(serialized_hash_file.data(),
serialized_hash_file.size());
file_->Close(); file_->Close();
if (bytes != static_cast<ssize_t>(data.size())) { if (bytes != static_cast<ssize_t>(serialized_hash_file.size())) {
LOGW("DeviceFiles::StoreFile: write failed: %d %d", data.size(), bytes); LOGW("DeviceFiles::StoreFile: write failed: (actual: %d, expected: %d)",
bytes,
serialized_hash_file.size());
return false; return false;
} }
LOGV("DeviceFiles::StoreFile: success: %s (%db)", path.c_str(), data.size()); LOGV("DeviceFiles::StoreFile: success: %s (%db)",
path.c_str(),
serialized_hash_file.size());
return true; return true;
} }
bool DeviceFiles::RetrieveFile(const char* name, std::string* data) { bool DeviceFiles::RetrieveFile(const char* name, std::string* serialized_file) {
if (!file_) { if (!file_) {
LOGW("DeviceFiles::RetrieveFile: Invalid file handle"); LOGW("DeviceFiles::RetrieveFile: Invalid file handle");
return false; return false;
@@ -414,8 +513,8 @@ bool DeviceFiles::RetrieveFile(const char* name, std::string* data) {
return false; return false;
} }
if (!data) { if (!serialized_file) {
LOGW("DeviceFiles::RetrieveFile: Unspecified data parameter"); LOGW("DeviceFiles::RetrieveFile: Unspecified serialized_file parameter");
return false; return false;
} }
@@ -434,7 +533,7 @@ bool DeviceFiles::RetrieveFile(const char* name, std::string* data) {
ssize_t bytes = file_->FileSize(path); ssize_t bytes = file_->FileSize(path);
if (bytes <= 0) { if (bytes <= 0) {
LOGW("DeviceFiles::RetrieveFile: File size invalid: %d", path.c_str()); LOGW("DeviceFiles::RetrieveFile: File size invalid: %s", path.c_str());
return false; return false;
} }
@@ -442,17 +541,37 @@ bool DeviceFiles::RetrieveFile(const char* name, std::string* data) {
return false; return false;
} }
data->resize(bytes); std::string serialized_hash_file;
bytes = file_->Read(&(*data)[0], data->size()); serialized_hash_file.resize(bytes);
bytes = file_->Read(&serialized_hash_file[0], serialized_hash_file.size());
file_->Close(); file_->Close();
if (bytes != static_cast<ssize_t>(data->size())) { if (bytes != static_cast<ssize_t>(serialized_hash_file.size())) {
LOGW("DeviceFiles::RetrieveFile: read failed"); LOGW("DeviceFiles::RetrieveFile: read failed");
return false; return false;
} }
LOGV("DeviceFiles::RetrieveFile: success: %s (%db)", path.c_str(), LOGV("DeviceFiles::RetrieveFile: success: %s (%db)", path.c_str(),
data->size()); serialized_hash_file.size());
HashedFile hash_file;
if (!hash_file.ParseFromString(serialized_hash_file)) {
LOGW("DeviceFiles::RetrieveFile: Unable to parse hash file");
return false;
}
std::string hash;
if (!Hash(hash_file.file(), &hash)) {
LOGW("DeviceFiles::RetrieveFile: Hash computation failed");
return false;
}
if (hash.compare(hash_file.hash())) {
LOGW("DeviceFiles::RetrieveFile: Hash mismatch");
return false;
}
*serialized_file = hash_file.file();
return true; return true;
} }
@@ -528,4 +647,14 @@ std::string DeviceFiles::GetLicenseFileNameExtension() {
return kLicenseFileNameExt; return kLicenseFileNameExt;
} }
std::string DeviceFiles::GetUsageInfoFileName() {
return kUsageInfoFileName;
}
void DeviceFiles::SetTestFile(File* file) {
if (file_) delete file_;
file_ = file;
test_file_ = true;
}
} // namespace wvcdm } // namespace wvcdm

View File

@@ -33,10 +33,21 @@ message License {
optional bytes release_server_url = 7; optional bytes release_server_url = 7;
} }
message UsageInfo {
message ProviderSession {
optional bytes token = 1;
optional bytes license_request = 2;
optional bytes license = 3;
}
repeated ProviderSession sessions = 1;
}
message File { message File {
enum FileType { enum FileType {
DEVICE_CERTIFICATE = 1; DEVICE_CERTIFICATE = 1;
LICENSE = 2; LICENSE = 2;
USAGE_INFO = 2;
} }
enum FileVersion { enum FileVersion {
@@ -47,6 +58,7 @@ message File {
optional FileVersion version = 2 [default = VERSION_1]; optional FileVersion version = 2 [default = VERSION_1];
optional DeviceCertificate device_certificate = 3; optional DeviceCertificate device_certificate = 3;
optional License license = 4; optional License license = 4;
optional UsageInfo usage_info = 5;
} }
message HashedFile { message HashedFile {

View File

@@ -6,6 +6,7 @@
#include "crypto_key.h" #include "crypto_key.h"
#include "crypto_session.h" #include "crypto_session.h"
#include "device_files.h"
#include "log.h" #include "log.h"
#include "policy_engine.h" #include "policy_engine.h"
#include "properties.h" #include "properties.h"
@@ -81,15 +82,16 @@ using video_widevine_server::sdk::ClientIdentification;
using video_widevine_server::sdk::ClientIdentification_NameValue; using video_widevine_server::sdk::ClientIdentification_NameValue;
using video_widevine_server::sdk::DeviceCertificate; using video_widevine_server::sdk::DeviceCertificate;
using video_widevine_server::sdk::EncryptedClientIdentification; using video_widevine_server::sdk::EncryptedClientIdentification;
using video_widevine_server::sdk::License;
using video_widevine_server::sdk::License_KeyContainer;
using video_widevine_server::sdk::LicenseError;
using video_widevine_server::sdk::LicenseIdentification;
using video_widevine_server::sdk::LicenseRequest; using video_widevine_server::sdk::LicenseRequest;
using video_widevine_server::sdk::LicenseRequest_ContentIdentification; using video_widevine_server::sdk::LicenseRequest_ContentIdentification;
using video_widevine_server::sdk::LicenseRequest_ContentIdentification_CENC; using video_widevine_server::sdk::LicenseRequest_ContentIdentification_CENC;
using video_widevine_server::sdk::LicenseRequest_ContentIdentification_WebM; using video_widevine_server::sdk::LicenseRequest_ContentIdentification_WebM;
using video_widevine_server::sdk:: using video_widevine_server::sdk::
LicenseRequest_ContentIdentification_ExistingLicense; LicenseRequest_ContentIdentification_ExistingLicense;
using video_widevine_server::sdk::License;
using video_widevine_server::sdk::License_KeyContainer;
using video_widevine_server::sdk::LicenseError;
using video_widevine_server::sdk::SignedDeviceCertificate; using video_widevine_server::sdk::SignedDeviceCertificate;
using video_widevine_server::sdk::SignedMessage; using video_widevine_server::sdk::SignedMessage;
@@ -424,7 +426,19 @@ bool CdmLicense::PrepareKeyUpdateRequest(bool is_renewal,
LicenseRequest_ContentIdentification_ExistingLicense* current_license = LicenseRequest_ContentIdentification_ExistingLicense* current_license =
license_request.mutable_content_id()->mutable_license(); license_request.mutable_content_id()->mutable_license();
current_license->mutable_license_id()->CopyFrom(policy_engine_->license_id()); LicenseIdentification license_id = policy_engine_->license_id();
current_license->mutable_license_id()->CopyFrom(license_id);
if (!is_renewal) {
if (license_id.has_provider_session_token()) {
std::string usage_report;
if (!session_->GenerateUsageReport(license_id.provider_session_token(),
&usage_report)) {
return false;
}
current_license->set_session_usage_table_entry(usage_report);
}
}
// Get/set the nonce. This value will be reflected in the Key Control Block // Get/set the nonce. This value will be reflected in the Key Control Block
// of the license response. // of the license response.
@@ -488,7 +502,7 @@ CdmResponseType CdmLicense::HandleKeyResponse(
break; break;
case SignedMessage::SERVICE_CERTIFICATE: case SignedMessage::SERVICE_CERTIFICATE:
return CdmLicense::HandleServiceCertificateResponse(signed_response); return CdmLicense::HandleServiceCertificateResponse(signed_response);
case SignedMessage::ERROR: case SignedMessage::ERROR_RESPONSE:
return HandleKeyErrorResponse(signed_response); return HandleKeyErrorResponse(signed_response);
default: default:
LOGE("CdmLicense::HandleKeyResponse: unrecognized signed message type: %d" LOGE("CdmLicense::HandleKeyResponse: unrecognized signed message type: %d"
@@ -546,6 +560,10 @@ CdmResponseType CdmLicense::HandleKeyResponse(
return KEY_ERROR; return KEY_ERROR;
} }
std::string provider_session_token;
if (license.id().has_provider_session_token())
provider_session_token_ = license.id().provider_session_token();
if (license.policy().has_renewal_server_url()) { if (license.policy().has_renewal_server_url()) {
server_url_ = license.policy().renewal_server_url(); server_url_ = license.policy().renewal_server_url();
} }
@@ -559,8 +577,8 @@ CdmResponseType CdmLicense::HandleKeyResponse(
signed_response.signature(), signed_response.signature(),
mac_key_iv, mac_key_iv,
mac_key, mac_key,
key_array.size(), key_array,
&key_array[0]); provider_session_token);
if (KEY_ADDED == resp) { if (KEY_ADDED == resp) {
loaded_keys_.clear(); loaded_keys_.clear();
@@ -590,7 +608,7 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
return KEY_ERROR; return KEY_ERROR;
} }
if (signed_response.type() == SignedMessage::ERROR) { if (signed_response.type() == SignedMessage::ERROR_RESPONSE) {
return HandleKeyErrorResponse(signed_response); return HandleKeyErrorResponse(signed_response);
} }
@@ -618,6 +636,14 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
server_url_ = license.policy().renewal_server_url(); server_url_ = license.policy().renewal_server_url();
} }
} }
else {
if (license.id().has_provider_session_token()) {
provider_session_token_ = license.id().provider_session_token();
session_->ReleaseUsageInformation(signed_response.msg(),
signed_response.signature(),
provider_session_token_);
}
}
// TODO(kqyang, jfore, gmorgan): change UpdateLicense function signature to // TODO(kqyang, jfore, gmorgan): change UpdateLicense function signature to
// be able to return true/false to accept/reject the license. (Pending code // be able to return true/false to accept/reject the license. (Pending code
@@ -637,8 +663,9 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
} }
bool CdmLicense::RestoreOfflineLicense( bool CdmLicense::RestoreOfflineLicense(
CdmKeyMessage& license_request, CdmKeyResponse& license_response, const CdmKeyMessage& license_request,
CdmKeyResponse& license_renewal_response) { const CdmKeyResponse& license_response,
const CdmKeyResponse& license_renewal_response) {
if (license_request.empty() || license_response.empty()) { if (license_request.empty() || license_response.empty()) {
LOGE( LOGE(
@@ -681,6 +708,77 @@ bool CdmLicense::RestoreOfflineLicense(
return true; return true;
} }
bool CdmLicense::RestoreUsageLicense(const CdmKeyMessage& license_request,
const CdmKeyResponse& license_response) {
if (license_request.empty() || license_response.empty()) {
LOGE(
"CdmLicense::RestoreUsageLicense: key_request or response empty: %u %u",
license_request.size(), license_response.size());
return false;
}
SignedMessage signed_request;
if (!signed_request.ParseFromString(license_request)) {
LOGE("CdmLicense::RestoreUsageLicense: license_request parse failed");
return false;
}
if (signed_request.type() != SignedMessage::LICENSE_REQUEST) {
LOGE(
"CdmLicense::RestoreUsageLicense: license request type: expected = %d,"
" actual = %d",
SignedMessage::LICENSE_REQUEST, signed_request.type());
return false;
}
key_request_ = signed_request.msg();
SignedMessage signed_response;
if (!signed_response.ParseFromString(license_response)) {
LOGE("CdmLicense::RestoreUsageLicense: unable to parse signed license"
" response");
return false;
}
if (SignedMessage::LICENSE != signed_response.type()) {
LOGE("CdmLicense::RestoreUsageLicense: unrecognized signed message type: %d"
, signed_response.type());
return false;
}
if (Properties::use_certificates_as_identification()) {
if (!signed_response.has_session_key()) {
LOGE("CdmLicense::RestoreUsageLicense: no session keys present");
return false;
}
if (!session_->GenerateDerivedKeys(key_request_,
signed_response.session_key()))
return false;
} else {
if (!session_->GenerateDerivedKeys(key_request_)) return false;
}
if (!signed_response.has_signature()) {
LOGE("CdmLicense::RestoreUsageLicense: license response is not signed");
return false;
}
License license;
if (!license.ParseFromString(signed_response.msg())) {
LOGE("CdmLicense::RestoreUsageLicense: unable to parse license response");
return false;
}
policy_engine_->SetLicense(license);
return true;
}
bool CdmLicense::IsKeyLoaded(const KeyId& key_id) {
return loaded_keys_.find(key_id) != loaded_keys_.end();
}
bool CdmLicense::PrepareServiceCertificateRequest(CdmKeyMessage* signed_request, bool CdmLicense::PrepareServiceCertificateRequest(CdmKeyMessage* signed_request,
std::string* server_url) { std::string* server_url) {
if (!initialized_) { if (!initialized_) {
@@ -804,8 +902,4 @@ bool CdmLicense::PrepareContentId(const CdmLicenseType license_type,
return true; return true;
} }
bool CdmLicense::IsKeyLoaded(const KeyId& key_id) {
return loaded_keys_.find(key_id) != loaded_keys_.end();
}
} // namespace wvcdm } // namespace wvcdm

View File

@@ -27,6 +27,7 @@ message LicenseIdentification {
optional bytes purchase_id = 3; optional bytes purchase_id = 3;
optional LicenseType type = 4; optional LicenseType type = 4;
optional int32 version = 5; optional int32 version = 5;
optional bytes provider_session_token = 6;
} }
message License { message License {
@@ -126,6 +127,8 @@ message License {
HDCP_NONE = 0; HDCP_NONE = 0;
HDCP_V1 = 1; HDCP_V1 = 1;
HDCP_V2 = 2; HDCP_V2 = 2;
HDCP_V2_1 = 3;
HDCP_V2_2 = 4;
} }
optional HDCP hdcp = 1 [default = HDCP_NONE]; optional HDCP hdcp = 1 [default = HDCP_NONE];
@@ -139,6 +142,15 @@ message License {
optional CGMS cgms_flags = 2 [default = CGMS_NONE]; optional CGMS cgms_flags = 2 [default = CGMS_NONE];
} }
message VideoResolutionConstraint {
// Minimum and maximum video resolutions in the range (height x width).
optional uint32 min_resolution_pixels = 1;
optional uint32 max_resolution_pixels = 2;
// Optional output protection requirements for this range. If not
// specified, the OutputProtection in the KeyContainer applies.
optional OutputProtection required_protection = 3;
}
message OperatorSessionKeyPermissions { message OperatorSessionKeyPermissions {
// Permissions/key usage flags for operator service keys // Permissions/key usage flags for operator service keys
// (type = OPERATOR_SESSION). // (type = OPERATOR_SESSION).
@@ -157,12 +169,20 @@ message License {
optional OutputProtection requested_protection = 7; optional OutputProtection requested_protection = 7;
optional KeyControl key_control = 8; optional KeyControl key_control = 8;
optional OperatorSessionKeyPermissions operator_session_key_permissions = 9; optional OperatorSessionKeyPermissions operator_session_key_permissions = 9;
// Optional video resolution constraints. If the video resolution of the
// content being decrypted/decoded falls within one of the specified ranges,
// the optional required_protections may be applied. Otherwise an error will
// be reported.
repeated VideoResolutionConstraint video_resolution_constraints = 10;
} }
optional LicenseIdentification id = 1; optional LicenseIdentification id = 1;
optional Policy policy = 2; optional Policy policy = 2;
repeated KeyContainer key = 3; repeated KeyContainer key = 3;
optional int64 license_start_time = 4; optional int64 license_start_time = 4;
optional bool remote_attestation_verified = 5 [default = false];
// Client token generated by the content provider. Optional.
optional bytes provider_client_token = 6;
} }
enum ProtocolVersion { enum ProtocolVersion {
@@ -187,6 +207,8 @@ message LicenseRequest {
message ExistingLicense { message ExistingLicense {
optional LicenseIdentification license_id = 1; optional LicenseIdentification license_id = 1;
optional int64 seconds_since_started = 2; optional int64 seconds_since_started = 2;
optional int64 seconds_since_last_played = 3;
optional bytes session_usage_table_entry = 4;
} }
// Exactly one of these must be present. // Exactly one of these must be present.
@@ -233,11 +255,22 @@ message LicenseError {
optional Error error_code = 1; optional Error error_code = 1;
} }
message RemoteAttestation {
// Encrypted ClientIdentification message containing the device remote
// attestation certificate. Required.
optional EncryptedClientIdentification certificate = 1;
// Bytes of salt which were added to the remote attestation challenge prior to
// signing it. Required.
optional bytes salt = 2;
// Signed remote attestation challenge + salt. Required.
optional bytes signature = 3;
}
message SignedMessage { message SignedMessage {
enum MessageType { enum MessageType {
LICENSE_REQUEST = 1; LICENSE_REQUEST = 1;
LICENSE = 2; LICENSE = 2;
ERROR = 3; ERROR_RESPONSE = 3;
SERVICE_CERTIFICATE_REQUEST = 4; SERVICE_CERTIFICATE_REQUEST = 4;
SERVICE_CERTIFICATE = 5; SERVICE_CERTIFICATE = 5;
} }
@@ -246,10 +279,20 @@ message SignedMessage {
optional bytes msg = 2; optional bytes msg = 2;
optional bytes signature = 3; optional bytes signature = 3;
optional bytes session_key = 4; optional bytes session_key = 4;
// Remote attestation data which will be present in the initial license
// request for ChromeOS client devices operating in verified mode. Remote
// attestation challenge data is |msg| field above. Optional.
optional RemoteAttestation remote_attestation = 5;
} }
// This message is used to pass optional data on initial license issuance. // This message is used to pass optional data on initial license issuance.
message SessionInit { message SessionInit {
enum ReplayControl {
NO_SESSION_USAGE = 0;
NONCE_REQUIRED_AND_NEW_SESSION_USAGE = 1;
NONCE_REQUIRED_OR_EXISTING_SESSION_USAGE = 2;
}
optional bytes session_id = 1; optional bytes session_id = 1;
optional bytes purchase_id = 2; optional bytes purchase_id = 2;
// master_signing_key should be 128 bits in length. // master_signing_key should be 128 bits in length.
@@ -258,6 +301,19 @@ message SessionInit {
// (server || client) HMAC-SHA256 keys. // (server || client) HMAC-SHA256 keys.
optional bytes signing_key = 4; optional bytes signing_key = 4;
optional int64 license_start_time = 5; optional int64 license_start_time = 5;
// Client token for the session. This session is for use by the license
// provider, and is akin to a client cookie. It will be copied to
// License::provider_client_token, and sent back by the client in
// ClientIdentification::provider_client_token in all license requests
// thereafter.
optional bytes provider_client_token = 6;
// Session token for the session. This token is for use by the license
// provider, and is akin to a session cookie. It will be copied to
// LicenseIdentfication::provider_session_token, and sent back in all
// license renewal and release requests for the session thereafter.
optional bytes provider_session_token = 7;
// Replay control indicator which will be encoded into V9+ KeyControl blocks.
optional ReplayControl replay_control = 8 [default = NO_SESSION_USAGE];
} }
// This message is used by the server to preserve and restore session state. // This message is used by the server to preserve and restore session state.
@@ -280,7 +336,7 @@ message SessionState {
// in the case of X509 certificates, the certificate authority to use. // in the case of X509 certificates, the certificate authority to use.
message ProvisioningOptions { message ProvisioningOptions {
enum CertificateType { enum CertificateType {
RSA_WIDEVINE = 0; // Default. The original certificate type. WIDEVINE_DRM = 0; // Default. The original certificate type.
X509 = 1; // X.509 certificate. X509 = 1; // X.509 certificate.
} }
@@ -336,6 +392,7 @@ message ClientIdentification {
enum TokenType { enum TokenType {
KEYBOX = 0; KEYBOX = 0;
DEVICE_CERTIFICATE = 1; DEVICE_CERTIFICATE = 1;
REMOTE_ATTESTATION_CERTIFICATE = 2;
} }
message NameValue { message NameValue {
@@ -343,12 +400,36 @@ message ClientIdentification {
optional string value = 2; optional string value = 2;
} }
// Capabilities which not all clients may support. Used for the license
// exchange protocol only.
message ClientCapabilities {
enum HdcpVersion {
HDCP_NONE = 0;
HDCP_V1 = 1;
HDCP_V2 = 2;
HDCP_V2_1 = 3;
HDCP_V2_2 = 4;
}
optional bool client_token = 1 [default = false];
optional bool session_token = 2 [default = false];
optional bool video_resolution_constraints = 3 [default = false];
optional HdcpVersion max_hdcp_version = 4 [default = HDCP_NONE];
}
// Type of factory-provisioned device root of trust. Optional. // Type of factory-provisioned device root of trust. Optional.
optional TokenType type = 1 [default = KEYBOX]; optional TokenType type = 1 [default = KEYBOX];
// Factory-provisioned device root of trust. Required. // Factory-provisioned device root of trust. Required.
optional bytes token = 2; optional bytes token = 2;
// Optional client information name/value pairs. // Optional client information name/value pairs.
repeated NameValue client_info = 3; repeated NameValue client_info = 3;
// Client token generated by the content provider. Optional.
optional bytes provider_client_token = 4;
// Number of licenses received by the client to which the token above belongs.
// Only present if client_token is specified.
optional uint32 license_counter = 5;
// List of non-baseline client capabilities.
optional ClientCapabilities client_capabilities = 6;
} }
// EncryptedClientIdentification message used to hold ClientIdentification // EncryptedClientIdentification message used to hold ClientIdentification
@@ -359,16 +440,16 @@ message EncryptedClientIdentification {
optional string service_id = 1; optional string service_id = 1;
// Serial number for the service certificate for which ClientIdentification is // Serial number for the service certificate for which ClientIdentification is
// encrypted. // encrypted.
optional string service_certificate_serial_number = 2; optional bytes service_certificate_serial_number = 2;
// Serialized ClientIdentification message, encrypted with the privacy key // Serialized ClientIdentification message, encrypted with the privacy key using
// using AES-128-CBC with PKCS#5 padding. // AES-128-CBC with PKCS#5 padding.
optional bytes encrypted_client_id = 3; optional bytes encrypted_client_id = 3;
// Initialization vector needed to decrypt encrypted_client_id. // Initialization vector needed to decrypt encrypted_client_id.
optional bytes encrypted_client_id_iv = 4; optional bytes encrypted_client_id_iv = 4;
// AES-128 privacy key, encrytped with the service public public key using // AES-128 privacy key, encrytped with the service public public key using
// RSA-OAEP. // RSA-OAEP.
optional bytes encrypted_privacy_key = 5; optional bytes encrypted_privacy_key = 5;
}; }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// device_certificate.proto // device_certificate.proto
@@ -400,9 +481,10 @@ message DeviceCertificate {
// Widevine system ID for the device. Required for intermediate and // Widevine system ID for the device. Required for intermediate and
// user device certificates. // user device certificates.
optional uint32 system_id = 5; optional uint32 system_id = 5;
// True if the certificate corresponds to a test (non production) device or // Deprecated field, which used to indicate whether the device was a test
// service. Optional. // (non-production) device. The test_device field in ProvisionedDeviceInfo
optional bool test_device = 6 [default = false]; // below should be observed instead.
optional bool test_device_deprecated = 6 [deprecated = true];
// Service identifier (web origin) for the service which owns the certificate. // Service identifier (web origin) for the service which owns the certificate.
// Required for service certificates. // Required for service certificates.
optional string service_id = 7; optional string service_id = 7;

View File

@@ -26,7 +26,10 @@ using ::testing::StrEq;
namespace { namespace {
const uint32_t kCertificateLen = 700; const uint32_t kCertificateLen = 700;
const uint32_t kWrappedKeyLen = 500; const uint32_t kWrappedKeyLen = 500;
const uint32_t kProtobufEstimatedLen = 75; const uint32_t kProtobufEstimatedOverhead = 75;
const uint32_t kLicenseRequestLen = 300;
const uint32_t kLicenseLen = 500;
const uint32_t kProviderSessionTokenLen = 128;
const std::string kTestCertificate = const std::string kTestCertificate =
"124B035F3D256A656F0E505A085E7A6C482B61035E0C4A540F7803137F4C3B45206B7F33" "124B035F3D256A656F0E505A085E7A6C482B61035E0C4A540F7803137F4C3B45206B7F33"
"347F4D7A005E56400F0955011F4E07072D0D46781817460974326A516E3944385760280E" "347F4D7A005E56400F0955011F4E07072D0D46781817460974326A516E3944385760280E"
@@ -881,8 +884,7 @@ LicenseInfo license_update_test_data[] = {
"D30B08B2C4673551293A2E68747470733A2F2F746573742E676F6F676C65" "D30B08B2C4673551293A2E68747470733A2F2F746573742E676F6F676C65"
"2E636F6D2F6C6963656E73652F47657443656E634C6963656E736512200A" "2E636F6D2F6C6963656E73652F47657443656E634C6963656E736512200A"
"1C78D0E574D0827C3AE78A05EEC90BAC31D10686EC19EB0599F75B2D1AB4" "1C78D0E574D0827C3AE78A05EEC90BAC31D10686EC19EB0599F75B2D1AB4"
"C5" "C5")},
)},
// license being released. all fields are identical except for license // license being released. all fields are identical except for license
// state and hashed file data // state and hashed file data
{"", DeviceFiles::kLicenseStateReleasing, "", "", "", "", "", "", {"", DeviceFiles::kLicenseStateReleasing, "", "", "", "", "", "",
@@ -981,6 +983,287 @@ LicenseInfo license_update_test_data[] = {
"7186A244EF561E3B07DC459BC681A0798B180667EA448327F6BBBD30212A" "7186A244EF561E3B07DC459BC681A0798B180667EA448327F6BBBD30212A"
"49")}}; "49")}};
struct UsageInfo {
std::string provider_session_token;
std::string license_request;
std::string license;
std::string file_data;
};
UsageInfo kUsageInfoTestData[] = {
{"", "", "", // 0 usage info records
wvcdm::a2bs_hex(
"0A06080210012A00122095053501C5FA405B7EF01DA94685C6B20CB36493"
"A9CF1653B720E2BEA3B77929")},
{// 1 usage info record
wvcdm::a2bs_hex(
"924B035FBDA56AE5EF0ED05A08DE7AECC8ABE1835E0C4A548F7803937F4C3B4520EB7"
"F3334FFCDFA00DE56408F09D5019FCE87072D0DC6789817468974B2EA51EE3944B8D7"
"E0A88E4F16EBB80F03BD845231A01E6146841CBAEF0134DCD9300DB2D92732992C0F2"
"310D8E386FB31C67B9477010DEF9D99C4272589572A26A17E"),
wvcdm::a2bs_hex(
"1E6FFBE66FC6153E7749906EC8F684E819467E16CAF317F315DB32B6D3FDD1A8E8A09"
"4174D92D063B88E4835EAB78BD09541EA7FE72F132EB7364E154BC1548FC40EC70927"
"75531508C95F9ED5D76F36BC0C198C3A33A1F9415B343905D6BE37645E6800F053B1D"
"A9A20286EFCBBC320424ADF7FB6E3D5D8E86C35E576A1A2A37D344A419C0F0034A1B5"
"F767D3C61D90DCA1119E5024C34EDE8FA7DD128696D8C435410F218E52A853AD214FD"
"05D0F8B3CB4832CFCD97FE159E6DEE64CE82CDAEC0321AE71B3BCBAE42DF9EA65E42E"
"151827086EADE71C138B972CC3992CF9ADA944C063816352ED8658D3FA07BE0F32239"
"E74A65932B069AAC4E8386DB59154AF9AEF71448128C66E510445294F44E511BD9B1A"
"F19D4D67E99363093BE888D4B2AB841CAFF252CAD13EDF8E"),
wvcdm::a2bs_hex(
"40FC62339728520E6C0C09907C26F3FB78287231661952A8B699E47AE241B999C029F"
"D2067836DC4BC64F66998A3ECD197DAE36F808A2E5A4C5BF25DD580E52B1C39A8B037"
"72BF82D58929766F2DA04F0E616F92B3A0EB75661B8FF5DE1EB807C990F9E6BA991C8"
"BAD5EB63B37E8663A4E22AA9DB2015D3DF8BED1C8313F85F13B9483C7A39C592436C8"
"B13C23F78F55CE812795335059F7F527CA580306A0AEE5A6D957A91F498F64AA2EFC6"
"780716400E17C7EEA30B2E6523B902986995E003C2D919A7DC7C0122CE9410037A660"
"2B59A63B5C89473D4E02DE35C1F01B12ADB48A3D94D43693F08268FECCC78DAF6F4C3"
"5FA32C538CD73FBF3CEA274B01179C02473486311956E5A0C78E44C59B2F34FF24B06"
"53A6379A2F5F6F51467CAE26D55CC5BBDCFC9BCFA7B8C5CBF82EBE7BD340C3DAE6374"
"D0692052C529AA33D7A6799C8F1F59C78575E51F707013026CC4F83F6B3328EE6FB1A"
"C91929A4491338E93D10EE6193014A73BA241A9A833EA835217894EB4FD4BDB8904A5"
"999928325D0AC31B6D58609EDD9D85E88F74B5BD6FA7BDD83C51EEB91633ED267ACA2"
"E103904BBE4C031A6483858FBAD74DACD01711F7B882749FFFBA0DB6C7D7109D82989"
"C7D4DB5A0F1E7506AC24C89CECAF231EFF99F96AD76E57DABDD3C2DFBA7BAA869A771"
"F561B165987E552824B0C914E708E425C3"),
wvcdm::a2bs_hex(
"0AB307080210012AAC070AA9070A8001924B035FBDA56AE5EF0ED05A08DE7AECC8ABE"
"1835E0C4A548F7803937F4C3B4520EB7F3334FFCDFA00DE56408F09D5019FCE87072D"
"0DC6789817468974B2EA51EE3944B8D7E0A88E4F16EBB80F03BD845231A01E6146841"
"CBAEF0134DCD9300DB2D92732992C0F2310D8E386FB31C67B9477010DEF9D99C42725"
"89572A26A17E12AC021E6FFBE66FC6153E7749906EC8F684E819467E16CAF317F315D"
"B32B6D3FDD1A8E8A094174D92D063B88E4835EAB78BD09541EA7FE72F132EB7364E15"
"4BC1548FC40EC7092775531508C95F9ED5D76F36BC0C198C3A33A1F9415B343905D6B"
"E37645E6800F053B1DA9A20286EFCBBC320424ADF7FB6E3D5D8E86C35E576A1A2A37D"
"344A419C0F0034A1B5F767D3C61D90DCA1119E5024C34EDE8FA7DD128696D8C435410"
"F218E52A853AD214FD05D0F8B3CB4832CFCD97FE159E6DEE64CE82CDAEC0321AE71B3"
"BCBAE42DF9EA65E42E151827086EADE71C138B972CC3992CF9ADA944C063816352ED8"
"658D3FA07BE0F32239E74A65932B069AAC4E8386DB59154AF9AEF71448128C66E5104"
"45294F44E511BD9B1AF19D4D67E99363093BE888D4B2AB841CAFF252CAD13EDF8E1AF"
"40340FC62339728520E6C0C09907C26F3FB78287231661952A8B699E47AE241B999C0"
"29FD2067836DC4BC64F66998A3ECD197DAE36F808A2E5A4C5BF25DD580E52B1C39A8B"
"03772BF82D58929766F2DA04F0E616F92B3A0EB75661B8FF5DE1EB807C990F9E6BA99"
"1C8BAD5EB63B37E8663A4E22AA9DB2015D3DF8BED1C8313F85F13B9483C7A39C59243"
"6C8B13C23F78F55CE812795335059F7F527CA580306A0AEE5A6D957A91F498F64AA2E"
"FC6780716400E17C7EEA30B2E6523B902986995E003C2D919A7DC7C0122CE9410037A"
"6602B59A63B5C89473D4E02DE35C1F01B12ADB48A3D94D43693F08268FECCC78DAF6F"
"4C35FA32C538CD73FBF3CEA274B01179C02473486311956E5A0C78E44C59B2F34FF24"
"B0653A6379A2F5F6F51467CAE26D55CC5BBDCFC9BCFA7B8C5CBF82EBE7BD340C3DAE6"
"374D0692052C529AA33D7A6799C8F1F59C78575E51F707013026CC4F83F6B3328EE6F"
"B1AC91929A4491338E93D10EE6193014A73BA241A9A833EA835217894EB4FD4BDB890"
"4A5999928325D0AC31B6D58609EDD9D85E88F74B5BD6FA7BDD83C51EEB91633ED267A"
"CA2E103904BBE4C031A6483858FBAD74DACD01711F7B882749FFFBA0DB6C7D7109D82"
"989C7D4DB5A0F1E7506AC24C89CECAF231EFF99F96AD76E57DABDD3C2DFBA7BAA869A"
"771F561B165987E552824B0C914E708E425C3122051C8F84C5713500997DC5B325BAE"
"D208B224DFAEB2B034E58046A62F503FED6E")},
{// 2 usage info records
wvcdm::a2bs_hex(
"7290396E183156BDF830B7BF31BA762CB2675528C9004FD24A61DAFB587ABCF1D36F8"
"7795EE0B3DA0B425616A66C82349B2E3BB8841C1335536865F919ED2AE671487B608B"
"21A362D888E0AB4F7AB7175B82F108617C3503F175435788AECAF7FFBFE76995D93CD"
"79424A843A247A8D8A6054A5B5404C9C057AACAD91A203229"),
wvcdm::a2bs_hex(
"3478A2D76DEB90BE713B03A11037EA7C305D1AF65099E3F2B92C4D4443A8F481C1177"
"DEF0A3CB49BA5F1448A10AF1207AD2D361B4A1F961B4B1F215B76A9A5005B414EF45E"
"AFBCF2636ABFC01413B27DD11871103579F8C041A799E22888D9ADB798E92A5E29BC4"
"6DECBC90991C65FE151C49F18068C1B65D0E90A9ECDA9248B87C120D5FD8EC81D4D36"
"B529FB2DAD39E0D39578B13B158E2B07C752D86F1A9D8160C93930C1F4F9E1D0D8E2C"
"5AB308732EB27722A6BF8BE852624C2BE3E4FE85819B89BEBA6535FCFBE85FA63A57B"
"D0FBAF284C64FFD97A146B76B3F37B576FC091C03E2222FBD24C2211344B7E2417EFC"
"36C4A54DCCC460CF810E7EA8AC6386D6AB567C819FED88A22CE55EF9BBE62C2CBC7AE"
"EDE5E5A69FF3472418CE2F4514496C59D26E72F3BFE0131F"),
wvcdm::a2bs_hex(
"C45FDCB3296A0EBE24FF381E027E6E2EF1AC289C67D3B858330669A81E8131583D2F1"
"40FD64615BDED0ED8316ABFD9C7E887433E1CAA6EA8E0C4F87ADB2A7FC3CF6FF87A7F"
"02AFF03BF5DB640AD8DDB572C41532E673618DCD8C33EF2BFE4E25EE821DF7D742B09"
"90398543B16EFCDBB03C6327B79D3664CED442E894020F4410ECC178C92AAEDFE39DC"
"563AC226FE9E0EF22E1C896C4F2835CDFDCD50B6C4DBA2B27A3B65DE3963D0A5F6E44"
"2A3C32008AB9D1ACBE4F366990EB43F8EE213B71E98DA090282680ABDD649BECA8970"
"0764561379F1DD23490CE967632ECA349AF8E1CBFA1F3A4F39F453614C8FFB5A17975"
"6243CB1FDB515834229BC64917C47A2F2E1116FAAC13368015312C31FD41215106469"
"BEE77D0EF2FE10CF645B3E82902EAF53A676933D0EC433949C1833BE52E76602CC3E4"
"E784C002E20624BCE0F38F9CBC478439899DA7F15554D0ACADEC140C00C8FA8FC9886"
"2D9933938781B30CB9C76899B3A48DBF170DDA0A18ED37D77F048ABBC85CB19469638"
"C2A32AA3180CF3943BD6B8C5CB26F2EA70868F18B0707C882054141086997A1AE5B70"
"9D4D0AA2B358990F244BA76C8E40791D29A0C63C9EF620B97FDFFA9B671E5A65AFCC1"
"C94CAACE0443E9D91F14028935BEA3988831BEBBFD3EB7C3A5AC9605B3534712A0912"
"4345ACB09665E357E58946871BC140D365"),
wvcdm::a2bs_hex(
"0ADF0E080210012AD80E0AA9070A8001924B035FBDA56AE5EF0ED05A08DE7AECC8ABE"
"1835E0C4A548F7803937F4C3B4520EB7F3334FFCDFA00DE56408F09D5019FCE87072D"
"0DC6789817468974B2EA51EE3944B8D7E0A88E4F16EBB80F03BD845231A01E6146841"
"CBAEF0134DCD9300DB2D92732992C0F2310D8E386FB31C67B9477010DEF9D99C42725"
"89572A26A17E12AC021E6FFBE66FC6153E7749906EC8F684E819467E16CAF317F315D"
"B32B6D3FDD1A8E8A094174D92D063B88E4835EAB78BD09541EA7FE72F132EB7364E15"
"4BC1548FC40EC7092775531508C95F9ED5D76F36BC0C198C3A33A1F9415B343905D6B"
"E37645E6800F053B1DA9A20286EFCBBC320424ADF7FB6E3D5D8E86C35E576A1A2A37D"
"344A419C0F0034A1B5F767D3C61D90DCA1119E5024C34EDE8FA7DD128696D8C435410"
"F218E52A853AD214FD05D0F8B3CB4832CFCD97FE159E6DEE64CE82CDAEC0321AE71B3"
"BCBAE42DF9EA65E42E151827086EADE71C138B972CC3992CF9ADA944C063816352ED8"
"658D3FA07BE0F32239E74A65932B069AAC4E8386DB59154AF9AEF71448128C66E5104"
"45294F44E511BD9B1AF19D4D67E99363093BE888D4B2AB841CAFF252CAD13EDF8E1AF"
"40340FC62339728520E6C0C09907C26F3FB78287231661952A8B699E47AE241B999C0"
"29FD2067836DC4BC64F66998A3ECD197DAE36F808A2E5A4C5BF25DD580E52B1C39A8B"
"03772BF82D58929766F2DA04F0E616F92B3A0EB75661B8FF5DE1EB807C990F9E6BA99"
"1C8BAD5EB63B37E8663A4E22AA9DB2015D3DF8BED1C8313F85F13B9483C7A39C59243"
"6C8B13C23F78F55CE812795335059F7F527CA580306A0AEE5A6D957A91F498F64AA2E"
"FC6780716400E17C7EEA30B2E6523B902986995E003C2D919A7DC7C0122CE9410037A"
"6602B59A63B5C89473D4E02DE35C1F01B12ADB48A3D94D43693F08268FECCC78DAF6F"
"4C35FA32C538CD73FBF3CEA274B01179C02473486311956E5A0C78E44C59B2F34FF24"
"B0653A6379A2F5F6F51467CAE26D55CC5BBDCFC9BCFA7B8C5CBF82EBE7BD340C3DAE6"
"374D0692052C529AA33D7A6799C8F1F59C78575E51F707013026CC4F83F6B3328EE6F"
"B1AC91929A4491338E93D10EE6193014A73BA241A9A833EA835217894EB4FD4BDB890"
"4A5999928325D0AC31B6D58609EDD9D85E88F74B5BD6FA7BDD83C51EEB91633ED267A"
"CA2E103904BBE4C031A6483858FBAD74DACD01711F7B882749FFFBA0DB6C7D7109D82"
"989C7D4DB5A0F1E7506AC24C89CECAF231EFF99F96AD76E57DABDD3C2DFBA7BAA869A"
"771F561B165987E552824B0C914E708E425C30AA9070A80017290396E183156BDF830"
"B7BF31BA762CB2675528C9004FD24A61DAFB587ABCF1D36F87795EE0B3DA0B425616A"
"66C82349B2E3BB8841C1335536865F919ED2AE671487B608B21A362D888E0AB4F7AB7"
"175B82F108617C3503F175435788AECAF7FFBFE76995D93CD79424A843A247A8D8A60"
"54A5B5404C9C057AACAD91A20322912AC023478A2D76DEB90BE713B03A11037EA7C30"
"5D1AF65099E3F2B92C4D4443A8F481C1177DEF0A3CB49BA5F1448A10AF1207AD2D361"
"B4A1F961B4B1F215B76A9A5005B414EF45EAFBCF2636ABFC01413B27DD11871103579"
"F8C041A799E22888D9ADB798E92A5E29BC46DECBC90991C65FE151C49F18068C1B65D"
"0E90A9ECDA9248B87C120D5FD8EC81D4D36B529FB2DAD39E0D39578B13B158E2B07C7"
"52D86F1A9D8160C93930C1F4F9E1D0D8E2C5AB308732EB27722A6BF8BE852624C2BE3"
"E4FE85819B89BEBA6535FCFBE85FA63A57BD0FBAF284C64FFD97A146B76B3F37B576F"
"C091C03E2222FBD24C2211344B7E2417EFC36C4A54DCCC460CF810E7EA8AC6386D6AB"
"567C819FED88A22CE55EF9BBE62C2CBC7AEEDE5E5A69FF3472418CE2F4514496C59D2"
"6E72F3BFE0131F1AF403C45FDCB3296A0EBE24FF381E027E6E2EF1AC289C67D3B8583"
"30669A81E8131583D2F140FD64615BDED0ED8316ABFD9C7E887433E1CAA6EA8E0C4F8"
"7ADB2A7FC3CF6FF87A7F02AFF03BF5DB640AD8DDB572C41532E673618DCD8C33EF2BF"
"E4E25EE821DF7D742B0990398543B16EFCDBB03C6327B79D3664CED442E894020F441"
"0ECC178C92AAEDFE39DC563AC226FE9E0EF22E1C896C4F2835CDFDCD50B6C4DBA2B27"
"A3B65DE3963D0A5F6E442A3C32008AB9D1ACBE4F366990EB43F8EE213B71E98DA0902"
"82680ABDD649BECA89700764561379F1DD23490CE967632ECA349AF8E1CBFA1F3A4F3"
"9F453614C8FFB5A179756243CB1FDB515834229BC64917C47A2F2E1116FAAC1336801"
"5312C31FD41215106469BEE77D0EF2FE10CF645B3E82902EAF53A676933D0EC433949"
"C1833BE52E76602CC3E4E784C002E20624BCE0F38F9CBC478439899DA7F15554D0ACA"
"DEC140C00C8FA8FC98862D9933938781B30CB9C76899B3A48DBF170DDA0A18ED37D77"
"F048ABBC85CB19469638C2A32AA3180CF3943BD6B8C5CB26F2EA70868F18B0707C882"
"054141086997A1AE5B709D4D0AA2B358990F244BA76C8E40791D29A0C63C9EF620B97"
"FDFFA9B671E5A65AFCC1C94CAACE0443E9D91F14028935BEA3988831BEBBFD3EB7C3A"
"5AC9605B3534712A09124345ACB09665E357E58946871BC140D3651220464E4A1BB23"
"1A5B0287888B34CA0A8CF5396EB2B8313377DC5ED5C41A9B389A9")},
{// 3 usage info records
wvcdm::a2bs_hex(
"983358221FB8DBF892047F00AA661F217EEC4E7A1626E8F98E025509E4D65A685E7D9"
"B169B98B16934F6E43E0E0E854A3FA9EB8E9A9D08E9D9B3A6C766AA44F7C655879BA2"
"DF5F38732FB7EDCA66D8C13A855B15E32CC9389B7DD119BA1F2417825FF1F52970F8E"
"985D34DD353D2AC8B24267353E5B8406C098427C4559A90CC"),
wvcdm::a2bs_hex(
"483EAC68243092009D06FAB41DB594ACB22E068C9524810758ECFF8BAB7E1B1ACA988"
"C3987023F01EFEC11529C7326279742E805E755A08EBBD9AA322F305805BE1166AB45"
"CB156FB0A9E6734371F4028707EE01CF2FB08465707E7E5613DD90D74B0D02536E26C"
"F1261CDDA8713943F3620ECC54095C76F8CD3CE31948C3CC0C9EB5582A4D087A54B39"
"1B4CDCBC98E35830B5932F6CF8D16427EF115CFF0A99499513702DD54C758E53248BB"
"5D195F2A2DD1DB18F97562F1F9034E223CEDB1E09ED1B0FE26089C20ED43B5D87B51F"
"6FC6C9F86255FBF70DF233F2665D604355BF9740A3B755521102E0B485C5CCCA607A9"
"A1BEB757BEDEF12327C637D17D6401E3756719F99BBE69B9CE4C8E47C2AC771F35A8E"
"E3FC4D58B2B2269CF85728E4DA7231BC8F0FD7C50E2A1EE9"),
wvcdm::a2bs_hex(
"5826D3A95F78879292612BCE06D845D64285CD45A7EAA6C87A9DBC3290B0B6AC95315"
"809F8CC7938768F9BD342C62CD4CE055866394489D955247CB0535001D50EFF4FEDF0"
"9501C58569B1EB9AA2305A113A5F4D4524AD34148A2DC48D2F522937F44A57FC76F57"
"EB1D4819C438EA42C7F8974FC7D2FE61CAAB3E1F27172FE6B8675DF4CCF1329A6EFB3"
"1F686FB0DC0F8B552D78970708D50C82ADBE333B585F6DE5A0D01D106F8232EB9ED45"
"42A2DC5AA031CC44652E8A42EDCA5AB08B0B5CA61A922E69A119E556F6014642522EA"
"1550F6D6E63EB25ACC03A4DD3F22F4686ED525F994FABA87629AF5939C16BA68C0F09"
"3EFE033CD319180BF69FCB72AC5123EBCB9DCF1AF00F0A68E31FF5B18FA8CFF3DFBB7"
"DA45413799105D67FA78217710D2F6C33394DD4088100013295FF43CF0598E6FE5C05"
"F03417CCD031F01CF63BECD444C750DF198345F155AB2B2AB94394A3C0C0AE05E386D"
"E6CC565AE82398BD0E377D6ABE103B9D5E84582C3772584B759891FC4B121A113370E"
"2DF5372DD81FB6358C64B0F6EB8F26193CA119E4D9D3D38036FA450EE2047CB2CE265"
"0FF37DF85BE23D58C17379FEC08DC0648236A107AE66178EEBF78F05F3B898424FA02"
"668B51F838AFA90D367B5CB425372D8CC3790BEA8AFB8795251FA09340D85A7F0B003"
"134C838F08BB1054D18404C3F69130700E"),
wvcdm::a2bs_hex(
"0A8B16080210012A84160AA9070A8001924B035FBDA56AE5EF0ED05A08DE7AECC8ABE"
"1835E0C4A548F7803937F4C3B4520EB7F3334FFCDFA00DE56408F09D5019FCE87072D"
"0DC6789817468974B2EA51EE3944B8D7E0A88E4F16EBB80F03BD845231A01E6146841"
"CBAEF0134DCD9300DB2D92732992C0F2310D8E386FB31C67B9477010DEF9D99C42725"
"89572A26A17E12AC021E6FFBE66FC6153E7749906EC8F684E819467E16CAF317F315D"
"B32B6D3FDD1A8E8A094174D92D063B88E4835EAB78BD09541EA7FE72F132EB7364E15"
"4BC1548FC40EC7092775531508C95F9ED5D76F36BC0C198C3A33A1F9415B343905D6B"
"E37645E6800F053B1DA9A20286EFCBBC320424ADF7FB6E3D5D8E86C35E576A1A2A37D"
"344A419C0F0034A1B5F767D3C61D90DCA1119E5024C34EDE8FA7DD128696D8C435410"
"F218E52A853AD214FD05D0F8B3CB4832CFCD97FE159E6DEE64CE82CDAEC0321AE71B3"
"BCBAE42DF9EA65E42E151827086EADE71C138B972CC3992CF9ADA944C063816352ED8"
"658D3FA07BE0F32239E74A65932B069AAC4E8386DB59154AF9AEF71448128C66E5104"
"45294F44E511BD9B1AF19D4D67E99363093BE888D4B2AB841CAFF252CAD13EDF8E1AF"
"40340FC62339728520E6C0C09907C26F3FB78287231661952A8B699E47AE241B999C0"
"29FD2067836DC4BC64F66998A3ECD197DAE36F808A2E5A4C5BF25DD580E52B1C39A8B"
"03772BF82D58929766F2DA04F0E616F92B3A0EB75661B8FF5DE1EB807C990F9E6BA99"
"1C8BAD5EB63B37E8663A4E22AA9DB2015D3DF8BED1C8313F85F13B9483C7A39C59243"
"6C8B13C23F78F55CE812795335059F7F527CA580306A0AEE5A6D957A91F498F64AA2E"
"FC6780716400E17C7EEA30B2E6523B902986995E003C2D919A7DC7C0122CE9410037A"
"6602B59A63B5C89473D4E02DE35C1F01B12ADB48A3D94D43693F08268FECCC78DAF6F"
"4C35FA32C538CD73FBF3CEA274B01179C02473486311956E5A0C78E44C59B2F34FF24"
"B0653A6379A2F5F6F51467CAE26D55CC5BBDCFC9BCFA7B8C5CBF82EBE7BD340C3DAE6"
"374D0692052C529AA33D7A6799C8F1F59C78575E51F707013026CC4F83F6B3328EE6F"
"B1AC91929A4491338E93D10EE6193014A73BA241A9A833EA835217894EB4FD4BDB890"
"4A5999928325D0AC31B6D58609EDD9D85E88F74B5BD6FA7BDD83C51EEB91633ED267A"
"CA2E103904BBE4C031A6483858FBAD74DACD01711F7B882749FFFBA0DB6C7D7109D82"
"989C7D4DB5A0F1E7506AC24C89CECAF231EFF99F96AD76E57DABDD3C2DFBA7BAA869A"
"771F561B165987E552824B0C914E708E425C30AA9070A80017290396E183156BDF830"
"B7BF31BA762CB2675528C9004FD24A61DAFB587ABCF1D36F87795EE0B3DA0B425616A"
"66C82349B2E3BB8841C1335536865F919ED2AE671487B608B21A362D888E0AB4F7AB7"
"175B82F108617C3503F175435788AECAF7FFBFE76995D93CD79424A843A247A8D8A60"
"54A5B5404C9C057AACAD91A20322912AC023478A2D76DEB90BE713B03A11037EA7C30"
"5D1AF65099E3F2B92C4D4443A8F481C1177DEF0A3CB49BA5F1448A10AF1207AD2D361"
"B4A1F961B4B1F215B76A9A5005B414EF45EAFBCF2636ABFC01413B27DD11871103579"
"F8C041A799E22888D9ADB798E92A5E29BC46DECBC90991C65FE151C49F18068C1B65D"
"0E90A9ECDA9248B87C120D5FD8EC81D4D36B529FB2DAD39E0D39578B13B158E2B07C7"
"52D86F1A9D8160C93930C1F4F9E1D0D8E2C5AB308732EB27722A6BF8BE852624C2BE3"
"E4FE85819B89BEBA6535FCFBE85FA63A57BD0FBAF284C64FFD97A146B76B3F37B576F"
"C091C03E2222FBD24C2211344B7E2417EFC36C4A54DCCC460CF810E7EA8AC6386D6AB"
"567C819FED88A22CE55EF9BBE62C2CBC7AEEDE5E5A69FF3472418CE2F4514496C59D2"
"6E72F3BFE0131F1AF403C45FDCB3296A0EBE24FF381E027E6E2EF1AC289C67D3B8583"
"30669A81E8131583D2F140FD64615BDED0ED8316ABFD9C7E887433E1CAA6EA8E0C4F8"
"7ADB2A7FC3CF6FF87A7F02AFF03BF5DB640AD8DDB572C41532E673618DCD8C33EF2BF"
"E4E25EE821DF7D742B0990398543B16EFCDBB03C6327B79D3664CED442E894020F441"
"0ECC178C92AAEDFE39DC563AC226FE9E0EF22E1C896C4F2835CDFDCD50B6C4DBA2B27"
"A3B65DE3963D0A5F6E442A3C32008AB9D1ACBE4F366990EB43F8EE213B71E98DA0902"
"82680ABDD649BECA89700764561379F1DD23490CE967632ECA349AF8E1CBFA1F3A4F3"
"9F453614C8FFB5A179756243CB1FDB515834229BC64917C47A2F2E1116FAAC1336801"
"5312C31FD41215106469BEE77D0EF2FE10CF645B3E82902EAF53A676933D0EC433949"
"C1833BE52E76602CC3E4E784C002E20624BCE0F38F9CBC478439899DA7F15554D0ACA"
"DEC140C00C8FA8FC98862D9933938781B30CB9C76899B3A48DBF170DDA0A18ED37D77"
"F048ABBC85CB19469638C2A32AA3180CF3943BD6B8C5CB26F2EA70868F18B0707C882"
"054141086997A1AE5B709D4D0AA2B358990F244BA76C8E40791D29A0C63C9EF620B97"
"FDFFA9B671E5A65AFCC1C94CAACE0443E9D91F14028935BEA3988831BEBBFD3EB7C3A"
"5AC9605B3534712A09124345ACB09665E357E58946871BC140D3650AA9070A8001983"
"358221FB8DBF892047F00AA661F217EEC4E7A1626E8F98E025509E4D65A685E7D9B16"
"9B98B16934F6E43E0E0E854A3FA9EB8E9A9D08E9D9B3A6C766AA44F7C655879BA2DF5"
"F38732FB7EDCA66D8C13A855B15E32CC9389B7DD119BA1F2417825FF1F52970F8E985"
"D34DD353D2AC8B24267353E5B8406C098427C4559A90CC12AC02483EAC68243092009"
"D06FAB41DB594ACB22E068C9524810758ECFF8BAB7E1B1ACA988C3987023F01EFEC11"
"529C7326279742E805E755A08EBBD9AA322F305805BE1166AB45CB156FB0A9E673437"
"1F4028707EE01CF2FB08465707E7E5613DD90D74B0D02536E26CF1261CDDA8713943F"
"3620ECC54095C76F8CD3CE31948C3CC0C9EB5582A4D087A54B391B4CDCBC98E35830B"
"5932F6CF8D16427EF115CFF0A99499513702DD54C758E53248BB5D195F2A2DD1DB18F"
"97562F1F9034E223CEDB1E09ED1B0FE26089C20ED43B5D87B51F6FC6C9F86255FBF70"
"DF233F2665D604355BF9740A3B755521102E0B485C5CCCA607A9A1BEB757BEDEF1232"
"7C637D17D6401E3756719F99BBE69B9CE4C8E47C2AC771F35A8EE3FC4D58B2B2269CF"
"85728E4DA7231BC8F0FD7C50E2A1EE91AF4035826D3A95F78879292612BCE06D845D6"
"4285CD45A7EAA6C87A9DBC3290B0B6AC95315809F8CC7938768F9BD342C62CD4CE055"
"866394489D955247CB0535001D50EFF4FEDF09501C58569B1EB9AA2305A113A5F4D45"
"24AD34148A2DC48D2F522937F44A57FC76F57EB1D4819C438EA42C7F8974FC7D2FE61"
"CAAB3E1F27172FE6B8675DF4CCF1329A6EFB31F686FB0DC0F8B552D78970708D50C82"
"ADBE333B585F6DE5A0D01D106F8232EB9ED4542A2DC5AA031CC44652E8A42EDCA5AB0"
"8B0B5CA61A922E69A119E556F6014642522EA1550F6D6E63EB25ACC03A4DD3F22F468"
"6ED525F994FABA87629AF5939C16BA68C0F093EFE033CD319180BF69FCB72AC5123EB"
"CB9DCF1AF00F0A68E31FF5B18FA8CFF3DFBB7DA45413799105D67FA78217710D2F6C3"
"3394DD4088100013295FF43CF0598E6FE5C05F03417CCD031F01CF63BECD444C750DF"
"198345F155AB2B2AB94394A3C0C0AE05E386DE6CC565AE82398BD0E377D6ABE103B9D"
"5E84582C3772584B759891FC4B121A113370E2DF5372DD81FB6358C64B0F6EB8F2619"
"3CA119E4D9D3D38036FA450EE2047CB2CE2650FF37DF85BE23D58C17379FEC08DC064"
"8236A107AE66178EEBF78F05F3B898424FA02668B51F838AFA90D367B5CB425372D8C"
"C3790BEA8AFB8795251FA09340D85A7F0B003134C838F08BB1054D18404C3F6913070"
"0E12202FF1FBA9926A24A1F79970EC427DDF87B4421488F7952499BC33CEB282D9E48"
"A")}};
} // namespace } // namespace
class MockFile : public File { class MockFile : public File {
@@ -1033,6 +1316,9 @@ class DeviceFilesSecurityLevelTest
: public DeviceFilesTest, : public DeviceFilesTest,
public ::testing::WithParamInterface<CdmSecurityLevel> {}; public ::testing::WithParamInterface<CdmSecurityLevel> {};
class DeviceFilesUsageInfoTest : public DeviceFilesTest,
public ::testing::WithParamInterface<int> {};
MATCHER(IsCreateFileFlagSet, "") { return File::kCreate & arg; } MATCHER(IsCreateFileFlagSet, "") { return File::kCreate & arg; }
MATCHER(IsBinaryFileFlagSet, "") { return File::kBinary & arg; } MATCHER(IsBinaryFileFlagSet, "") { return File::kBinary & arg; }
MATCHER_P(IsStrEq, str, "") { MATCHER_P(IsStrEq, str, "") {
@@ -1040,18 +1326,29 @@ MATCHER_P(IsStrEq, str, "") {
// as well as pointer to data but that will introduce a dependency on tr1 // as well as pointer to data but that will introduce a dependency on tr1
return memcmp(arg, str.c_str(), str.size()) == 0; return memcmp(arg, str.c_str(), str.size()) == 0;
} }
MATCHER_P2(Contains, str1, str2, "") { MATCHER_P3(Contains, str1, str2, size, "") {
// Estimating the length of data. We can have gmock provide length // Estimating the length of data. We can have gmock provide length
// as well as pointer to data but that will introduce a dependency on tr1 // as well as pointer to data but that will introduce a dependency on tr1
std::string data(arg, str1.size() + str2.size() + kProtobufEstimatedLen); std::string data(
arg, size + str1.size() + str2.size() + kProtobufEstimatedOverhead);
return (data.find(str1) != std::string::npos && return (data.find(str1) != std::string::npos &&
data.find(str2) != std::string::npos); data.find(str2) != std::string::npos);
} }
MATCHER_P4(Contains, str1, str2, str3, size, "") {
// Estimating the length of data. We can have gmock provide length
// as well as pointer to data but that will introduce a dependency on tr1
std::string data(arg, size + str1.size() + str2.size() + str3.size() +
kProtobufEstimatedOverhead);
return (data.find(str1) != std::string::npos &&
data.find(str2) != std::string::npos &&
data.find(str3) != std::string::npos);
}
MATCHER_P6(Contains, str1, str2, str3, str4, str5, str6, "") { MATCHER_P6(Contains, str1, str2, str3, str4, str5, str6, "") {
// Estimating the length of data. We can have gmock provide length // Estimating the length of data. We can have gmock provide length
// as well as pointer to data but that will introduce a dependency on tr1 // as well as pointer to data but that will introduce a dependency on tr1
std::string data(arg, str1.size() + str2.size() + str3.size() + str4.size() + std::string data(arg, str1.size() + str2.size() + str3.size() + str4.size() +
str5.size() + str6.size() + kProtobufEstimatedLen); str5.size() + str6.size() +
kProtobufEstimatedOverhead);
return (data.find(str1) != std::string::npos && return (data.find(str1) != std::string::npos &&
data.find(str2) != std::string::npos && data.find(str2) != std::string::npos &&
data.find(str3) != std::string::npos && data.find(str3) != std::string::npos &&
@@ -1080,14 +1377,15 @@ TEST_P(DeviceFilesStoreTest, StoreCertificate) {
EXPECT_CALL(file, Open(StrEq(device_certificate_path), EXPECT_CALL(file, Open(StrEq(device_certificate_path),
AllOf(IsCreateFileFlagSet(), IsBinaryFileFlagSet()))) AllOf(IsCreateFileFlagSet(), IsBinaryFileFlagSet())))
.WillOnce(Return(true)); .WillOnce(Return(true));
EXPECT_CALL(file, Write(Contains(certificate, wrapped_private_key), EXPECT_CALL(file, Write(Contains(certificate, wrapped_private_key, 0),
Gt(certificate.size() + wrapped_private_key.size()))) Gt(certificate.size() + wrapped_private_key.size())))
.WillOnce(ReturnArg<1>()); .WillOnce(ReturnArg<1>());
EXPECT_CALL(file, Close()).Times(1); EXPECT_CALL(file, Close()).Times(1);
EXPECT_CALL(file, Read(_, _)).Times(0); EXPECT_CALL(file, Read(_, _)).Times(0);
DeviceFiles device_files; DeviceFiles device_files;
EXPECT_TRUE(device_files.Init(&file, kSecurityLevelL1)); EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
device_files.SetTestFile(&file);
EXPECT_TRUE(device_files.StoreCertificate(certificate, wrapped_private_key)); EXPECT_TRUE(device_files.StoreCertificate(certificate, wrapped_private_key));
} }
@@ -1112,7 +1410,8 @@ TEST_F(DeviceFilesTest, ReadCertificate) {
EXPECT_CALL(file, Write(_, _)).Times(0); EXPECT_CALL(file, Write(_, _)).Times(0);
DeviceFiles device_files; DeviceFiles device_files;
EXPECT_TRUE(device_files.Init(&file, kSecurityLevelL1)); EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
device_files.SetTestFile(&file);
std::string certificate, wrapped_private_key; std::string certificate, wrapped_private_key;
ASSERT_TRUE( ASSERT_TRUE(
@@ -1141,14 +1440,15 @@ TEST_P(DeviceFilesSecurityLevelTest, SecurityLevel) {
EXPECT_CALL(file, Open(StrEq(device_certificate_path), EXPECT_CALL(file, Open(StrEq(device_certificate_path),
AllOf(IsCreateFileFlagSet(), IsBinaryFileFlagSet()))) AllOf(IsCreateFileFlagSet(), IsBinaryFileFlagSet())))
.WillOnce(Return(true)); .WillOnce(Return(true));
EXPECT_CALL(file, Write(Contains(certificate, wrapped_private_key), EXPECT_CALL(file, Write(Contains(certificate, wrapped_private_key, 0),
Gt(certificate.size() + wrapped_private_key.size()))) Gt(certificate.size() + wrapped_private_key.size())))
.WillOnce(ReturnArg<1>()); .WillOnce(ReturnArg<1>());
EXPECT_CALL(file, Close()).Times(1); EXPECT_CALL(file, Close()).Times(1);
EXPECT_CALL(file, Read(_, _)).Times(0); EXPECT_CALL(file, Read(_, _)).Times(0);
DeviceFiles device_files; DeviceFiles device_files;
EXPECT_TRUE(device_files.Init(&file, security_level)); EXPECT_TRUE(device_files.Init(security_level));
device_files.SetTestFile(&file);
EXPECT_TRUE(device_files.StoreCertificate(certificate, wrapped_private_key)); EXPECT_TRUE(device_files.StoreCertificate(certificate, wrapped_private_key));
} }
@@ -1188,7 +1488,8 @@ TEST_P(DeviceFilesStoreTest, StoreLicense) {
EXPECT_CALL(file, Read(_, _)).Times(0); EXPECT_CALL(file, Read(_, _)).Times(0);
DeviceFiles device_files; DeviceFiles device_files;
EXPECT_TRUE(device_files.Init(&file, kSecurityLevelL1)); EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
device_files.SetTestFile(&file);
EXPECT_TRUE(device_files.StoreLicense( EXPECT_TRUE(device_files.StoreLicense(
license_test_data[license_num].key_set_id, license_test_data[license_num].key_set_id,
license_test_data[license_num].license_state, license_test_data[license_num].license_state,
@@ -1206,7 +1507,8 @@ INSTANTIATE_TEST_CASE_P(StoreLicense, DeviceFilesStoreTest,
TEST_F(DeviceFilesTest, StoreLicenses) { TEST_F(DeviceFilesTest, StoreLicenses) {
MockFile file; MockFile file;
EXPECT_CALL(file, IsDirectory(StrEq(device_base_path_))) EXPECT_CALL(file, IsDirectory(StrEq(device_base_path_)))
.Times(kNumberOfLicenses).WillRepeatedly(Return(true)); .Times(kNumberOfLicenses)
.WillRepeatedly(Return(true));
EXPECT_CALL(file, CreateDirectory(_)).Times(0); EXPECT_CALL(file, CreateDirectory(_)).Times(0);
for (size_t i = 0; i < kNumberOfLicenses; ++i) { for (size_t i = 0; i < kNumberOfLicenses; ++i) {
@@ -1231,7 +1533,8 @@ TEST_F(DeviceFilesTest, StoreLicenses) {
EXPECT_CALL(file, Read(_, _)).Times(0); EXPECT_CALL(file, Read(_, _)).Times(0);
DeviceFiles device_files; DeviceFiles device_files;
EXPECT_TRUE(device_files.Init(&file, kSecurityLevelL1)); EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
device_files.SetTestFile(&file);
for (size_t i = 0; i < kNumberOfLicenses; i++) { for (size_t i = 0; i < kNumberOfLicenses; i++) {
EXPECT_TRUE(device_files.StoreLicense( EXPECT_TRUE(device_files.StoreLicense(
license_test_data[i].key_set_id, license_test_data[i].license_state, license_test_data[i].key_set_id, license_test_data[i].license_state,
@@ -1266,7 +1569,8 @@ TEST_F(DeviceFilesTest, RetrieveLicenses) {
EXPECT_CALL(file, Write(_, _)).Times(0); EXPECT_CALL(file, Write(_, _)).Times(0);
DeviceFiles device_files; DeviceFiles device_files;
EXPECT_TRUE(device_files.Init(&file, kSecurityLevelL1)); EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
device_files.SetTestFile(&file);
DeviceFiles::LicenseState license_state; DeviceFiles::LicenseState license_state;
CdmInitData pssh_data; CdmInitData pssh_data;
CdmKeyMessage key_request; CdmKeyMessage key_request;
@@ -1318,12 +1622,11 @@ TEST_F(DeviceFilesTest, SecurityLevelPathBackwardCompatibility) {
std::string old_path = base_path + DeviceFiles::GetCertificateFileName(); std::string old_path = base_path + DeviceFiles::GetCertificateFileName();
old_files.push_back(DeviceFiles::GetCertificateFileName()); old_files.push_back(DeviceFiles::GetCertificateFileName());
EXPECT_CALL(file, IsRegularFile(StrEq(old_path))) EXPECT_CALL(file, IsRegularFile(StrEq(old_path))).WillOnce(Return(true));
.WillOnce(Return(true));
EXPECT_CALL(file, Remove(StrEq(old_path))).WillOnce(Return(true)); EXPECT_CALL(file, Remove(StrEq(old_path))).WillOnce(Return(true));
for (size_t i = 0; i < security_dirs.size(); ++i) { for (size_t i = 0; i < security_dirs.size(); ++i) {
new_path = base_path + security_dirs[i] + new_path =
DeviceFiles::GetCertificateFileName(); base_path + security_dirs[i] + DeviceFiles::GetCertificateFileName();
EXPECT_CALL(file, Copy(StrEq(old_path), StrEq(new_path))) EXPECT_CALL(file, Copy(StrEq(old_path), StrEq(new_path)))
.WillOnce(Return(true)); .WillOnce(Return(true));
} }
@@ -1357,7 +1660,8 @@ TEST_F(DeviceFilesTest, SecurityLevelPathBackwardCompatibility) {
EXPECT_CALL(file, Write(_, _)).Times(0); EXPECT_CALL(file, Write(_, _)).Times(0);
DeviceFiles device_files; DeviceFiles device_files;
EXPECT_TRUE(device_files.Init(&file, kSecurityLevelL1)); EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
device_files.SetTestFile(&file);
Properties::Init(); Properties::Init();
std::string certificate, wrapped_private_key; std::string certificate, wrapped_private_key;
@@ -1371,12 +1675,14 @@ TEST_F(DeviceFilesTest, UpdateLicenseState) {
license_update_test_data[0].key_set_id + license_update_test_data[0].key_set_id +
DeviceFiles::GetLicenseFileNameExtension(); DeviceFiles::GetLicenseFileNameExtension();
EXPECT_CALL(file, IsDirectory(StrEq(device_base_path_))).Times(2) EXPECT_CALL(file, IsDirectory(StrEq(device_base_path_)))
.Times(2)
.WillRepeatedly(Return(true)); .WillRepeatedly(Return(true));
EXPECT_CALL(file, CreateDirectory(_)).Times(0); EXPECT_CALL(file, CreateDirectory(_)).Times(0);
EXPECT_CALL(file, Open(StrEq(license_path), EXPECT_CALL(file, Open(StrEq(license_path),
AllOf(IsCreateFileFlagSet(), IsBinaryFileFlagSet()))) AllOf(IsCreateFileFlagSet(), IsBinaryFileFlagSet())))
.Times(2).WillRepeatedly(Return(true)); .Times(2)
.WillRepeatedly(Return(true));
EXPECT_CALL(file, Write(IsStrEq(license_update_test_data[0].file_data), EXPECT_CALL(file, Write(IsStrEq(license_update_test_data[0].file_data),
Eq(license_update_test_data[0].file_data.size()))) Eq(license_update_test_data[0].file_data.size())))
.WillOnce(ReturnArg<1>()); .WillOnce(ReturnArg<1>());
@@ -1387,7 +1693,8 @@ TEST_F(DeviceFilesTest, UpdateLicenseState) {
EXPECT_CALL(file, Read(_, _)).Times(0); EXPECT_CALL(file, Read(_, _)).Times(0);
DeviceFiles device_files; DeviceFiles device_files;
EXPECT_TRUE(device_files.Init(&file, kSecurityLevelL1)); EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
device_files.SetTestFile(&file);
EXPECT_TRUE(device_files.StoreLicense( EXPECT_TRUE(device_files.StoreLicense(
license_update_test_data[0].key_set_id, license_update_test_data[0].key_set_id,
license_update_test_data[0].license_state, license_update_test_data[0].license_state,
@@ -1417,7 +1724,9 @@ TEST_F(DeviceFilesTest, DeleteLicense) {
size_t size = license_test_data[0].file_data.size(); size_t size = license_test_data[0].file_data.size();
EXPECT_CALL(file, Exists(StrEq(license_path))).Times(2).WillOnce(Return(true)) EXPECT_CALL(file, Exists(StrEq(license_path)))
.Times(2)
.WillOnce(Return(true))
.WillOnce(Return(false)); .WillOnce(Return(false));
EXPECT_CALL(file, FileSize(StrEq(license_path))).WillOnce(Return(size)); EXPECT_CALL(file, FileSize(StrEq(license_path))).WillOnce(Return(size));
EXPECT_CALL(file, Open(StrEq(license_path), IsBinaryFileFlagSet())) EXPECT_CALL(file, Open(StrEq(license_path), IsBinaryFileFlagSet()))
@@ -1431,7 +1740,8 @@ TEST_F(DeviceFilesTest, DeleteLicense) {
EXPECT_CALL(file, Write(_, _)).Times(0); EXPECT_CALL(file, Write(_, _)).Times(0);
DeviceFiles device_files; DeviceFiles device_files;
EXPECT_TRUE(device_files.Init(&file, kSecurityLevelL1)); EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
device_files.SetTestFile(&file);
DeviceFiles::LicenseState license_state; DeviceFiles::LicenseState license_state;
CdmInitData pssh_data; CdmInitData pssh_data;
CdmKeyMessage key_request; CdmKeyMessage key_request;
@@ -1455,4 +1765,154 @@ TEST_F(DeviceFilesTest, DeleteLicense) {
EXPECT_FALSE(device_files.LicenseExists(license_test_data[0].key_set_id)); EXPECT_FALSE(device_files.LicenseExists(license_test_data[0].key_set_id));
} }
TEST_P(DeviceFilesUsageInfoTest, Read) {
MockFile file;
std::string path = device_base_path_ + DeviceFiles::GetUsageInfoFileName();
int index = GetParam();
std::string data;
if (index >= 0) {
data = kUsageInfoTestData[index].file_data;
}
if (index >= 0) {
EXPECT_CALL(file, Exists(StrEq(path))).WillOnce(Return(true));
EXPECT_CALL(file, FileSize(StrEq(path))).WillOnce(Return(data.size()));
EXPECT_CALL(file, Open(StrEq(path), IsBinaryFileFlagSet()))
.WillOnce(Return(true));
EXPECT_CALL(file, Read(NotNull(), Eq(data.size()))).WillOnce(DoAll(
SetArrayArgument<0>(data.begin(), data.end()), Return(data.size())));
EXPECT_CALL(file, Close()).Times(1);
} else {
EXPECT_CALL(file, Exists(StrEq(path))).Times(2).WillRepeatedly(
Return(false));
EXPECT_CALL(file, FileSize(_)).Times(0);
EXPECT_CALL(file, Open(_, _)).Times(0);
EXPECT_CALL(file, Close()).Times(0);
}
EXPECT_CALL(file, Write(_, _)).Times(0);
DeviceFiles device_files;
EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
device_files.SetTestFile(&file);
std::vector<std::pair<CdmKeyMessage, CdmKeyResponse> > license_info;
ASSERT_TRUE(device_files.RetrieveUsageInfo(&license_info));
if (index >= 0) {
EXPECT_EQ(index, license_info.size());
for (size_t i = 0; i < license_info.size(); ++i) {
bool found = false;
for (size_t j = 0; j <= static_cast<size_t>(index); ++j) {
if ((license_info[i].first.compare(
kUsageInfoTestData[j].license_request) == 0) &&
(license_info[i].second.compare(kUsageInfoTestData[j].license) ==
0)) {
found = true;
}
}
EXPECT_TRUE(found);
}
} else {
EXPECT_EQ(0, license_info.size());
}
}
TEST_P(DeviceFilesUsageInfoTest, Store) {
MockFile file;
std::string pst(GenerateRandomData(kProviderSessionTokenLen));
std::string license_request(GenerateRandomData(kLicenseRequestLen));
std::string license(GenerateRandomData(kLicenseLen));
std::string path = device_base_path_ + DeviceFiles::GetUsageInfoFileName();
int index = GetParam();
std::string data;
if (index >= 0) {
data = kUsageInfoTestData[index].file_data;
}
EXPECT_CALL(file, IsDirectory(StrEq(device_base_path_)))
.WillRepeatedly(Return(true));
EXPECT_CALL(file, CreateDirectory(_)).Times(0);
EXPECT_CALL(file, Exists(StrEq(path))).WillOnce(Return(index >= 0));
if (index >= 0) {
EXPECT_CALL(file, FileSize(StrEq(path))).WillOnce(Return(data.size()));
EXPECT_CALL(file, Open(StrEq(path), IsBinaryFileFlagSet()))
.Times(2)
.WillRepeatedly(Return(true));
EXPECT_CALL(file, Read(NotNull(), Eq(data.size()))).WillOnce(DoAll(
SetArrayArgument<0>(data.begin(), data.end()), Return(data.size())));
EXPECT_CALL(file, Close()).Times(2);
} else {
EXPECT_CALL(file, FileSize(_)).Times(0);
EXPECT_CALL(file, Open(_, _)).Times(1).WillOnce(Return(true));
EXPECT_CALL(file, Close()).Times(1);
}
EXPECT_CALL(file, Write(Contains(pst, license_request, license, data.size()),
Gt(pst.size() + license_request.size() +
license.size()))).WillOnce(ReturnArg<1>());
DeviceFiles device_files;
EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
device_files.SetTestFile(&file);
ASSERT_TRUE(device_files.StoreUsageInfo(pst, license_request, license));
}
TEST_P(DeviceFilesUsageInfoTest, Delete) {
MockFile file;
std::string path = device_base_path_ + DeviceFiles::GetUsageInfoFileName();
int index = GetParam();
if (index < 0) return;
std::string data, pst, prev_data, prev_pst, prev_license;
if (index >= 0) {
data = kUsageInfoTestData[index].file_data;
if (index >= 1) {
pst = kUsageInfoTestData[index].provider_session_token;
prev_data = kUsageInfoTestData[index - 1].file_data;
prev_pst = kUsageInfoTestData[index - 1].provider_session_token;
prev_license = kUsageInfoTestData[index - 1].license;
}
}
EXPECT_CALL(file, IsDirectory(StrEq(device_base_path_)))
.WillRepeatedly(Return(true));
EXPECT_CALL(file, CreateDirectory(_)).Times(0);
EXPECT_CALL(file, Exists(StrEq(path))).WillOnce(Return(index >= 0));
EXPECT_CALL(file, FileSize(StrEq(path))).WillOnce(Return(data.size()));
if (index >= 1) {
EXPECT_CALL(file, Open(StrEq(path), IsBinaryFileFlagSet()))
.Times(2)
.WillRepeatedly(Return(true));
EXPECT_CALL(file, Write(Contains(prev_pst, prev_license, prev_data.size()),
Gt(prev_pst.size() + prev_license.size())))
.WillOnce(ReturnArg<1>());
EXPECT_CALL(file, Close()).Times(2);
} else {
EXPECT_CALL(file, Open(StrEq(path), IsBinaryFileFlagSet()))
.WillOnce(Return(true));
EXPECT_CALL(file, Write(_, _)).Times(0);
EXPECT_CALL(file, Close()).Times(1);
}
EXPECT_CALL(file, Read(NotNull(), Eq(data.size()))).WillOnce(DoAll(
SetArrayArgument<0>(data.begin(), data.end()), Return(data.size())));
DeviceFiles device_files;
EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
device_files.SetTestFile(&file);
if (index >= 1) {
ASSERT_TRUE(device_files.DeleteUsageInfo(pst));
} else {
ASSERT_FALSE(device_files.DeleteUsageInfo(pst));
}
}
INSTANTIATE_TEST_CASE_P(UsageInfo, DeviceFilesUsageInfoTest,
::testing::Values(-1, 0, 1, 2, 3));
} // namespace wvcdm } // namespace wvcdm

View File

@@ -82,9 +82,9 @@ class WvContentDecryptionModule : public TimerHandler {
std::string* wrapped_key); std::string* wrapped_key);
// Secure stop related methods // Secure stop related methods
virtual CdmResponseType GetSecureStops(CdmSecureStops* secure_stops); virtual CdmResponseType GetUsageInfo(CdmUsageInfo* usage_info);
virtual CdmResponseType ReleaseSecureStops( virtual CdmResponseType ReleaseUsageInfo(
const CdmSecureStopReleaseMessage& message); const CdmUsageInfoReleaseMessage& message);
// Accept encrypted buffer and decrypt data. // Accept encrypted buffer and decrypt data.
// Decryption parameters that need to be specified are // Decryption parameters that need to be specified are

View File

@@ -149,14 +149,14 @@ CdmResponseType WvContentDecryptionModule::HandleProvisioningResponse(
return cdm_engine_->HandleProvisioningResponse(response, cert, wrapped_key); return cdm_engine_->HandleProvisioningResponse(response, cert, wrapped_key);
} }
CdmResponseType WvContentDecryptionModule::GetSecureStops( CdmResponseType WvContentDecryptionModule::GetUsageInfo(
CdmSecureStops* secure_stops) { CdmUsageInfo* usage_info) {
return cdm_engine_->GetSecureStops(secure_stops); return cdm_engine_->GetUsageInfo(usage_info);
} }
CdmResponseType WvContentDecryptionModule::ReleaseSecureStops( CdmResponseType WvContentDecryptionModule::ReleaseUsageInfo(
const CdmSecureStopReleaseMessage& message) { const CdmUsageInfoReleaseMessage& message) {
return cdm_engine_->ReleaseSecureStops(message); return cdm_engine_->ReleaseUsageInfo(message);
} }
CdmResponseType WvContentDecryptionModule::Decrypt( CdmResponseType WvContentDecryptionModule::Decrypt(

View File

@@ -236,6 +236,114 @@ SubSampleInfo single_encrypted_sub_sample_icp = {
"58b938c2e3ca4c2ce48942da97f9e45797f2c074ac6004734e93784a48af6160"), "58b938c2e3ca4c2ce48942da97f9e45797f2c074ac6004734e93784a48af6160"),
wvcdm::a2b_hex("4cca615fc013102892f91efee936639b"), 0}; wvcdm::a2b_hex("4cca615fc013102892f91efee936639b"), 0};
SubSampleInfo usage_info_sub_samples_icp[] = {
{true, 1, true, true, false,
wvcdm::a2bs_hex("E82DDD1D07CBB31CDD31EBAAE0894609"),
wvcdm::a2b_hex(
"fe8670a01c86906c056b4bf85ad278464c4eb79c60de1da8480e66e78561350e"
"a25ae19a001f834c43aaeadf900b3c5a6745e885a4d1d1ae5bafac08dc1d60e5"
"f3465da303909ec4b09023490471f670b615d77db844192854fdab52b7806203"
"89b374594bbb6a2f2fcc31036d7cb8a3f80c0e27637b58a7650028fbf2470d68"
"1bbd77934af165d215ef325c74438c9d99a20fc628792db28c05ed5deff7d9d4"
"dba02ddb6cf11dc6e78cb5200940af9a2321c3a7c4c79be67b54a744dae1209c"
"fa02fc250ce18d30c7da9c3a4a6c9619bf8561a42ff1e55a7b14fa3c8de69196"
"c2b8e3ff672fc37003b479da5d567b7199917dbe5aa402890ebb066bce140b33"),
wvcdm::a2b_hex(
"d08733bd0ef671f467906b50ff8322091400f86fd6f016fea2b86e33923775b3"
"ebb4c8c6f3ba8b78dd200a74d3872a40264ab99e1d422e4f819abb7f249114aa"
"b334420b37c86ce81938615ab9d3a6b2de8db545cd88e35091031e73016fb386"
"1b754298329b52dbe483de3a532277815e659f3e05e89257333225b933d92e15"
"ef2deff287a192d2c8fc942a29a5f3a1d54440ac6385de7b34bb650b889e4ae9"
"58c957b5f5ff268f445c0a6b825fcad55290cb7b5c9814bc4c72984dcf4c8fd7"
"5f511c173b2e0a3163b18a1eac58539e5c188aeb0751b946ad4dcd08ea777a7f"
"37326df26fa509343faa98dff667629f557873f1284903202e451227ef465a62"),
wvcdm::a2b_hex("7362b5140c4ce0cd5f863858668d3f1a"), 0},
{true, 1, true, true, false,
wvcdm::a2bs_hex("04B2B456405CAD7170BE848CA75AA2DF"),
wvcdm::a2b_hex(
"ccb68f97b03e7af1a9e208d91655ba645cc5a5d454f3cb7c3d621e98a7592d90"
"4ff7023555f0e99bcf3918948f4fca7a430faf17d7d67268d81d8096d7c48809"
"c14220e634680fbe0c760571dd86a1905835035f4a238c2d7f17bd1363b113c1"
"91782aebb77a1064142a68b59ecdcc6990ed4244082464d91dbfe09e08744b2f"
"d1e850a008acbbe129fbd050c8dc1b28cb8cc2c1e2d920ea458f74809297b513"
"85307b481cbb81d6759385ee782d6c0e101c20ca1937cfd0d6e024da1a0f718a"
"fb7c4ff3df1ca87e67602d28168233cc2448d44b79f405d4c6e67eb88d705050"
"2a806cb986423e3b0e7a97738e1d1d143b4f5f926a4e2f37c7fbe65f56d5b690"),
wvcdm::a2b_hex(
"fa35aa1f5e5d7b958880d5eed9cc1bb81d36ebd04c0250a8c752ea5f413bbdcf"
"3785790c8dba7a0b21c71346bb7f946a9b71c0d2fe87d2e2fab14e35ee8400e7"
"097a7d2d9a25b468e848e8dee2388f890967516c7dab96db4713c7855f717aed"
"2ae9c2895baaa636e4a610ab26b35d771d62397ba40d78694dab70dcbdfa91c3"
"6af79ad6b6ebb479b4a5fbc242a8574ebe6717f0813fbd6f726ce2af4d522e66"
"b36c940fce519c913db56a6372c3636b10c0149b4cd97e74c576765b533abdc2"
"729f1470dd7f9a60d3572dcc9839582a4606ee17eaced39797daef8f885d3f8f"
"e14877ae530451c4242bbc3934f85a5bb71b363351894f881896471cfeaf68b2"),
wvcdm::a2b_hex("4a59e3e5f3e4f7e2f494ad09c12a9e4c"), 0},
{true, 1, true, true, false,
wvcdm::a2bs_hex("3AE243D83B93B3311A1D777FF5FBE01A"),
wvcdm::a2b_hex(
"934997779aa1aeb45d6ba8845f13786575d0adf85a5e93674d9597f8d4286ed7"
"dcce02f306e502bbd9f1cadf502f354038ca921276d158d911bdf3171d335b18"
"0ae0f9abece16ff31ee263228354f724da2f3723b19caa38ea02bd6563b01208"
"fb5bf57854ac0fe38d5883197ef90324b2721ff20fdcf9a53819515e6daa096e"
"70f6f5c1d29a4a13dafd127e2e1f761ea0e28fd451607552ecbaef5da3c780bc"
"aaf2667b4cc4f858f01d480cac9e32c3fbb5705e5d2adcceebefc2535c117208"
"e65f604799fc3d7223e16908550f287a4bea687008cb0064cf14d3aeedb8c705"
"09ebc5c2b8b5315f43c04d78d2f55f4b32c7d33e157114362106395cc0bb6d93"),
wvcdm::a2b_hex(
"2dd54eee1307753508e1f250d637044d6e8f5abf057dab73e9e95f83910e4efc"
"191c9bac63950f13fd51833dd94a4d03f2b64fb5c721970c418fe53fa6f74ad5"
"a6e16477a35c7aa6e28909b069cd25770ef80da20918fc30fe95fd5c87fd3522"
"1649de17ca2c7b3dc31f936f0cbdf97c7b1c15de3a86b279dc4b4de64943914a"
"99734556c4b7a1a0b022c1933cb0786068fc18d49fed2f2b49f3ac6d01c32d07"
"92175ce2844eaf9064e6a3fcffade038d690cbed81659351163a22432f0d0545"
"037e1c805d8e92a1272b4196ad0ce22f26bb80063137a8e454d3b97e2414283d"
"ed0716cd8bceb80cf59166a217006bd147c51b04dfb183088ce3f51e9b9f759e"),
wvcdm::a2b_hex("b358ab21ac90455bbf60490daad457e3"), 0},
{true, 1, true, true, false,
wvcdm::a2bs_hex("5292104C011418973C31235953FC8205"),
wvcdm::a2b_hex(
"d433adfd3d892d5c3e7d54ab0218ee0712400a920d4b71d553912451169f9b79"
"3f103260cf04c34f6a5944bb96da79946a62bdbcd804ca28b17656338edfa700"
"5c090f2750663a026fd15a0b0e448adbbfd53f613ea3993d9fd504421b575f28"
"12020bb8cca0ce333eabee0403df9f410c6473d7673d6991caab6ea2ece8f743"
"5a3ca049fa00c96c9b7c47e3073d25d08f23b47ffc509c48a81a2f98c9ec8a1d"
"e41764c14a5010df8b4692e8612a45bf0645601d4910119e6268ca4f6d8016a8"
"3d933d53f44243674b522bae43043c068c8cae43f0ac224198de71315b3a6f82"
"c1b523bbdcdb3e9f162c308684dd17e364b448ed0e90b0e496b8cf633a982708"),
wvcdm::a2b_hex(
"5efb5e5b913785e9935e67e763b8ff29a6687ac6c18d5a7e16951beb704f9c95"
"f081ca28f54c3e237fb5a7b0444e9a3e17da91e5cf2c0a8f009a873fb079c339"
"81b0ebc565b2c56d983ee33686fa5057c9891e246b67bb6950400acb06d5ae50"
"0e61a7e9289ea67ec2e88e8d0cc3c494fd996e93270e9b264a21818987e969c5"
"1e2955c5a53202e5aec1e2c906e1c006325112eb5c33ee37d0c07ea97d80c17f"
"d56e0efcf40c8c98981a86c18a159f05d851891236c124641d4584c49ccd7478"
"4f328a9cacae0f945238d98741b2969fe258903e85f963daba7168f05c18b09f"
"660dae18de41b1c49769cd38e24b135c37a65b69533f5c7d085898faedfbed5d"),
wvcdm::a2b_hex("cef7e8aaa6ec1154cb68a988f7c9e803"), 0},
{true, 1, true, true, false,
wvcdm::a2bs_hex("D7C01C2F868AE314BCB893E4E9C6AC75"),
wvcdm::a2b_hex(
"fa5d28677721de488ffc209321529728c77bc338accd45ccc98ab2063fc8c373"
"48c7698534175d72bf185690d19474d08c4fd4ed4eb46d858633f05337d70e92"
"03f7ee6bec0f7003bdf6fa665ba172855a51a82da406348ba651a2f62888c30a"
"7b4e1355bb94a9ff5c458f397c9a09e5d7785b286ef83142ddad324cc74e1929"
"60ad1c34c425cdefbedcb62ca9b21ac4f3df7f5922e263cb7798de54b622ab3f"
"64a0dd6ee1e40be6ecc857e657994ecac02ccfafc9036f382d7dbdf35c903356"
"40b7c9db088143060b24f24b21c4a7c2faeb3d308e57c5a75955fd704cfe4dee"
"71a4a7d823102b90eddded795ca6eb36282d777db8cfd783e50e5c2a816ee9ed"),
wvcdm::a2b_hex(
"d5db2f50c0f5a39414ddfa5129c2c641836a8c6312b26a210c996988e0c768d5"
"9a3adff117293b52b0653c0d6e22589edda804fb8caa7442362fe4caf9053b6a"
"2a34896399259a188f0c805de54b091a7eabff098b28d54584c01dd83301e4ca"
"a01b226c4541af1592d4440e103eb55bbd08c471efb0856ec9ced43211fc3325"
"3d402dff0d15f40833dd71259a8d40d527659ef3e5f9fd0826c9471dddb17e1e"
"fab916abc957fb07d7eac4a368ac92a8fb16d995613af47303034ee57b59b1d7"
"101aa031f5586b2f6b4c74372c4d7306db02509b5924d52c46a270f427743a85"
"614f080d83f3b15cbc6600ddda43adff5d2941da13ebe49d80fd0cea5025412b"),
wvcdm::a2b_hex("964c2dfda920357c668308d52d33c652"), 0}
};
// License duration + fudge factor // License duration + fudge factor
const uint32_t kSingleEncryptedSubSampleIcpLicenseDurationExpiration = 5 + 2; const uint32_t kSingleEncryptedSubSampleIcpLicenseDurationExpiration = 5 + 2;
@@ -253,6 +361,17 @@ SessionSharingSubSampleInfo session_sharing_sub_samples[] = {
{ &single_encrypted_sub_sample, true } { &single_encrypted_sub_sample, true }
}; };
struct UsageInfoSubSampleInfo {
SubSampleInfo* sub_sample;
uint32_t usage_info;
};
UsageInfoSubSampleInfo usage_info_sub_sample_info[] = {
{ &usage_info_sub_samples_icp[0], 1 },
{ &usage_info_sub_samples_icp[0], 3 },
{ &usage_info_sub_samples_icp[0], 5 }
};
} // namespace } // namespace
namespace wvcdm { namespace wvcdm {
@@ -408,6 +527,33 @@ class WvCdmRequestLicenseTest : public testing::Test {
return message; return message;
} }
// Post a request and extract the signed provisioning message from
// the HTTP response.
std::string GetUsageInfoResponse(const std::string& server_url,
const std::string& client_auth,
const std::string& usage_info_request) {
// Use secure connection and chunk transfer coding.
UrlRequest url_request(server_url + client_auth, g_port,
g_use_secure_transfer, g_use_chunked_transfer);
if (!url_request.is_connected()) {
return "";
}
url_request.PostRequest(usage_info_request);
std::string message;
int resp_bytes = url_request.GetResponse(&message);
int status_code = url_request.GetStatusCode(message);
EXPECT_EQ(kHttpOk, status_code);
std::string usage_info;
if (kHttpOk == status_code) {
LicenseRequest license;
license.GetDrmMessage(message, usage_info);
LOGV("HTTP response body: (%u bytes)", usage_info.size());
}
return usage_info;
}
void VerifyKeyRequestResponse(const std::string& server_url, void VerifyKeyRequestResponse(const std::string& server_url,
const std::string& client_auth, const std::string& client_auth,
std::string& init_data, bool is_renewal) { std::string& init_data, bool is_renewal) {
@@ -586,7 +732,8 @@ TEST_F(WvCdmRequestLicenseTest, ForceL3Test) {
File file; File file;
DeviceFiles handle; DeviceFiles handle;
EXPECT_TRUE(handle.Init(&file, kSecurityLevelL3)); EXPECT_TRUE(handle.Init(kSecurityLevelL3));
handle.SetTestFile(&file);
EXPECT_TRUE(handle.DeleteAllFiles()); EXPECT_TRUE(handle.DeleteAllFiles());
EXPECT_EQ(NEED_PROVISIONING, EXPECT_EQ(NEED_PROVISIONING,
@@ -766,6 +913,80 @@ TEST_F(WvCdmRequestLicenseTest, OfflineLicenseRenewal) {
decryptor_.CloseSession(session_id_); decryptor_.CloseSession(session_id_);
} }
class WvCdmUsageInfoTest
: public WvCdmRequestLicenseTest,
public ::testing::WithParamInterface<UsageInfoSubSampleInfo*> {};
TEST_P(WvCdmUsageInfoTest, DISABLED_UsageInfo) {
File file;
DeviceFiles handle;
std::string level = GetSecurityLevel(NULL).c_str();
CdmSecurityLevel security_level = kSecurityLevelUninitialized;
if (level.compare(wvcdm::QUERY_VALUE_SECURITY_LEVEL_L1) == 0) {
security_level = kSecurityLevelL1;
} else if (level.compare(wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3) == 0) {
security_level = kSecurityLevelL3;
} else {
EXPECT_TRUE(false);
}
EXPECT_TRUE(handle.Init(security_level));
handle.SetTestFile(&file);
EXPECT_TRUE(handle.DeleteUsageInfo());
UsageInfoSubSampleInfo* usage_info_data = GetParam();
for (size_t i = 0; i < usage_info_data->usage_info; ++i) {
SubSampleInfo* data = usage_info_data->sub_sample + i;
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
std::string key_id = a2bs_hex(
"000000427073736800000000" // blob size and pssh
"EDEF8BA979D64ACEA3C827DCD51D21ED00000022" // Widevine system id
"08011a0d7769646576696e655f74657374220f73" // pssh data
"747265616d696e675f636c6970");
char ch = 0x33 + i;
key_id.append(1, ch);
GenerateKeyRequest(g_key_system, key_id, kLicenseTypeStreaming);
VerifyKeyRequestResponse(g_license_server, g_client_auth, data->key_id,
false);
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
CdmDecryptionParameters decryption_parameters(
&data->key_id, &data->encrypt_data.front(), data->encrypt_data.size(),
&data->iv, data->block_offset, &decrypt_buffer[0]);
decryption_parameters.is_encrypted = data->is_encrypted;
decryption_parameters.is_secure = data->is_secure;
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_, data->validate_key_id,
decryption_parameters));
EXPECT_TRUE(std::equal(data->decrypt_data.begin(), data->decrypt_data.end(),
decrypt_buffer.begin()));
decryptor_.CloseSession(session_id_);
}
uint32_t num_usage_info = 0;
CdmUsageInfo usage_info;
CdmUsageInfoReleaseMessage release_msg;
CdmResponseType status = decryptor_.GetUsageInfo(&usage_info);
EXPECT_EQ(usage_info.empty() ? NO_ERROR : KEY_MESSAGE, status);
while (usage_info.size() > 0) {
for (size_t i = 0; i < usage_info.size(); ++i) {
release_msg = GetUsageInfoResponse(g_license_server, g_client_auth,
usage_info[i]);
EXPECT_EQ(NO_ERROR, decryptor_.ReleaseUsageInfo(release_msg));
}
status = decryptor_.GetUsageInfo(&usage_info);
EXPECT_EQ(usage_info.empty() ? NO_ERROR : KEY_MESSAGE, status);
}
}
INSTANTIATE_TEST_CASE_P(
Cdm, WvCdmUsageInfoTest,
::testing::Values(&usage_info_sub_sample_info[0],
&usage_info_sub_sample_info[1],
&usage_info_sub_sample_info[2]));
TEST_F(WvCdmRequestLicenseTest, QueryUnmodifiedSessionStatus) { TEST_F(WvCdmRequestLicenseTest, QueryUnmodifiedSessionStatus) {
// Test that the global value is returned when no properties are modifying it. // Test that the global value is returned when no properties are modifying it.
CdmQueryMap system_query_info; CdmQueryMap system_query_info;

View File

@@ -376,12 +376,12 @@ status_t WVDrmPlugin::provideProvisionResponse(
} }
status_t WVDrmPlugin::getSecureStops(List<Vector<uint8_t> >& secureStops) { status_t WVDrmPlugin::getSecureStops(List<Vector<uint8_t> >& secureStops) {
CdmSecureStops cdmSecureStops; CdmUsageInfo cdmUsageInfo;
CdmResponseType res = mCDM->GetSecureStops(&cdmSecureStops); CdmResponseType res = mCDM->GetUsageInfo(&cdmUsageInfo);
if (isCdmResponseTypeSuccess(res)) { if (isCdmResponseTypeSuccess(res)) {
secureStops.clear(); secureStops.clear();
for (CdmSecureStops::const_iterator iter = cdmSecureStops.begin(); for (CdmUsageInfo::const_iterator iter = cdmUsageInfo.begin();
iter != cdmSecureStops.end(); iter != cdmUsageInfo.end();
++iter) { ++iter) {
const string& cdmStop = *iter; const string& cdmStop = *iter;
@@ -396,10 +396,8 @@ status_t WVDrmPlugin::getSecureStops(List<Vector<uint8_t> >& secureStops) {
} }
status_t WVDrmPlugin::releaseSecureStops(const Vector<uint8_t>& ssRelease) { status_t WVDrmPlugin::releaseSecureStops(const Vector<uint8_t>& ssRelease) {
CdmSecureStopReleaseMessage cdmMessage(ssRelease.begin(), ssRelease.end()); CdmUsageInfoReleaseMessage cdmMessage(ssRelease.begin(), ssRelease.end());
CdmResponseType res = mCDM->ReleaseUsageInfo(cdmMessage);
CdmResponseType res = mCDM->ReleaseSecureStops(cdmMessage);
return mapCdmResponseType(res); return mapCdmResponseType(res);
} }

View File

@@ -64,10 +64,10 @@ class MockCDM : public WvContentDecryptionModule {
MOCK_METHOD3(HandleProvisioningResponse, MOCK_METHOD3(HandleProvisioningResponse,
CdmResponseType(CdmProvisioningResponse&, std::string*, std::string*)); CdmResponseType(CdmProvisioningResponse&, std::string*, std::string*));
MOCK_METHOD1(GetSecureStops, CdmResponseType(CdmSecureStops*)); MOCK_METHOD1(GetUsageInfo, CdmResponseType(CdmUsageInfo*));
MOCK_METHOD1(ReleaseSecureStops, MOCK_METHOD1(ReleaseUsageInfo,
CdmResponseType(const CdmSecureStopReleaseMessage&)); CdmResponseType(const CdmUsageInfoReleaseMessage&));
MOCK_METHOD2(AttachEventListener, bool(const CdmSessionId&, MOCK_METHOD2(AttachEventListener, bool(const CdmSessionId&,
WvCdmEventListener*)); WvCdmEventListener*));
@@ -568,12 +568,12 @@ TEST_F(WVDrmPluginTest, GetsSecureStops) {
} }
fclose(fp); fclose(fp);
CdmSecureStops cdmStops; CdmUsageInfo cdmStops;
for (uint32_t i = 0; i < kStopCount; ++i) { for (uint32_t i = 0; i < kStopCount; ++i) {
cdmStops.push_back(string(stopsRaw[i], stopsRaw[i] + kStopSize)); cdmStops.push_back(string(stopsRaw[i], stopsRaw[i] + kStopSize));
} }
EXPECT_CALL(cdm, GetSecureStops(_)) EXPECT_CALL(cdm, GetUsageInfo(_))
.WillOnce(DoAll(SetArgPointee<0>(cdmStops), .WillOnce(DoAll(SetArgPointee<0>(cdmStops),
Return(wvcdm::NO_ERROR))); Return(wvcdm::NO_ERROR)));
@@ -610,7 +610,7 @@ TEST_F(WVDrmPluginTest, ReleasesSecureStops) {
Vector<uint8_t> message; Vector<uint8_t> message;
message.appendArray(messageRaw, kMessageSize); message.appendArray(messageRaw, kMessageSize);
EXPECT_CALL(cdm, ReleaseSecureStops(ElementsAreArray(messageRaw, EXPECT_CALL(cdm, ReleaseUsageInfo(ElementsAreArray(messageRaw,
kMessageSize))) kMessageSize)))
.Times(1); .Times(1);