Fixes for query information and usage reporting
* The Usage APIs return usage reports from either L1 or L3 (if available). * Correction to when usage reports are saved. In addition to other events they are now saved when keys are loaded, usage reports are released and soon after first decryption and periodically (60 seconds) after that, if decryption takes place. * Usage reports now get deleted on an unprovision request. * Policy timer is now started when offline licenses are restored. * Usage session is now released, when a usage response is received. * Usage tests ahev been enabled. * Added CDM extended duration (integration) tests to test usage reporting and querying. These need to be run manually as they take a while (currently half an hour). b/15592374 [ Merge of https://widevine-internal-review.googlesource.com/#/c/10800 from the Widevine CDM repo ] Change-Id: Ia817e03ebbe880e08ba7b4a235ecb82b3ff35fbf
This commit is contained in:
@@ -49,6 +49,7 @@ adb root && adb wait-for-device remount
|
|||||||
|
|
||||||
adb push $OUT/system/bin/oemcrypto_test /system/bin
|
adb push $OUT/system/bin/oemcrypto_test /system/bin
|
||||||
adb push $OUT/system/bin/request_license_test /system/bin
|
adb push $OUT/system/bin/request_license_test /system/bin
|
||||||
|
adb push $OUT/system/bin/cdm_extended_duration_test /system/bin
|
||||||
adb push $OUT/system/bin/policy_engine_unittest /system/bin
|
adb push $OUT/system/bin/policy_engine_unittest /system/bin
|
||||||
adb push $OUT/system/bin/libwvdrmmediacrypto_test /system/bin
|
adb push $OUT/system/bin/libwvdrmmediacrypto_test /system/bin
|
||||||
adb push $OUT/system/bin/libwvdrmdrmplugin_test /system/bin
|
adb push $OUT/system/bin/libwvdrmdrmplugin_test /system/bin
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ namespace wvcdm {
|
|||||||
|
|
||||||
class CdmClientPropertySet;
|
class CdmClientPropertySet;
|
||||||
class CryptoEngine;
|
class CryptoEngine;
|
||||||
|
class UsagePropertySet;
|
||||||
class WvCdmEventListener;
|
class WvCdmEventListener;
|
||||||
|
|
||||||
typedef std::map<CdmSessionId, CdmSession*> CdmSessionMap;
|
typedef std::map<CdmSessionId, CdmSession*> CdmSessionMap;
|
||||||
@@ -117,6 +118,8 @@ class CdmEngine {
|
|||||||
private:
|
private:
|
||||||
// private methods
|
// private methods
|
||||||
bool ValidateKeySystem(const CdmKeySystem& key_system);
|
bool ValidateKeySystem(const CdmKeySystem& key_system);
|
||||||
|
CdmResponseType GetUsageInfo(SecurityLevel requested_security_level,
|
||||||
|
CdmUsageInfo* usage_info);
|
||||||
|
|
||||||
void OnKeyReleaseEvent(const CdmKeySetId& key_set_id);
|
void OnKeyReleaseEvent(const CdmKeySetId& key_set_id);
|
||||||
|
|
||||||
@@ -132,7 +135,8 @@ class CdmEngine {
|
|||||||
|
|
||||||
// usage related variables
|
// usage related variables
|
||||||
scoped_ptr<CdmSession> usage_session_;
|
scoped_ptr<CdmSession> usage_session_;
|
||||||
int64_t last_usage_information_update_time;
|
scoped_ptr<UsagePropertySet> usage_property_set_;
|
||||||
|
int64_t last_usage_information_update_time_;
|
||||||
|
|
||||||
CORE_DISALLOW_COPY_AND_ASSIGN(CdmEngine);
|
CORE_DISALLOW_COPY_AND_ASSIGN(CdmEngine);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -88,8 +88,10 @@ class CdmSession {
|
|||||||
|
|
||||||
virtual CdmResponseType UpdateUsageInformation();
|
virtual CdmResponseType UpdateUsageInformation();
|
||||||
|
|
||||||
|
virtual bool is_initial_usage_update() { return is_initial_usage_update_; }
|
||||||
virtual bool is_usage_update_needed() { return is_usage_update_needed_; }
|
virtual bool is_usage_update_needed() { return is_usage_update_needed_; }
|
||||||
virtual void reset_is_usage_update_needed() {
|
virtual void reset_usage_flags() {
|
||||||
|
is_initial_usage_update_ = false;
|
||||||
is_usage_update_needed_ = false;
|
is_usage_update_needed_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,10 +119,13 @@ class CdmSession {
|
|||||||
bool license_received_;
|
bool license_received_;
|
||||||
bool is_offline_;
|
bool is_offline_;
|
||||||
bool is_release_;
|
bool is_release_;
|
||||||
bool is_usage_update_needed_;
|
CdmSecurityLevel security_level_;
|
||||||
|
|
||||||
|
// decryption and usage flags
|
||||||
bool is_initial_decryption_;
|
bool is_initial_decryption_;
|
||||||
bool has_decrypted_recently_;
|
bool has_decrypted_recently_;
|
||||||
CdmSecurityLevel security_level_;
|
bool is_initial_usage_update_;
|
||||||
|
bool is_usage_update_needed_;
|
||||||
|
|
||||||
// information useful for offline and usage scenarios
|
// information useful for offline and usage scenarios
|
||||||
CdmKeyMessage key_request_;
|
CdmKeyMessage key_request_;
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ class CryptoSession {
|
|||||||
// Media data path
|
// Media data path
|
||||||
virtual CdmResponseType Decrypt(const CdmDecryptionParameters& parameters);
|
virtual CdmResponseType Decrypt(const CdmDecryptionParameters& parameters);
|
||||||
|
|
||||||
|
// Usage related methods
|
||||||
virtual bool UsageInformationSupport(bool* has_support);
|
virtual bool UsageInformationSupport(bool* has_support);
|
||||||
virtual CdmResponseType UpdateUsageInformation();
|
virtual CdmResponseType UpdateUsageInformation();
|
||||||
virtual CdmResponseType DeactivateUsageInformation(
|
virtual CdmResponseType DeactivateUsageInformation(
|
||||||
@@ -95,6 +96,7 @@ class CryptoSession {
|
|||||||
virtual CdmResponseType ReleaseUsageInformation(
|
virtual CdmResponseType ReleaseUsageInformation(
|
||||||
const std::string& message, const std::string& signature,
|
const std::string& message, const std::string& signature,
|
||||||
const std::string& provider_session_token);
|
const std::string& provider_session_token);
|
||||||
|
virtual CdmResponseType DeleteAllUsageReports();
|
||||||
|
|
||||||
virtual bool GetHdcpCapabilities(OemCryptoHdcpVersion* current,
|
virtual bool GetHdcpCapabilities(OemCryptoHdcpVersion* current,
|
||||||
OemCryptoHdcpVersion* max);
|
OemCryptoHdcpVersion* max);
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ class DeviceFiles {
|
|||||||
FRIEND_TEST(DeviceFilesUsageInfoTest, Store);
|
FRIEND_TEST(DeviceFilesUsageInfoTest, Store);
|
||||||
FRIEND_TEST(WvCdmRequestLicenseTest, UnprovisionTest);
|
FRIEND_TEST(WvCdmRequestLicenseTest, UnprovisionTest);
|
||||||
FRIEND_TEST(WvCdmRequestLicenseTest, ForceL3Test);
|
FRIEND_TEST(WvCdmRequestLicenseTest, ForceL3Test);
|
||||||
FRIEND_TEST(WvCdmUsageInfoTest, DISABLED_UsageInfo);
|
FRIEND_TEST(WvCdmUsageInfoTest, UsageInfo);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
scoped_ptr<File> file_;
|
scoped_ptr<File> file_;
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class CdmLicense {
|
|||||||
const CdmKeyResponse& license_renewal_response,
|
const CdmKeyResponse& license_renewal_response,
|
||||||
int64_t playback_start_time,
|
int64_t playback_start_time,
|
||||||
int64_t last_playback_time);
|
int64_t last_playback_time);
|
||||||
virtual bool RestoreUsageLicense(const CdmKeyMessage& license_request,
|
virtual bool RestoreLicenseForRelease(const CdmKeyMessage& license_request,
|
||||||
const CdmKeyResponse& license_response);
|
const CdmKeyResponse& license_response);
|
||||||
virtual bool HasInitData() { return !stored_init_data_.empty(); }
|
virtual bool HasInitData() { return !stored_init_data_.empty(); }
|
||||||
virtual bool IsKeyLoaded(const KeyId& key_id);
|
virtual bool IsKeyLoaded(const KeyId& key_id);
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ std::string HexEncode(const uint8_t* bytes, unsigned size);
|
|||||||
std::string IntToString(int value);
|
std::string IntToString(int value);
|
||||||
std::string UintToString(unsigned int value);
|
std::string UintToString(unsigned int value);
|
||||||
int64_t htonll64(int64_t x);
|
int64_t htonll64(int64_t x);
|
||||||
|
int64_t ntohll64(int64_t x);
|
||||||
|
|
||||||
}; // namespace wvcdm
|
}; // namespace wvcdm
|
||||||
|
|
||||||
|
|||||||
@@ -25,13 +25,36 @@ namespace {
|
|||||||
|
|
||||||
namespace wvcdm {
|
namespace wvcdm {
|
||||||
|
|
||||||
|
class UsagePropertySet : public CdmClientPropertySet {
|
||||||
|
public:
|
||||||
|
UsagePropertySet() {}
|
||||||
|
virtual ~UsagePropertySet() {}
|
||||||
|
void set_security_level(SecurityLevel security_level) {
|
||||||
|
if (kLevel3 == security_level)
|
||||||
|
security_level_ = QUERY_VALUE_SECURITY_LEVEL_L3;
|
||||||
|
else
|
||||||
|
security_level_.clear();
|
||||||
|
}
|
||||||
|
virtual const std::string& security_level() const { return security_level_; }
|
||||||
|
virtual bool use_privacy_mode() const { return false; }
|
||||||
|
virtual const std::string& service_certificate() const { return empty_; }
|
||||||
|
virtual bool is_session_sharing_enabled() const { return false; }
|
||||||
|
virtual uint32_t session_sharing_id() const { return 0; }
|
||||||
|
virtual void set_session_sharing_id(uint32_t id) {
|
||||||
|
id; // noop to suppress warning
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::string security_level_;
|
||||||
|
const std::string empty_;
|
||||||
|
};
|
||||||
|
|
||||||
bool CdmEngine::seeded_ = false;
|
bool CdmEngine::seeded_ = false;
|
||||||
|
|
||||||
CdmEngine::CdmEngine()
|
CdmEngine::CdmEngine()
|
||||||
: cert_provisioning_(NULL),
|
: cert_provisioning_(NULL),
|
||||||
cert_provisioning_requested_security_level_(kLevelDefault),
|
cert_provisioning_requested_security_level_(kLevelDefault),
|
||||||
usage_session_(NULL),
|
usage_session_(NULL),
|
||||||
last_usage_information_update_time(0) {
|
last_usage_information_update_time_(0) {
|
||||||
Properties::Init();
|
Properties::Init();
|
||||||
if (!seeded_) {
|
if (!seeded_) {
|
||||||
Clock clock;
|
Clock clock;
|
||||||
@@ -269,7 +292,7 @@ CdmResponseType CdmEngine::RestoreKey(
|
|||||||
LOGI("CdmEngine::RestoreKey");
|
LOGI("CdmEngine::RestoreKey");
|
||||||
|
|
||||||
if (key_set_id.empty()) {
|
if (key_set_id.empty()) {
|
||||||
LOGI("CdmEngine::RestoreKey: invalid key set id");
|
LOGE("CdmEngine::RestoreKey: invalid key set id");
|
||||||
return KEY_ERROR;
|
return KEY_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,6 +309,9 @@ CdmResponseType CdmEngine::RestoreKey(
|
|||||||
cert_provisioning_requested_security_level_ =
|
cert_provisioning_requested_security_level_ =
|
||||||
iter->second->GetRequestedSecurityLevel();
|
iter->second->GetRequestedSecurityLevel();
|
||||||
}
|
}
|
||||||
|
if (KEY_ADDED != sts) {
|
||||||
|
LOGE("CdmEngine::RestoreKey: restore offline session error = %d", sts);
|
||||||
|
}
|
||||||
return sts;
|
return sts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -539,11 +565,46 @@ CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) {
|
|||||||
LOGE("CdmEngine::Unprovision: unable to delete files");
|
LOGE("CdmEngine::Unprovision: unable to delete files");
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
return NO_ERROR;
|
|
||||||
|
scoped_ptr<CryptoSession> crypto_session(new CryptoSession());
|
||||||
|
CdmResponseType status = crypto_session->Open(
|
||||||
|
security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault);
|
||||||
|
if (NO_ERROR != status) {
|
||||||
|
LOGE("CdmEngine::Unprovision: error opening crypto session: %d", status);
|
||||||
|
return UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
status = crypto_session->DeleteAllUsageReports();
|
||||||
|
if (status != NO_ERROR) {
|
||||||
|
LOGE("CdmEngine::Unprovision: error deleteing usage reports: %d", status);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType CdmEngine::GetUsageInfo(CdmUsageInfo* usage_info) {
|
CdmResponseType CdmEngine::GetUsageInfo(CdmUsageInfo* usage_info) {
|
||||||
usage_session_.reset(new CdmSession(NULL));
|
// Return a random usage report from a random security level
|
||||||
|
SecurityLevel security_level = ((rand() % 2) == 0) ? kLevelDefault : kLevel3;
|
||||||
|
CdmResponseType status = GetUsageInfo(security_level, usage_info);
|
||||||
|
|
||||||
|
if (KEY_MESSAGE == status && !usage_info->empty())
|
||||||
|
return status;
|
||||||
|
|
||||||
|
security_level = (kLevel3 == security_level) ? kLevelDefault : kLevel3;
|
||||||
|
status = GetUsageInfo(security_level, usage_info);
|
||||||
|
if (NEED_PROVISIONING == status)
|
||||||
|
return NO_ERROR; // Valid scenario that one of the security
|
||||||
|
// levels has not been provisioned
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
CdmResponseType CdmEngine::GetUsageInfo(
|
||||||
|
SecurityLevel requested_security_level,
|
||||||
|
CdmUsageInfo* usage_info) {
|
||||||
|
if (NULL == usage_property_set_.get()) {
|
||||||
|
usage_property_set_.reset(new UsagePropertySet());
|
||||||
|
}
|
||||||
|
usage_property_set_->set_security_level(requested_security_level);
|
||||||
|
|
||||||
|
usage_session_.reset(new CdmSession(usage_property_set_.get()));
|
||||||
|
|
||||||
CdmResponseType status = usage_session_->Init();
|
CdmResponseType status = usage_session_->Init();
|
||||||
if (NO_ERROR != status) {
|
if (NO_ERROR != status) {
|
||||||
@@ -600,6 +661,7 @@ CdmResponseType CdmEngine::ReleaseUsageInfo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType status = usage_session_->ReleaseKey(message);
|
CdmResponseType status = usage_session_->ReleaseKey(message);
|
||||||
|
usage_session_.reset(NULL);
|
||||||
if (NO_ERROR != status) {
|
if (NO_ERROR != status) {
|
||||||
LOGE("CdmEngine::ReleaseUsageInfo: release key error: %d", status);
|
LOGE("CdmEngine::ReleaseUsageInfo: release key error: %d", status);
|
||||||
}
|
}
|
||||||
@@ -724,29 +786,44 @@ bool CdmEngine::ValidateKeySystem(const CdmKeySystem& key_system) {
|
|||||||
void CdmEngine::OnTimerEvent() {
|
void CdmEngine::OnTimerEvent() {
|
||||||
Clock clock;
|
Clock clock;
|
||||||
uint64_t current_time = clock.GetCurrentTime();
|
uint64_t current_time = clock.GetCurrentTime();
|
||||||
bool update_usage_information = false;
|
bool usage_update_period_expired = false;
|
||||||
|
|
||||||
if (current_time - last_usage_information_update_time >
|
if (current_time - last_usage_information_update_time_ >
|
||||||
kUpdateUsageInformationPeriod) {
|
kUpdateUsageInformationPeriod) {
|
||||||
update_usage_information = true;
|
usage_update_period_expired = true;
|
||||||
last_usage_information_update_time = current_time;
|
last_usage_information_update_time_ = current_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_initial_usage_update = false;
|
||||||
|
bool is_usage_update_needed = false;
|
||||||
|
|
||||||
for (CdmSessionMap::iterator iter = sessions_.begin();
|
for (CdmSessionMap::iterator iter = sessions_.begin();
|
||||||
iter != sessions_.end(); ++iter) {
|
iter != sessions_.end(); ++iter) {
|
||||||
iter->second->OnTimerEvent(update_usage_information);
|
is_initial_usage_update = is_initial_usage_update ||
|
||||||
|
iter->second->is_initial_usage_update();
|
||||||
|
is_usage_update_needed = is_usage_update_needed ||
|
||||||
|
iter->second->is_usage_update_needed();
|
||||||
|
|
||||||
if (update_usage_information && iter->second->is_usage_update_needed()) {
|
iter->second->OnTimerEvent(usage_update_period_expired);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_usage_update_needed &&
|
||||||
|
(usage_update_period_expired || is_initial_usage_update)) {
|
||||||
|
bool has_usage_been_updated = false;
|
||||||
|
for (CdmSessionMap::iterator iter = sessions_.begin();
|
||||||
|
iter != sessions_.end(); ++iter) {
|
||||||
|
iter->second->reset_usage_flags();
|
||||||
|
if (!has_usage_been_updated) {
|
||||||
// usage is updated for all sessions so this needs to be
|
// usage is updated for all sessions so this needs to be
|
||||||
// called only once per update usage information period
|
// called only once per update usage information period
|
||||||
CdmResponseType status = iter->second->UpdateUsageInformation();
|
CdmResponseType status = iter->second->UpdateUsageInformation();
|
||||||
if (NO_ERROR != status) {
|
if (NO_ERROR != status) {
|
||||||
LOGW("Update usage information failed: %d", status);
|
LOGW("Update usage information failed: %d", status);
|
||||||
} else {
|
} else {
|
||||||
update_usage_information = false;
|
has_usage_been_updated = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
iter->second->reset_is_usage_update_needed();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ void CdmSession::Create(
|
|||||||
license_received_ = false;
|
license_received_ = false;
|
||||||
is_offline_ = false;
|
is_offline_ = false;
|
||||||
is_release_ = false;
|
is_release_ = false;
|
||||||
|
is_initial_usage_update_ = true;
|
||||||
is_usage_update_needed_ = false;
|
is_usage_update_needed_ = false;
|
||||||
is_initial_decryption_ = true;
|
is_initial_decryption_ = true;
|
||||||
has_decrypted_recently_ = false;
|
has_decrypted_recently_ = false;
|
||||||
@@ -152,12 +153,19 @@ CdmResponseType CdmSession::RestoreOfflineSession(
|
|||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (license_type == kLicenseTypeRelease) {
|
||||||
|
if (!license_parser_->RestoreLicenseForRelease(key_request_,
|
||||||
|
key_response_)) {
|
||||||
|
return UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (!license_parser_->RestoreOfflineLicense(key_request_, key_response_,
|
if (!license_parser_->RestoreOfflineLicense(key_request_, key_response_,
|
||||||
offline_key_renewal_response_,
|
offline_key_renewal_response_,
|
||||||
playback_start_time,
|
playback_start_time,
|
||||||
last_playback_time)) {
|
last_playback_time)) {
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
license_received_ = true;
|
license_received_ = true;
|
||||||
is_offline_ = true;
|
is_offline_ = true;
|
||||||
@@ -172,7 +180,7 @@ CdmResponseType CdmSession::RestoreUsageSession(
|
|||||||
key_request_ = key_request;
|
key_request_ = key_request;
|
||||||
key_response_ = key_response;
|
key_response_ = key_response;
|
||||||
|
|
||||||
if (!license_parser_->RestoreUsageLicense(key_request_, key_response_)) {
|
if (!license_parser_->RestoreLicenseForRelease(key_request_, key_response_)) {
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -421,10 +421,19 @@ CdmResponseType CryptoSession::LoadKeys(
|
|||||||
provider_session_token.length());
|
provider_session_token.length());
|
||||||
|
|
||||||
if (OEMCrypto_SUCCESS == sts) {
|
if (OEMCrypto_SUCCESS == sts) {
|
||||||
|
if (!provider_session_token.empty()) {
|
||||||
|
sts = OEMCrypto_UpdateUsageTable();
|
||||||
|
if (sts != OEMCrypto_SUCCESS) {
|
||||||
|
LOGW("CryptoSession::LoadKeys: OEMCrypto_UpdateUsageTable error=%ld",
|
||||||
|
sts);
|
||||||
|
}
|
||||||
|
}
|
||||||
return KEY_ADDED;
|
return KEY_ADDED;
|
||||||
} else if (OEMCrypto_ERROR_TOO_MANY_KEYS == sts) {
|
} else if (OEMCrypto_ERROR_TOO_MANY_KEYS == sts) {
|
||||||
|
LOGE("CryptoSession::LoadKeys: OEMCrypto_LoadKeys error=%d", sts);
|
||||||
return INSUFFICIENT_CRYPTO_RESOURCES;
|
return INSUFFICIENT_CRYPTO_RESOURCES;
|
||||||
} else {
|
} else {
|
||||||
|
LOGE("CryptoSession::LoadKeys: OEMCrypto_LoadKeys error=%d", sts);
|
||||||
return KEY_ERROR;
|
return KEY_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -439,7 +448,7 @@ bool CryptoSession::LoadCertificatePrivateKey(std::string& wrapped_key) {
|
|||||||
wrapped_key.size());
|
wrapped_key.size());
|
||||||
|
|
||||||
if (OEMCrypto_SUCCESS != sts) {
|
if (OEMCrypto_SUCCESS != sts) {
|
||||||
LOGD("LoadCertificatePrivateKey: OEMCrypto_LoadDeviceRSAKey error=%d", sts);
|
LOGE("LoadCertificatePrivateKey: OEMCrypto_LoadDeviceRSAKey error=%d", sts);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -509,7 +518,7 @@ bool CryptoSession::GenerateDerivedKeys(const std::string& message) {
|
|||||||
enc_deriv_message.size());
|
enc_deriv_message.size());
|
||||||
|
|
||||||
if (OEMCrypto_SUCCESS != sts) {
|
if (OEMCrypto_SUCCESS != sts) {
|
||||||
LOGD("GenerateDerivedKeys: OEMCrypto_GenerateDerivedKeys error=%d", sts);
|
LOGE("GenerateDerivedKeys: OEMCrypto_GenerateDerivedKeys error=%d", sts);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -533,7 +542,7 @@ bool CryptoSession::GenerateDerivedKeys(const std::string& message,
|
|||||||
enc_deriv_message.size());
|
enc_deriv_message.size());
|
||||||
|
|
||||||
if (OEMCrypto_SUCCESS != sts) {
|
if (OEMCrypto_SUCCESS != sts) {
|
||||||
LOGD("GenerateDerivedKeys: OEMCrypto_DeriveKeysFromSessionKey err=%d", sts);
|
LOGE("GenerateDerivedKeys: OEMCrypto_DeriveKeysFromSessionKey err=%d", sts);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -554,7 +563,7 @@ bool CryptoSession::GenerateSignature(const std::string& message,
|
|||||||
|
|
||||||
if (OEMCrypto_SUCCESS != sts) {
|
if (OEMCrypto_SUCCESS != sts) {
|
||||||
if (OEMCrypto_ERROR_SHORT_BUFFER != sts) {
|
if (OEMCrypto_ERROR_SHORT_BUFFER != sts) {
|
||||||
LOGD("GenerateSignature: OEMCrypto_GenerateSignature err=%d", sts);
|
LOGE("GenerateSignature: OEMCrypto_GenerateSignature err=%d", sts);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -567,7 +576,7 @@ bool CryptoSession::GenerateSignature(const std::string& message,
|
|||||||
&length);
|
&length);
|
||||||
|
|
||||||
if (OEMCrypto_SUCCESS != sts) {
|
if (OEMCrypto_SUCCESS != sts) {
|
||||||
LOGD("GenerateSignature: OEMCrypto_GenerateSignature err=%d", sts);
|
LOGE("GenerateSignature: OEMCrypto_GenerateSignature err=%d", sts);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -593,7 +602,7 @@ bool CryptoSession::GenerateRsaSignature(const std::string& message,
|
|||||||
|
|
||||||
if (OEMCrypto_SUCCESS != sts) {
|
if (OEMCrypto_SUCCESS != sts) {
|
||||||
if (OEMCrypto_ERROR_SHORT_BUFFER != sts) {
|
if (OEMCrypto_ERROR_SHORT_BUFFER != sts) {
|
||||||
LOGD("GenerateRsaSignature: OEMCrypto_GenerateRSASignature err=%d", sts);
|
LOGE("GenerateRsaSignature: OEMCrypto_GenerateRSASignature err=%d", sts);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -606,7 +615,7 @@ bool CryptoSession::GenerateRsaSignature(const std::string& message,
|
|||||||
&length, kSign_RSASSA_PSS);
|
&length, kSign_RSASSA_PSS);
|
||||||
|
|
||||||
if (OEMCrypto_SUCCESS != sts) {
|
if (OEMCrypto_SUCCESS != sts) {
|
||||||
LOGD("GenerateRsaSignature: OEMCrypto_GenerateRSASignature err=%d", sts);
|
LOGE("GenerateRsaSignature: OEMCrypto_GenerateRSASignature err=%d", sts);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -774,10 +783,32 @@ CdmResponseType CryptoSession::GenerateUsageReport(
|
|||||||
*usage_duration_status = kUsageDurationPlaybackNotBegun;
|
*usage_duration_status = kUsageDurationPlaybackNotBegun;
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
LOGV("OEMCrypto_PST_Report.status: %d\n", pst_report.status);
|
||||||
|
LOGV("OEMCrypto_PST_Report.clock_security_level: %d\n",
|
||||||
|
pst_report.clock_security_level);
|
||||||
|
LOGV("OEMCrypto_PST_Report.pst_length: %d\n", pst_report.pst_length);
|
||||||
|
LOGV("OEMCrypto_PST_Report.padding: %d\n", pst_report.padding);
|
||||||
|
LOGV("OEMCrypto_PST_Report.seconds_since_license_received: %lld\n",
|
||||||
|
ntohll64(pst_report.seconds_since_license_received));
|
||||||
|
LOGV("OEMCrypto_PST_Report.seconds_since_first_decrypt: %lld\n",
|
||||||
|
ntohll64(pst_report.seconds_since_first_decrypt));
|
||||||
|
LOGV("OEMCrypto_PST_Report.seconds_since_last_decrypt: %lld\n",
|
||||||
|
ntohll64(pst_report.seconds_since_last_decrypt));
|
||||||
|
LOGV("OEMCrypto_PST_Report: %s\n", b2a_hex(*usage_report).c_str());
|
||||||
|
|
||||||
|
// When usage report state is inactive, we have to deduce whether the
|
||||||
|
// license was ever used.
|
||||||
|
if (kInactive == pst_report.status &&
|
||||||
|
(0 > ntohll64(pst_report.seconds_since_first_decrypt) ||
|
||||||
|
ntohll64(pst_report.seconds_since_license_received) <
|
||||||
|
ntohll64(pst_report.seconds_since_first_decrypt))) {
|
||||||
|
*usage_duration_status = kUsageDurationPlaybackNotBegun;
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
*usage_duration_status = kUsageDurationsValid;
|
*usage_duration_status = kUsageDurationsValid;
|
||||||
*seconds_since_started = pst_report.seconds_since_first_decrypt;
|
*seconds_since_started = ntohll64(pst_report.seconds_since_first_decrypt);
|
||||||
*seconds_since_last_played = pst_report.seconds_since_last_decrypt;
|
*seconds_since_last_played = ntohll64(pst_report.seconds_since_last_decrypt);
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -799,6 +830,31 @@ CdmResponseType CryptoSession::ReleaseUsageInformation(
|
|||||||
status);
|
status);
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
|
status = OEMCrypto_UpdateUsageTable();
|
||||||
|
if (status != OEMCrypto_SUCCESS) {
|
||||||
|
LOGW("CryptoSession::ReleaseUsageInformation: OEMCrypto_UpdateUsageTable: "
|
||||||
|
"error=%ld",
|
||||||
|
status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
CdmResponseType CryptoSession::DeleteAllUsageReports() {
|
||||||
|
LOGV("DeleteAllUsageReports");
|
||||||
|
OEMCryptoResult status = OEMCrypto_DeleteUsageTable();
|
||||||
|
|
||||||
|
if (OEMCrypto_SUCCESS != status) {
|
||||||
|
LOGE("CryptoSession::DeleteAllUsageReports: Delete Usage Table error =%ld",
|
||||||
|
status);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = OEMCrypto_UpdateUsageTable();
|
||||||
|
if (status != OEMCrypto_SUCCESS) {
|
||||||
|
LOGE("CryptoSession::ReleaseUsageInformation: OEMCrypto_UpdateUsageTable: "
|
||||||
|
"error=%ld",
|
||||||
|
status);
|
||||||
|
}
|
||||||
|
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
@@ -840,7 +896,7 @@ bool CryptoSession::RewrapDeviceRSAKey(const std::string& message,
|
|||||||
const std::string& enc_rsa_key,
|
const std::string& enc_rsa_key,
|
||||||
const std::string& rsa_key_iv,
|
const std::string& rsa_key_iv,
|
||||||
std::string* wrapped_rsa_key) {
|
std::string* wrapped_rsa_key) {
|
||||||
LOGD("CryptoSession::RewrapDeviceRSAKey, session id=%ld",
|
LOGV("CryptoSession::RewrapDeviceRSAKey, session id=%ld",
|
||||||
static_cast<uint32_t>(oec_session_id_));
|
static_cast<uint32_t>(oec_session_id_));
|
||||||
|
|
||||||
const uint8_t* signed_msg = reinterpret_cast<const uint8_t*>(message.data());
|
const uint8_t* signed_msg = reinterpret_cast<const uint8_t*>(message.data());
|
||||||
|
|||||||
@@ -755,7 +755,6 @@ bool CdmLicense::RestoreOfflineLicense(
|
|||||||
const CdmKeyResponse& license_renewal_response,
|
const CdmKeyResponse& license_renewal_response,
|
||||||
int64_t playback_start_time,
|
int64_t playback_start_time,
|
||||||
int64_t last_playback_time) {
|
int64_t last_playback_time) {
|
||||||
|
|
||||||
if (license_request.empty() || license_response.empty()) {
|
if (license_request.empty() || license_response.empty()) {
|
||||||
LOGE(
|
LOGE(
|
||||||
"CdmLicense::RestoreOfflineLicense: key_request or response empty: "
|
"CdmLicense::RestoreOfflineLicense: key_request or response empty: "
|
||||||
@@ -827,26 +826,28 @@ bool CdmLicense::RestoreOfflineLicense(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CdmLicense::RestoreUsageLicense(const CdmKeyMessage& license_request,
|
bool CdmLicense::RestoreLicenseForRelease(
|
||||||
|
const CdmKeyMessage& license_request,
|
||||||
const CdmKeyResponse& license_response) {
|
const CdmKeyResponse& license_response) {
|
||||||
|
|
||||||
if (license_request.empty() || license_response.empty()) {
|
if (license_request.empty() || license_response.empty()) {
|
||||||
LOGE(
|
LOGE(
|
||||||
"CdmLicense::RestoreUsageLicense: key_request or response empty: %u %u",
|
"CdmLicense::RestoreLicenseForRelease: key_request or response empty:"
|
||||||
|
" %u %u",
|
||||||
license_request.size(), license_response.size());
|
license_request.size(), license_response.size());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SignedMessage signed_request;
|
SignedMessage signed_request;
|
||||||
if (!signed_request.ParseFromString(license_request)) {
|
if (!signed_request.ParseFromString(license_request)) {
|
||||||
LOGE("CdmLicense::RestoreUsageLicense: license_request parse failed");
|
LOGE("CdmLicense::RestoreLicenseForRelease: license_request parse failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signed_request.type() != SignedMessage::LICENSE_REQUEST) {
|
if (signed_request.type() != SignedMessage::LICENSE_REQUEST) {
|
||||||
LOGE(
|
LOGE(
|
||||||
"CdmLicense::RestoreUsageLicense: license request type: expected = %d,"
|
"CdmLicense::RestoreLicenseForRelease: license request type: expected "
|
||||||
" actual = %d",
|
"= %d, actual = %d",
|
||||||
SignedMessage::LICENSE_REQUEST, signed_request.type());
|
SignedMessage::LICENSE_REQUEST, signed_request.type());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -855,20 +856,21 @@ bool CdmLicense::RestoreUsageLicense(const CdmKeyMessage& license_request,
|
|||||||
|
|
||||||
SignedMessage signed_response;
|
SignedMessage signed_response;
|
||||||
if (!signed_response.ParseFromString(license_response)) {
|
if (!signed_response.ParseFromString(license_response)) {
|
||||||
LOGE("CdmLicense::RestoreUsageLicense: unable to parse signed license"
|
LOGE("CdmLicense::RestoreLicenseForRelease: unable to parse signed license"
|
||||||
" response");
|
" response");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SignedMessage::LICENSE != signed_response.type()) {
|
if (SignedMessage::LICENSE != signed_response.type()) {
|
||||||
LOGE("CdmLicense::RestoreUsageLicense: unrecognized signed message type: %d"
|
LOGE("CdmLicense::RestoreLicenseForRelease: unrecognized signed message "
|
||||||
|
"type: %d"
|
||||||
, signed_response.type());
|
, signed_response.type());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Properties::use_certificates_as_identification()) {
|
if (Properties::use_certificates_as_identification()) {
|
||||||
if (!signed_response.has_session_key()) {
|
if (!signed_response.has_session_key()) {
|
||||||
LOGE("CdmLicense::RestoreUsageLicense: no session keys present");
|
LOGE("CdmLicense::RestoreLicenseForRelease: no session keys present");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -880,16 +882,24 @@ bool CdmLicense::RestoreUsageLicense(const CdmKeyMessage& license_request,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!signed_response.has_signature()) {
|
if (!signed_response.has_signature()) {
|
||||||
LOGE("CdmLicense::RestoreUsageLicense: license response is not signed");
|
LOGE("CdmLicense::RestoreLicenseForRelease: license response is not"
|
||||||
|
" signed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
License license;
|
License license;
|
||||||
if (!license.ParseFromString(signed_response.msg())) {
|
if (!license.ParseFromString(signed_response.msg())) {
|
||||||
LOGE("CdmLicense::RestoreUsageLicense: unable to parse license response");
|
LOGE("CdmLicense::RestoreLicenseForRelease: unable to parse license"
|
||||||
|
" response");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (license.id().has_provider_session_token())
|
||||||
|
provider_session_token_ = license.id().provider_session_token();
|
||||||
|
|
||||||
|
if (license.policy().has_renewal_server_url())
|
||||||
|
server_url_ = license.policy().renewal_server_url();
|
||||||
|
|
||||||
policy_engine_->SetLicense(license);
|
policy_engine_->SetLicense(license);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,14 +174,31 @@ int64_t htonll64(int64_t x) { // Convert to big endian (network-byte-order)
|
|||||||
int64_t number;
|
int64_t number;
|
||||||
} mixed;
|
} mixed;
|
||||||
mixed.number = 1;
|
mixed.number = 1;
|
||||||
if (mixed.array[0] == 1) {
|
if (mixed.array[0] == 1) { // Little Endian.
|
||||||
mixed.number = x; // Little Endian.
|
mixed.number = x;
|
||||||
uint32_t temp = mixed.array[0];
|
uint32_t temp = mixed.array[0];
|
||||||
mixed.array[0] = htonl(mixed.array[1]);
|
mixed.array[0] = htonl(mixed.array[1]);
|
||||||
mixed.array[1] = htonl(temp);
|
mixed.array[1] = htonl(temp);
|
||||||
return mixed.number;
|
return mixed.number;
|
||||||
} else {
|
} else { // Big Endian.
|
||||||
return x; // Big Endian.
|
return x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t ntohll64(int64_t x) { // Convert from big endian (network-byte-order)
|
||||||
|
union {
|
||||||
|
uint32_t array[2];
|
||||||
|
int64_t number;
|
||||||
|
} mixed;
|
||||||
|
mixed.number = 1;
|
||||||
|
if (mixed.array[0] == 1) { // Little Endian.
|
||||||
|
mixed.number = x;
|
||||||
|
uint32_t temp = mixed.array[0];
|
||||||
|
mixed.array[0] = ntohl(mixed.array[1]);
|
||||||
|
mixed.array[1] = ntohl(temp);
|
||||||
|
return mixed.number;
|
||||||
|
} else { // Big Endian.
|
||||||
|
return x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
240
libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp
Normal file
240
libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "cdm_session.h"
|
||||||
|
#include "crypto_key.h"
|
||||||
|
#include "gmock/gmock.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "properties.h"
|
||||||
|
#include "string_conversions.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const std::string kToken = wvcdm::a2bs_hex(
|
||||||
|
"0AAE02080212107E0A892DEEB021E7AF696B938BB1D5B1188B85AD9D05228E023082010A02"
|
||||||
|
"82010100DBEDF2BFB0EC98213766E65049B9AB176FA4B1FBFBB2A0C96C87D9F2B895E0ED77"
|
||||||
|
"93BDA057E6BC3E0CA2348BC6831E03609445CA4D418CB98EAC98FFC87AB2364CE76BA26BEE"
|
||||||
|
"CDB0C45BD2A6FE9FD38CC5A1C26303AEEB7E9C3CAFAB0D10E46C07E50BEDAB42BF21F40BD2"
|
||||||
|
"E055DB0B455191D6B4CEEB11B3F1AFA42B5C0CE4C96B75A5283C0E3AE049AA7CF86D1C4EF6"
|
||||||
|
"6A9088B53BCF320ABC9B98A22C219DC109014EFEA72DA5FF2ED5D655DE7AE06EAC6C6B4191"
|
||||||
|
"523B2CD2DC1EBFF5F08B11CFE056F2826C1323F12704EC7EBBC1AF935129E5543804492AF9"
|
||||||
|
"23B848F4AF47B4BFB131C39DDDC99DBAEEE0F30AD2ADBBC63E60793D0876E37391008BB4DB"
|
||||||
|
"F7020301000128DD22128002A9E571776EA9D22A1BD14248DA88E12FD859989F613360B8D2"
|
||||||
|
"DA40AF31CC071C7A138466F0EB745E3FD664C0E1A5E4F01098B8D56C34A0158DF9916D192F"
|
||||||
|
"841ADCA17FD630E1C0CBE652CAC6A52B6A1581BE4029CE6FAE0E04D2D2C7861187AF8299D8"
|
||||||
|
"3E008DB9A2789672CA1DED903773D7E82B234CE2C799EB73CF80600C08F17EEDDDF369D2B8"
|
||||||
|
"4A08292F22D1F18FE89521905E713BA674F2217881DBD7711B8C48D5FDCE6FAB51F935E293"
|
||||||
|
"CB29191AB012B115FD2F5F23164B063D0A929C3E254BF0F4FA60051EB6B3498ED99FF77C19"
|
||||||
|
"68E8CD83A35CEB054D05433FD0EA6AAE43C87DDA377591D1DCC1831EE130BFFF6D139A5ADA"
|
||||||
|
"738B0F257CCE2649E71AB4050AAE020801121017DCBC27D11341D497135442A188DAA6188F"
|
||||||
|
"89809105228E023082010A0282010100D21ADD7549D2748B3494526A9C3FB86C79376BBE8C"
|
||||||
|
"8856F601B8D10461F77ACC7331B10DEBF365120056CDB5662D25907B74F12382F0F4A0CA47"
|
||||||
|
"5EEA9562815C6228F6F698ADA27879D8890F2A2D96A746DDEF5316301C003519C2A2250354"
|
||||||
|
"674169FDDA41CE14D3C52BEA7A20384515012D5952B38AA19E15E8563CC7AAA81C2122880A"
|
||||||
|
"A370A64FEA23C53FB83AC3DB5753214730A349E07F64BF32BE7EAD30D02612AF110BB44FB0"
|
||||||
|
"8E1D308173B327EF64D40C41639542B2D1A73C98A6607EC6C683B513A58470514106EF87AE"
|
||||||
|
"1E7B9C695B93A104DF7437BFC4167789748A43ED208F2C1FA710793C688885EAE732A8BFDF"
|
||||||
|
"5B423B23D75B88FC0ADC8FBDB5020301000128DD2212800372D2FB88098BA3B85B6B4354E0"
|
||||||
|
"3767DBE2D7724663FB0A62ABF7704EA910E01F221349EE16D0152C769384050CE78520668C"
|
||||||
|
"06CCFD3D789AF3EB69FF163615CD609169FDBE2E15A029D34AD2605625BC81844C9D1E2CE0"
|
||||||
|
"519039F3799ADAEF86641E20B033DC16DF2E5B9A1A2A417B8BB3B7A4D9AD1A99367448587D"
|
||||||
|
"A13DDE05A3ED9D62FA42078973B4AA40263D7BFA23F1072E94CDF323FA45F78408823E55C4"
|
||||||
|
"F4C5C723819CF44CE6D98E50C04EC24D93B1AAB8877B9108B9CA391308E1A3645EBB0E7CAC"
|
||||||
|
"BB40B5451560ED799421873BFB5ABB917FA60DB9C77CB8606AF7E3142626F5EA40E5CB8AA0"
|
||||||
|
"89D8E7D6A9361935C426A4450EA8BC2E57290D3BF0A0962991D2A91B752FC80C3E7E4E5503"
|
||||||
|
"3D71C94B325307A68815F026448F56A2741CEBEFC18E8C142F5F62BFAA67A291517DDE982D"
|
||||||
|
"8CD5A9DF6E3D3A99B806F6D60991358C5BE77117D4F3168F3348E9A048539F892F4D783152"
|
||||||
|
"C7A8095224AA56B78C5CF7BD1AB1B179C0C0D11E3C3BAC84C141A00191321E3ACC17242E68"
|
||||||
|
"3C");
|
||||||
|
const std::string kWrappedKey = wvcdm::a2bs_hex(
|
||||||
|
"3B84252DD84F1A710365014A114507FFFA3DD404625D61D1EEC7C3A39D72CB8D9318ADE9DA"
|
||||||
|
"05D69F9776DAFDA49A97BC30E84CA275925DFD98CA04F7DB23465103A224852192DE232902"
|
||||||
|
"99FF82024F5CCA7716ACA9BE0B56348BA16B9E3136D73789C842CB2ECA4820DDAAF59CCB9B"
|
||||||
|
"FCF2B4B0E2E5199FDCEC8DEBFFE50BB03041D8E767EA3FE6834C2E79E261ABF17B68EA66E1"
|
||||||
|
"45AD0A6B056F39C06531A9038C996BADD524E57AE7D5339F13C574E7A398C03D65FD730BAC"
|
||||||
|
"36F25347350DD2AD69EFA4DC040DC2D9DD4F53A729839FA3496CF580F2CBD51C3522DD67BC"
|
||||||
|
"BA4A91E89E2BD70449F28E026638920A6DF7B9A0B2C977ACC65AE845E76EF81CADAA746DAF"
|
||||||
|
"51D4D6FCBC083BE50DA1874D6EB1A30579B23C30881D94A8E5181FE20BF8F8C5F2522B1E7D"
|
||||||
|
"092B1E20BDE5373F40286DE15267247F88C564BD4EBF4F69B889A03C9892584DC340D87EE1"
|
||||||
|
"DFF2942D1B7E7EBD846349575F2DE6FDEF71BB005CFBEA845D87937BEBCAFEAC785A092C0A"
|
||||||
|
"76CE7F7A4FE2F8E43045DED5202A2A55F547BA5DE67AF9E6B2B7DC89EFAD34AC0B40BF4B8F"
|
||||||
|
"F82F8706B9A88FB9C7A0972E4A4B6CA970BF4F086573D595E5DB8ED0FDA4F9446ACD4B119C"
|
||||||
|
"1E949C194B042A5CFFC13043FF79F049068A67CC1EB671A10EF7DA927753C4D149E9D0000D"
|
||||||
|
"4307008BA0AED576ACCADF0CE6758F683087F26C2E38297B8C7D78DC3F1E8F24D7B3A0BED9"
|
||||||
|
"C066F8348FD19CDB54A92C4E944EE11E11B3B44344E0DB0E1B4BD6CF9295AB66C05454776A"
|
||||||
|
"8FE33AF659F67718AB43ACB52E83F8C29129DCE9654E8F1EBF9DAB9E933955E24389A37DBE"
|
||||||
|
"17BA89AC8C750B025CB2F65D5C8BF32FED87EF368F15751AA2114159B6C9C6C814D0720DA4"
|
||||||
|
"6E885BBB764ADC250D05F70306C3190991C31439BF273A33B6D1773E4FD089F32E753FA3C7"
|
||||||
|
"7B5ED7DB28407D87396F1F8C83B58176EDFE1F923BDB7DA0ADE58CA2BCD6E76F9463BE7A5A"
|
||||||
|
"909BE2731241BF1436F3E6A639FC7C717445D89AA5812E4532405B0FB368FE736E22D10FFD"
|
||||||
|
"15FACCF69FAC468B5552C7887763B96578038CCF154F333E2095BBFF71D5C1235E032174FB"
|
||||||
|
"44EAB4A753E7A917666A400EBE4F3D2C90100155C27F4B30C8ACFEDA6EFC763EF3556874E5"
|
||||||
|
"8A5AB0AEBBF39990F79EF4D65EC4697D7BBEEF4F32AE8C4A8A94814A9BE532B5AC902BC0C5"
|
||||||
|
"FB0A3E661AFF5961B6E79C82CC32FA7B7B48297347503FD58B110B93208167CC1FB96AD822"
|
||||||
|
"42F60B9D2BF9CCEE8E778A3D3A3302303FB4E33F607D46AACE49D3546A993EDC6FBEE6E19D"
|
||||||
|
"36831D85877013C57FE335F38D5CD9C3E09C1CEE28BC92C53A364663A7C031DF43B89BAAB4"
|
||||||
|
"AA8176900FD483AD70E3844BD15EE4F01D8BE72186BBF9E019FCEE5961166696854D1A901F"
|
||||||
|
"9D71B69B05F75FF233DB3C37F18DCADA640F68C4386F2E528CD77B93521A4574EF399375CD"
|
||||||
|
"2BE7B9FDC0AE62249717B7E0022BF55C0D023669DD09355EAA90E9DF9BEA309DF7561423BF"
|
||||||
|
"1DAD177F07A442E1591553924C0F67C2E86774009825490322A6B74319B4C77AA6195CA393"
|
||||||
|
"03A311F762FB0FD445278D9ACF26A9049C5031BE91F2C4A6BE994CA5A3CEBC2ACCF93AB1EB"
|
||||||
|
"993A6AA6DEB152DE8C9BB0E6B37B478393B50D1AAE99C086A0ED6D93BA7DD2DEEAB58EE34B"
|
||||||
|
"C5EE06BE238E8DE6CB44211097C5C90D5C04857918856F86B7036986C20A43153892ED9093"
|
||||||
|
"33EF70621A98184DDAB5E14BC971CF98CF6C91A37FFA83B00AD3BCABBAAB2DEF1C52F43003"
|
||||||
|
"E74C92B44F9205D22262FB47948654229DE1920F8EDF96A19A88A1CA1552F8856FB4CBF83B"
|
||||||
|
"AA3348419159D207F65FCE9C1A500C6818");
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace wvcdm {
|
||||||
|
|
||||||
|
// gmock methods
|
||||||
|
using ::testing::_;
|
||||||
|
using ::testing::Eq;
|
||||||
|
using ::testing::NotNull;
|
||||||
|
using ::testing::Return;
|
||||||
|
using ::testing::SetArgPointee;
|
||||||
|
using ::testing::StrEq;
|
||||||
|
|
||||||
|
class MockDeviceFiles : public DeviceFiles {
|
||||||
|
public:
|
||||||
|
MOCK_METHOD1(Init, bool(CdmSecurityLevel));
|
||||||
|
MOCK_METHOD2(RetrieveCertificate, bool(std::string*, std::string*));
|
||||||
|
};
|
||||||
|
|
||||||
|
class MockCryptoSession : public CryptoSession {
|
||||||
|
public:
|
||||||
|
MOCK_METHOD1(GetToken, bool(std::string*));
|
||||||
|
MOCK_METHOD0(GetSecurityLevel, CdmSecurityLevel());
|
||||||
|
MOCK_METHOD0(Open, CdmResponseType());
|
||||||
|
MOCK_METHOD1(Open, CdmResponseType(SecurityLevel));
|
||||||
|
MOCK_METHOD1(LoadCertificatePrivateKey, bool(std::string&));
|
||||||
|
MOCK_METHOD0(DeleteAllUsageReports, CdmResponseType());
|
||||||
|
};
|
||||||
|
|
||||||
|
class MockPolicyEngine : public PolicyEngine {
|
||||||
|
public:
|
||||||
|
// Leaving a place holder for when PolicyEngine methods need to be mocked
|
||||||
|
};
|
||||||
|
|
||||||
|
class MockCdmLicense : public CdmLicense {
|
||||||
|
public:
|
||||||
|
MOCK_METHOD3(Init, bool(const std::string&, CryptoSession*, PolicyEngine*));
|
||||||
|
};
|
||||||
|
|
||||||
|
class CdmSessionTest : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
virtual void SetUp() {
|
||||||
|
license_parser_ = new MockCdmLicense();
|
||||||
|
crypto_session_ = new MockCryptoSession();
|
||||||
|
policy_engine_ = new MockPolicyEngine();
|
||||||
|
file_handle_ = new MockDeviceFiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void TearDown() {
|
||||||
|
if (cdm_session_) delete cdm_session_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateSession() {
|
||||||
|
cdm_session_ = new CdmSession(license_parser_, crypto_session_,
|
||||||
|
policy_engine_, file_handle_, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateSession(const CdmClientPropertySet* cdm_client_property_set) {
|
||||||
|
cdm_session_ =
|
||||||
|
new CdmSession(license_parser_, crypto_session_, policy_engine_,
|
||||||
|
file_handle_, cdm_client_property_set);
|
||||||
|
}
|
||||||
|
|
||||||
|
CdmSession* cdm_session_;
|
||||||
|
MockCdmLicense* license_parser_;
|
||||||
|
MockCryptoSession* crypto_session_;
|
||||||
|
MockPolicyEngine* policy_engine_;
|
||||||
|
MockDeviceFiles* file_handle_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(CdmSessionTest, InitWithCertificate) {
|
||||||
|
CdmSecurityLevel level = kSecurityLevelL1;
|
||||||
|
EXPECT_CALL(*crypto_session_, GetSecurityLevel()).WillOnce(Return(level));
|
||||||
|
EXPECT_CALL(*crypto_session_, Open(Eq(kLevelDefault)))
|
||||||
|
.WillOnce(Return(NO_ERROR));
|
||||||
|
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
|
||||||
|
EXPECT_CALL(*file_handle_, RetrieveCertificate(NotNull(), NotNull()))
|
||||||
|
.WillOnce(DoAll(SetArgPointee<0>(kToken), SetArgPointee<1>(kWrappedKey),
|
||||||
|
Return(true)));
|
||||||
|
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey)))
|
||||||
|
.WillOnce(Return(true));
|
||||||
|
EXPECT_CALL(*license_parser_,
|
||||||
|
Init(Eq(kToken), Eq(crypto_session_), Eq(policy_engine_)))
|
||||||
|
.WillOnce(Return(true));
|
||||||
|
|
||||||
|
Properties::set_use_certificates_as_identification(true);
|
||||||
|
|
||||||
|
CreateSession();
|
||||||
|
ASSERT_EQ(NO_ERROR, cdm_session_->Init());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CdmSessionTest, InitWithKeybox) {
|
||||||
|
CdmSecurityLevel level = kSecurityLevelL1;
|
||||||
|
EXPECT_CALL(*crypto_session_, GetSecurityLevel()).WillOnce(Return(level));
|
||||||
|
EXPECT_CALL(*crypto_session_, Open(Eq(kLevelDefault)))
|
||||||
|
.WillOnce(Return(NO_ERROR));
|
||||||
|
EXPECT_CALL(*crypto_session_, GetToken(NotNull()))
|
||||||
|
.WillOnce(DoAll(SetArgPointee<0>(kToken), Return(true)));
|
||||||
|
EXPECT_CALL(*license_parser_,
|
||||||
|
Init(Eq(kToken), Eq(crypto_session_), Eq(policy_engine_)))
|
||||||
|
.WillOnce(Return(true));
|
||||||
|
|
||||||
|
Properties::set_use_certificates_as_identification(false);
|
||||||
|
|
||||||
|
CreateSession();
|
||||||
|
ASSERT_EQ(NO_ERROR, cdm_session_->Init());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CdmSessionTest, ReInitFail) {
|
||||||
|
CdmSecurityLevel level = kSecurityLevelL1;
|
||||||
|
EXPECT_CALL(*crypto_session_, GetSecurityLevel()).WillOnce(Return(level));
|
||||||
|
EXPECT_CALL(*crypto_session_, Open(Eq(kLevelDefault)))
|
||||||
|
.WillOnce(Return(NO_ERROR));
|
||||||
|
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
|
||||||
|
EXPECT_CALL(*file_handle_, RetrieveCertificate(NotNull(), NotNull()))
|
||||||
|
.WillOnce(DoAll(SetArgPointee<0>(kToken), SetArgPointee<1>(kWrappedKey),
|
||||||
|
Return(true)));
|
||||||
|
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey)))
|
||||||
|
.WillOnce(Return(true));
|
||||||
|
EXPECT_CALL(*license_parser_,
|
||||||
|
Init(Eq(kToken), Eq(crypto_session_), Eq(policy_engine_)))
|
||||||
|
.WillOnce(Return(true));
|
||||||
|
|
||||||
|
Properties::set_use_certificates_as_identification(true);
|
||||||
|
|
||||||
|
CreateSession();
|
||||||
|
ASSERT_EQ(NO_ERROR, cdm_session_->Init());
|
||||||
|
ASSERT_EQ(UNKNOWN_ERROR, cdm_session_->Init());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CdmSessionTest, InitFailCryptoError) {
|
||||||
|
CdmSecurityLevel level = kSecurityLevelL1;
|
||||||
|
EXPECT_CALL(*crypto_session_, GetSecurityLevel()).WillOnce(Return(level));
|
||||||
|
EXPECT_CALL(*crypto_session_, Open(Eq(kLevelDefault)))
|
||||||
|
.WillOnce(Return(UNKNOWN_ERROR));
|
||||||
|
|
||||||
|
Properties::set_use_certificates_as_identification(true);
|
||||||
|
|
||||||
|
CreateSession();
|
||||||
|
ASSERT_EQ(UNKNOWN_ERROR, cdm_session_->Init());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CdmSessionTest, InitNeedsProvisioning) {
|
||||||
|
CdmSecurityLevel level = kSecurityLevelL1;
|
||||||
|
EXPECT_CALL(*crypto_session_, GetSecurityLevel()).WillOnce(Return(level));
|
||||||
|
EXPECT_CALL(*crypto_session_, Open(Eq(kLevelDefault)))
|
||||||
|
.WillOnce(Return(NO_ERROR));
|
||||||
|
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
|
||||||
|
EXPECT_CALL(*file_handle_, RetrieveCertificate(NotNull(), NotNull()))
|
||||||
|
.WillOnce(Return(false));
|
||||||
|
|
||||||
|
Properties::set_use_certificates_as_identification(true);
|
||||||
|
|
||||||
|
CreateSession();
|
||||||
|
ASSERT_EQ(NEED_PROVISIONING, cdm_session_->Init());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // wvcdm
|
||||||
@@ -27,7 +27,7 @@ const std::string kCpOfflineKeyId =
|
|||||||
"00000020" // pssh data size
|
"00000020" // pssh data size
|
||||||
// pssh data:
|
// pssh data:
|
||||||
"08011a0d7769646576696e655f746573"
|
"08011a0d7769646576696e655f746573"
|
||||||
"74220d6f66666c696e655f636c697031";
|
"74220d6f66666c696e655f636c697032";
|
||||||
|
|
||||||
// Google Play license server data
|
// Google Play license server data
|
||||||
const std::string kGpLicenseServer =
|
const std::string kGpLicenseServer =
|
||||||
|
|||||||
@@ -106,7 +106,10 @@ CdmResponseType WvContentDecryptionModule::AddKey(
|
|||||||
CdmResponseType WvContentDecryptionModule::RestoreKey(
|
CdmResponseType WvContentDecryptionModule::RestoreKey(
|
||||||
const CdmSessionId& session_id,
|
const CdmSessionId& session_id,
|
||||||
const CdmKeySetId& key_set_id) {
|
const CdmKeySetId& key_set_id) {
|
||||||
return cdm_engine_->RestoreKey(session_id, key_set_id);
|
CdmResponseType sts = cdm_engine_->RestoreKey(session_id, key_set_id);
|
||||||
|
if (sts == KEY_ADDED)
|
||||||
|
EnablePolicyTimer();
|
||||||
|
return sts;
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType WvContentDecryptionModule::CancelKeyRequest(
|
CdmResponseType WvContentDecryptionModule::CancelKeyRequest(
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ test_name := cdm_engine_test
|
|||||||
test_src_dir := ../core/test
|
test_src_dir := ../core/test
|
||||||
include $(LOCAL_PATH)/unit-test.mk
|
include $(LOCAL_PATH)/unit-test.mk
|
||||||
|
|
||||||
|
test_name := cdm_extended_duration_test
|
||||||
|
test_src_dir := .
|
||||||
|
include $(LOCAL_PATH)/unit-test.mk
|
||||||
|
|
||||||
test_name := cdm_session_unittest
|
test_name := cdm_session_unittest
|
||||||
test_src_dir := ../core/test
|
test_src_dir := ../core/test
|
||||||
include $(LOCAL_PATH)/unit-test.mk
|
include $(LOCAL_PATH)/unit-test.mk
|
||||||
|
|||||||
1278
libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp
Normal file
1278
libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -581,8 +581,49 @@ class WvCdmRequestLicenseTest : public testing::Test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Unprovision() {
|
||||||
|
EXPECT_EQ(NO_ERROR, decryptor_.Unprovision(kSecurityLevelL1));
|
||||||
|
EXPECT_EQ(NO_ERROR, decryptor_.Unprovision(kSecurityLevelL3));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Provision() {
|
||||||
|
CdmResponseType status =
|
||||||
|
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
|
||||||
|
switch (status) {
|
||||||
|
case NO_ERROR:
|
||||||
|
decryptor_.CloseSession(session_id_);
|
||||||
|
return;
|
||||||
|
case NEED_PROVISIONING:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
EXPECT_EQ(NO_ERROR, status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string provisioning_server_url;
|
||||||
|
CdmCertificateType cert_type = kCertificateWidevine;
|
||||||
|
std::string cert_authority, cert, wrapped_key;
|
||||||
|
|
||||||
|
status = decryptor_.GetProvisioningRequest(
|
||||||
|
cert_type, cert_authority, &key_msg_, &provisioning_server_url);
|
||||||
|
EXPECT_EQ(wvcdm::NO_ERROR, status);
|
||||||
|
if (NO_ERROR != status) return;
|
||||||
|
EXPECT_EQ(provisioning_server_url, g_config->provisioning_server_url());
|
||||||
|
|
||||||
|
std::string response =
|
||||||
|
GetCertRequestResponse(g_config->provisioning_server_url());
|
||||||
|
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||||
|
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.HandleProvisioningResponse(
|
||||||
|
response, &cert, &wrapped_key));
|
||||||
|
EXPECT_EQ(0, static_cast<int>(cert.size()));
|
||||||
|
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
|
||||||
|
decryptor_.CloseSession(session_id_);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::string GetSecurityLevel(TestWvCdmClientPropertySet* property_set) {
|
std::string GetSecurityLevel(TestWvCdmClientPropertySet* property_set) {
|
||||||
decryptor_.OpenSession(g_key_system, property_set, &session_id_);
|
EXPECT_EQ(NO_ERROR,
|
||||||
|
decryptor_.OpenSession(g_key_system, property_set, &session_id_));
|
||||||
CdmQueryMap query_info;
|
CdmQueryMap query_info;
|
||||||
EXPECT_EQ(wvcdm::NO_ERROR,
|
EXPECT_EQ(wvcdm::NO_ERROR,
|
||||||
decryptor_.QuerySessionStatus(session_id_, &query_info));
|
decryptor_.QuerySessionStatus(session_id_, &query_info));
|
||||||
@@ -864,6 +905,9 @@ TEST_F(WvCdmRequestLicenseTest, AddStreamingKeyTest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WvCdmRequestLicenseTest, AddKeyOfflineTest) {
|
TEST_F(WvCdmRequestLicenseTest, AddKeyOfflineTest) {
|
||||||
|
Unprovision();
|
||||||
|
Provision();
|
||||||
|
|
||||||
// override default settings unless configured through the command line
|
// override default settings unless configured through the command line
|
||||||
std::string key_id;
|
std::string key_id;
|
||||||
std::string client_auth;
|
std::string client_auth;
|
||||||
@@ -876,6 +920,9 @@ TEST_F(WvCdmRequestLicenseTest, AddKeyOfflineTest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WvCdmRequestLicenseTest, RestoreOfflineKeyTest) {
|
TEST_F(WvCdmRequestLicenseTest, RestoreOfflineKeyTest) {
|
||||||
|
Unprovision();
|
||||||
|
Provision();
|
||||||
|
|
||||||
// override default settings unless configured through the command line
|
// override default settings unless configured through the command line
|
||||||
std::string key_id;
|
std::string key_id;
|
||||||
std::string client_auth;
|
std::string client_auth;
|
||||||
@@ -896,6 +943,9 @@ TEST_F(WvCdmRequestLicenseTest, RestoreOfflineKeyTest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WvCdmRequestLicenseTest, ReleaseOfflineKeyTest) {
|
TEST_F(WvCdmRequestLicenseTest, ReleaseOfflineKeyTest) {
|
||||||
|
Unprovision();
|
||||||
|
Provision();
|
||||||
|
|
||||||
// override default settings unless configured through the command line
|
// override default settings unless configured through the command line
|
||||||
std::string key_id;
|
std::string key_id;
|
||||||
std::string client_auth;
|
std::string client_auth;
|
||||||
@@ -923,6 +973,9 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseOfflineKeyTest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WvCdmRequestLicenseTest, ReleaseRetryOfflineKeyTest) {
|
TEST_F(WvCdmRequestLicenseTest, ReleaseRetryOfflineKeyTest) {
|
||||||
|
Unprovision();
|
||||||
|
Provision();
|
||||||
|
|
||||||
// override default settings unless configured through the command line
|
// override default settings unless configured through the command line
|
||||||
std::string key_id;
|
std::string key_id;
|
||||||
std::string client_auth;
|
std::string client_auth;
|
||||||
@@ -959,6 +1012,9 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseRetryOfflineKeyTest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WvCdmRequestLicenseTest, ExpiryOnReleaseOfflineKeyTest) {
|
TEST_F(WvCdmRequestLicenseTest, ExpiryOnReleaseOfflineKeyTest) {
|
||||||
|
Unprovision();
|
||||||
|
Provision();
|
||||||
|
|
||||||
// override default settings unless configured through the command line
|
// override default settings unless configured through the command line
|
||||||
std::string key_id;
|
std::string key_id;
|
||||||
std::string client_auth;
|
std::string client_auth;
|
||||||
@@ -1034,7 +1090,7 @@ class WvCdmUsageInfoTest
|
|||||||
: public WvCdmRequestLicenseTest,
|
: public WvCdmRequestLicenseTest,
|
||||||
public ::testing::WithParamInterface<UsageInfoSubSampleInfo*> {};
|
public ::testing::WithParamInterface<UsageInfoSubSampleInfo*> {};
|
||||||
|
|
||||||
TEST_P(WvCdmUsageInfoTest, DISABLED_UsageInfo) {
|
TEST_P(WvCdmUsageInfoTest, UsageInfo) {
|
||||||
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
|
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
|
||||||
DeviceFiles handle;
|
DeviceFiles handle;
|
||||||
EXPECT_TRUE(handle.Init(security_level));
|
EXPECT_TRUE(handle.Init(security_level));
|
||||||
|
|||||||
Reference in New Issue
Block a user