Changes from Widevine CDM repo
Squashed commit of these CLs from the widevine cdm repo: Update YT CP server URI to point to the UAT server https://widevine-internal-review.googlesource.com/#/c/9327/ OEMCrypto Version 9 API https://widevine-internal-review.googlesource.com/#/c/9142/ Correct Device ID length in OEMCrypto reference version https://widevine-internal-review.googlesource.com/#/c/8723/ Modify tests to prevent intermittent failures https://widevine-internal-review.googlesource.com/#/c/8982/ Generate a unique license request ID https://widevine-internal-review.googlesource.com/#/c/8721/ Re-enable android timer mechanisms https://widevine-internal-review.googlesource.com/#/c/8833/ Do not close CDM session on removeKeys https://widevine-internal-review.googlesource.com/#/c/8703/ And numerous changes required by Eureka, Steel, and CTE versions of Widevine CDM, as highlighted here: https://widevine-internal-review.googlesource.com/#/c/8596/ https://widevine-internal-review.googlesource.com/#/c/8955/ https://widevine-internal-review.googlesource.com/#/c/8922/ https://widevine-internal-review.googlesource.com/#/c/8890/ https://widevine-internal-review.googlesource.com/#/c/8871/ https://widevine-internal-review.googlesource.com/#/c/8706/ https://widevine-internal-review.googlesource.com/#/c/8425/ Change-Id: Iafd33905227e74eb2132c240b929d2282ab68042
This commit is contained in:
@@ -5,7 +5,6 @@
|
||||
|
||||
#include "certificate_provisioning.h"
|
||||
#include "oemcrypto_adapter.h"
|
||||
#include "timer.h"
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
namespace wvcdm {
|
||||
@@ -18,121 +17,114 @@ class WvCdmEventListener;
|
||||
typedef std::map<CdmSessionId, CdmSession*> CdmSessionMap;
|
||||
typedef std::map<CdmKeySetId, CdmSessionId> CdmReleaseKeySetMap;
|
||||
|
||||
class CdmEngine : public TimerHandler {
|
||||
class CdmEngine {
|
||||
public:
|
||||
CdmEngine();
|
||||
virtual ~CdmEngine();
|
||||
|
||||
// Session related methods
|
||||
virtual CdmResponseType OpenSession(
|
||||
const CdmKeySystem& key_system,
|
||||
const CdmClientPropertySet* property_set,
|
||||
CdmSessionId* session_id);
|
||||
virtual CdmResponseType CloseSession(const CdmSessionId& session_id);
|
||||
CdmResponseType OpenSession(const CdmKeySystem& key_system,
|
||||
const CdmClientPropertySet* property_set,
|
||||
CdmSessionId* session_id);
|
||||
CdmResponseType CloseSession(const CdmSessionId& session_id);
|
||||
|
||||
virtual CdmResponseType OpenKeySetSession(const CdmKeySetId& key_set_id);
|
||||
virtual CdmResponseType CloseKeySetSession(const CdmKeySetId& key_set_id);
|
||||
CdmResponseType OpenKeySetSession(const CdmKeySetId& key_set_id);
|
||||
CdmResponseType CloseKeySetSession(const CdmKeySetId& key_set_id);
|
||||
|
||||
// License related methods
|
||||
// Construct a valid license request
|
||||
virtual CdmResponseType GenerateKeyRequest(const CdmSessionId& session_id,
|
||||
const CdmKeySetId& key_set_id,
|
||||
const CdmInitData& init_data,
|
||||
const CdmLicenseType license_type,
|
||||
CdmAppParameterMap& app_parameters,
|
||||
CdmKeyMessage* key_request,
|
||||
std::string* server_url);
|
||||
CdmResponseType GenerateKeyRequest(const CdmSessionId& session_id,
|
||||
const CdmKeySetId& key_set_id,
|
||||
const CdmInitData& init_data,
|
||||
const CdmLicenseType license_type,
|
||||
CdmAppParameterMap& app_parameters,
|
||||
CdmKeyMessage* key_request,
|
||||
std::string* server_url);
|
||||
|
||||
// Accept license response and extract key info.
|
||||
virtual CdmResponseType AddKey(const CdmSessionId& session_id,
|
||||
const CdmKeyResponse& key_data,
|
||||
CdmKeySetId* key_set_id);
|
||||
CdmResponseType AddKey(const CdmSessionId& session_id,
|
||||
const CdmKeyResponse& key_data,
|
||||
CdmKeySetId* key_set_id);
|
||||
|
||||
virtual CdmResponseType RestoreKey(const CdmSessionId& session_id,
|
||||
const CdmKeySetId& key_set_id);
|
||||
CdmResponseType RestoreKey(const CdmSessionId& session_id,
|
||||
const CdmKeySetId& key_set_id);
|
||||
|
||||
CdmResponseType CancelKeyRequest(const CdmSessionId& session_id);
|
||||
|
||||
// Construct valid renewal request for the current session keys.
|
||||
virtual CdmResponseType GenerateRenewalRequest(const CdmSessionId& session_id,
|
||||
CdmKeyMessage* key_request,
|
||||
std::string* server_url);
|
||||
CdmResponseType GenerateRenewalRequest(const CdmSessionId& session_id,
|
||||
CdmKeyMessage* key_request,
|
||||
std::string* server_url);
|
||||
|
||||
// Accept renewal response and update key info.
|
||||
virtual CdmResponseType RenewKey(const CdmSessionId& session_id,
|
||||
const CdmKeyResponse& key_data);
|
||||
CdmResponseType RenewKey(const CdmSessionId& session_id,
|
||||
const CdmKeyResponse& key_data);
|
||||
|
||||
// Query system information
|
||||
virtual CdmResponseType QueryStatus(CdmQueryMap* info);
|
||||
CdmResponseType QueryStatus(CdmQueryMap* info);
|
||||
|
||||
// Query session information
|
||||
virtual CdmResponseType QuerySessionStatus(const CdmSessionId& session_id,
|
||||
CdmQueryMap* key_info);
|
||||
|
||||
// Query license information
|
||||
virtual CdmResponseType QueryKeyStatus(const CdmSessionId& session_id,
|
||||
CdmQueryMap* key_info);
|
||||
CdmResponseType QueryKeyStatus(const CdmSessionId& session_id,
|
||||
CdmQueryMap* key_info);
|
||||
|
||||
// Query seesion control information
|
||||
virtual CdmResponseType QueryKeyControlInfo(const CdmSessionId& session_id,
|
||||
CdmQueryMap* key_info);
|
||||
CdmResponseType QueryKeyControlInfo(const CdmSessionId& session_id,
|
||||
CdmQueryMap* key_info);
|
||||
|
||||
// Provisioning related methods
|
||||
virtual CdmResponseType GetProvisioningRequest(
|
||||
CdmProvisioningRequest* request,
|
||||
std::string* default_url);
|
||||
CdmResponseType GetProvisioningRequest(CdmProvisioningRequest* request,
|
||||
std::string* default_url);
|
||||
|
||||
virtual CdmResponseType HandleProvisioningResponse(
|
||||
CdmProvisioningResponse& response);
|
||||
CdmResponseType HandleProvisioningResponse(CdmProvisioningResponse& response);
|
||||
|
||||
// Secure stop related methods
|
||||
virtual CdmResponseType GetSecureStops(CdmSecureStops* secure_stops);
|
||||
virtual CdmResponseType ReleaseSecureStops(
|
||||
CdmResponseType GetSecureStops(CdmSecureStops* secure_stops);
|
||||
CdmResponseType ReleaseSecureStops(
|
||||
const CdmSecureStopReleaseMessage& message);
|
||||
|
||||
// Decryption and key related methods
|
||||
// Accept encrypted buffer and return decrypted data.
|
||||
virtual CdmResponseType Decrypt(const CdmSessionId& session_id,
|
||||
const CdmDecryptionParameters& parameters);
|
||||
CdmResponseType Decrypt(const CdmSessionId& session_id,
|
||||
const CdmDecryptionParameters& parameters);
|
||||
|
||||
size_t SessionSize() const { return sessions_.size(); }
|
||||
|
||||
// Is the key known to any session?
|
||||
virtual bool IsKeyValid(const KeyId& key_id);
|
||||
virtual bool FindSessionForKey(const KeyId& key_id, CdmSessionId* sessionId);
|
||||
bool IsKeyLoaded(const KeyId& key_id);
|
||||
bool FindSessionForKey(const KeyId& key_id, CdmSessionId* sessionId);
|
||||
|
||||
// Event listener related methods
|
||||
virtual bool AttachEventListener(const CdmSessionId& session_id,
|
||||
WvCdmEventListener* listener);
|
||||
virtual bool DetachEventListener(const CdmSessionId& session_id,
|
||||
WvCdmEventListener* listener);
|
||||
bool AttachEventListener(const CdmSessionId& session_id,
|
||||
WvCdmEventListener* listener);
|
||||
bool DetachEventListener(const CdmSessionId& session_id,
|
||||
WvCdmEventListener* listener);
|
||||
|
||||
// Parse a blob of multiple concatenated PSSH atoms to extract the first
|
||||
// widevine pssh
|
||||
static bool ExtractWidevinePssh(const CdmInitData& init_data,
|
||||
CdmInitData* output);
|
||||
|
||||
// Timer expiration method
|
||||
void OnTimerEvent();
|
||||
|
||||
private:
|
||||
// private methods
|
||||
// Cancel all sessions
|
||||
virtual bool CancelSessions();
|
||||
virtual bool ValidateKeySystem(const CdmKeySystem& key_system);
|
||||
bool CancelSessions();
|
||||
bool ValidateKeySystem(const CdmKeySystem& key_system);
|
||||
|
||||
// timer related methods to drive policy decisions
|
||||
virtual void EnablePolicyTimer();
|
||||
virtual void DisablePolicyTimer(bool force);
|
||||
virtual void OnTimerEvent();
|
||||
|
||||
virtual void OnKeyReleaseEvent(const CdmKeySetId& key_set_id);
|
||||
void OnKeyReleaseEvent(const CdmKeySetId& key_set_id);
|
||||
|
||||
// instance variables
|
||||
CdmSessionMap sessions_;
|
||||
CdmReleaseKeySetMap release_key_sets_;
|
||||
|
||||
CertificateProvisioning cert_provisioning_;
|
||||
SecurityLevel cert_provisioning_requested_security_level_;
|
||||
|
||||
// policy timer
|
||||
Timer policy_timer_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(CdmEngine);
|
||||
};
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ class CdmSession {
|
||||
// ReleaseKey() - Accept response and release key.
|
||||
CdmResponseType ReleaseKey(const CdmKeyResponse& key_response);
|
||||
|
||||
bool IsKeyValid(const KeyId& key_id);
|
||||
bool IsKeyLoaded(const KeyId& key_id);
|
||||
|
||||
bool AttachEventListener(WvCdmEventListener* listener);
|
||||
bool DetachEventListener(WvCdmEventListener* listener);
|
||||
@@ -119,8 +119,6 @@ class CdmSession {
|
||||
// license type release and offline related information
|
||||
CdmKeySetId key_set_id_;
|
||||
|
||||
KeyId key_id_;
|
||||
|
||||
// Used for certificate based licensing
|
||||
std::string wrapped_key_;
|
||||
bool is_certificate_loaded_;
|
||||
|
||||
@@ -63,7 +63,6 @@ class CryptoSession {
|
||||
std::string* wrapped_rsa_key);
|
||||
|
||||
// Media data path
|
||||
bool SelectKey(const std::string& key_id);
|
||||
CdmResponseType Decrypt(const CdmDecryptionParameters& parameters);
|
||||
|
||||
bool GetRandom(size_t data_length, uint8_t* random_data);
|
||||
@@ -80,6 +79,8 @@ class CryptoSession {
|
||||
size_t GetOffset(std::string message, std::string field);
|
||||
bool SetDestinationBufferType();
|
||||
|
||||
bool SelectKey(const std::string& key_id);
|
||||
|
||||
static const size_t kSignatureSize = 32; // size for HMAC-SHA256 signature
|
||||
static Lock crypto_lock_;
|
||||
static bool initialized_;
|
||||
|
||||
@@ -59,6 +59,9 @@ class DeviceFiles {
|
||||
bool RetrieveFile(const char* name, std::string* data);
|
||||
|
||||
private:
|
||||
// Certificate and offline licenses are now stored in security
|
||||
// level specific directories. In an earlier version they were
|
||||
// stored in a common directory and need to be copied over.
|
||||
virtual void SecurityLevelPathBackwardCompatibility();
|
||||
|
||||
File* file_;
|
||||
|
||||
@@ -12,6 +12,8 @@ namespace wvcdm {
|
||||
// File class. The implementation is platform dependent.
|
||||
class File {
|
||||
public:
|
||||
class Impl;
|
||||
|
||||
// defines as bit flag
|
||||
enum OpenFlags {
|
||||
kNoFlags = 0,
|
||||
@@ -39,7 +41,6 @@ class File {
|
||||
virtual ssize_t FileSize(const std::string& file_path);
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
Impl *impl_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(File);
|
||||
|
||||
@@ -27,7 +27,12 @@ class PolicyEngine {
|
||||
// status is not calculated to avoid overhead in the decryption path.
|
||||
inline bool can_decrypt() { return can_decrypt_; }
|
||||
|
||||
void OnTimerEvent(bool& event_occurred, CdmEventType& event);
|
||||
// OnTimerEvent is called when a timer fires. It notifies the Policy Engine
|
||||
// that the timer has fired and that it should check whether any events have
|
||||
// occurred since the last timer event. If so, it sets event_occurred to true
|
||||
// and sets event to point to the event that occurred. If not, it sets
|
||||
// event_occurred to false.
|
||||
void OnTimerEvent(bool* event_occurred, CdmEventType* event);
|
||||
|
||||
// SetLicense is used in handling the initial license response. It stores
|
||||
// an exact copy of the policy information stored in the license.
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
namespace wvcdm {
|
||||
|
||||
typedef std::map<CdmSessionId, const CdmClientPropertySet*>
|
||||
CdmClientPropertySetMap;
|
||||
CdmClientPropertySetMap;
|
||||
|
||||
// This class saves information about features and properties enabled
|
||||
// for a given platform. At initialization it initializes properties from
|
||||
@@ -42,9 +42,7 @@ class Properties {
|
||||
static inline bool use_certificates_as_identification() {
|
||||
return use_certificates_as_identification_;
|
||||
}
|
||||
static inline bool extract_pssh_data() {
|
||||
return extract_pssh_data_;
|
||||
}
|
||||
static inline bool extract_pssh_data() { return extract_pssh_data_; }
|
||||
static inline bool decrypt_with_empty_session_support() {
|
||||
return decrypt_with_empty_session_support_;
|
||||
}
|
||||
@@ -64,13 +62,12 @@ class Properties {
|
||||
static bool GetSecurityLevelDirectories(std::vector<std::string>* dirs);
|
||||
static const std::string GetSecurityLevel(const CdmSessionId& session_id);
|
||||
static const std::vector<uint8_t> GetServiceCertificate(
|
||||
const CdmSessionId& session_id);
|
||||
const CdmSessionId& session_id);
|
||||
static bool UsePrivacyMode(const CdmSessionId& session_id);
|
||||
static uint32_t GetSessionSharingId(const CdmSessionId& session_id);
|
||||
|
||||
static bool AddSessionPropertySet(
|
||||
const CdmSessionId& session_id,
|
||||
const CdmClientPropertySet* property_set);
|
||||
static bool AddSessionPropertySet(const CdmSessionId& session_id,
|
||||
const CdmClientPropertySet* property_set);
|
||||
static bool RemoveSessionPropertySet(const CdmSessionId& session_id);
|
||||
|
||||
private:
|
||||
@@ -94,16 +91,17 @@ class Properties {
|
||||
static void set_use_certificates_as_identification(bool flag) {
|
||||
use_certificates_as_identification_ = flag;
|
||||
}
|
||||
static void set_extract_pssh_data(bool flag) {
|
||||
extract_pssh_data_ = flag;
|
||||
}
|
||||
static void set_extract_pssh_data(bool flag) { extract_pssh_data_ = flag; }
|
||||
|
||||
static void set_decrypt_with_empty_session_support(bool flag) {
|
||||
decrypt_with_empty_session_support_ = flag;
|
||||
}
|
||||
static void set_security_level_path_backward_compatibility_support(bool flag) {
|
||||
static void set_security_level_path_backward_compatibility_support(
|
||||
bool flag) {
|
||||
security_level_path_backward_compatibility_support_ = flag;
|
||||
}
|
||||
|
||||
private:
|
||||
static bool begin_license_usage_when_received_;
|
||||
static bool require_explicit_renew_request_;
|
||||
static bool oem_crypto_use_secure_buffers_;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
namespace wvcdm {
|
||||
|
||||
std::vector<uint8_t> a2b_hex(const std::string& b);
|
||||
std::vector<uint8_t> a2b_hex(const std::string& label, const std::string& b);
|
||||
std::string a2bs_hex(const std::string& b);
|
||||
std::string b2a_hex(const std::vector<uint8_t>& b);
|
||||
std::string b2a_hex(const std::string& b);
|
||||
|
||||
@@ -31,6 +31,8 @@ class TimerHandler {
|
||||
|
||||
class Timer {
|
||||
public:
|
||||
class Impl;
|
||||
|
||||
Timer();
|
||||
~Timer();
|
||||
|
||||
@@ -39,7 +41,6 @@ class Timer {
|
||||
bool IsRunning();
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
Impl *impl_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(Timer);
|
||||
|
||||
@@ -54,7 +54,7 @@ static const std::string QUERY_VALUE_OFFLINE = "Offline";
|
||||
static const std::string QUERY_VALUE_SECURITY_LEVEL_L1 = "L1";
|
||||
static const std::string QUERY_VALUE_SECURITY_LEVEL_L2 = "L2";
|
||||
static const std::string QUERY_VALUE_SECURITY_LEVEL_L3 = "L3";
|
||||
static const std::string QUERY_VALUE_SECURITY_LEVEL_Unknown = "Unknown";
|
||||
static const std::string QUERY_VALUE_SECURITY_LEVEL_UNKNOWN = "Unknown";
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
namespace wvcdm {
|
||||
|
||||
// Listener for events from the Content Decryption Module.
|
||||
// The caller of the CDM API must provide an implementation for onEvent
|
||||
// The caller of the CDM API must provide an implementation for OnEvent
|
||||
// and signal its intent by using the Attach/DetachEventListener methods
|
||||
// in the WvContentDecryptionModule class.
|
||||
class WvCdmEventListener {
|
||||
@@ -16,7 +16,7 @@ class WvCdmEventListener {
|
||||
WvCdmEventListener() {}
|
||||
virtual ~WvCdmEventListener() {}
|
||||
|
||||
virtual void onEvent(const CdmSessionId& session_id,
|
||||
virtual void OnEvent(const CdmSessionId& session_id,
|
||||
CdmEventType cdm_event) = 0;
|
||||
|
||||
private:
|
||||
|
||||
@@ -28,6 +28,11 @@ typedef std::vector<uint8_t> CdmSecureStopReleaseMessage;
|
||||
typedef std::string CdmProvisioningRequest;
|
||||
typedef std::string CdmProvisioningResponse;
|
||||
|
||||
// Types for shared host/cdm interface pairs used to shared vendor data.
|
||||
typedef std::pair<std::string, std::string> kStringPairs;
|
||||
typedef std::vector<uint8_t> kVectorBytes;
|
||||
typedef std::pair<std::string, kVectorBytes> kVectorPairs;
|
||||
|
||||
enum CdmResponseType {
|
||||
NO_ERROR,
|
||||
UNKNOWN_ERROR,
|
||||
|
||||
@@ -15,10 +15,6 @@
|
||||
#include "wv_cdm_constants.h"
|
||||
#include "wv_cdm_event_listener.h"
|
||||
|
||||
namespace {
|
||||
const int kCdmPolicyTimerDurationSeconds = 1;
|
||||
}
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
CdmEngine::CdmEngine()
|
||||
@@ -29,7 +25,6 @@ CdmEngine::CdmEngine()
|
||||
CdmEngine::~CdmEngine() {
|
||||
CancelSessions();
|
||||
|
||||
DisablePolicyTimer(true);
|
||||
CdmSessionMap::iterator i(sessions_.begin());
|
||||
for (; i != sessions_.end(); ++i)
|
||||
delete i->second;
|
||||
@@ -101,7 +96,6 @@ CdmResponseType CdmEngine::CloseSession(const CdmSessionId& session_id) {
|
||||
|
||||
CdmSession* session = iter->second;
|
||||
sessions_.erase(session_id);
|
||||
DisablePolicyTimer(false);
|
||||
delete session;
|
||||
return NO_ERROR;
|
||||
}
|
||||
@@ -248,10 +242,6 @@ CdmResponseType CdmEngine::AddKey(
|
||||
return sts;
|
||||
}
|
||||
|
||||
if (!license_type_release) {
|
||||
EnablePolicyTimer();
|
||||
}
|
||||
|
||||
return KEY_ADDED;
|
||||
}
|
||||
|
||||
@@ -286,9 +276,6 @@ CdmResponseType CdmEngine::CancelKeyRequest(const CdmSessionId& session_id) {
|
||||
|
||||
//TODO(gmorgan): Issue: what is semantics of canceling a key request. Should
|
||||
//this call cancel all keys for the session?
|
||||
// TODO(jfore): We should disable the policy timer here if there are no
|
||||
// active sessions. Sessions are currently not being destroyed here. We can
|
||||
// add this logic once the semantics of canceling the key is worked out.
|
||||
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
@@ -296,8 +283,8 @@ CdmResponseType CdmEngine::CancelKeyRequest(const CdmSessionId& session_id) {
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
// TODO(edwinwong, rfrias): unload keys here
|
||||
DisablePolicyTimer(false);
|
||||
// Re-initialize to release crypto session/keys without closing session
|
||||
iter->second->Init();
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -372,7 +359,8 @@ CdmResponseType CdmEngine::QueryStatus(CdmQueryMap* key_info) {
|
||||
break;
|
||||
case kSecurityLevelUninitialized:
|
||||
case kSecurityLevelUnknown:
|
||||
(*key_info)[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_Unknown;
|
||||
(*key_info)[QUERY_KEY_SECURITY_LEVEL] =
|
||||
QUERY_VALUE_SECURITY_LEVEL_UNKNOWN;
|
||||
break;
|
||||
default:
|
||||
return KEY_ERROR;
|
||||
@@ -504,8 +492,13 @@ CdmResponseType CdmEngine::Decrypt(
|
||||
}
|
||||
|
||||
if (parameters.decrypt_buffer == NULL) {
|
||||
LOGE("CdmEngine::Decrypt: no dest decrypt buffer");
|
||||
return KEY_ERROR;
|
||||
if (!parameters.is_secure &&
|
||||
!Properties::Properties::oem_crypto_use_fifo()) {
|
||||
LOGE("CdmEngine::Decrypt: no dest decrypt buffer");
|
||||
return KEY_ERROR;
|
||||
} // else we must be level 1 direct and we don't need to return a buffer.
|
||||
// TODO:(eschacker) look at renaming Properties::oem_crypto_use_fifo()
|
||||
// to something like Properties::oem_crypto_use_direct_rendering().
|
||||
}
|
||||
|
||||
CdmSessionMap::iterator iter;
|
||||
@@ -514,7 +507,7 @@ CdmResponseType CdmEngine::Decrypt(
|
||||
|
||||
// Loop through the sessions to find the session containing the key_id.
|
||||
for (iter = sessions_.begin(); iter != sessions_.end(); ++iter) {
|
||||
if (iter->second->IsKeyValid(*parameters.key_id)) break;
|
||||
if (iter->second->IsKeyLoaded(*parameters.key_id)) break;
|
||||
}
|
||||
} else {
|
||||
iter = sessions_.find(session_id);
|
||||
@@ -527,10 +520,10 @@ CdmResponseType CdmEngine::Decrypt(
|
||||
return iter->second->Decrypt(parameters);
|
||||
}
|
||||
|
||||
bool CdmEngine::IsKeyValid(const KeyId& key_id) {
|
||||
bool CdmEngine::IsKeyLoaded(const KeyId& key_id) {
|
||||
for (CdmSessionMap::iterator iter = sessions_.begin();
|
||||
iter != sessions_.end(); ++iter) {
|
||||
if (iter->second->IsKeyValid(key_id)) {
|
||||
if (iter->second->IsKeyLoaded(key_id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -545,14 +538,21 @@ bool CdmEngine::FindSessionForKey(
|
||||
return false;
|
||||
}
|
||||
|
||||
CdmSessionMap::iterator iter = sessions_.find(*session_id);
|
||||
if (iter != sessions_.end()) {
|
||||
if (iter->second->IsKeyLoaded(key_id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t session_sharing_id = Properties::GetSessionSharingId(*session_id);
|
||||
|
||||
for (CdmSessionMap::iterator iter = sessions_.begin();
|
||||
iter != sessions_.end(); ++iter) {
|
||||
CdmSessionId id = iter->second->session_id();
|
||||
if (Properties::GetSessionSharingId(id) == session_sharing_id) {
|
||||
if (iter->second->IsKeyValid(key_id)) {
|
||||
*session_id = id;
|
||||
for (iter = sessions_.begin(); iter != sessions_.end(); ++iter) {
|
||||
CdmSessionId local_session_id = iter->second->session_id();
|
||||
if (Properties::GetSessionSharingId(local_session_id) ==
|
||||
session_sharing_id) {
|
||||
if (iter->second->IsKeyLoaded(key_id)) {
|
||||
*session_id = local_session_id;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -684,16 +684,6 @@ bool CdmEngine::ExtractWidevinePssh(
|
||||
return false;
|
||||
}
|
||||
|
||||
void CdmEngine::EnablePolicyTimer() {
|
||||
if (!policy_timer_.IsRunning())
|
||||
policy_timer_.Start(this, kCdmPolicyTimerDurationSeconds);
|
||||
}
|
||||
|
||||
void CdmEngine::DisablePolicyTimer(bool force) {
|
||||
if ((sessions_.size() == 0 || force) && policy_timer_.IsRunning())
|
||||
policy_timer_.Stop();
|
||||
}
|
||||
|
||||
void CdmEngine::OnTimerEvent() {
|
||||
for (CdmSessionMap::iterator iter = sessions_.begin();
|
||||
iter != sessions_.end(); ++iter) {
|
||||
|
||||
@@ -95,7 +95,10 @@ CdmResponseType CdmSession::RestoreOfflineSession(
|
||||
}
|
||||
|
||||
if (Properties::use_certificates_as_identification()) {
|
||||
if (!crypto_session_->LoadCertificatePrivateKey(wrapped_key_)) {
|
||||
if (is_certificate_loaded_ ||
|
||||
crypto_session_->LoadCertificatePrivateKey(wrapped_key_)) {
|
||||
is_certificate_loaded_ = true;
|
||||
} else {
|
||||
return NEED_PROVISIONING;
|
||||
}
|
||||
}
|
||||
@@ -165,8 +168,7 @@ CdmResponseType CdmSession::GenerateKeyRequest(
|
||||
if (is_certificate_loaded_ ||
|
||||
crypto_session_->LoadCertificatePrivateKey(wrapped_key_)) {
|
||||
is_certificate_loaded_ = true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
reinitialize_session_ = true;
|
||||
return NEED_PROVISIONING;
|
||||
}
|
||||
@@ -241,12 +243,12 @@ CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response,
|
||||
|
||||
CdmResponseType CdmSession::QueryStatus(CdmQueryMap* key_info) {
|
||||
if (crypto_session_.get() == NULL) {
|
||||
LOGW("CdmSession::QueryStatus: Invalid crypto session");
|
||||
LOGE("CdmSession::QueryStatus: Invalid crypto session");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
if (!crypto_session_->IsOpen()) {
|
||||
LOGW("CdmSession::QueryStatus: Crypto session not open");
|
||||
LOGE("CdmSession::QueryStatus: Crypto session not open");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
@@ -262,7 +264,8 @@ CdmResponseType CdmSession::QueryStatus(CdmQueryMap* key_info) {
|
||||
break;
|
||||
case kSecurityLevelUninitialized:
|
||||
case kSecurityLevelUnknown:
|
||||
(*key_info)[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_Unknown;
|
||||
(*key_info)[QUERY_KEY_SECURITY_LEVEL] =
|
||||
QUERY_VALUE_SECURITY_LEVEL_UNKNOWN;
|
||||
break;
|
||||
default:
|
||||
return KEY_ERROR;
|
||||
@@ -321,8 +324,10 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
|
||||
// session keys.
|
||||
CdmResponseType CdmSession::GenerateRenewalRequest(CdmKeyMessage* key_request,
|
||||
std::string* server_url) {
|
||||
if (!license_parser_.PrepareKeyUpdateRequest(true, key_request, server_url))
|
||||
if (!license_parser_.PrepareKeyUpdateRequest(true, key_request, server_url)) {
|
||||
LOGE("CdmSession::GenerateRenewalRequest: ERROR on prepare");
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
if (license_type_ == kLicenseTypeOffline) {
|
||||
offline_key_renewal_request_ = *key_request;
|
||||
@@ -364,7 +369,7 @@ CdmResponseType CdmSession::ReleaseKey(const CdmKeyResponse& key_response) {
|
||||
return sts;
|
||||
}
|
||||
|
||||
bool CdmSession::IsKeyValid(const KeyId& key_id) {
|
||||
bool CdmSession::IsKeyLoaded(const KeyId& key_id) {
|
||||
return license_parser_.IsKeyLoaded(key_id);
|
||||
}
|
||||
|
||||
@@ -428,12 +433,12 @@ void CdmSession::OnTimerEvent() {
|
||||
bool event_occurred = false;
|
||||
CdmEventType event;
|
||||
|
||||
policy_engine_.OnTimerEvent(event_occurred, event);
|
||||
policy_engine_.OnTimerEvent(&event_occurred, &event);
|
||||
|
||||
if (event_occurred) {
|
||||
for (CdmEventListenerIter iter = listeners_.begin();
|
||||
iter != listeners_.end(); ++iter) {
|
||||
(*iter)->onEvent(session_id_, event);
|
||||
(*iter)->OnEvent(session_id_, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -442,7 +447,7 @@ void CdmSession::OnKeyReleaseEvent(const CdmKeySetId& key_set_id) {
|
||||
if (key_set_id_ == key_set_id) {
|
||||
for (CdmEventListenerIter iter = listeners_.begin();
|
||||
iter != listeners_.end(); ++iter) {
|
||||
(*iter)->onEvent(session_id_, LICENSE_EXPIRED_EVENT);
|
||||
(*iter)->OnEvent(session_id_, LICENSE_EXPIRED_EVENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,11 +176,20 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
if (!signed_response.has_signature() || !signed_response.has_message()) {
|
||||
LOGE("HandleProvisioningResponse: signature or message not found");
|
||||
return UNKNOWN_ERROR;
|
||||
bool error = false;
|
||||
if (!signed_response.has_signature()) {
|
||||
LOGE("HandleProvisioningResponse: signature not found");
|
||||
error = true;
|
||||
}
|
||||
|
||||
if (!signed_response.has_message()) {
|
||||
LOGE("HandleProvisioningResponse: message not found");
|
||||
error = true;
|
||||
}
|
||||
|
||||
if (error)
|
||||
return UNKNOWN_ERROR;
|
||||
|
||||
const std::string& signed_message = signed_response.message();
|
||||
ProvisioningResponse provisioning_response;
|
||||
|
||||
|
||||
@@ -155,10 +155,7 @@ bool CryptoSession::GetDeviceUniqueId(std::string* device_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
id.resize(id_length + 1);
|
||||
id[id_length] = '\0';
|
||||
|
||||
*device_id = reinterpret_cast<const char*>(&id[0]);
|
||||
device_id->assign(reinterpret_cast<char *>(&id[0]), id_length);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -358,6 +355,8 @@ CdmResponseType CryptoSession::LoadKeys(const std::string& message,
|
||||
if (mac_key.size() >= MAC_KEY_SIZE && mac_key_iv.size() >= KEY_IV_SIZE) {
|
||||
enc_mac_key = msg + GetOffset(message, mac_key);
|
||||
enc_mac_key_iv = msg + GetOffset(message, mac_key_iv);
|
||||
} else {
|
||||
LOGV("CryptoSession::LoadKeys: enc_mac_key not set");
|
||||
}
|
||||
std::vector<OEMCrypto_KeyObject> load_key_array(num_keys);
|
||||
for (int i = 0; i < num_keys; ++i) {
|
||||
@@ -394,7 +393,7 @@ CdmResponseType CryptoSession::LoadKeys(const std::string& message,
|
||||
}
|
||||
|
||||
bool CryptoSession::LoadCertificatePrivateKey(std::string& wrapped_key) {
|
||||
LOGV("CryptoSession::LoadKeys: Lock");
|
||||
LOGV("CryptoSession::LoadCertificatePrivateKey: Lock");
|
||||
AutoLock auto_lock(crypto_lock_);
|
||||
|
||||
LOGV("LoadDeviceRSAKey: id=%ld", (uint32_t)oec_session_id_);
|
||||
@@ -566,7 +565,7 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) {
|
||||
AutoLock auto_lock(crypto_lock_);
|
||||
// Check if key needs to be selected
|
||||
if (params.is_encrypted) {
|
||||
if (key_id_.compare(*params.key_id) != 0) {
|
||||
if (key_id_ != *params.key_id) {
|
||||
if (SelectKey(*params.key_id)) {
|
||||
key_id_ = *params.key_id;
|
||||
} else {
|
||||
@@ -604,7 +603,7 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) {
|
||||
|
||||
switch (sts) {
|
||||
case OEMCrypto_SUCCESS:
|
||||
break;
|
||||
return NO_ERROR;
|
||||
case OEMCrypto_ERROR_INSUFFICIENT_RESOURCES:
|
||||
return INSUFFICIENT_CRYPTO_RESOURCES;
|
||||
case OEMCrypto_ERROR_KEY_EXPIRED:
|
||||
@@ -612,7 +611,6 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) {
|
||||
default:
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
bool CryptoSession::GenerateNonce(uint32_t* nonce) {
|
||||
|
||||
@@ -22,8 +22,11 @@ namespace {
|
||||
const char kCertificateFileName[] = "cert.bin";
|
||||
const char kLicenseFileNameExt[] = ".lic";
|
||||
const char kWildcard[] = "*";
|
||||
const char kPathDelimiter[] = "/";
|
||||
const char *kSecurityLevelPathCompatibilityExclusionList[] = { "ay64.dat" };
|
||||
const char kDirectoryDelimiter = '/';
|
||||
const char* kSecurityLevelPathCompatibilityExclusionList[] = {"ay64.dat"};
|
||||
size_t kSecurityLevelPathCompatibilityExclusionListSize =
|
||||
sizeof(kSecurityLevelPathCompatibilityExclusionList) /
|
||||
sizeof(*kSecurityLevelPathCompatibilityExclusionList);
|
||||
} // namespace
|
||||
|
||||
namespace wvcdm {
|
||||
@@ -436,7 +439,6 @@ bool DeviceFiles::RetrieveFile(const char* name, std::string* data) {
|
||||
}
|
||||
|
||||
if (!file_->Open(path, File::kReadOnly | File::kBinary)) {
|
||||
LOGW("DeviceFiles::RetrieveFile: File open failed: %s", path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -457,27 +459,33 @@ bool DeviceFiles::RetrieveFile(const char* name, std::string* data) {
|
||||
void DeviceFiles::SecurityLevelPathBackwardCompatibility() {
|
||||
std::string path;
|
||||
if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) {
|
||||
LOGW("DeviceFiles::SecurityLevelPathBackwardCompatibility: Unable to "
|
||||
LOGW(
|
||||
"DeviceFiles::SecurityLevelPathBackwardCompatibility: Unable to "
|
||||
"get base path");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> security_dirs;
|
||||
if (!Properties::GetSecurityLevelDirectories(&security_dirs)) {
|
||||
LOGW("DeviceFiles::SecurityLevelPathBackwardCompatibility: Unable to "
|
||||
LOGW(
|
||||
"DeviceFiles::SecurityLevelPathBackwardCompatibility: Unable to "
|
||||
"get security directories");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t pos = std::string::npos;
|
||||
for (size_t i = 0; i < security_dirs.size(); ++i) {
|
||||
pos = path.rfind(security_dirs[i]);
|
||||
if (std::string::npos != pos)
|
||||
pos = path.find(security_dirs[i]);
|
||||
if (pos != std::string::npos && pos > 0 &&
|
||||
pos == path.size() - security_dirs[i].size() &&
|
||||
path[pos - 1] == kDirectoryDelimiter) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos == std::string::npos) {
|
||||
LOGV("DeviceFiles::SecurityLevelPathBackwardCompatibility: Security level "
|
||||
LOGV(
|
||||
"DeviceFiles::SecurityLevelPathBackwardCompatibility: Security level "
|
||||
"specific path not found. Check properties?");
|
||||
return;
|
||||
}
|
||||
@@ -485,16 +493,16 @@ void DeviceFiles::SecurityLevelPathBackwardCompatibility() {
|
||||
std::string from_dir(path, 0, pos);
|
||||
|
||||
std::vector<std::string> files;
|
||||
file_->List(from_dir, &files);
|
||||
if (!file_->List(from_dir, &files)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < files.size(); ++i) {
|
||||
std::string from = from_dir + files[i];
|
||||
bool exclude = false;
|
||||
for (size_t j = 0;
|
||||
j < sizeof(kSecurityLevelPathCompatibilityExclusionList) /
|
||||
sizeof(const char*);
|
||||
j++) {
|
||||
if (files[i].compare(kSecurityLevelPathCompatibilityExclusionList[j]) == 0) {
|
||||
for (size_t j = 0; j < kSecurityLevelPathCompatibilityExclusionListSize;
|
||||
++j) {
|
||||
if (files[i] == kSecurityLevelPathCompatibilityExclusionList[j]) {
|
||||
exclude = true;
|
||||
break;
|
||||
}
|
||||
@@ -504,8 +512,7 @@ void DeviceFiles::SecurityLevelPathBackwardCompatibility() {
|
||||
|
||||
for (size_t j = 0; j < security_dirs.size(); ++j) {
|
||||
std::string to_dir = from_dir + security_dirs[j];
|
||||
if (!file_->Exists(to_dir))
|
||||
file_->CreateDirectory(to_dir);
|
||||
if (!file_->Exists(to_dir)) file_->CreateDirectory(to_dir);
|
||||
std::string to = to_dir + files[i];
|
||||
file_->Copy(from, to);
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ typedef OEMCryptoResult (*L1_GenerateRSASignature_t)(OEMCrypto_SESSION session,
|
||||
size_t message_length,
|
||||
uint8_t* signature,
|
||||
size_t* signature_length,
|
||||
RSA_Padding_Scheme algorithm);
|
||||
RSA_Padding_Scheme padding_scheme);
|
||||
typedef OEMCryptoResult (*L1_DeriveKeysFromSessionKey_t)(
|
||||
OEMCrypto_SESSION session, const uint8_t* enc_session_key,
|
||||
size_t enc_session_key_length, const uint8_t* mac_key_context,
|
||||
@@ -318,7 +318,7 @@ class Adapter {
|
||||
}
|
||||
|
||||
LevelSession get(OEMCrypto_SESSION session) {
|
||||
AutoLock auto_lock(lookup_lock_);
|
||||
AutoLock auto_lock(session_map_lock_);
|
||||
map_iterator pair = session_map_.find(session);
|
||||
if (pair == session_map_.end()) {
|
||||
return LevelSession();
|
||||
@@ -327,7 +327,6 @@ class Adapter {
|
||||
}
|
||||
|
||||
OEMCryptoResult OpenSession(OEMCrypto_SESSION* session, SecurityLevel level) {
|
||||
AutoLock auto_lock(lookup_lock_);
|
||||
LevelSession new_session;
|
||||
OEMCryptoResult result;
|
||||
if (level == kLevelDefault && level1_valid_) {
|
||||
@@ -340,6 +339,7 @@ class Adapter {
|
||||
*session = new_session.session + kLevel3Offset;
|
||||
}
|
||||
if (result == OEMCrypto_SUCCESS) {
|
||||
AutoLock auto_lock(session_map_lock_);
|
||||
// Make sure session is not already in my list of sessions.
|
||||
while (session_map_.find(*session) != session_map_.end()) {
|
||||
(*session)++;
|
||||
@@ -350,7 +350,7 @@ class Adapter {
|
||||
}
|
||||
|
||||
OEMCryptoResult CloseSession(OEMCrypto_SESSION session) {
|
||||
AutoLock auto_lock(lookup_lock_);
|
||||
AutoLock auto_lock(session_map_lock_);
|
||||
map_iterator pair = session_map_.find(session);
|
||||
if (pair == session_map_.end()) {
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
@@ -367,7 +367,7 @@ class Adapter {
|
||||
struct FunctionPointers level1_;
|
||||
struct FunctionPointers level3_;
|
||||
std::map<OEMCrypto_SESSION, LevelSession> session_map_;
|
||||
Lock lookup_lock_;
|
||||
Lock session_map_lock_;
|
||||
// This is just for debugging the map between session ids.
|
||||
// If we add this to the level 3 session id, then the external session
|
||||
// id will match the internal session id in the last two digits.
|
||||
@@ -583,12 +583,13 @@ extern "C" OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_GenerateRSASignature(
|
||||
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
|
||||
uint8_t* signature, size_t* signature_length, RSA_Padding_Scheme algorithm) {
|
||||
uint8_t* signature, size_t* signature_length, RSA_Padding_Scheme padding_scheme) {
|
||||
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
LevelSession pair = kAdapter->get(session);
|
||||
if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
return pair.fcn->GenerateRSASignature(pair.session, message, message_length,
|
||||
signature, signature_length, algorithm);
|
||||
signature, signature_length,
|
||||
padding_scheme);
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(
|
||||
|
||||
@@ -40,8 +40,8 @@ void PolicyEngine::Init(Clock* clock) {
|
||||
clock_ = clock;
|
||||
}
|
||||
|
||||
void PolicyEngine::OnTimerEvent(bool& event_occured, CdmEventType& event) {
|
||||
event_occured = false;
|
||||
void PolicyEngine::OnTimerEvent(bool* event_occurred, CdmEventType* event) {
|
||||
*event_occurred = false;
|
||||
int64_t current_time = clock_->GetCurrentTime();
|
||||
|
||||
// License expiration trumps all.
|
||||
@@ -50,8 +50,8 @@ void PolicyEngine::OnTimerEvent(bool& event_occured, CdmEventType& event) {
|
||||
license_state_ != kLicenseStateExpired) {
|
||||
license_state_ = kLicenseStateExpired;
|
||||
can_decrypt_ = false;
|
||||
event = LICENSE_EXPIRED_EVENT;
|
||||
event_occured = true;
|
||||
*event = LICENSE_EXPIRED_EVENT;
|
||||
*event_occurred = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -91,8 +91,8 @@ void PolicyEngine::OnTimerEvent(bool& event_occured, CdmEventType& event) {
|
||||
|
||||
if (renewal_needed) {
|
||||
UpdateRenewalRequest(current_time);
|
||||
event = LICENSE_RENEWAL_NEEDED_EVENT;
|
||||
event_occured = true;
|
||||
*event = LICENSE_RENEWAL_NEEDED_EVENT;
|
||||
*event_occurred = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,6 +109,10 @@ void PolicyEngine::UpdateLicense(
|
||||
if (!license.has_policy())
|
||||
return;
|
||||
|
||||
if (kLicenseStateExpired == license_state_) {
|
||||
LOGD("PolicyEngine::UpdateLicense: updating an expired license");
|
||||
}
|
||||
|
||||
policy_.MergeFrom(license.policy());
|
||||
|
||||
if (!policy_.can_play()) {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace {
|
||||
const char *kSecurityLevelDirs[] = { "L1/", "L3/" };
|
||||
const char* kSecurityLevelDirs[] = {"L1/", "L3/"};
|
||||
} // namespace
|
||||
|
||||
namespace wvcdm {
|
||||
@@ -30,20 +30,20 @@ void Properties::Init() {
|
||||
kPropertyUseCertificatesAsIdentification;
|
||||
extract_pssh_data_ = kExtractPsshData;
|
||||
decrypt_with_empty_session_support_ = kDecryptWithEmptySessionSupport;
|
||||
security_level_path_backward_compatibility_support_ = kSecurityLevelPathBackwardCompatibilitySupport;
|
||||
security_level_path_backward_compatibility_support_ =
|
||||
kSecurityLevelPathBackwardCompatibilitySupport;
|
||||
session_property_set_.reset(new CdmClientPropertySetMap());
|
||||
}
|
||||
|
||||
bool Properties::AddSessionPropertySet(
|
||||
const CdmSessionId& session_id,
|
||||
const CdmClientPropertySet* property_set) {
|
||||
const CdmSessionId& session_id, const CdmClientPropertySet* property_set) {
|
||||
if (NULL == session_property_set_.get()) {
|
||||
return false;
|
||||
}
|
||||
std::pair<CdmClientPropertySetMap::iterator, bool> result =
|
||||
session_property_set_->insert(
|
||||
std::pair<const CdmSessionId,
|
||||
const CdmClientPropertySet*>(session_id, property_set));
|
||||
session_property_set_->insert(
|
||||
std::pair<const CdmSessionId, const CdmClientPropertySet*>(
|
||||
session_id, property_set));
|
||||
return result.second;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ bool Properties::RemoveSessionPropertySet(const CdmSessionId& session_id) {
|
||||
}
|
||||
|
||||
const CdmClientPropertySet* Properties::GetCdmClientPropertySet(
|
||||
const CdmSessionId& session_id) {
|
||||
const CdmSessionId& session_id) {
|
||||
if (NULL != session_property_set_.get()) {
|
||||
CdmClientPropertySetMap::const_iterator it =
|
||||
session_property_set_->find(session_id);
|
||||
@@ -112,7 +112,7 @@ uint32_t Properties::GetSessionSharingId(const CdmSessionId& session_id) {
|
||||
}
|
||||
|
||||
bool Properties::GetSecurityLevelDirectories(std::vector<std::string>* dirs) {
|
||||
dirs->resize(sizeof(kSecurityLevelDirs)/sizeof(const char*));
|
||||
dirs->resize(sizeof(kSecurityLevelDirs) / sizeof(const char*));
|
||||
for (size_t i = 0; i < dirs->size(); ++i) {
|
||||
(*dirs)[i] = kSecurityLevelDirs[i];
|
||||
}
|
||||
|
||||
@@ -50,6 +50,16 @@ std::vector<uint8_t> a2b_hex(const std::string& byte) {
|
||||
return array;
|
||||
}
|
||||
|
||||
// converts an ascii hex string(2 bytes per digit) into a decimal byte string
|
||||
// dump the string with the label.
|
||||
std::vector<uint8_t> a2b_hex(const std::string& label, const std::string& byte) {
|
||||
|
||||
std::cout << std::endl << "[[DUMP: " << label << " ]= \"" << byte << "\"]"
|
||||
<< std::endl << std::endl;
|
||||
|
||||
return a2b_hex(byte);
|
||||
}
|
||||
|
||||
std::string a2bs_hex(const std::string& byte) {
|
||||
std::vector<uint8_t> array = a2b_hex(byte);
|
||||
return std::string(array.begin(), array.end());
|
||||
@@ -141,7 +151,7 @@ std::string IntToString(int value) {
|
||||
memset(buffer, 0, kOutputBufSize);
|
||||
snprintf(buffer, kOutputBufSize, "%d", value);
|
||||
|
||||
std::string out_string(buffer, sizeof(buffer));
|
||||
std::string out_string(buffer);
|
||||
return out_string;
|
||||
}
|
||||
|
||||
@@ -153,7 +163,7 @@ std::string UintToString(unsigned int value) {
|
||||
memset(buffer, 0, kOutputBufSize);
|
||||
snprintf(buffer, kOutputBufSize, "%u", value);
|
||||
|
||||
std::string out_string(buffer, sizeof(buffer));
|
||||
std::string out_string(buffer);
|
||||
return out_string;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#if defined(CHROMIUM_BUILD)
|
||||
#include "base/at_exit.h"
|
||||
#include "base/message_loop.h"
|
||||
#include "base/message_loop/message_loop.h"
|
||||
#endif
|
||||
#include "cdm_engine.h"
|
||||
#include "config_test_env.h"
|
||||
@@ -19,7 +19,9 @@
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
namespace {
|
||||
// Http OK response code.
|
||||
const int kHttpOk = 200;
|
||||
|
||||
// Default license server, can be configured using --server command line option
|
||||
// Default key id (pssh), can be configured using --keyid command line option
|
||||
std::string g_client_auth;
|
||||
@@ -88,12 +90,11 @@ namespace wvcdm {
|
||||
class WvCdmEngineTest : public testing::Test {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
cdm_engine_.reset(new CdmEngine());
|
||||
cdm_engine_->OpenSession(g_key_system, NULL, &session_id_);
|
||||
cdm_engine_.OpenSession(g_key_system, NULL, &session_id_);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
cdm_engine_->CloseSession(session_id_);
|
||||
cdm_engine_.CloseSession(session_id_);
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -110,21 +111,21 @@ class WvCdmEngineTest : public testing::Test {
|
||||
}
|
||||
|
||||
EXPECT_EQ(KEY_MESSAGE,
|
||||
cdm_engine_->GenerateKeyRequest(session_id_,
|
||||
key_set_id,
|
||||
init_data,
|
||||
kLicenseTypeStreaming,
|
||||
app_parameters,
|
||||
&key_msg_,
|
||||
&server_url));
|
||||
cdm_engine_.GenerateKeyRequest(session_id_,
|
||||
key_set_id,
|
||||
init_data,
|
||||
kLicenseTypeStreaming,
|
||||
app_parameters,
|
||||
&key_msg_,
|
||||
&server_url));
|
||||
}
|
||||
|
||||
void GenerateRenewalRequest(const std::string& key_system,
|
||||
const std::string& init_data) {
|
||||
EXPECT_EQ(KEY_MESSAGE,
|
||||
cdm_engine_->GenerateRenewalRequest(session_id_,
|
||||
&key_msg_,
|
||||
&server_url_));
|
||||
cdm_engine_.GenerateRenewalRequest(session_id_,
|
||||
&key_msg_,
|
||||
&server_url_));
|
||||
}
|
||||
|
||||
// posts a request and extracts the drm message from the response
|
||||
@@ -164,18 +165,18 @@ class WvCdmEngineTest : public testing::Test {
|
||||
std::string resp = GetKeyRequestResponse(server_url,
|
||||
client_auth);
|
||||
CdmKeySetId key_set_id;
|
||||
EXPECT_EQ(cdm_engine_->AddKey(session_id_, resp, &key_set_id), KEY_ADDED);
|
||||
EXPECT_EQ(cdm_engine_.AddKey(session_id_, resp, &key_set_id), KEY_ADDED);
|
||||
}
|
||||
|
||||
void VerifyRenewalKeyResponse(const std::string& server_url,
|
||||
const std::string& client_auth,
|
||||
std::string& init_data){
|
||||
std::string& init_data) {
|
||||
std::string resp = GetKeyRequestResponse(server_url,
|
||||
client_auth);
|
||||
EXPECT_EQ(cdm_engine_->RenewKey(session_id_, resp), wvcdm::KEY_ADDED);
|
||||
EXPECT_EQ(cdm_engine_.RenewKey(session_id_, resp), wvcdm::KEY_ADDED);
|
||||
}
|
||||
|
||||
scoped_ptr<CdmEngine> cdm_engine_;
|
||||
CdmEngine cdm_engine_;
|
||||
std::string key_msg_;
|
||||
std::string session_id_;
|
||||
std::string server_url_;
|
||||
@@ -198,7 +199,10 @@ TEST_F(WvCdmEngineTest, BaseMessageTest) {
|
||||
TEST_F(WvCdmEngineTest, WrongMessageTest) {
|
||||
std::string wrong_message = a2bs_hex(g_wrong_key_id);
|
||||
GenerateKeyRequest(g_key_system, wrong_message);
|
||||
GetKeyRequestResponse(g_license_server, g_client_auth);
|
||||
|
||||
// We should receive a response with no license, i.e. the extracted license
|
||||
// response message should be empty.
|
||||
ASSERT_EQ("", GetKeyRequestResponse(g_license_server, g_client_auth));
|
||||
}
|
||||
|
||||
TEST_F(WvCdmEngineTest, NormalDecryption) {
|
||||
@@ -313,7 +317,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
#if defined(CHROMIUM_BUILD)
|
||||
base::AtExitManager exit;
|
||||
MessageLoop ttr(MessageLoop::TYPE_IO);
|
||||
base::MessageLoop ttr(base::MessageLoop::TYPE_IO);
|
||||
#endif
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
namespace {
|
||||
// Youtube Content Protection license server data
|
||||
const std::string kYtCpLicenseServer =
|
||||
"http://kir03wwwg185.widevine.net/drm";
|
||||
"http://wv-ref-eme-player.appspot.com/proxy";
|
||||
const std::string kYtCpClientAuth = "";
|
||||
const std::string kYtCpKeyId =
|
||||
"000000347073736800000000" // blob size and pssh
|
||||
|
||||
@@ -26,6 +26,7 @@ using ::testing::StrEq;
|
||||
namespace {
|
||||
const uint32_t kCertificateLen = 700;
|
||||
const uint32_t kWrappedKeyLen = 500;
|
||||
const uint32_t kProtobufEstimatedLen = 75;
|
||||
const std::string kTestCertificate =
|
||||
"124B035F3D256A656F0E505A085E7A6C482B61035E0C4A540F7803137F4C3B45206B7F33"
|
||||
"347F4D7A005E56400F0955011F4E07072D0D46781817460974326A516E3944385760280E"
|
||||
@@ -209,7 +210,7 @@ LicenseInfo license_test_data[] = {
|
||||
"0112001A16200342120A106B63746C0000000000ECDCBE0000000020DBDF"
|
||||
"A68F051A20182F029E35047A3841FA176C74E5B387350E8D58DEA6878FF0"
|
||||
"BEA6CABACA1C2C"),
|
||||
"https://jmt17.google.com/video/license/GetCencLicense",
|
||||
"https://jmt17.google.com/video-dev/license/GetCencLicense",
|
||||
wvcdm::a2bs_hex(
|
||||
"0AAF150802100122A8150801121408011210303132333435363738394142"
|
||||
"434445461A9D0E080112950C0AD70B080112EF090AB002080212103E560E"
|
||||
@@ -1038,7 +1039,7 @@ MATCHER_P(IsStrEq, str, "") {
|
||||
MATCHER_P2(Contains, str1, str2, "") {
|
||||
// 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, str1.size() + str2.size() + 75);
|
||||
std::string data(arg, str1.size() + str2.size() + kProtobufEstimatedLen);
|
||||
return (data.find(str1) != std::string::npos &&
|
||||
data.find(str2) != std::string::npos);
|
||||
}
|
||||
@@ -1046,7 +1047,7 @@ MATCHER_P6(Contains, str1, str2, str3, str4, str5, str6, "") {
|
||||
// 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, str1.size() + str2.size() + str3.size() + str4.size() +
|
||||
str5.size() + str6.size() + 75);
|
||||
str5.size() + str6.size() + kProtobufEstimatedLen);
|
||||
return (data.find(str1) != std::string::npos &&
|
||||
data.find(str2) != std::string::npos &&
|
||||
data.find(str3) != std::string::npos &&
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "test_vectors.h"
|
||||
|
||||
namespace {
|
||||
const std::string kTestDirName = "test";
|
||||
const std::string kTestDirName = "test_dir";
|
||||
const std::string kTestFileName = "test.txt";
|
||||
const std::string kTestFileName2 = "test2.txt";
|
||||
const std::string kTestFileNameExt = ".txt";
|
||||
@@ -210,7 +210,7 @@ TEST_F(FileTest, CopyFile) {
|
||||
EXPECT_TRUE(wr_file.Open(path, File::kCreate | File::kBinary));
|
||||
EXPECT_TRUE(wr_file.Write(write_data.data(), write_data.size()));
|
||||
wr_file.Close();
|
||||
EXPECT_TRUE(file.Exists(path));
|
||||
ASSERT_TRUE(file.Exists(path));
|
||||
|
||||
std::string path_copy = test_vectors::kTestDir + kTestFileName2;
|
||||
EXPECT_FALSE(file.Exists(path_copy));
|
||||
@@ -257,9 +257,9 @@ TEST_F(FileTest, ListFiles) {
|
||||
EXPECT_EQ(3u, files.size());
|
||||
|
||||
for (size_t i = 0; i < files.size(); ++i) {
|
||||
EXPECT_TRUE(files[i].compare(kTestDirName) == 0 ||
|
||||
files[i].compare(kTestFileName) == 0 ||
|
||||
files[i].compare(kTestFileName2) == 0);
|
||||
EXPECT_TRUE(files[i] == kTestDirName ||
|
||||
files[i] == kTestFileName ||
|
||||
files[i] == kTestFileName2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ class PolicyEngineTest : public ::testing::Test {
|
||||
policy->set_renewal_recovery_duration_seconds(license_duration_ -
|
||||
license_renewal_delay_); // 10 minutes
|
||||
policy->set_renewal_server_url(
|
||||
"https://jmt17.google.com/video/license/GetCencLicense");
|
||||
"https://jmt17.google.com/video-dev/license/GetCencLicense");
|
||||
policy->set_renewal_delay_seconds(license_renewal_delay_);
|
||||
policy->set_renewal_retry_interval_seconds(
|
||||
license_renewal_retry_interval_);
|
||||
@@ -97,7 +97,7 @@ TEST_F(PolicyEngineTest, PlaybackSuccess) {
|
||||
|
||||
bool event_occurred;
|
||||
CdmEventType event;
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->BeginDecryption();
|
||||
@@ -115,7 +115,7 @@ TEST_F(PolicyEngineTest, PlaybackFailed_CanPlayFalse) {
|
||||
|
||||
bool event_occurred;
|
||||
CdmEventType event;
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->BeginDecryption();
|
||||
@@ -141,10 +141,10 @@ TEST_F(PolicyEngineTest, PlaybackFails_RentalDurationExpired) {
|
||||
|
||||
bool event_occurred;
|
||||
CdmEventType event;
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_TRUE(event_occurred);
|
||||
EXPECT_EQ(LICENSE_EXPIRED_EVENT, event);
|
||||
|
||||
@@ -171,10 +171,10 @@ TEST_F(PolicyEngineTest, PlaybackFails_PlaybackDurationExpired) {
|
||||
|
||||
bool event_occurred;
|
||||
CdmEventType event;
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_TRUE(event_occurred);
|
||||
EXPECT_EQ(LICENSE_EXPIRED_EVENT, event);
|
||||
|
||||
@@ -198,10 +198,10 @@ TEST_F(PolicyEngineTest, PlaybackFails_LicenseDurationExpired) {
|
||||
|
||||
bool event_occurred;
|
||||
CdmEventType event;
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_TRUE(event_occurred);
|
||||
EXPECT_EQ(LICENSE_EXPIRED_EVENT, event);
|
||||
|
||||
@@ -226,10 +226,10 @@ TEST_F(PolicyEngineTest, PlaybackOk_RentalDuration0) {
|
||||
|
||||
bool event_occurred;
|
||||
CdmEventType event;
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_TRUE(event_occurred);
|
||||
EXPECT_EQ(LICENSE_EXPIRED_EVENT, event);
|
||||
|
||||
@@ -254,10 +254,10 @@ TEST_F(PolicyEngineTest, PlaybackOk_PlaybackDuration0) {
|
||||
|
||||
bool event_occurred;
|
||||
CdmEventType event;
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_TRUE(event_occurred);
|
||||
EXPECT_EQ(LICENSE_EXPIRED_EVENT, event);
|
||||
|
||||
@@ -282,10 +282,10 @@ TEST_F(PolicyEngineTest, PlaybackOk_LicenseDuration0) {
|
||||
|
||||
bool event_occurred;
|
||||
CdmEventType event;
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_TRUE(event_occurred);
|
||||
EXPECT_EQ(LICENSE_EXPIRED_EVENT, event);
|
||||
|
||||
@@ -312,10 +312,10 @@ TEST_F(PolicyEngineTest, PlaybackOk_Durations0) {
|
||||
|
||||
bool event_occurred;
|
||||
CdmEventType event;
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||
@@ -343,13 +343,13 @@ TEST_F(PolicyEngineTest, PlaybackFailed_CanRenewFalse) {
|
||||
|
||||
bool event_occurred;
|
||||
CdmEventType event;
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_TRUE(event_occurred);
|
||||
EXPECT_EQ(LICENSE_EXPIRED_EVENT, event);
|
||||
|
||||
@@ -374,10 +374,10 @@ TEST_F(PolicyEngineTest, PlaybackOk_RenewSuccess) {
|
||||
|
||||
bool event_occurred;
|
||||
CdmEventType event;
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_TRUE(event_occurred);
|
||||
EXPECT_EQ(LICENSE_RENEWAL_NEEDED_EVENT, event);
|
||||
|
||||
@@ -389,7 +389,7 @@ TEST_F(PolicyEngineTest, PlaybackOk_RenewSuccess) {
|
||||
id->set_version(2);
|
||||
policy_engine_->UpdateLicense(license_);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||
@@ -412,10 +412,10 @@ TEST_F(PolicyEngineTest, PlaybackFailed_RenewFailedVersionNotUpdated) {
|
||||
|
||||
bool event_occurred;
|
||||
CdmEventType event;
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_TRUE(event_occurred);
|
||||
EXPECT_EQ(LICENSE_RENEWAL_NEEDED_EVENT, event);
|
||||
|
||||
@@ -425,13 +425,13 @@ TEST_F(PolicyEngineTest, PlaybackFailed_RenewFailedVersionNotUpdated) {
|
||||
license_renewal_delay_ + 15);
|
||||
policy_engine_->UpdateLicense(license_);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_TRUE(event_occurred);
|
||||
EXPECT_EQ(LICENSE_RENEWAL_NEEDED_EVENT, event);
|
||||
|
||||
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_TRUE(event_occurred);
|
||||
EXPECT_EQ(LICENSE_EXPIRED_EVENT, event);
|
||||
|
||||
@@ -459,37 +459,37 @@ TEST_F(PolicyEngineTest, PlaybackFailed_RepeatedRenewFailures) {
|
||||
|
||||
bool event_occurred;
|
||||
CdmEventType event;
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_TRUE(event_occurred);
|
||||
EXPECT_EQ(LICENSE_RENEWAL_NEEDED_EVENT, event);
|
||||
|
||||
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_TRUE(event_occurred);
|
||||
EXPECT_EQ(LICENSE_RENEWAL_NEEDED_EVENT, event);
|
||||
|
||||
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_TRUE(event_occurred);
|
||||
EXPECT_EQ(LICENSE_RENEWAL_NEEDED_EVENT, event);
|
||||
|
||||
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_TRUE(event_occurred);
|
||||
EXPECT_EQ(LICENSE_EXPIRED_EVENT, event);
|
||||
|
||||
@@ -519,37 +519,37 @@ TEST_F(PolicyEngineTest, PlaybackOk_RenewSuccessAfterExpiry) {
|
||||
|
||||
bool event_occurred;
|
||||
CdmEventType event;
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_TRUE(event_occurred);
|
||||
EXPECT_EQ(LICENSE_RENEWAL_NEEDED_EVENT, event);
|
||||
|
||||
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_TRUE(event_occurred);
|
||||
EXPECT_EQ(LICENSE_RENEWAL_NEEDED_EVENT, event);
|
||||
|
||||
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_TRUE(event_occurred);
|
||||
EXPECT_EQ(LICENSE_RENEWAL_NEEDED_EVENT, event);
|
||||
|
||||
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_TRUE(event_occurred);
|
||||
EXPECT_EQ(LICENSE_EXPIRED_EVENT, event);
|
||||
|
||||
@@ -566,7 +566,7 @@ TEST_F(PolicyEngineTest, PlaybackOk_RenewSuccessAfterExpiry) {
|
||||
|
||||
policy_engine_->UpdateLicense(license_);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||
@@ -593,25 +593,25 @@ TEST_F(PolicyEngineTest, PlaybackOk_RenewSuccessAfterFailures) {
|
||||
|
||||
bool event_occurred;
|
||||
CdmEventType event;
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_TRUE(event_occurred);
|
||||
EXPECT_EQ(LICENSE_RENEWAL_NEEDED_EVENT, event);
|
||||
|
||||
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_TRUE(event_occurred);
|
||||
EXPECT_EQ(LICENSE_RENEWAL_NEEDED_EVENT, event);
|
||||
|
||||
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
license_.set_license_start_time(license_start_time_ +
|
||||
@@ -620,12 +620,12 @@ TEST_F(PolicyEngineTest, PlaybackOk_RenewSuccessAfterFailures) {
|
||||
id->set_version(2);
|
||||
policy_engine_->UpdateLicense(license_);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||
@@ -647,13 +647,13 @@ TEST_F(PolicyEngineTest, PlaybackOk_RenewedWithUsage) {
|
||||
|
||||
bool event_occurred;
|
||||
CdmEventType event;
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->BeginDecryption();
|
||||
EXPECT_FALSE(policy_engine_->can_decrypt());
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_TRUE(event_occurred);
|
||||
EXPECT_EQ(LICENSE_RENEWAL_NEEDED_EVENT, event);
|
||||
|
||||
@@ -663,7 +663,7 @@ TEST_F(PolicyEngineTest, PlaybackOk_RenewedWithUsage) {
|
||||
id->set_version(2);
|
||||
policy_engine_->UpdateLicense(license_);
|
||||
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||
@@ -723,7 +723,7 @@ TEST_F(PolicyEngineTest, QuerySuccess_Offline) {
|
||||
|
||||
bool event_occurred;
|
||||
CdmEventType event;
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->BeginDecryption();
|
||||
@@ -765,7 +765,7 @@ TEST_F(PolicyEngineTest, QuerySuccess_DurationExpired) {
|
||||
|
||||
bool event_occurred;
|
||||
CdmEventType event;
|
||||
policy_engine_->OnTimerEvent(event_occurred, event);
|
||||
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||
EXPECT_FALSE(event_occurred);
|
||||
|
||||
policy_engine_->BeginDecryption();
|
||||
|
||||
@@ -114,12 +114,14 @@ int UrlRequest::GetResponse(std::string* message) {
|
||||
bytes = socket_.Read(buffer_, kHttpBufferSize, kTimeoutInMs);
|
||||
if (bytes > 0) {
|
||||
response.append(buffer_, bytes);
|
||||
attempts = kSingleReadAttempt;
|
||||
if (bytes < static_cast<int>(kHttpBufferSize)) {
|
||||
attempts = kSingleReadAttempt;
|
||||
}
|
||||
} else {
|
||||
if (bytes < 0) LOGE("read error = ", errno);
|
||||
// bytes == 0 indicates nothing to read
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ConcatenateChunkedResponse(response, message);
|
||||
LOGD("HTTP response: (%d): %s", message->size(), b2a_hex(*message).c_str());
|
||||
|
||||
@@ -3,17 +3,19 @@
|
||||
#ifndef CDM_BASE_WV_CONTENT_DECRYPTION_MODULE_H_
|
||||
#define CDM_BASE_WV_CONTENT_DECRYPTION_MODULE_H_
|
||||
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
#include <UniquePtr.h>
|
||||
|
||||
#include "lock.h"
|
||||
#include "timer.h"
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
class CdmClientPropertySet;
|
||||
class CdmEngine;
|
||||
class WvCdmEventListener;
|
||||
|
||||
class WvContentDecryptionModule {
|
||||
class WvContentDecryptionModule : public TimerHandler {
|
||||
public:
|
||||
WvContentDecryptionModule();
|
||||
virtual ~WvContentDecryptionModule();
|
||||
@@ -91,6 +93,14 @@ class WvContentDecryptionModule {
|
||||
private:
|
||||
uint32_t GenerateSessionSharingId();
|
||||
|
||||
// timer related methods to drive policy decisions
|
||||
void EnablePolicyTimer();
|
||||
void DisablePolicyTimer(bool force);
|
||||
void OnTimerEvent();
|
||||
|
||||
static Lock session_sharing_id_generation_lock_;
|
||||
Timer policy_timer_;
|
||||
|
||||
// instance variables
|
||||
UniquePtr<CdmEngine> cdm_engine_;
|
||||
|
||||
|
||||
@@ -18,8 +18,12 @@
|
||||
namespace {
|
||||
const char kCurrentDirectory[] = ".";
|
||||
const char kParentDirectory[] = "..";
|
||||
const char kPathDelimiter[] = "/";
|
||||
const char kDirectoryDelimiter = '/';
|
||||
const char kWildcard[] = "*";
|
||||
bool IsCurrentOrParentDirectory(char* dir) {
|
||||
return strcmp(dir, kCurrentDirectory) == 0 ||
|
||||
strcmp(dir, kParentDirectory) == 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace wvcdm {
|
||||
@@ -114,9 +118,8 @@ bool File::Remove(const std::string& path) {
|
||||
// first remove files and dir within it
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
if (strcmp(entry->d_name, kCurrentDirectory) &&
|
||||
(strcmp(entry->d_name, kParentDirectory))) {
|
||||
std::string path_to_remove = path + kPathDelimiter;
|
||||
if (!IsCurrentOrParentDirectory(entry->d_name)) {
|
||||
std::string path_to_remove = path + kDirectoryDelimiter;
|
||||
path_to_remove += entry->d_name;
|
||||
if (!Remove(path_to_remove)) {
|
||||
closedir(dir);
|
||||
@@ -141,7 +144,7 @@ bool File::Remove(const std::string& path) {
|
||||
}
|
||||
} else {
|
||||
// Handle wildcard specified file deletion
|
||||
size_t delimiter_pos = path.rfind(kPathDelimiter, wildcard_pos);
|
||||
size_t delimiter_pos = path.rfind(kDirectoryDelimiter, wildcard_pos);
|
||||
if (delimiter_pos == std::string::npos) {
|
||||
LOGW("File::Remove: unable to find path delimiter before wildcard");
|
||||
return false;
|
||||
@@ -163,7 +166,7 @@ bool File::Remove(const std::string& path) {
|
||||
if (strcmp(entry->d_name + filename_len - ext.size(), ext.c_str()) ==
|
||||
0) {
|
||||
std::string file_path_to_remove =
|
||||
dir_path + kPathDelimiter + entry->d_name;
|
||||
dir_path + kDirectoryDelimiter + entry->d_name;
|
||||
if (!Remove(file_path_to_remove)) {
|
||||
closedir(dir);
|
||||
return false;
|
||||
@@ -180,34 +183,34 @@ bool File::Remove(const std::string& path) {
|
||||
bool File::Copy(const std::string& src, const std::string& dest) {
|
||||
struct stat stat_buf;
|
||||
if (stat(src.c_str(), &stat_buf)) {
|
||||
LOGV("File::Copy: file %s does not exist: %d", src.c_str(), errno);
|
||||
LOGV("File::Copy: file %s stat error: %d", src.c_str(), errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
int fd_src = open(src.c_str(), O_RDONLY);
|
||||
if (fd_src < 0) {
|
||||
LOGV("File::Copy: unable to open file %s: %d", src.c_str(), errno);
|
||||
LOGW("File::Copy: unable to open file %s: %d", src.c_str(), errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
int fd_dest = open(dest.c_str(), O_WRONLY|O_CREAT, stat_buf.st_mode);
|
||||
int fd_dest = open(dest.c_str(), O_WRONLY | O_CREAT, stat_buf.st_mode);
|
||||
if (fd_dest < 0) {
|
||||
LOGV("File::Copy: unable to open file %s: %d", dest.c_str(), errno);
|
||||
LOGW("File::Copy: unable to open file %s: %d", dest.c_str(), errno);
|
||||
close(fd_src);
|
||||
return false;
|
||||
}
|
||||
|
||||
off_t offset = 0;
|
||||
bool sts = true;
|
||||
bool status = true;
|
||||
if (sendfile(fd_dest, fd_src, &offset, stat_buf.st_size) < 0) {
|
||||
LOGV("File::Copy: unable to copy %s to %s: %d", src.c_str(), dest.c_str(),
|
||||
errno);
|
||||
sts = false;
|
||||
status = false;
|
||||
}
|
||||
|
||||
close(fd_src);
|
||||
close(fd_dest);
|
||||
return sts;
|
||||
return status;
|
||||
}
|
||||
|
||||
bool File::List(const std::string& path, std::vector<std::string>* files) {
|
||||
@@ -221,16 +224,16 @@ bool File::List(const std::string& path, std::vector<std::string>* files) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DIR* dir;
|
||||
if ((dir = opendir(path.c_str())) == NULL) {
|
||||
DIR* dir = opendir(path.c_str());
|
||||
if (dir == NULL) {
|
||||
LOGW("File::List: unable to open directory %s: %d", path.c_str(), errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
files->clear();
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
if (strcmp(entry->d_name, kCurrentDirectory) &&
|
||||
(strcmp(entry->d_name, kParentDirectory))) {
|
||||
if (!IsCurrentOrParentDirectory(entry->d_name)) {
|
||||
files->push_back(entry->d_name);
|
||||
}
|
||||
}
|
||||
@@ -241,31 +244,29 @@ bool File::List(const std::string& path, std::vector<std::string>* files) {
|
||||
|
||||
bool File::CreateDirectory(std::string path) {
|
||||
size_t size = path.size();
|
||||
if ((size == 1) && (path[0] == kPathDelimiter[0])) return true;
|
||||
if ((size == 1) && (path[0] == kDirectoryDelimiter)) return true;
|
||||
|
||||
if (size <= 1) return false;
|
||||
|
||||
if (path.at(size - 1) == kPathDelimiter[0]) {
|
||||
--size;
|
||||
path.resize(size);
|
||||
}
|
||||
|
||||
size_t pos = path.find(kPathDelimiter[0], 1);
|
||||
size_t pos = path.find(kDirectoryDelimiter, 1);
|
||||
while (pos < size) {
|
||||
path.at(pos) = '\0';
|
||||
path[pos] = '\0';
|
||||
if (mkdir(path.c_str(), 0775) != 0) {
|
||||
if (errno != EEXIST) {
|
||||
LOGW("File::CreateDirectory: mkdir failed: %d\n", errno);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
path.at(pos) = kPathDelimiter[0];
|
||||
pos = path.find(kPathDelimiter[0], pos + 1);
|
||||
path[pos] = kDirectoryDelimiter;
|
||||
pos = path.find(kDirectoryDelimiter, pos + 1);
|
||||
}
|
||||
if (mkdir(path.c_str(), 0775) != 0) {
|
||||
if (errno != EEXIST) {
|
||||
LOGW("File::CreateDirectory: mkdir failed: %d\n", errno);
|
||||
return false;
|
||||
|
||||
if (path[size - 1] != kDirectoryDelimiter) {
|
||||
if (mkdir(path.c_str(), 0775) != 0) {
|
||||
if (errno != EEXIST) {
|
||||
LOGW("File::CreateDirectory: mkdir failed: %d\n", errno);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -11,18 +11,27 @@
|
||||
#include "wv_cdm_constants.h"
|
||||
#include "wv_cdm_event_listener.h"
|
||||
|
||||
namespace {
|
||||
const int kCdmPolicyTimerDurationSeconds = 1;
|
||||
}
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
Lock WvContentDecryptionModule::session_sharing_id_generation_lock_;
|
||||
|
||||
WvContentDecryptionModule::WvContentDecryptionModule()
|
||||
: cdm_engine_(new CdmEngine()) {}
|
||||
|
||||
WvContentDecryptionModule::~WvContentDecryptionModule() {}
|
||||
WvContentDecryptionModule::~WvContentDecryptionModule() {
|
||||
DisablePolicyTimer(true);
|
||||
}
|
||||
|
||||
CdmResponseType WvContentDecryptionModule::OpenSession(
|
||||
const CdmKeySystem& key_system,
|
||||
CdmClientPropertySet* property_set,
|
||||
CdmSessionId* session_id) {
|
||||
if (property_set && property_set->is_session_sharing_enabled()) {
|
||||
AutoLock auto_lock(session_sharing_id_generation_lock_);
|
||||
if (property_set->session_sharing_id() == 0)
|
||||
property_set->set_session_sharing_id(GenerateSessionSharingId());
|
||||
}
|
||||
@@ -32,7 +41,9 @@ CdmResponseType WvContentDecryptionModule::OpenSession(
|
||||
|
||||
CdmResponseType WvContentDecryptionModule::CloseSession(
|
||||
const CdmSessionId& session_id) {
|
||||
return cdm_engine_->CloseSession(session_id);
|
||||
CdmResponseType sts = cdm_engine_->CloseSession(session_id);
|
||||
DisablePolicyTimer(false);
|
||||
return sts;
|
||||
}
|
||||
|
||||
CdmResponseType WvContentDecryptionModule::GenerateKeyRequest(
|
||||
@@ -49,13 +60,19 @@ CdmResponseType WvContentDecryptionModule::GenerateKeyRequest(
|
||||
if (sts != NO_ERROR)
|
||||
return sts;
|
||||
}
|
||||
sts = cdm_engine_->GenerateKeyRequest(session_id, key_set_id,
|
||||
init_data, license_type,
|
||||
app_parameters, key_request,
|
||||
server_url);
|
||||
sts = cdm_engine_->GenerateKeyRequest(session_id, key_set_id, init_data,
|
||||
license_type, app_parameters,
|
||||
key_request, server_url);
|
||||
|
||||
if (license_type == kLicenseTypeRelease && sts != KEY_MESSAGE) {
|
||||
cdm_engine_->CloseKeySetSession(key_set_id);
|
||||
switch(license_type) {
|
||||
case kLicenseTypeRelease:
|
||||
if (sts != KEY_MESSAGE)
|
||||
cdm_engine_->CloseKeySetSession(key_set_id);
|
||||
break;
|
||||
default:
|
||||
if (sts == KEY_MESSAGE)
|
||||
EnablePolicyTimer();
|
||||
break;
|
||||
}
|
||||
return sts;
|
||||
}
|
||||
@@ -124,16 +141,17 @@ CdmResponseType WvContentDecryptionModule::Decrypt(
|
||||
const CdmSessionId& session_id,
|
||||
bool validate_key_id,
|
||||
const CdmDecryptionParameters& parameters) {
|
||||
CdmSessionId id = session_id;
|
||||
CdmSessionId local_session_id = session_id;
|
||||
if (validate_key_id &&
|
||||
Properties::GetSessionSharingId(session_id) != 0) {
|
||||
bool status = cdm_engine_->FindSessionForKey(*parameters.key_id, &id);
|
||||
bool status = cdm_engine_->FindSessionForKey(*parameters.key_id,
|
||||
&local_session_id);
|
||||
if (!status) {
|
||||
LOGE("WvContentDecryptionModule::Decrypt: unable to find session");
|
||||
return NEED_KEY;
|
||||
}
|
||||
}
|
||||
return cdm_engine_->Decrypt(id, parameters);
|
||||
return cdm_engine_->Decrypt(local_session_id, parameters);
|
||||
}
|
||||
|
||||
bool WvContentDecryptionModule::AttachEventListener(
|
||||
@@ -146,9 +164,25 @@ bool WvContentDecryptionModule::DetachEventListener(
|
||||
return cdm_engine_->DetachEventListener(session_id, listener);
|
||||
}
|
||||
|
||||
void WvContentDecryptionModule::EnablePolicyTimer() {
|
||||
if (!policy_timer_.IsRunning())
|
||||
policy_timer_.Start(this, kCdmPolicyTimerDurationSeconds);
|
||||
}
|
||||
|
||||
void WvContentDecryptionModule::DisablePolicyTimer(bool force) {
|
||||
if ((cdm_engine_->SessionSize() == 0 || force) && policy_timer_.IsRunning())
|
||||
policy_timer_.Stop();
|
||||
}
|
||||
|
||||
void WvContentDecryptionModule::OnTimerEvent() {
|
||||
cdm_engine_->OnTimerEvent();
|
||||
}
|
||||
|
||||
uint32_t WvContentDecryptionModule::GenerateSessionSharingId() {
|
||||
static int next_session_sharing_id = 0;
|
||||
return ++next_session_sharing_id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
|
||||
namespace {
|
||||
const char kPathDelimiter = '/';
|
||||
// Http OK response code.
|
||||
const int kHttpOk = 200;
|
||||
|
||||
// Default license server, can be configured using --server command line option
|
||||
// Default key id (pssh), can be configured using --keyid command line option
|
||||
std::string g_client_auth;
|
||||
@@ -239,10 +242,10 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet {
|
||||
return service_certificate_;
|
||||
}
|
||||
virtual bool use_privacy_mode() const { return use_privacy_mode_; }
|
||||
bool is_session_sharing_enabled() const {
|
||||
virtual bool is_session_sharing_enabled() const {
|
||||
return is_session_sharing_enabled_;
|
||||
}
|
||||
uint32_t session_sharing_id() const { return session_sharing_id_; }
|
||||
virtual uint32_t session_sharing_id() const { return session_sharing_id_; }
|
||||
|
||||
void set_security_level(const std::string& security_level) {
|
||||
if (!security_level.compare(QUERY_VALUE_SECURITY_LEVEL_L1) ||
|
||||
@@ -273,7 +276,7 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet {
|
||||
class TestWvCdmEventListener : public WvCdmEventListener {
|
||||
public:
|
||||
TestWvCdmEventListener() : WvCdmEventListener() {}
|
||||
virtual void onEvent(const CdmSessionId& id, CdmEventType event) {
|
||||
virtual void OnEvent(const CdmSessionId& id, CdmEventType event) {
|
||||
session_id_ = id;
|
||||
event_type_ = event;
|
||||
}
|
||||
@@ -333,8 +336,7 @@ class WvCdmRequestLicenseTest : public testing::Test {
|
||||
|
||||
// Post a request and extract the drm message from the response
|
||||
std::string GetKeyRequestResponse(const std::string& server_url,
|
||||
const std::string& client_auth,
|
||||
int expected_response) {
|
||||
const std::string& client_auth) {
|
||||
// Use secure connection and chunk transfer coding.
|
||||
UrlRequest url_request(server_url + client_auth, g_port,
|
||||
g_use_secure_transfer, g_use_chunked_transfer);
|
||||
@@ -345,15 +347,11 @@ class WvCdmRequestLicenseTest : public testing::Test {
|
||||
std::string message;
|
||||
int resp_bytes = url_request.GetResponse(&message);
|
||||
|
||||
// Youtube server returns 400 for invalid message while play server returns
|
||||
// 500, so just test inequity here for invalid message
|
||||
int status_code = url_request.GetStatusCode(message);
|
||||
if (expected_response == 200) {
|
||||
EXPECT_EQ(200, status_code);
|
||||
}
|
||||
EXPECT_EQ(kHttpOk, status_code);
|
||||
|
||||
std::string drm_msg;
|
||||
if (200 == status_code) {
|
||||
if (kHttpOk == status_code) {
|
||||
LicenseRequest lic_request;
|
||||
lic_request.GetDrmMessage(message, drm_msg);
|
||||
LOGV("HTTP response body: (%u bytes)", drm_msg.size());
|
||||
@@ -363,8 +361,7 @@ class WvCdmRequestLicenseTest : public testing::Test {
|
||||
|
||||
// Post a request and extract the signed provisioning message from
|
||||
// the HTTP response.
|
||||
std::string GetCertRequestResponse(const std::string& server_url,
|
||||
int expected_response) {
|
||||
std::string GetCertRequestResponse(const std::string& server_url) {
|
||||
// Use secure connection and chunk transfer coding.
|
||||
UrlRequest url_request(server_url, kDefaultHttpsPort, true, true);
|
||||
if (!url_request.is_connected()) {
|
||||
@@ -376,21 +373,15 @@ class WvCdmRequestLicenseTest : public testing::Test {
|
||||
int resp_bytes = url_request.GetResponse(&message);
|
||||
LOGD("end %d bytes response dump", resp_bytes);
|
||||
|
||||
// Youtube server returns 400 for invalid message while play server returns
|
||||
// 500, so just test inequity here for invalid message
|
||||
int status_code = url_request.GetStatusCode(message);
|
||||
if (expected_response == 200) {
|
||||
EXPECT_EQ(200, status_code);
|
||||
} else {
|
||||
EXPECT_NE(200, status_code);
|
||||
}
|
||||
EXPECT_EQ(kHttpOk, status_code);
|
||||
return message;
|
||||
}
|
||||
|
||||
void VerifyKeyRequestResponse(const std::string& server_url,
|
||||
const std::string& client_auth,
|
||||
std::string& init_data, bool is_renewal) {
|
||||
std::string resp = GetKeyRequestResponse(server_url, client_auth, 200);
|
||||
std::string resp = GetKeyRequestResponse(server_url, client_auth);
|
||||
|
||||
if (is_renewal) {
|
||||
// TODO application makes a license request, CDM will renew the license
|
||||
@@ -403,20 +394,24 @@ class WvCdmRequestLicenseTest : public testing::Test {
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetSecurityLevel(TestWvCdmClientPropertySet* property_set) {
|
||||
decryptor_.OpenSession(g_key_system, property_set, &session_id_);
|
||||
CdmQueryMap query_info;
|
||||
EXPECT_EQ(wvcdm::NO_ERROR,
|
||||
decryptor_.QuerySessionStatus(session_id_, &query_info));
|
||||
CdmQueryMap::iterator itr =
|
||||
query_info.find(wvcdm::QUERY_KEY_SECURITY_LEVEL);
|
||||
EXPECT_TRUE(itr != query_info.end());
|
||||
decryptor_.CloseSession(session_id_);
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
wvcdm::WvContentDecryptionModule decryptor_;
|
||||
CdmKeyMessage key_msg_;
|
||||
CdmSessionId session_id_;
|
||||
CdmKeySetId key_set_id_;
|
||||
};
|
||||
|
||||
class WvCdmDecryptionTest
|
||||
: public WvCdmRequestLicenseTest,
|
||||
public ::testing::WithParamInterface<SubSampleInfo*> {};
|
||||
|
||||
class WvCdmSessionSharingTest
|
||||
: public WvCdmRequestLicenseTest,
|
||||
public ::testing::WithParamInterface<SessionSharingSubSampleInfo*> {};
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, ProvisioningTest) {
|
||||
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
|
||||
std::string provisioning_server_url;
|
||||
@@ -426,7 +421,7 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningTest) {
|
||||
EXPECT_EQ(provisioning_server_url, g_config->provisioning_server_url());
|
||||
|
||||
std::string response =
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url(), 200);
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url());
|
||||
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.HandleProvisioningResponse(response));
|
||||
decryptor_.CloseSession(session_id_);
|
||||
@@ -445,12 +440,12 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningRetryTest) {
|
||||
EXPECT_EQ(provisioning_server_url, g_config->provisioning_server_url());
|
||||
|
||||
std::string response =
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url(), 200);
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url());
|
||||
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.HandleProvisioningResponse(response));
|
||||
|
||||
response =
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url(), 200);
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url());
|
||||
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||
EXPECT_EQ(wvcdm::UNKNOWN_ERROR,
|
||||
decryptor_.HandleProvisioningResponse(response));
|
||||
@@ -471,17 +466,16 @@ TEST_F(WvCdmRequestLicenseTest, PropertySetTest) {
|
||||
property_set_L3.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
|
||||
property_set_L3.set_use_privacy_mode(false);
|
||||
|
||||
CdmResponseType sts = decryptor_.OpenSession(g_key_system, &property_set_L3,
|
||||
&session_id_L3);
|
||||
CdmResponseType sts =
|
||||
decryptor_.OpenSession(g_key_system, &property_set_L3, &session_id_L3);
|
||||
|
||||
if (NEED_PROVISIONING == sts) {
|
||||
std::string provisioning_server_url;
|
||||
EXPECT_EQ(
|
||||
NO_ERROR,
|
||||
decryptor_.GetProvisioningRequest(&key_msg_, &provisioning_server_url));
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.GetProvisioningRequest(
|
||||
&key_msg_, &provisioning_server_url));
|
||||
EXPECT_EQ(provisioning_server_url, g_config->provisioning_server_url());
|
||||
std::string response =
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url(), 200);
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url());
|
||||
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.HandleProvisioningResponse(response));
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.OpenSession(g_key_system, &property_set_L3,
|
||||
@@ -498,7 +492,7 @@ TEST_F(WvCdmRequestLicenseTest, PropertySetTest) {
|
||||
!security_level.compare(QUERY_VALUE_SECURITY_LEVEL_L3));
|
||||
EXPECT_TRUE(Properties::UsePrivacyMode(session_id_L1));
|
||||
EXPECT_EQ(Properties::GetSecurityLevel(session_id_L3),
|
||||
QUERY_VALUE_SECURITY_LEVEL_L3);
|
||||
QUERY_VALUE_SECURITY_LEVEL_L3);
|
||||
EXPECT_FALSE(Properties::UsePrivacyMode(session_id_L3));
|
||||
security_level = Properties::GetSecurityLevel(session_id_Ln);
|
||||
EXPECT_TRUE(security_level.empty() ||
|
||||
@@ -520,17 +514,16 @@ TEST_F(WvCdmRequestLicenseTest, ForceL3Test) {
|
||||
EXPECT_EQ(NEED_PROVISIONING,
|
||||
decryptor_.OpenSession(g_key_system, &property_set, &session_id_));
|
||||
std::string provisioning_server_url;
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
decryptor_.GetProvisioningRequest(&key_msg_,
|
||||
&provisioning_server_url));
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.GetProvisioningRequest(
|
||||
&key_msg_, &provisioning_server_url));
|
||||
EXPECT_EQ(provisioning_server_url, g_config->provisioning_server_url());
|
||||
std::string response =
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url(), 200);
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url());
|
||||
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.HandleProvisioningResponse(response));
|
||||
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.OpenSession(g_key_system, &property_set,
|
||||
&session_id_));
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
decryptor_.OpenSession(g_key_system, &property_set, &session_id_));
|
||||
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeStreaming);
|
||||
VerifyKeyRequestResponse(g_license_server, g_client_auth, g_key_id, false);
|
||||
decryptor_.CloseSession(session_id_);
|
||||
@@ -543,8 +536,8 @@ TEST_F(WvCdmRequestLicenseTest, DISABLED_PrivacyModeTest) {
|
||||
decryptor_.OpenSession(g_key_system, &property_set, &session_id_);
|
||||
|
||||
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeStreaming);
|
||||
std::string resp = GetKeyRequestResponse(g_license_server,
|
||||
g_client_auth, 200);
|
||||
std::string resp =
|
||||
GetKeyRequestResponse(g_license_server, g_client_auth);
|
||||
EXPECT_EQ(decryptor_.AddKey(session_id_, resp, &key_set_id_),
|
||||
wvcdm::NEED_KEY);
|
||||
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeStreaming);
|
||||
@@ -552,7 +545,8 @@ TEST_F(WvCdmRequestLicenseTest, DISABLED_PrivacyModeTest) {
|
||||
decryptor_.CloseSession(session_id_);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, DISABLED_PrivacyModeWithServiceCertificateTest) {
|
||||
TEST_F(WvCdmRequestLicenseTest,
|
||||
DISABLED_PrivacyModeWithServiceCertificateTest) {
|
||||
TestWvCdmClientPropertySet property_set;
|
||||
|
||||
property_set.set_use_privacy_mode(true);
|
||||
@@ -563,68 +557,10 @@ TEST_F(WvCdmRequestLicenseTest, DISABLED_PrivacyModeWithServiceCertificateTest)
|
||||
decryptor_.CloseSession(session_id_);
|
||||
}
|
||||
|
||||
TEST_P(WvCdmSessionSharingTest, SessionSharingTest) {
|
||||
SessionSharingSubSampleInfo* session_sharing_info = GetParam();
|
||||
|
||||
TestWvCdmClientPropertySet property_set;
|
||||
property_set.set_session_sharing_mode(
|
||||
session_sharing_info->session_sharing_enabled);
|
||||
|
||||
decryptor_.OpenSession(g_key_system, &property_set, &session_id_);
|
||||
CdmSessionId gp_session_id_1 = session_id_;
|
||||
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeStreaming);
|
||||
VerifyKeyRequestResponse(g_license_server, g_client_auth, g_key_id, false);
|
||||
|
||||
// TODO(rfrias): Move content information to ConfigTestEnv
|
||||
std::string gp_client_auth2 =
|
||||
"?source=YOUTUBE&video_id=z3S_NhwueaM&oauth=ya.gtsqawidevine";
|
||||
std::string gp_key_id2 =
|
||||
wvcdm::a2bs_hex(
|
||||
"000000347073736800000000" // blob size and pssh
|
||||
"edef8ba979d64acea3c827dcd51d21ed00000014" // Widevine system id
|
||||
"08011210bdf1cb4fffc6506b8b7945b0bd2917fb"); // pssh data
|
||||
|
||||
decryptor_.OpenSession(g_key_system, &property_set, &session_id_);
|
||||
CdmSessionId gp_session_id_2 = session_id_;
|
||||
GenerateKeyRequest(g_key_system, gp_key_id2, kLicenseTypeStreaming);
|
||||
VerifyKeyRequestResponse(g_license_server, gp_client_auth2, gp_key_id2, false);
|
||||
|
||||
SubSampleInfo* data = session_sharing_info->sub_sample;
|
||||
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;
|
||||
|
||||
if (session_sharing_info->session_sharing_enabled || !data->is_encrypted) {
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(gp_session_id_2,
|
||||
data->validate_key_id,
|
||||
decryption_parameters));
|
||||
EXPECT_TRUE(std::equal(data->decrypt_data.begin(), data->decrypt_data.end(),
|
||||
decrypt_buffer.begin()));
|
||||
} else {
|
||||
EXPECT_EQ(NEED_KEY, decryptor_.Decrypt(gp_session_id_2,
|
||||
data->validate_key_id,
|
||||
decryption_parameters));
|
||||
}
|
||||
|
||||
decryptor_.CloseSession(gp_session_id_1);
|
||||
decryptor_.CloseSession(gp_session_id_2);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
Cdm, WvCdmSessionSharingTest,
|
||||
::testing::Range(&session_sharing_sub_samples[0],
|
||||
&session_sharing_sub_samples[6]));
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, BaseMessageTest) {
|
||||
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
|
||||
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeStreaming);
|
||||
GetKeyRequestResponse(g_license_server, g_client_auth, 200);
|
||||
GetKeyRequestResponse(g_license_server, g_client_auth);
|
||||
decryptor_.CloseSession(session_id_);
|
||||
}
|
||||
|
||||
@@ -633,7 +569,9 @@ TEST_F(WvCdmRequestLicenseTest, WrongMessageTest) {
|
||||
|
||||
std::string wrong_message = wvcdm::a2bs_hex(g_wrong_key_id);
|
||||
GenerateKeyRequest(g_key_system, wrong_message, kLicenseTypeStreaming);
|
||||
GetKeyRequestResponse(g_license_server, g_client_auth, 500);
|
||||
// We should receive a response with no license, i.e. the extracted license
|
||||
// response message should be empty.
|
||||
EXPECT_EQ("", GetKeyRequestResponse(g_license_server, g_client_auth));
|
||||
decryptor_.CloseSession(session_id_);
|
||||
}
|
||||
|
||||
@@ -666,7 +604,7 @@ TEST_F(WvCdmRequestLicenseTest, RestoreOfflineKeyTest) {
|
||||
decryptor_.CloseSession(session_id_);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, DISABLED_ReleaseOfflineKeyTest) {
|
||||
TEST_F(WvCdmRequestLicenseTest, ReleaseOfflineKeyTest) {
|
||||
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
|
||||
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeOffline);
|
||||
VerifyKeyRequestResponse(g_license_server, g_client_auth, g_key_id, false);
|
||||
@@ -688,7 +626,7 @@ TEST_F(WvCdmRequestLicenseTest, DISABLED_ReleaseOfflineKeyTest) {
|
||||
VerifyKeyRequestResponse(g_license_server, g_client_auth, g_key_id, false);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, DISABLED_ExpiryOnReleaseOfflineKeyTest) {
|
||||
TEST_F(WvCdmRequestLicenseTest, ExpiryOnReleaseOfflineKeyTest) {
|
||||
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
|
||||
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeOffline);
|
||||
VerifyKeyRequestResponse(g_license_server, g_client_auth, g_key_id, false);
|
||||
@@ -744,7 +682,7 @@ TEST_F(WvCdmRequestLicenseTest, OfflineLicenseRenewal) {
|
||||
decryptor_.CloseSession(session_id_);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, QuerySessionStatus) {
|
||||
TEST_F(WvCdmRequestLicenseTest, QueryUnmodifiedSessionStatus) {
|
||||
// Test that the global value is returned when no properties are modifying it.
|
||||
CdmQueryMap system_query_info;
|
||||
CdmQueryMap::iterator system_itr;
|
||||
@@ -752,30 +690,15 @@ TEST_F(WvCdmRequestLicenseTest, QuerySessionStatus) {
|
||||
system_itr = system_query_info.find(wvcdm::QUERY_KEY_SECURITY_LEVEL);
|
||||
ASSERT_TRUE(system_itr != system_query_info.end());
|
||||
|
||||
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
|
||||
CdmQueryMap unmodified_query_info;
|
||||
CdmQueryMap::iterator unmodified_itr;
|
||||
ASSERT_EQ(wvcdm::NO_ERROR,
|
||||
decryptor_.QuerySessionStatus(session_id_, &unmodified_query_info));
|
||||
unmodified_itr = unmodified_query_info.find(wvcdm::QUERY_KEY_SECURITY_LEVEL);
|
||||
ASSERT_TRUE(unmodified_itr != unmodified_query_info.end());
|
||||
EXPECT_EQ(system_itr->second, unmodified_itr->second);
|
||||
decryptor_.CloseSession(session_id_);
|
||||
EXPECT_EQ(system_itr->second, GetSecurityLevel(NULL));
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, QueryModifiedSessionStatus) {
|
||||
// Test that L3 is returned when properties downgrade security.
|
||||
TestWvCdmClientPropertySet property_set_L3;
|
||||
property_set_L3.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
|
||||
|
||||
decryptor_.OpenSession(g_key_system, &property_set_L3, &session_id_);
|
||||
CdmQueryMap modified_query_info;
|
||||
CdmQueryMap::iterator modified_itr;
|
||||
ASSERT_EQ(wvcdm::NO_ERROR,
|
||||
decryptor_.QuerySessionStatus(session_id_, &modified_query_info));
|
||||
modified_itr = modified_query_info.find(wvcdm::QUERY_KEY_SECURITY_LEVEL);
|
||||
ASSERT_TRUE(modified_itr != modified_query_info.end());
|
||||
EXPECT_EQ(QUERY_VALUE_SECURITY_LEVEL_L3, modified_itr->second);
|
||||
decryptor_.CloseSession(session_id_);
|
||||
|
||||
EXPECT_EQ(QUERY_VALUE_SECURITY_LEVEL_L3, GetSecurityLevel(&property_set_L3));
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, QueryKeyStatus) {
|
||||
@@ -891,20 +814,15 @@ TEST_F(WvCdmRequestLicenseTest, SecurityLevelPathBackwardCompatibility) {
|
||||
size_t pos = std::string::npos;
|
||||
for (size_t i = 0; i < security_dirs.size(); i++) {
|
||||
pos = base_path.rfind(security_dirs[i]);
|
||||
if (std::string::npos != pos)
|
||||
break;
|
||||
if (std::string::npos != pos) break;
|
||||
}
|
||||
|
||||
EXPECT_NE(std::string::npos, pos);
|
||||
std::string old_base_path(base_path, 0, pos);
|
||||
std::string path(old_base_path);
|
||||
path += kPathDelimiter;
|
||||
size_t path_len = path.size();
|
||||
File file;
|
||||
for (size_t i = 0; i < security_dirs.size(); i++) {
|
||||
path.append(security_dirs[i]);
|
||||
std::string path = old_base_path + kPathDelimiter + security_dirs[i];
|
||||
file.Remove(path);
|
||||
path.resize(path_len);
|
||||
}
|
||||
|
||||
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
|
||||
@@ -913,7 +831,7 @@ TEST_F(WvCdmRequestLicenseTest, SecurityLevelPathBackwardCompatibility) {
|
||||
&key_msg_, &provisioning_server_url));
|
||||
EXPECT_EQ(provisioning_server_url, g_config->provisioning_server_url());
|
||||
std::string response =
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url(), 200);
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url());
|
||||
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.HandleProvisioningResponse(response));
|
||||
decryptor_.CloseSession(session_id_);
|
||||
@@ -964,56 +882,21 @@ TEST_F(WvCdmRequestLicenseTest, SecurityLevelPathBackwardCompatibility) {
|
||||
decryptor_.GenerateKeyRequest(session_id_, key_set_id, g_key_id,
|
||||
kLicenseTypeStreaming, app_parameters,
|
||||
&key_msg_, &server_url));
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
decryptor_.GetProvisioningRequest(&key_msg_,
|
||||
&provisioning_server_url));
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.GetProvisioningRequest(
|
||||
&key_msg_, &provisioning_server_url));
|
||||
EXPECT_EQ(provisioning_server_url, g_config->provisioning_server_url());
|
||||
response =
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url(), 200);
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url());
|
||||
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.HandleProvisioningResponse(response));
|
||||
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.OpenSession(g_key_system, &property_set,
|
||||
&session_id_));
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
decryptor_.OpenSession(g_key_system, &property_set, &session_id_));
|
||||
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeStreaming);
|
||||
VerifyKeyRequestResponse(g_license_server, g_client_auth, g_key_id, false);
|
||||
decryptor_.CloseSession(session_id_);
|
||||
}
|
||||
|
||||
TEST_P(WvCdmDecryptionTest, DecryptionTest) {
|
||||
SubSampleInfo* data = GetParam();
|
||||
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
|
||||
if (data->retrieve_key) {
|
||||
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeStreaming);
|
||||
VerifyKeyRequestResponse(g_license_server, g_client_auth, g_key_id, false);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < data->num_of_subsamples; i++) {
|
||||
std::vector<uint8_t> decrypt_buffer((data + i)->encrypt_data.size());
|
||||
CdmDecryptionParameters decryption_parameters(
|
||||
&(data + i)->key_id, &(data + i)->encrypt_data.front(),
|
||||
(data + i)->encrypt_data.size(), &(data + i)->iv,
|
||||
(data + i)->block_offset, &decrypt_buffer[0]);
|
||||
decryption_parameters.is_encrypted = (data + i)->is_encrypted;
|
||||
decryption_parameters.is_secure = (data + i)->is_secure;
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_,
|
||||
(data+i)->validate_key_id,
|
||||
decryption_parameters));
|
||||
|
||||
EXPECT_TRUE(std::equal((data + i)->decrypt_data.begin(),
|
||||
(data + i)->decrypt_data.end(),
|
||||
decrypt_buffer.begin()));
|
||||
}
|
||||
decryptor_.CloseSession(session_id_);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
Cdm, WvCdmDecryptionTest,
|
||||
::testing::Values(&clear_sub_sample, &clear_sub_sample_no_key,
|
||||
&single_encrypted_sub_sample,
|
||||
&switch_key_encrypted_sub_sample[0],
|
||||
&partial_single_encrypted_sub_sample));
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, DISABLED_OfflineLicenseDecryptionTest) {
|
||||
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
|
||||
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeOffline);
|
||||
@@ -1181,6 +1064,107 @@ TEST_F(WvCdmRequestLicenseTest, KeyControlBlockDecryptionTest) {
|
||||
decryptor_.CloseSession(session_id_);
|
||||
}
|
||||
*/
|
||||
|
||||
class WvCdmSessionSharingTest
|
||||
: public WvCdmRequestLicenseTest,
|
||||
public ::testing::WithParamInterface<SessionSharingSubSampleInfo*> {};
|
||||
|
||||
TEST_P(WvCdmSessionSharingTest, SessionSharingTest) {
|
||||
SessionSharingSubSampleInfo* session_sharing_info = GetParam();
|
||||
|
||||
TestWvCdmClientPropertySet property_set;
|
||||
property_set.set_session_sharing_mode(
|
||||
session_sharing_info->session_sharing_enabled);
|
||||
|
||||
decryptor_.OpenSession(g_key_system, &property_set, &session_id_);
|
||||
CdmSessionId gp_session_id_1 = session_id_;
|
||||
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeStreaming);
|
||||
VerifyKeyRequestResponse(g_license_server, g_client_auth, g_key_id, false);
|
||||
|
||||
// TODO(rfrias): Move content information to ConfigTestEnv
|
||||
std::string gp_client_auth2 =
|
||||
"?source=YOUTUBE&video_id=z3S_NhwueaM&oauth=ya.gtsqawidevine";
|
||||
std::string gp_key_id2 =
|
||||
wvcdm::a2bs_hex(
|
||||
"000000347073736800000000" // blob size and pssh
|
||||
"edef8ba979d64acea3c827dcd51d21ed00000014" // Widevine system id
|
||||
"08011210bdf1cb4fffc6506b8b7945b0bd2917fb"); // pssh data
|
||||
|
||||
decryptor_.OpenSession(g_key_system, &property_set, &session_id_);
|
||||
CdmSessionId gp_session_id_2 = session_id_;
|
||||
GenerateKeyRequest(g_key_system, gp_key_id2, kLicenseTypeStreaming);
|
||||
VerifyKeyRequestResponse(g_license_server, gp_client_auth2, gp_key_id2, false);
|
||||
|
||||
SubSampleInfo* data = session_sharing_info->sub_sample;
|
||||
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;
|
||||
|
||||
if (session_sharing_info->session_sharing_enabled || !data->is_encrypted) {
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(gp_session_id_2,
|
||||
data->validate_key_id,
|
||||
decryption_parameters));
|
||||
EXPECT_TRUE(std::equal(data->decrypt_data.begin(), data->decrypt_data.end(),
|
||||
decrypt_buffer.begin()));
|
||||
} else {
|
||||
EXPECT_EQ(NEED_KEY, decryptor_.Decrypt(gp_session_id_2,
|
||||
data->validate_key_id,
|
||||
decryption_parameters));
|
||||
}
|
||||
|
||||
decryptor_.CloseSession(gp_session_id_1);
|
||||
decryptor_.CloseSession(gp_session_id_2);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
Cdm, WvCdmSessionSharingTest,
|
||||
::testing::Range(&session_sharing_sub_samples[0],
|
||||
&session_sharing_sub_samples[6]));
|
||||
|
||||
class WvCdmDecryptionTest
|
||||
: public WvCdmRequestLicenseTest,
|
||||
public ::testing::WithParamInterface<SubSampleInfo*> {};
|
||||
|
||||
TEST_P(WvCdmDecryptionTest, DecryptionTest) {
|
||||
SubSampleInfo* data = GetParam();
|
||||
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
|
||||
if (data->retrieve_key) {
|
||||
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeStreaming);
|
||||
VerifyKeyRequestResponse(g_license_server, g_client_auth, g_key_id, false);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < data->num_of_subsamples; i++) {
|
||||
std::vector<uint8_t> decrypt_buffer((data + i)->encrypt_data.size());
|
||||
CdmDecryptionParameters decryption_parameters(
|
||||
&(data + i)->key_id, &(data + i)->encrypt_data.front(),
|
||||
(data + i)->encrypt_data.size(), &(data + i)->iv,
|
||||
(data + i)->block_offset, &decrypt_buffer[0]);
|
||||
decryption_parameters.is_encrypted = (data + i)->is_encrypted;
|
||||
decryption_parameters.is_secure = (data + i)->is_secure;
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_,
|
||||
(data+i)->validate_key_id,
|
||||
decryption_parameters));
|
||||
|
||||
EXPECT_TRUE(std::equal((data + i)->decrypt_data.begin(),
|
||||
(data + i)->decrypt_data.end(),
|
||||
decrypt_buffer.begin()));
|
||||
}
|
||||
decryptor_.CloseSession(session_id_);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
Cdm, WvCdmDecryptionTest,
|
||||
::testing::Values(&clear_sub_sample, &clear_sub_sample_no_key,
|
||||
&single_encrypted_sub_sample,
|
||||
&switch_key_encrypted_sub_sample[0],
|
||||
&partial_single_encrypted_sub_sample));
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
void show_menu(char* prog_name) {
|
||||
@@ -1190,40 +1174,36 @@ void show_menu(char* prog_name) {
|
||||
<< std::endl;
|
||||
std::cout << " e.g. adb shell '" << prog_name << " --server=\"url\"'"
|
||||
<< std::endl;
|
||||
std::cout << " or adb shell '" << prog_name << " -u\"url\"'"
|
||||
<< std::endl << std::endl;
|
||||
std::cout << " or adb shell '" << prog_name << " -u\"url\"'" << std::endl
|
||||
<< std::endl;
|
||||
|
||||
std::cout << std::setw(35) << std::left << " -c/--chunked_transfer";
|
||||
std::cout << "specifies chunked transfer encoding in request"
|
||||
<< std::endl << std::endl;
|
||||
std::cout << "specifies chunked transfer encoding in request" << std::endl
|
||||
<< std::endl;
|
||||
|
||||
std::cout << std::setw(35) << std::left << " -f/--use_full_path";
|
||||
std::cout << "specify server url is not a proxy server" << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << std::setw(35) << std::left
|
||||
<< " -i/--license_server_id=<gp/cp>";
|
||||
std::cout << std::setw(35) << std::left << " -i/--license_server_id=<gp/cp>";
|
||||
std::cout << "specifies which default server settings to use: " << std::endl;
|
||||
std::cout << std::setw(35) << std::left << " ";
|
||||
std::cout << "gp (case sensitive) for GooglePlay server" << std::endl;
|
||||
std::cout << std::setw(35) << std::left << " ";
|
||||
std::cout << "cp (case sensitive) for Youtube Content Protection server"
|
||||
<< std::endl << std::endl;
|
||||
|
||||
std::cout << std::setw(35) << std::left << " -k/--keyid=<key_id>";
|
||||
std::cout << "configure the key id or pssh, in hex format"
|
||||
<< std::endl << std::endl;
|
||||
|
||||
std::cout << std::setw(35) << std::left
|
||||
<< " -p/--port=<port>";
|
||||
std::cout << std::setw(35) << std::left << " -k/--keyid=<key_id>";
|
||||
std::cout << "configure the key id or pssh, in hex format" << std::endl
|
||||
<< std::endl;
|
||||
|
||||
std::cout << std::setw(35) << std::left << " -p/--port=<port>";
|
||||
std::cout << "specifies the connection port" << std::endl << std::endl;
|
||||
|
||||
std::cout << std::setw(35) << std::left
|
||||
<< " -s/--secure_transfer";
|
||||
std::cout << std::setw(35) << std::left << " -s/--secure_transfer";
|
||||
std::cout << "use https transfer protocol" << std::endl << std::endl;
|
||||
|
||||
std::cout << std::setw(35) << std::left
|
||||
<< " -u/--server=<server_url>";
|
||||
std::cout << std::setw(35) << std::left << " -u/--server=<server_url>";
|
||||
std::cout
|
||||
<< "configure the license server url, please include http[s] in the url"
|
||||
<< std::endl << std::endl;
|
||||
@@ -1234,15 +1214,14 @@ int main(int argc, char** argv) {
|
||||
|
||||
bool show_usage = false;
|
||||
static const struct option long_options[] = {
|
||||
{ "chunked_transfer", no_argument, NULL, 'c' },
|
||||
{ "keyid", required_argument, NULL, 'k' },
|
||||
{ "license_server_id", required_argument, NULL, 'i' },
|
||||
{ "license_server_url", required_argument, NULL, 'u' },
|
||||
{ "port", required_argument, NULL, 'p' },
|
||||
{ "secure_transfer", no_argument, NULL, 's' },
|
||||
{ "use_full_path", no_argument, NULL, 'f' },
|
||||
{ NULL, 0, NULL, '\0' }
|
||||
};
|
||||
{"chunked_transfer", no_argument, NULL, 'c'},
|
||||
{"keyid", required_argument, NULL, 'k'},
|
||||
{"license_server_id", required_argument, NULL, 'i'},
|
||||
{"license_server_url", required_argument, NULL, 'u'},
|
||||
{"port", required_argument, NULL, 'p'},
|
||||
{"secure_transfer", no_argument, NULL, 's'},
|
||||
{"use_full_path", no_argument, NULL, 'f'},
|
||||
{NULL, 0, NULL, '\0'}};
|
||||
|
||||
int option_index = 0;
|
||||
int opt = 0;
|
||||
|
||||
Reference in New Issue
Block a user