Source release v2.1.4-0-804 + third_party libs
Change-Id: I1db8582efba613fa8a2b91a9c2697c5dfb2a8abf
This commit is contained in:
117
README.upgrading
Normal file
117
README.upgrading
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
README.upgrading for Widevine CDM Partner Kit v2.1
|
||||||
|
Date: 7/02/2014
|
||||||
|
|
||||||
|
This document provides details on important changes between versions of the
|
||||||
|
Widevine CDM. Some upgrades may require you to make changes to your
|
||||||
|
application, so please read carefully.
|
||||||
|
|
||||||
|
NOTE: All gyp variables have default values in platforms/global_config.gypi.
|
||||||
|
You may override these defaults in your platform-specific gypi.
|
||||||
|
|
||||||
|
|
||||||
|
New in v2.1.4:
|
||||||
|
=====
|
||||||
|
New gyp variables have been introduced to make the build more configurable:
|
||||||
|
* properties_source_file
|
||||||
|
Allows the file cdm/src/properties_common.cpp to be replaced with a
|
||||||
|
platform-specific version.
|
||||||
|
* protobuf_gyp
|
||||||
|
For gyp-based projects with their own internal version of protobuf, allows
|
||||||
|
the path to the protobuf gyp file to be overridden. The default is
|
||||||
|
third_party/protobuf.gyp. Ignored if use_system_protobuf is 'true'.
|
||||||
|
|
||||||
|
|
||||||
|
New in v2.1.3:
|
||||||
|
=====
|
||||||
|
New gyp variables have been introduced to make the build more configurable:
|
||||||
|
* oemcrypto_v8
|
||||||
|
The current version of OEMCrypto is v9. Set to 'true' if your system
|
||||||
|
supplies OEMCrypto v8. Defaults to 'false'.
|
||||||
|
|
||||||
|
The CDM interface (class ContentDecryptionModule) has been simplified.
|
||||||
|
The following methods have been removed:
|
||||||
|
* InitializeAudioDecoder()
|
||||||
|
* InitializeVideoDecoder
|
||||||
|
* DeinitializeDecoder
|
||||||
|
* ResetDecoder
|
||||||
|
* DecryptAndDecodeFrame
|
||||||
|
* DecryptAndDecodeSamples
|
||||||
|
|
||||||
|
The Host interface (class Host) has been simplified.
|
||||||
|
The following methods have been removed:
|
||||||
|
* GetPrivateData
|
||||||
|
* PersistPlatformString
|
||||||
|
* GetPlatformByteArray
|
||||||
|
* SetPlatformByteArray
|
||||||
|
* PersistPlatformByteArray
|
||||||
|
|
||||||
|
The following Host methods have changed:
|
||||||
|
* GetPlatformString
|
||||||
|
Now does the job of GetPlatformByteArray as well.
|
||||||
|
* SetPlatformString
|
||||||
|
Now does the job of SetPlatformByteArray, PersistPlatformString, and
|
||||||
|
PersistPlatformByteArray as well.
|
||||||
|
* SetTimer
|
||||||
|
This should schedule a single callback, not a repeating timer. Multiple
|
||||||
|
timer callbacks may be scheduled by the CDM at once. All callbacks should
|
||||||
|
occur serially on the same thread/queue as all other calls into the CDM.
|
||||||
|
|
||||||
|
|
||||||
|
New in v2.1.2:
|
||||||
|
=====
|
||||||
|
The following file locations have changed:
|
||||||
|
|
||||||
|
./cdm/cdm_api_internal.gyp => ./cdm/cdm.gyp
|
||||||
|
./cdm/cdm_api_external.gyp => ./cdm/cdm_unittests.gyp
|
||||||
|
|
||||||
|
If you have your own gyp files which depend on CDM targets, please update them
|
||||||
|
accordingly.
|
||||||
|
|
||||||
|
./build.py will use the ninja build tool if available. Otherwise, it will
|
||||||
|
continue to use make.
|
||||||
|
|
||||||
|
The Host is no longer expected to allocate a Buffer before calling
|
||||||
|
ContentDecryptionModule::Decrypt. The CDM will now call Host::Allocate and
|
||||||
|
DecryptedBlock::SetBuffer as needed in its Decrypt method. To avoid the
|
||||||
|
potential for a memory leak, make sure that your Host implementation no
|
||||||
|
longer allocates a Buffer before calling Decrypt.
|
||||||
|
|
||||||
|
For more details on the Host interface, see "Widevine Security Integration
|
||||||
|
Guide for CENC: EME Supplement".
|
||||||
|
|
||||||
|
|
||||||
|
New in v2.1.1:
|
||||||
|
=====
|
||||||
|
The following file locations have changed:
|
||||||
|
|
||||||
|
./build/build.py => ./build.py
|
||||||
|
./build/platforms/ => ./platforms/
|
||||||
|
./build/global_config.gypi => ./platforms/global_config.gypi
|
||||||
|
./build/protoc.gypi => ./third_party/protoc.gypi
|
||||||
|
|
||||||
|
The file ./build/platforms/cdm_platforms.py no longer exists. Platform
|
||||||
|
definitions are now based on the folder structure in ./platforms rather than
|
||||||
|
a python-based config file.
|
||||||
|
|
||||||
|
The OEMCrypto interface has been updated to v9, and documentation has been
|
||||||
|
updated in oemcrypto/include. The following functions were added:
|
||||||
|
|
||||||
|
* OEMCrypto_GetHDCPCapability
|
||||||
|
* OEMCrypto_SupportsUsageTable
|
||||||
|
* OEMCrypto_UpdateUsageTable
|
||||||
|
* OEMCrypto_DeactivateUsageEntry
|
||||||
|
* OEMCrypto_ReportUsage
|
||||||
|
* OEMCrypto_DeleteUsageEntry
|
||||||
|
* OEMCrypto_DeleteUsageTable
|
||||||
|
|
||||||
|
The file ./platforms/x86-64/x86-64.gypi now contains examples of how settings
|
||||||
|
can be customized for a given platform.
|
||||||
|
|
||||||
|
New gyp variables have been introduced to make the build more configurable:
|
||||||
|
* use_system_protobuf
|
||||||
|
Allows building protobuf from source, rather than using a system-wide
|
||||||
|
installation of the library and its tools. Defaults to 'true'.
|
||||||
|
* protobuf_source_dir
|
||||||
|
The path to the protobuf sources. Ignored if use_system_protobuf is
|
||||||
|
'true'. The source dir is expected to have a valid config.h for the
|
||||||
|
platform.
|
||||||
@@ -39,8 +39,8 @@
|
|||||||
'../third_party/stringencoders/src',
|
'../third_party/stringencoders/src',
|
||||||
],
|
],
|
||||||
'sources': [
|
'sources': [
|
||||||
|
'<(properties_source_file)',
|
||||||
'../cdm/src/file_store.cpp',
|
'../cdm/src/file_store.cpp',
|
||||||
'../cdm/src/properties_common.cpp',
|
|
||||||
'../core/src/string_conversions.cpp',
|
'../core/src/string_conversions.cpp',
|
||||||
'../linux/src/lock.cpp',
|
'../linux/src/lock.cpp',
|
||||||
'../linux/src/log.cpp',
|
'../linux/src/log.cpp',
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
// Widevine CDM Kit Version
|
// Widevine CDM Kit Version
|
||||||
#define WV_CDM_VERSION "v2.1.3-2-789"
|
#define WV_CDM_VERSION "v2.1.4-0-804"
|
||||||
|
|
||||||
|
|||||||
@@ -83,12 +83,8 @@ bool Properties::GetFactoryKeyboxPath(std::string* keybox) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Properties::GetOEMCryptoPath(std::string* library_name) {
|
bool Properties::GetOEMCryptoPath(std::string* library_name) {
|
||||||
if (!library_name) {
|
LOGE("Properties::GetOEMCryptoPath: Unimplemented property");
|
||||||
LOGW("Properties::GetOEMCryptoPath: Invalid parameter");
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*library_name = "out/Default/lib.target/liboemcrypto.so";
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace wvcdm
|
} // namespace wvcdm
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ static double GetCurrentTime() {
|
|||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
tv.tv_sec = tv.tv_usec = 0;
|
tv.tv_sec = tv.tv_usec = 0;
|
||||||
gettimeofday(&tv, NULL);
|
gettimeofday(&tv, NULL);
|
||||||
return tv.tv_sec;
|
return tv.tv_sec + (tv.tv_usec / (1000.0 * 1000.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// These classes below are naive implementation of the abstract classes defined
|
// These classes below are naive implementation of the abstract classes defined
|
||||||
@@ -111,6 +111,7 @@ class TestHost : public cdm::Host {
|
|||||||
void FastForwardTime(double seconds);
|
void FastForwardTime(double seconds);
|
||||||
int KeyMessagesSize() const;
|
int KeyMessagesSize() const;
|
||||||
int KeyErrorsSize() const;
|
int KeyErrorsSize() const;
|
||||||
|
int NumTimers() const;
|
||||||
|
|
||||||
// Returns Key{Message,Error} (replace Message with Error for KeyError). It
|
// Returns Key{Message,Error} (replace Message with Error for KeyError). It
|
||||||
// returns the most recent message passed to SendKeyMessage(). Another call
|
// returns the most recent message passed to SendKeyMessage(). Another call
|
||||||
@@ -130,7 +131,9 @@ class TestHost : public cdm::Host {
|
|||||||
: expiry_time(expiry_time), context(context) {}
|
: expiry_time(expiry_time), context(context) {}
|
||||||
|
|
||||||
bool operator<(const Timer& other) const {
|
bool operator<(const Timer& other) const {
|
||||||
return expiry_time < other.expiry_time;
|
// We want to reverse the order so that the smallest expiry times go to
|
||||||
|
// the top of the priority queue.
|
||||||
|
return expiry_time > other.expiry_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
double expiry_time;
|
double expiry_time;
|
||||||
@@ -235,6 +238,7 @@ void TestHost::FastForwardTime(double seconds) {
|
|||||||
} else {
|
} else {
|
||||||
Timer t = timers_.top();
|
Timer t = timers_.top();
|
||||||
timers_.pop();
|
timers_.pop();
|
||||||
|
ASSERT_GE(t.expiry_time, current_time_);
|
||||||
current_time_ = t.expiry_time;
|
current_time_ = t.expiry_time;
|
||||||
cdm_->TimerExpired(t.context);
|
cdm_->TimerExpired(t.context);
|
||||||
}
|
}
|
||||||
@@ -255,6 +259,8 @@ int TestHost::KeyMessagesSize() const { return key_messages_.size(); }
|
|||||||
|
|
||||||
int TestHost::KeyErrorsSize() const { return key_errors_.size(); }
|
int TestHost::KeyErrorsSize() const { return key_errors_.size(); }
|
||||||
|
|
||||||
|
int TestHost::NumTimers() const { return timers_.size(); }
|
||||||
|
|
||||||
TestHost::KeyMessage TestHost::GetLastKeyMessage() {
|
TestHost::KeyMessage TestHost::GetLastKeyMessage() {
|
||||||
if (!has_new_key_message_) {
|
if (!has_new_key_message_) {
|
||||||
LOGD("No NEW");
|
LOGD("No NEW");
|
||||||
@@ -289,6 +295,9 @@ TestHost::KeyError TestHost::GetKeyError(int index) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TestHost::SetCdmPtr(cdm::ContentDecryptionModule* cdm) {
|
void TestHost::SetCdmPtr(cdm::ContentDecryptionModule* cdm) {
|
||||||
|
if (cdm_) {
|
||||||
|
cdm_->Destroy();
|
||||||
|
}
|
||||||
cdm_ = cdm;
|
cdm_ = cdm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -959,6 +968,113 @@ class WvCdmApiTest : public testing::Test {
|
|||||||
scoped_ptr<TestHost> host_;
|
scoped_ptr<TestHost> host_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class DummyCDM : public cdm::ContentDecryptionModule {
|
||||||
|
public:
|
||||||
|
DummyCDM()
|
||||||
|
: timer_fired_(false),
|
||||||
|
last_context_(NULL) {}
|
||||||
|
|
||||||
|
virtual cdm::Status GenerateKeyRequest(const char*, int, const uint8_t*, int)
|
||||||
|
OVERRIDE {
|
||||||
|
return cdm::kSessionError;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual cdm::Status AddKey(const char*, int, const uint8_t*, int,
|
||||||
|
const uint8_t*, int) OVERRIDE {
|
||||||
|
return cdm::kSessionError;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool IsKeyValid(const uint8_t*, int) OVERRIDE {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual cdm::Status CancelKeyRequest(const char*, int) OVERRIDE {
|
||||||
|
return cdm::kSessionError;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void TimerExpired(void* context) OVERRIDE {
|
||||||
|
timer_fired_ = true;
|
||||||
|
last_context_ = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual cdm::Status Decrypt(const cdm::InputBuffer&, cdm::DecryptedBlock*)
|
||||||
|
OVERRIDE {
|
||||||
|
return cdm::kSessionError;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual cdm::Status DecryptDecodeAndRenderFrame(const cdm::InputBuffer&)
|
||||||
|
OVERRIDE {
|
||||||
|
return cdm::kSessionError;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual cdm::Status DecryptDecodeAndRenderSamples(const cdm::InputBuffer&)
|
||||||
|
OVERRIDE {
|
||||||
|
return cdm::kSessionError;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Destroy() OVERRIDE {
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual cdm::Status GetProvisioningRequest(std::string*, std::string*)
|
||||||
|
OVERRIDE {
|
||||||
|
return cdm::kSessionError;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual cdm::Status HandleProvisioningResponse(std::string&) OVERRIDE {
|
||||||
|
return cdm::kSessionError;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TimerFired() const {
|
||||||
|
return timer_fired_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* LastTimerContext() const {
|
||||||
|
return last_context_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetTimerStatus() {
|
||||||
|
timer_fired_ = false;
|
||||||
|
last_context_ = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool timer_fired_;
|
||||||
|
void* last_context_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(WvCdmApiTest, TestHostTimer) {
|
||||||
|
// Validate that the TestHost timers are processed in the correct order.
|
||||||
|
// To do this, we replace the cdm with a dummy that only tracks timers.
|
||||||
|
DummyCDM* cdm = new DummyCDM();
|
||||||
|
|
||||||
|
// The old CDM is destroyed by SetCdmPtr.
|
||||||
|
cdm_ = cdm;
|
||||||
|
host_->SetCdmPtr(cdm);
|
||||||
|
|
||||||
|
const double kTimerDelaySeconds = 1.0;
|
||||||
|
const int64_t kTimerDelayMs = kTimerDelaySeconds * 1000;
|
||||||
|
void* kCtx1 = reinterpret_cast<void*>(0x1);
|
||||||
|
void* kCtx2 = reinterpret_cast<void*>(0x2);
|
||||||
|
|
||||||
|
host_->SetTimer(kTimerDelayMs * 1, kCtx1);
|
||||||
|
host_->SetTimer(kTimerDelayMs * 2, kCtx2);
|
||||||
|
|
||||||
|
host_->FastForwardTime(kTimerDelaySeconds);
|
||||||
|
EXPECT_TRUE(cdm->TimerFired());
|
||||||
|
EXPECT_EQ(kCtx1, cdm->LastTimerContext());
|
||||||
|
cdm->ResetTimerStatus();
|
||||||
|
|
||||||
|
host_->FastForwardTime(kTimerDelaySeconds);
|
||||||
|
EXPECT_TRUE(cdm->TimerFired());
|
||||||
|
EXPECT_EQ(kCtx2, cdm->LastTimerContext());
|
||||||
|
cdm->ResetTimerStatus();
|
||||||
|
|
||||||
|
host_->FastForwardTime(kTimerDelaySeconds);
|
||||||
|
EXPECT_FALSE(cdm->TimerFired());
|
||||||
|
}
|
||||||
|
|
||||||
// Note that these tests, BaseMessageTest, NormalDecryption and TimeTest,
|
// Note that these tests, BaseMessageTest, NormalDecryption and TimeTest,
|
||||||
// are dependent on getting back a license from the license server where the
|
// are dependent on getting back a license from the license server where the
|
||||||
// url for the license server is defined in the conf_test_env.cpp. If these
|
// url for the license server is defined in the conf_test_env.cpp. If these
|
||||||
@@ -966,7 +1082,6 @@ class WvCdmApiTest : public testing::Test {
|
|||||||
// and works in your test environment.
|
// and works in your test environment.
|
||||||
|
|
||||||
TEST_F(WvCdmApiTest, DeviceCertificateTest) {
|
TEST_F(WvCdmApiTest, DeviceCertificateTest) {
|
||||||
host_->SetPlatformString("DeviceCertificate", "");
|
|
||||||
GenerateKeyRequest(g_key_system, g_key_id); // It will have to provision -
|
GenerateKeyRequest(g_key_system, g_key_id); // It will have to provision -
|
||||||
// in here.
|
// in here.
|
||||||
TestHost::KeyMessage key_msg = host_->GetLastKeyMessage();
|
TestHost::KeyMessage key_msg = host_->GetLastKeyMessage();
|
||||||
@@ -1027,6 +1142,9 @@ TEST_F(WvCdmApiTest, TimeTest) {
|
|||||||
std::string drm_msg = GetKeyRequestResponse(g_license_server,
|
std::string drm_msg = GetKeyRequestResponse(g_license_server,
|
||||||
g_client_auth, 200);
|
g_client_auth, 200);
|
||||||
AddKey(key_msg.session_id, drm_msg);
|
AddKey(key_msg.session_id, drm_msg);
|
||||||
|
// We expect that by the time we've added a key, the CDM has set a timer.
|
||||||
|
// Otherwise, it couldn't correctly handle renewal.
|
||||||
|
EXPECT_NE(0, host_->NumTimers());
|
||||||
|
|
||||||
host_->FastForwardTime(kTestPolicyRenewalDelaySeconds +
|
host_->FastForwardTime(kTestPolicyRenewalDelaySeconds +
|
||||||
kDelayWaitToForRenewalMessageSeconds);
|
kDelayWaitToForRenewalMessageSeconds);
|
||||||
|
|||||||
@@ -3,15 +3,16 @@
|
|||||||
#ifndef WVCDM_CORE_CDM_ENGINE_H_
|
#ifndef WVCDM_CORE_CDM_ENGINE_H_
|
||||||
#define WVCDM_CORE_CDM_ENGINE_H_
|
#define WVCDM_CORE_CDM_ENGINE_H_
|
||||||
|
|
||||||
|
#include "cdm_session.h"
|
||||||
#include "certificate_provisioning.h"
|
#include "certificate_provisioning.h"
|
||||||
#include "initialization_data.h"
|
#include "initialization_data.h"
|
||||||
#include "oemcrypto_adapter.h"
|
#include "oemcrypto_adapter.h"
|
||||||
|
#include "scoped_ptr.h"
|
||||||
#include "wv_cdm_types.h"
|
#include "wv_cdm_types.h"
|
||||||
|
|
||||||
namespace wvcdm {
|
namespace wvcdm {
|
||||||
|
|
||||||
class CdmClientPropertySet;
|
class CdmClientPropertySet;
|
||||||
class CdmSession;
|
|
||||||
class CryptoEngine;
|
class CryptoEngine;
|
||||||
class WvCdmEventListener;
|
class WvCdmEventListener;
|
||||||
|
|
||||||
@@ -121,8 +122,11 @@ class CdmEngine {
|
|||||||
CdmReleaseKeySetMap release_key_sets_;
|
CdmReleaseKeySetMap release_key_sets_;
|
||||||
CertificateProvisioning cert_provisioning_;
|
CertificateProvisioning cert_provisioning_;
|
||||||
SecurityLevel cert_provisioning_requested_security_level_;
|
SecurityLevel cert_provisioning_requested_security_level_;
|
||||||
CdmSession* usage_session_;
|
|
||||||
|
|
||||||
|
static bool seeded_;
|
||||||
|
|
||||||
|
// usage related variables
|
||||||
|
scoped_ptr<CdmSession> usage_session_;
|
||||||
int64_t last_usage_information_update_time;
|
int64_t last_usage_information_update_time;
|
||||||
|
|
||||||
CORE_DISALLOW_COPY_AND_ASSIGN(CdmEngine);
|
CORE_DISALLOW_COPY_AND_ASSIGN(CdmEngine);
|
||||||
|
|||||||
@@ -31,11 +31,6 @@ class CdmSession {
|
|||||||
virtual CdmResponseType RestoreUsageSession(
|
virtual CdmResponseType RestoreUsageSession(
|
||||||
const CdmKeyMessage& key_request, const CdmKeyResponse& key_response);
|
const CdmKeyMessage& key_request, const CdmKeyResponse& key_response);
|
||||||
|
|
||||||
virtual void set_key_system(const CdmKeySystem& ksystem) {
|
|
||||||
key_system_ = ksystem;
|
|
||||||
}
|
|
||||||
virtual const CdmKeySystem& key_system() { return key_system_; }
|
|
||||||
|
|
||||||
virtual const CdmSessionId& session_id() { return session_id_; }
|
virtual const CdmSessionId& session_id() { return session_id_; }
|
||||||
|
|
||||||
virtual CdmResponseType GenerateKeyRequest(
|
virtual CdmResponseType GenerateKeyRequest(
|
||||||
@@ -99,6 +94,11 @@ class CdmSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Internal constructor
|
||||||
|
void Create(CdmLicense* license_parser, CryptoSession* crypto_session,
|
||||||
|
PolicyEngine* policy_engine, DeviceFiles* file_handle,
|
||||||
|
const CdmClientPropertySet* cdm_client_property_set);
|
||||||
|
|
||||||
// Generate unique ID for each new session.
|
// Generate unique ID for each new session.
|
||||||
CdmSessionId GenerateSessionId();
|
CdmSessionId GenerateSessionId();
|
||||||
bool GenerateKeySetId(CdmKeySetId* key_set_id);
|
bool GenerateKeySetId(CdmKeySetId* key_set_id);
|
||||||
@@ -108,17 +108,18 @@ class CdmSession {
|
|||||||
bool DeleteLicense();
|
bool DeleteLicense();
|
||||||
|
|
||||||
// instance variables
|
// instance variables
|
||||||
const CdmSessionId session_id_;
|
bool initialized_;
|
||||||
CdmKeySystem key_system_;
|
CdmSessionId session_id_;
|
||||||
CdmLicense license_parser_;
|
scoped_ptr<CdmLicense> license_parser_;
|
||||||
scoped_ptr<CryptoSession> crypto_session_;
|
scoped_ptr<CryptoSession> crypto_session_;
|
||||||
PolicyEngine policy_engine_;
|
scoped_ptr<PolicyEngine> policy_engine_;
|
||||||
|
scoped_ptr<DeviceFiles> file_handle_;
|
||||||
bool license_received_;
|
bool license_received_;
|
||||||
bool reinitialize_session_;
|
|
||||||
bool is_offline_;
|
bool is_offline_;
|
||||||
bool is_release_;
|
bool is_release_;
|
||||||
bool is_usage_update_needed_;
|
bool is_usage_update_needed_;
|
||||||
bool is_initial_decryption_;
|
bool is_initial_decryption_;
|
||||||
|
CdmSecurityLevel security_level_;
|
||||||
|
|
||||||
// information useful for offline and usage scenarios
|
// information useful for offline and usage scenarios
|
||||||
CdmKeyMessage key_request_;
|
CdmKeyMessage key_request_;
|
||||||
@@ -133,12 +134,18 @@ class CdmSession {
|
|||||||
// license type release and offline related information
|
// license type release and offline related information
|
||||||
CdmKeySetId key_set_id_;
|
CdmKeySetId key_set_id_;
|
||||||
|
|
||||||
// Used for certificate based licensing
|
|
||||||
std::string wrapped_key_;
|
|
||||||
bool is_certificate_loaded_;
|
|
||||||
|
|
||||||
std::set<WvCdmEventListener*> listeners_;
|
std::set<WvCdmEventListener*> listeners_;
|
||||||
|
|
||||||
|
// For testing only
|
||||||
|
// Takes ownership of license_parser, crypto_session, policy_engine
|
||||||
|
// and device_files
|
||||||
|
CdmSession(CdmLicense* license_parser, CryptoSession* crypto_session,
|
||||||
|
PolicyEngine* policy_engine, DeviceFiles* file_handle,
|
||||||
|
const CdmClientPropertySet* cdm_client_property_set);
|
||||||
|
#if defined(UNIT_TEST)
|
||||||
|
friend class CdmSessionTest;
|
||||||
|
#endif
|
||||||
|
|
||||||
CORE_DISALLOW_COPY_AND_ASSIGN(CdmSession);
|
CORE_DISALLOW_COPY_AND_ASSIGN(CdmSession);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ class CryptoSession {
|
|||||||
virtual bool GetToken(std::string* token);
|
virtual bool GetToken(std::string* token);
|
||||||
virtual CdmSecurityLevel GetSecurityLevel();
|
virtual CdmSecurityLevel GetSecurityLevel();
|
||||||
virtual bool GetDeviceUniqueId(std::string* device_id);
|
virtual bool GetDeviceUniqueId(std::string* device_id);
|
||||||
|
virtual bool GetApiVersion(uint32_t* version);
|
||||||
virtual bool GetSystemId(uint32_t* system_id);
|
virtual bool GetSystemId(uint32_t* system_id);
|
||||||
virtual bool GetProvisioningId(std::string* provisioning_id);
|
virtual bool GetProvisioningId(std::string* provisioning_id);
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#ifndef WVCDM_CORE_DEVICE_FILES_H_
|
#ifndef WVCDM_CORE_DEVICE_FILES_H_
|
||||||
#define WVCDM_CORE_DEVICE_FILES_H_
|
#define WVCDM_CORE_DEVICE_FILES_H_
|
||||||
|
|
||||||
|
#include "scoped_ptr.h"
|
||||||
#include "wv_cdm_types.h"
|
#include "wv_cdm_types.h"
|
||||||
|
|
||||||
#if defined(UNIT_TEST)
|
#if defined(UNIT_TEST)
|
||||||
@@ -21,11 +22,13 @@ class DeviceFiles {
|
|||||||
kLicenseStateUnknown,
|
kLicenseStateUnknown,
|
||||||
} LicenseState;
|
} LicenseState;
|
||||||
|
|
||||||
DeviceFiles(): file_(NULL), security_level_(kSecurityLevelUninitialized),
|
DeviceFiles();
|
||||||
initialized_(false), test_file_(false) {}
|
|
||||||
virtual ~DeviceFiles();
|
virtual ~DeviceFiles();
|
||||||
|
|
||||||
virtual bool Init(CdmSecurityLevel security_level);
|
virtual bool Init(CdmSecurityLevel security_level);
|
||||||
|
virtual bool Reset(CdmSecurityLevel security_level) {
|
||||||
|
return Init(security_level);
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool StoreCertificate(const std::string& certificate,
|
virtual bool StoreCertificate(const std::string& certificate,
|
||||||
const std::string& wrapped_private_key);
|
const std::string& wrapped_private_key);
|
||||||
@@ -93,7 +96,7 @@ class DeviceFiles {
|
|||||||
FRIEND_TEST(WvCdmUsageInfoTest, DISABLED_UsageInfo);
|
FRIEND_TEST(WvCdmUsageInfoTest, DISABLED_UsageInfo);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
File* file_;
|
scoped_ptr<File> file_;
|
||||||
CdmSecurityLevel security_level_;
|
CdmSecurityLevel security_level_;
|
||||||
bool initialized_;
|
bool initialized_;
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ class PolicyEngine {
|
|||||||
private:
|
private:
|
||||||
typedef enum {
|
typedef enum {
|
||||||
kLicenseStateInitial,
|
kLicenseStateInitial,
|
||||||
|
kLicenseStatePending, // if license is issued for sometime in the future
|
||||||
kLicenseStateCanPlay,
|
kLicenseStateCanPlay,
|
||||||
kLicenseStateNeedRenewal,
|
kLicenseStateNeedRenewal,
|
||||||
kLicenseStateWaitingLicenseUpdate,
|
kLicenseStateWaitingLicenseUpdate,
|
||||||
@@ -91,18 +92,14 @@ class PolicyEngine {
|
|||||||
// from the license server we will get an updated id field.
|
// from the license server we will get an updated id field.
|
||||||
video_widevine_server::sdk::LicenseIdentification license_id_;
|
video_widevine_server::sdk::LicenseIdentification license_id_;
|
||||||
|
|
||||||
// This is the license start time that gets sent from the server in each
|
// The server returns the license start time in the license/license renewal
|
||||||
// license request or renewal.
|
// response based off the request time sent by the client in the
|
||||||
|
// license request/renewal
|
||||||
int64_t license_start_time_;
|
int64_t license_start_time_;
|
||||||
|
|
||||||
// This is the time at which the license was received and playback was
|
|
||||||
// started. These times are based off the local clock in case there is a
|
|
||||||
// discrepency between local and server time.
|
|
||||||
int64_t license_received_time_;
|
|
||||||
int64_t playback_start_time_;
|
int64_t playback_start_time_;
|
||||||
|
|
||||||
// This is used as a reference point for policy management. This value
|
// This is used as a reference point for policy management. This value
|
||||||
// represents an offset from license_received_time_. This is used to
|
// represents an offset from license_start_time_. This is used to
|
||||||
// calculate the time where renewal retries should occur.
|
// calculate the time where renewal retries should occur.
|
||||||
int64_t next_renewal_time_;
|
int64_t next_renewal_time_;
|
||||||
int64_t policy_max_duration_seconds_;
|
int64_t policy_max_duration_seconds_;
|
||||||
|
|||||||
@@ -87,6 +87,14 @@ class Properties {
|
|||||||
security_level_path_backward_compatibility_support_ = flag;
|
security_level_path_backward_compatibility_support_ = flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(UNIT_TEST)
|
||||||
|
FRIEND_TEST(CdmSessionTest, InitWithCertificate);
|
||||||
|
FRIEND_TEST(CdmSessionTest, InitWithKeybox);
|
||||||
|
FRIEND_TEST(CdmSessionTest, ReInitFail);
|
||||||
|
FRIEND_TEST(CdmSessionTest, InitFailCryptoError);
|
||||||
|
FRIEND_TEST(CdmSessionTest, InitNeedsProvisioning);
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool oem_crypto_use_secure_buffers_;
|
static bool oem_crypto_use_secure_buffers_;
|
||||||
static bool oem_crypto_use_fifo_;
|
static bool oem_crypto_use_fifo_;
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include "cdm_engine.h"
|
#include "cdm_engine.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
@@ -18,22 +20,26 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const uint32_t kUpdateUsageInformationPeriod = 60; // seconds
|
const uint32_t kUpdateUsageInformationPeriod = 60; // seconds
|
||||||
const size_t kMinNoncesPerSession = 4;
|
const size_t kUsageReportsPerRequest = 1;
|
||||||
} // unnamed namespace
|
} // unnamed namespace
|
||||||
|
|
||||||
namespace wvcdm {
|
namespace wvcdm {
|
||||||
|
|
||||||
|
bool CdmEngine::seeded_ = false;
|
||||||
|
|
||||||
CdmEngine::CdmEngine()
|
CdmEngine::CdmEngine()
|
||||||
: cert_provisioning_requested_security_level_(kLevelDefault),
|
: cert_provisioning_requested_security_level_(kLevelDefault),
|
||||||
usage_session_(NULL),
|
usage_session_(NULL),
|
||||||
last_usage_information_update_time(0) {
|
last_usage_information_update_time(0) {
|
||||||
Properties::Init();
|
Properties::Init();
|
||||||
|
if (!seeded_) {
|
||||||
|
Clock clock;
|
||||||
|
srand(clock.GetCurrentTime());
|
||||||
|
seeded_ = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmEngine::~CdmEngine() {
|
CdmEngine::~CdmEngine() {
|
||||||
if (NULL != usage_session_)
|
|
||||||
delete usage_session_;
|
|
||||||
|
|
||||||
CdmSessionMap::iterator i(sessions_.begin());
|
CdmSessionMap::iterator i(sessions_.begin());
|
||||||
for (; i != sessions_.end(); ++i) {
|
for (; i != sessions_.end(); ++i) {
|
||||||
delete i->second;
|
delete i->second;
|
||||||
@@ -505,9 +511,7 @@ CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType CdmEngine::GetUsageInfo(CdmUsageInfo* usage_info) {
|
CdmResponseType CdmEngine::GetUsageInfo(CdmUsageInfo* usage_info) {
|
||||||
if (NULL == usage_session_) {
|
usage_session_.reset(new CdmSession(NULL));
|
||||||
usage_session_ = new CdmSession(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
CdmResponseType status = usage_session_->Init();
|
CdmResponseType status = usage_session_->Init();
|
||||||
if (NO_ERROR != status) {
|
if (NO_ERROR != status) {
|
||||||
@@ -533,35 +537,32 @@ CdmResponseType CdmEngine::GetUsageInfo(CdmUsageInfo* usage_info) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string server_url;
|
std::string server_url;
|
||||||
// rate limit secure stop messages based on minimum nonce
|
usage_info->resize(kUsageReportsPerRequest);
|
||||||
// table size per session
|
|
||||||
usage_info->resize(license_info.size() >= kMinNoncesPerSession - 1
|
uint32_t index = rand() % license_info.size();
|
||||||
? kMinNoncesPerSession - 1
|
status = usage_session_->RestoreUsageSession(license_info[index].first,
|
||||||
: license_info.size());
|
license_info[index].second);
|
||||||
for (size_t i = 0; i < usage_info->size(); ++i) {
|
if (KEY_ADDED != status) {
|
||||||
status = usage_session_->RestoreUsageSession(license_info[i].first,
|
LOGE("CdmEngine::GetUsageInfo: restore usage session (%d) error %ld",
|
||||||
license_info[i].second);
|
index, status);
|
||||||
if (KEY_ADDED != status) {
|
usage_info->clear();
|
||||||
LOGE("CdmEngine::GetUsageInfo: restore usage session error: %ld",
|
return status;
|
||||||
status);
|
}
|
||||||
usage_info->clear();
|
|
||||||
return status;
|
status = usage_session_->GenerateReleaseRequest(&(*usage_info)[0], &server_url);
|
||||||
}
|
|
||||||
status = usage_session_->GenerateReleaseRequest(&(*usage_info)[i],
|
if (KEY_MESSAGE != status) {
|
||||||
&server_url);
|
LOGE("CdmEngine::GetUsageInfo: generate release request error: %ld",
|
||||||
if (KEY_MESSAGE != status) {
|
status);
|
||||||
LOGE("CdmEngine::GetUsageInfo: generate release request error: %ld",
|
usage_info->clear();
|
||||||
status);
|
return status;
|
||||||
usage_info->clear();
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return KEY_MESSAGE;
|
return KEY_MESSAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType CdmEngine::ReleaseUsageInfo(
|
CdmResponseType CdmEngine::ReleaseUsageInfo(
|
||||||
const CdmUsageInfoReleaseMessage& message) {
|
const CdmUsageInfoReleaseMessage& message) {
|
||||||
if (NULL == usage_session_) {
|
if (NULL == usage_session_.get()) {
|
||||||
LOGE("CdmEngine::ReleaseUsageInfo: cdm session not initialized");
|
LOGE("CdmEngine::ReleaseUsageInfo: cdm session not initialized");
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
@@ -569,9 +570,8 @@ CdmResponseType CdmEngine::ReleaseUsageInfo(
|
|||||||
CdmResponseType status = usage_session_->ReleaseKey(message);
|
CdmResponseType status = usage_session_->ReleaseKey(message);
|
||||||
if (NO_ERROR != status) {
|
if (NO_ERROR != status) {
|
||||||
LOGE("CdmEngine::ReleaseUsageInfo: release key error: %ld", status);
|
LOGE("CdmEngine::ReleaseUsageInfo: release key error: %ld", status);
|
||||||
return UNKNOWN_ERROR;
|
|
||||||
}
|
}
|
||||||
return NO_ERROR;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType CdmEngine::Decrypt(
|
CdmResponseType CdmEngine::Decrypt(
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "cdm_engine.h"
|
#include "cdm_engine.h"
|
||||||
#include "clock.h"
|
|
||||||
#include "crypto_session.h"
|
#include "crypto_session.h"
|
||||||
#include "device_files.h"
|
#include "device_files.h"
|
||||||
#include "file_store.h"
|
#include "file_store.h"
|
||||||
@@ -25,16 +24,56 @@ namespace wvcdm {
|
|||||||
|
|
||||||
typedef std::set<WvCdmEventListener*>::iterator CdmEventListenerIter;
|
typedef std::set<WvCdmEventListener*>::iterator CdmEventListenerIter;
|
||||||
|
|
||||||
CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set)
|
CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set) {
|
||||||
: session_id_(GenerateSessionId()),
|
Create(new CdmLicense(), new CryptoSession(), new PolicyEngine(),
|
||||||
crypto_session_(NULL),
|
new DeviceFiles(), cdm_client_property_set);
|
||||||
license_received_(false),
|
}
|
||||||
reinitialize_session_(false),
|
|
||||||
is_offline_(false),
|
CdmSession::CdmSession(
|
||||||
is_release_(false),
|
CdmLicense* license_parser,
|
||||||
is_usage_update_needed_(false),
|
CryptoSession* crypto_session,
|
||||||
is_initial_decryption_(true),
|
PolicyEngine* policy_engine,
|
||||||
is_certificate_loaded_(false) {
|
DeviceFiles* file_handle,
|
||||||
|
const CdmClientPropertySet* cdm_client_property_set) {
|
||||||
|
Create(license_parser, crypto_session, policy_engine, file_handle,
|
||||||
|
cdm_client_property_set);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CdmSession::Create(
|
||||||
|
CdmLicense* license_parser,
|
||||||
|
CryptoSession* crypto_session,
|
||||||
|
PolicyEngine* policy_engine,
|
||||||
|
DeviceFiles* file_handle,
|
||||||
|
const CdmClientPropertySet* cdm_client_property_set) {
|
||||||
|
// Just return on failures. Failures will be signaled in Init.
|
||||||
|
if (NULL == license_parser) {
|
||||||
|
LOGE("CdmSession::Create: License parser not provided");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (NULL == crypto_session) {
|
||||||
|
LOGE("CdmSession::Create: Crypto session not provided");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (NULL == policy_engine) {
|
||||||
|
LOGE("CdmSession::Create: Policy engine not provided");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (NULL == file_handle) {
|
||||||
|
LOGE("CdmSession::Create: Device files not provided");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
initialized_ = false;
|
||||||
|
session_id_ = GenerateSessionId();
|
||||||
|
license_parser_.reset(license_parser);
|
||||||
|
crypto_session_.reset(crypto_session);
|
||||||
|
file_handle_.reset(file_handle);
|
||||||
|
policy_engine_.reset(policy_engine);
|
||||||
|
license_received_ = false;
|
||||||
|
is_offline_ = false;
|
||||||
|
is_release_ = false;
|
||||||
|
is_usage_update_needed_ = false;
|
||||||
|
is_initial_decryption_ = true;
|
||||||
|
security_level_ = crypto_session_.get()->GetSecurityLevel();
|
||||||
if (cdm_client_property_set) {
|
if (cdm_client_property_set) {
|
||||||
Properties::AddSessionPropertySet(session_id_, cdm_client_property_set);
|
Properties::AddSessionPropertySet(session_id_, cdm_client_property_set);
|
||||||
}
|
}
|
||||||
@@ -43,29 +82,36 @@ CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set)
|
|||||||
CdmSession::~CdmSession() { Properties::RemoveSessionPropertySet(session_id_); }
|
CdmSession::~CdmSession() { Properties::RemoveSessionPropertySet(session_id_); }
|
||||||
|
|
||||||
CdmResponseType CdmSession::Init() {
|
CdmResponseType CdmSession::Init() {
|
||||||
scoped_ptr<CryptoSession> session(new CryptoSession());
|
if (session_id_.empty()) {
|
||||||
|
LOGE("CdmSession::Init: Failed, session not properly constructed");
|
||||||
CdmResponseType sts = session->Open(GetRequestedSecurityLevel());
|
return UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
if (initialized_) {
|
||||||
|
LOGE("CdmSession::Init: Failed due to previous initialization");
|
||||||
|
return UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
CdmResponseType sts = crypto_session_->Open(GetRequestedSecurityLevel());
|
||||||
if (NO_ERROR != sts) return sts;
|
if (NO_ERROR != sts) return sts;
|
||||||
|
|
||||||
std::string token;
|
std::string token;
|
||||||
if (Properties::use_certificates_as_identification()) {
|
if (Properties::use_certificates_as_identification()) {
|
||||||
DeviceFiles handle;
|
std::string wrapped_key;
|
||||||
if (!handle.Init(session.get()->GetSecurityLevel()) ||
|
if (!file_handle_->Init(security_level_) ||
|
||||||
!handle.RetrieveCertificate(&token, &wrapped_key_)) {
|
!file_handle_->RetrieveCertificate(&token, &wrapped_key) ||
|
||||||
|
!crypto_session_->LoadCertificatePrivateKey(wrapped_key)) {
|
||||||
return NEED_PROVISIONING;
|
return NEED_PROVISIONING;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!session->GetToken(&token)) return UNKNOWN_ERROR;
|
if (!crypto_session_->GetToken(&token)) return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!license_parser_.Init(token, session.get(), &policy_engine_))
|
if (!license_parser_->Init(token, crypto_session_.get(),
|
||||||
|
policy_engine_.get()))
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
|
|
||||||
crypto_session_.reset(session.release());
|
|
||||||
license_received_ = false;
|
license_received_ = false;
|
||||||
reinitialize_session_ = false;
|
|
||||||
is_initial_decryption_ = true;
|
is_initial_decryption_ = true;
|
||||||
|
initialized_ = true;
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,17 +120,17 @@ CdmResponseType CdmSession::RestoreOfflineSession(
|
|||||||
key_set_id_ = key_set_id;
|
key_set_id_ = key_set_id;
|
||||||
|
|
||||||
// Retrieve license information from persistent store
|
// Retrieve license information from persistent store
|
||||||
DeviceFiles handle;
|
if (!file_handle_->Reset(security_level_))
|
||||||
if (!handle.Init(crypto_session_->GetSecurityLevel()))
|
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
|
|
||||||
DeviceFiles::LicenseState license_state;
|
DeviceFiles::LicenseState license_state;
|
||||||
|
|
||||||
if (!handle.RetrieveLicense(key_set_id, &license_state, &offline_init_data_,
|
if (!file_handle_->RetrieveLicense(key_set_id, &license_state,
|
||||||
&key_request_, &key_response_,
|
&offline_init_data_,
|
||||||
&offline_key_renewal_request_,
|
&key_request_, &key_response_,
|
||||||
&offline_key_renewal_response_,
|
&offline_key_renewal_request_,
|
||||||
&offline_release_server_url_)) {
|
&offline_key_renewal_response_,
|
||||||
|
&offline_release_server_url_)) {
|
||||||
LOGE("CdmSession::Init failed to retrieve license. key set id = %s",
|
LOGE("CdmSession::Init failed to retrieve license. key set id = %s",
|
||||||
key_set_id.c_str());
|
key_set_id.c_str());
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
@@ -95,17 +141,8 @@ CdmResponseType CdmSession::RestoreOfflineSession(
|
|||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Properties::use_certificates_as_identification()) {
|
if (!license_parser_->RestoreOfflineLicense(key_request_, key_response_,
|
||||||
if (is_certificate_loaded_ ||
|
offline_key_renewal_response_)) {
|
||||||
crypto_session_->LoadCertificatePrivateKey(wrapped_key_)) {
|
|
||||||
is_certificate_loaded_ = true;
|
|
||||||
} else {
|
|
||||||
return NEED_PROVISIONING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!license_parser_.RestoreOfflineLicense(key_request_, key_response_,
|
|
||||||
offline_key_renewal_response_)) {
|
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,16 +158,8 @@ CdmResponseType CdmSession::RestoreUsageSession(
|
|||||||
|
|
||||||
key_request_ = key_request;
|
key_request_ = key_request;
|
||||||
key_response_ = key_response;
|
key_response_ = key_response;
|
||||||
if (Properties::use_certificates_as_identification()) {
|
|
||||||
if (is_certificate_loaded_ ||
|
|
||||||
crypto_session_->LoadCertificatePrivateKey(wrapped_key_)) {
|
|
||||||
is_certificate_loaded_ = true;
|
|
||||||
} else {
|
|
||||||
return NEED_PROVISIONING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!license_parser_.RestoreUsageLicense(key_request_, key_response_)) {
|
if (!license_parser_->RestoreUsageLicense(key_request_, key_response_)) {
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,14 +173,6 @@ CdmResponseType CdmSession::GenerateKeyRequest(
|
|||||||
const InitializationData& init_data, const CdmLicenseType license_type,
|
const InitializationData& init_data, const CdmLicenseType license_type,
|
||||||
const CdmAppParameterMap& app_parameters, CdmKeyMessage* key_request,
|
const CdmAppParameterMap& app_parameters, CdmKeyMessage* key_request,
|
||||||
std::string* server_url) {
|
std::string* server_url) {
|
||||||
if (reinitialize_session_) {
|
|
||||||
CdmResponseType sts = Init();
|
|
||||||
if (sts != NO_ERROR) {
|
|
||||||
LOGW("CdmSession::GenerateKeyRequest: Reinitialization failed");
|
|
||||||
return sts;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (crypto_session_.get() == NULL) {
|
if (crypto_session_.get() == NULL) {
|
||||||
LOGW("CdmSession::GenerateKeyRequest: Invalid crypto session");
|
LOGW("CdmSession::GenerateKeyRequest: Invalid crypto session");
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
@@ -182,24 +203,14 @@ CdmResponseType CdmSession::GenerateKeyRequest(
|
|||||||
init_data.type().c_str());
|
init_data.type().c_str());
|
||||||
return KEY_ERROR;
|
return KEY_ERROR;
|
||||||
}
|
}
|
||||||
if (init_data.IsEmpty() && !license_parser_.HasInitData()) {
|
if (init_data.IsEmpty() && !license_parser_->HasInitData()) {
|
||||||
LOGW("CdmSession::GenerateKeyRequest: init data absent");
|
LOGW("CdmSession::GenerateKeyRequest: init data absent");
|
||||||
return KEY_ERROR;
|
return KEY_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Properties::use_certificates_as_identification()) {
|
if (!license_parser_->PrepareKeyRequest(init_data, license_type,
|
||||||
if (is_certificate_loaded_ ||
|
app_parameters, session_id_,
|
||||||
crypto_session_->LoadCertificatePrivateKey(wrapped_key_)) {
|
key_request, server_url)) {
|
||||||
is_certificate_loaded_ = true;
|
|
||||||
} else {
|
|
||||||
reinitialize_session_ = true;
|
|
||||||
return NEED_PROVISIONING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!license_parser_.PrepareKeyRequest(init_data, license_type,
|
|
||||||
app_parameters, session_id_,
|
|
||||||
key_request, server_url)) {
|
|
||||||
return KEY_ERROR;
|
return KEY_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,18 +238,19 @@ CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_release_) {
|
if (is_release_) {
|
||||||
return ReleaseKey(key_response);
|
CdmResponseType sts = ReleaseKey(key_response);
|
||||||
|
return (NO_ERROR == sts) ? KEY_ADDED : sts;
|
||||||
} else if (license_received_) { // renewal
|
} else if (license_received_) { // renewal
|
||||||
return RenewKey(key_response);
|
return RenewKey(key_response);
|
||||||
} else {
|
} else {
|
||||||
CdmResponseType sts = license_parser_.HandleKeyResponse(key_response);
|
CdmResponseType sts = license_parser_->HandleKeyResponse(key_response);
|
||||||
|
|
||||||
if (sts != KEY_ADDED) return sts;
|
if (sts != KEY_ADDED) return sts;
|
||||||
|
|
||||||
license_received_ = true;
|
license_received_ = true;
|
||||||
key_response_ = key_response;
|
key_response_ = key_response;
|
||||||
|
|
||||||
if (is_offline_ || !license_parser_.provider_session_token().empty()) {
|
if (is_offline_ || !license_parser_->provider_session_token().empty()) {
|
||||||
sts = StoreLicense();
|
sts = StoreLicense();
|
||||||
if (sts != NO_ERROR) return sts;
|
if (sts != NO_ERROR) return sts;
|
||||||
}
|
}
|
||||||
@@ -281,7 +293,7 @@ CdmResponseType CdmSession::QueryStatus(CdmQueryMap* key_info) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType CdmSession::QueryKeyStatus(CdmQueryMap* key_info) {
|
CdmResponseType CdmSession::QueryKeyStatus(CdmQueryMap* key_info) {
|
||||||
return policy_engine_.Query(key_info);
|
return policy_engine_->Query(key_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType CdmSession::QueryKeyControlInfo(CdmQueryMap* key_info) {
|
CdmResponseType CdmSession::QueryKeyControlInfo(CdmQueryMap* key_info) {
|
||||||
@@ -316,12 +328,12 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
|
|||||||
|
|
||||||
if (NO_ERROR == status) {
|
if (NO_ERROR == status) {
|
||||||
if (is_initial_decryption_) {
|
if (is_initial_decryption_) {
|
||||||
policy_engine_.BeginDecryption();
|
policy_engine_->BeginDecryption();
|
||||||
is_initial_decryption_ = false;
|
is_initial_decryption_ = false;
|
||||||
}
|
}
|
||||||
if (!is_usage_update_needed_) {
|
if (!is_usage_update_needed_) {
|
||||||
is_usage_update_needed_ =
|
is_usage_update_needed_ =
|
||||||
!license_parser_.provider_session_token().empty();
|
!license_parser_->provider_session_token().empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,7 +345,8 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
|
|||||||
// session keys.
|
// session keys.
|
||||||
CdmResponseType CdmSession::GenerateRenewalRequest(CdmKeyMessage* key_request,
|
CdmResponseType CdmSession::GenerateRenewalRequest(CdmKeyMessage* key_request,
|
||||||
std::string* server_url) {
|
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");
|
LOGE("CdmSession::GenerateRenewalRequest: ERROR on prepare");
|
||||||
return KEY_ERROR;
|
return KEY_ERROR;
|
||||||
}
|
}
|
||||||
@@ -347,7 +360,7 @@ CdmResponseType CdmSession::GenerateRenewalRequest(CdmKeyMessage* key_request,
|
|||||||
// RenewKey() - Accept renewal response and update key info.
|
// RenewKey() - Accept renewal response and update key info.
|
||||||
CdmResponseType CdmSession::RenewKey(const CdmKeyResponse& key_response) {
|
CdmResponseType CdmSession::RenewKey(const CdmKeyResponse& key_response) {
|
||||||
CdmResponseType sts =
|
CdmResponseType sts =
|
||||||
license_parser_.HandleKeyUpdateResponse(true, key_response);
|
license_parser_->HandleKeyUpdateResponse(true, key_response);
|
||||||
if (sts != KEY_ADDED) return sts;
|
if (sts != KEY_ADDED) return sts;
|
||||||
|
|
||||||
if (is_offline_) {
|
if (is_offline_) {
|
||||||
@@ -360,7 +373,7 @@ CdmResponseType CdmSession::RenewKey(const CdmKeyResponse& key_response) {
|
|||||||
CdmResponseType CdmSession::GenerateReleaseRequest(CdmKeyMessage* key_request,
|
CdmResponseType CdmSession::GenerateReleaseRequest(CdmKeyMessage* key_request,
|
||||||
std::string* server_url) {
|
std::string* server_url) {
|
||||||
is_release_ = true;
|
is_release_ = true;
|
||||||
if (!license_parser_.PrepareKeyUpdateRequest(false, key_request, server_url))
|
if (!license_parser_->PrepareKeyUpdateRequest(false, key_request, server_url))
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
|
|
||||||
if (is_offline_) { // Mark license as being released
|
if (is_offline_) { // Mark license as being released
|
||||||
@@ -372,19 +385,19 @@ CdmResponseType CdmSession::GenerateReleaseRequest(CdmKeyMessage* key_request,
|
|||||||
|
|
||||||
// ReleaseKey() - Accept release response and release license.
|
// ReleaseKey() - Accept release response and release license.
|
||||||
CdmResponseType CdmSession::ReleaseKey(const CdmKeyResponse& key_response) {
|
CdmResponseType CdmSession::ReleaseKey(const CdmKeyResponse& key_response) {
|
||||||
CdmResponseType sts = license_parser_.HandleKeyUpdateResponse(false,
|
CdmResponseType sts = license_parser_->HandleKeyUpdateResponse(false,
|
||||||
key_response);
|
key_response);
|
||||||
if (NO_ERROR != sts)
|
if (KEY_ADDED != sts)
|
||||||
return sts;
|
return sts;
|
||||||
|
|
||||||
if (is_offline_ || !license_parser_.provider_session_token().empty()) {
|
if (is_offline_ || !license_parser_->provider_session_token().empty()) {
|
||||||
DeleteLicense();
|
DeleteLicense();
|
||||||
}
|
}
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CdmSession::IsKeyLoaded(const KeyId& key_id) {
|
bool CdmSession::IsKeyLoaded(const KeyId& key_id) {
|
||||||
return license_parser_.IsKeyLoaded(key_id);
|
return license_parser_->IsKeyLoaded(key_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmSessionId CdmSession::GenerateSessionId() {
|
CdmSessionId CdmSession::GenerateSessionId() {
|
||||||
@@ -401,8 +414,7 @@ bool CdmSession::GenerateKeySetId(CdmKeySetId* key_set_id) {
|
|||||||
std::vector<uint8_t> random_data(
|
std::vector<uint8_t> random_data(
|
||||||
(kKeySetIdLength - sizeof(KEY_SET_ID_PREFIX)) / 2, 0);
|
(kKeySetIdLength - sizeof(KEY_SET_ID_PREFIX)) / 2, 0);
|
||||||
|
|
||||||
DeviceFiles handle;
|
if (!file_handle_->Reset(security_level_))
|
||||||
if (!handle.Init(crypto_session_->GetSecurityLevel()))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
while (key_set_id->empty()) {
|
while (key_set_id->empty()) {
|
||||||
@@ -412,7 +424,7 @@ bool CdmSession::GenerateKeySetId(CdmKeySetId* key_set_id) {
|
|||||||
*key_set_id = KEY_SET_ID_PREFIX + b2a_hex(random_data);
|
*key_set_id = KEY_SET_ID_PREFIX + b2a_hex(random_data);
|
||||||
|
|
||||||
// key set collision
|
// key set collision
|
||||||
if (handle.LicenseExists(*key_set_id)) {
|
if (file_handle_->LicenseExists(*key_set_id)) {
|
||||||
key_set_id->clear();
|
key_set_id->clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -440,20 +452,20 @@ CdmResponseType CdmSession::StoreLicense() {
|
|||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string provider_session_token = license_parser_.provider_session_token();
|
std::string provider_session_token =
|
||||||
|
license_parser_->provider_session_token();
|
||||||
if (provider_session_token.empty()) {
|
if (provider_session_token.empty()) {
|
||||||
LOGE("CdmSession::StoreLicense: No provider session token and not offline");
|
LOGE("CdmSession::StoreLicense: No provider session token and not offline");
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceFiles handle;
|
if (!file_handle_->Reset(security_level_)) {
|
||||||
if (!handle.Init(crypto_session_->GetSecurityLevel())) {
|
|
||||||
LOGE("CdmSession::StoreLicense: Unable to initialize device files");
|
LOGE("CdmSession::StoreLicense: Unable to initialize device files");
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!handle.StoreUsageInfo(provider_session_token, key_request_,
|
if (!file_handle_->StoreUsageInfo(provider_session_token, key_request_,
|
||||||
key_response_)) {
|
key_response_)) {
|
||||||
LOGE("CdmSession::StoreLicense: Unable to store usage info");
|
LOGE("CdmSession::StoreLicense: Unable to store usage info");
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
@@ -461,31 +473,29 @@ CdmResponseType CdmSession::StoreLicense() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CdmSession::StoreLicense(DeviceFiles::LicenseState state) {
|
bool CdmSession::StoreLicense(DeviceFiles::LicenseState state) {
|
||||||
DeviceFiles handle;
|
if (!file_handle_->Reset(security_level_))
|
||||||
if (!handle.Init(crypto_session_->GetSecurityLevel()))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return handle.StoreLicense(
|
return file_handle_->StoreLicense(
|
||||||
key_set_id_, state, offline_init_data_, key_request_,
|
key_set_id_, state, offline_init_data_, key_request_,
|
||||||
key_response_, offline_key_renewal_request_,
|
key_response_, offline_key_renewal_request_,
|
||||||
offline_key_renewal_response_, offline_release_server_url_);
|
offline_key_renewal_response_, offline_release_server_url_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CdmSession::DeleteLicense() {
|
bool CdmSession::DeleteLicense() {
|
||||||
if (!is_offline_ && license_parser_.provider_session_token().empty())
|
if (!is_offline_ && license_parser_->provider_session_token().empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
DeviceFiles handle;
|
if (!file_handle_->Reset(security_level_)) {
|
||||||
if (!handle.Init(crypto_session_->GetSecurityLevel())) {
|
|
||||||
LOGE("CdmSession::DeleteLicense: Unable to initialize device files");
|
LOGE("CdmSession::DeleteLicense: Unable to initialize device files");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_offline_)
|
if (is_offline_)
|
||||||
return handle.DeleteLicense(key_set_id_);
|
return file_handle_->DeleteLicense(key_set_id_);
|
||||||
else
|
else
|
||||||
return handle.DeleteUsageInfo(
|
return file_handle_->DeleteUsageInfo(
|
||||||
license_parser_.provider_session_token());
|
license_parser_->provider_session_token());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CdmSession::AttachEventListener(WvCdmEventListener* listener) {
|
bool CdmSession::AttachEventListener(WvCdmEventListener* listener) {
|
||||||
@@ -501,7 +511,7 @@ void CdmSession::OnTimerEvent() {
|
|||||||
bool event_occurred = false;
|
bool event_occurred = false;
|
||||||
CdmEventType event;
|
CdmEventType event;
|
||||||
|
|
||||||
policy_engine_.OnTimerEvent(&event_occurred, &event);
|
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||||
|
|
||||||
if (event_occurred) {
|
if (event_occurred) {
|
||||||
for (CdmEventListenerIter iter = listeners_.begin();
|
for (CdmEventListenerIter iter = listeners_.begin();
|
||||||
|
|||||||
@@ -159,6 +159,25 @@ bool CryptoSession::GetDeviceUniqueId(std::string* device_id) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CryptoSession::GetApiVersion(uint32_t* version) {
|
||||||
|
if (!version) {
|
||||||
|
LOGE("CryptoSession::GetApiVersion: No buffer passed to method.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!initialized_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CdmSecurityLevel level = GetSecurityLevel();
|
||||||
|
SecurityLevel security_level = kLevelDefault;
|
||||||
|
if (kSecurityLevelL3 == level) security_level = kLevel3;
|
||||||
|
|
||||||
|
LOGV("CryptoSession::GetApiVersion: Lock");
|
||||||
|
AutoLock auto_lock(crypto_lock_);
|
||||||
|
*version = OEMCrypto_APIVersion(security_level);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool CryptoSession::GetSystemId(uint32_t* system_id) {
|
bool CryptoSession::GetSystemId(uint32_t* system_id) {
|
||||||
if (!system_id) {
|
if (!system_id) {
|
||||||
LOGE("CryptoSession::GetSystemId : No buffer passed to method.");
|
LOGE("CryptoSession::GetSystemId : No buffer passed to method.");
|
||||||
|
|||||||
@@ -55,8 +55,13 @@ bool Hash(const std::string& data, std::string* hash) {
|
|||||||
|
|
||||||
namespace wvcdm {
|
namespace wvcdm {
|
||||||
|
|
||||||
|
DeviceFiles::DeviceFiles()
|
||||||
|
: file_(NULL), security_level_(kSecurityLevelUninitialized),
|
||||||
|
initialized_(false), test_file_(false) {
|
||||||
|
}
|
||||||
|
|
||||||
DeviceFiles::~DeviceFiles() {
|
DeviceFiles::~DeviceFiles() {
|
||||||
if (!file_ && !test_file_) delete file_;
|
if (test_file_) file_.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeviceFiles::Init(CdmSecurityLevel security_level) {
|
bool DeviceFiles::Init(CdmSecurityLevel security_level) {
|
||||||
@@ -69,7 +74,7 @@ bool DeviceFiles::Init(CdmSecurityLevel security_level) {
|
|||||||
LOGW("DeviceFiles::Init: Unsupported security level %d", security_level);
|
LOGW("DeviceFiles::Init: Unsupported security level %d", security_level);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
file_ = new File();
|
if (!test_file_) file_.reset(new File());
|
||||||
security_level_ = security_level;
|
security_level_ = security_level;
|
||||||
initialized_ = true;
|
initialized_ = true;
|
||||||
return true;
|
return true;
|
||||||
@@ -363,18 +368,13 @@ bool DeviceFiles::DeleteUsageInfo(const std::string& provider_session_token) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
UsageInfo* updated_info = file.mutable_usage_info();
|
UsageInfo* usage_info = file.mutable_usage_info();
|
||||||
UsageInfo info(*(const_cast<const UsageInfo*>(updated_info)));
|
int index = 0;
|
||||||
updated_info->clear_sessions();
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (int i = 0; i < info.sessions_size(); ++i) {
|
for (; index < usage_info->sessions_size(); ++index) {
|
||||||
if (info.sessions(i).token().compare(provider_session_token) == 0) {
|
if (usage_info->sessions(index).token().compare(provider_session_token) == 0) {
|
||||||
found = true;
|
found = true;
|
||||||
} else {
|
break;
|
||||||
updated_info->add_sessions()->set_token(info.sessions(i).token());
|
|
||||||
updated_info->add_sessions()->set_license_request(
|
|
||||||
info.sessions(i).license_request());
|
|
||||||
updated_info->add_sessions()->set_license(info.sessions(i).license());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,6 +384,13 @@ bool DeviceFiles::DeleteUsageInfo(const std::string& provider_session_token) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
google::protobuf::RepeatedPtrField<UsageInfo_ProviderSession>* sessions =
|
||||||
|
usage_info->mutable_sessions();
|
||||||
|
if (index < usage_info->sessions_size() - 1) {
|
||||||
|
sessions->SwapElements(index, usage_info->sessions_size() - 1);
|
||||||
|
}
|
||||||
|
sessions->RemoveLast();
|
||||||
|
|
||||||
file.SerializeToString(&serialized_file);
|
file.SerializeToString(&serialized_file);
|
||||||
return StoreFile(kUsageInfoFileName, serialized_file);
|
return StoreFile(kUsageInfoFileName, serialized_file);
|
||||||
}
|
}
|
||||||
@@ -452,7 +459,7 @@ bool DeviceFiles::RetrieveUsageInfo(std::vector<
|
|||||||
|
|
||||||
bool DeviceFiles::StoreFile(const char* name,
|
bool DeviceFiles::StoreFile(const char* name,
|
||||||
const std::string& serialized_file) {
|
const std::string& serialized_file) {
|
||||||
if (!file_) {
|
if (!file_.get()) {
|
||||||
LOGW("DeviceFiles::StoreFile: Invalid file handle");
|
LOGW("DeviceFiles::StoreFile: Invalid file handle");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -512,7 +519,7 @@ bool DeviceFiles::StoreFile(const char* name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool DeviceFiles::RetrieveFile(const char* name, std::string* serialized_file) {
|
bool DeviceFiles::RetrieveFile(const char* name, std::string* serialized_file) {
|
||||||
if (!file_) {
|
if (!file_.get()) {
|
||||||
LOGW("DeviceFiles::RetrieveFile: Invalid file handle");
|
LOGW("DeviceFiles::RetrieveFile: Invalid file handle");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -661,8 +668,7 @@ std::string DeviceFiles::GetUsageInfoFileName() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DeviceFiles::SetTestFile(File* file) {
|
void DeviceFiles::SetTestFile(File* file) {
|
||||||
if (file_) delete file_;
|
file_.reset(file);
|
||||||
file_ = file;
|
|
||||||
test_file_ = true;
|
test_file_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "clock.h"
|
||||||
#include "crypto_key.h"
|
#include "crypto_key.h"
|
||||||
#include "crypto_session.h"
|
#include "crypto_session.h"
|
||||||
#include "device_files.h"
|
#include "device_files.h"
|
||||||
@@ -22,6 +23,7 @@ std::string kDeviceNameKey = "device_name";
|
|||||||
std::string kProductNameKey = "product_name";
|
std::string kProductNameKey = "product_name";
|
||||||
std::string kBuildInfoKey = "build_info";
|
std::string kBuildInfoKey = "build_info";
|
||||||
std::string kDeviceIdKey = "device_id";
|
std::string kDeviceIdKey = "device_id";
|
||||||
|
std::string kOemCryptoApiVersion = "oemcrypto_api_version";
|
||||||
const unsigned char kServiceCertificateCAPublicKey[] = {
|
const unsigned char kServiceCertificateCAPublicKey[] = {
|
||||||
0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, 0x81,
|
0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, 0x81,
|
||||||
0x00, 0xb4, 0xfe, 0x39, 0xc3, 0x65, 0x90, 0x03,
|
0x00, 0xb4, 0xfe, 0x39, 0xc3, 0x65, 0x90, 0x03,
|
||||||
@@ -254,12 +256,17 @@ bool CdmLicense::PrepareKeyRequest(const InitializationData& init_data,
|
|||||||
client_info->set_name(kBuildInfoKey);
|
client_info->set_name(kBuildInfoKey);
|
||||||
client_info->set_value(value);
|
client_info->set_value(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session_->GetDeviceUniqueId(&value)) {
|
if (session_->GetDeviceUniqueId(&value)) {
|
||||||
client_info = client_id->add_client_info();
|
client_info = client_id->add_client_info();
|
||||||
client_info->set_name(kDeviceIdKey);
|
client_info->set_name(kDeviceIdKey);
|
||||||
client_info->set_value(value);
|
client_info->set_value(value);
|
||||||
}
|
}
|
||||||
|
uint32_t version = 0;
|
||||||
|
if (session_->GetApiVersion(&version)) {
|
||||||
|
client_info = client_id->add_client_info();
|
||||||
|
client_info->set_name(kOemCryptoApiVersion);
|
||||||
|
client_info->set_value(UintToString(version));
|
||||||
|
}
|
||||||
|
|
||||||
if (privacy_mode_enabled) {
|
if (privacy_mode_enabled) {
|
||||||
EncryptedClientIdentification* encrypted_client_id =
|
EncryptedClientIdentification* encrypted_client_id =
|
||||||
@@ -353,12 +360,11 @@ bool CdmLicense::PrepareKeyRequest(const InitializationData& init_data,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The time field will be updated once the cdm wrapper
|
|
||||||
// has been updated to pass us in the time.
|
|
||||||
license_request.set_request_time(0);
|
|
||||||
|
|
||||||
license_request.set_type(LicenseRequest::NEW);
|
license_request.set_type(LicenseRequest::NEW);
|
||||||
|
|
||||||
|
Clock clock;
|
||||||
|
license_request.set_request_time(clock.GetCurrentTime());
|
||||||
|
|
||||||
// Get/set the nonce. This value will be reflected in the Key Control Block
|
// Get/set the nonce. This value will be reflected in the Key Control Block
|
||||||
// of the license response.
|
// of the license response.
|
||||||
uint32_t nonce;
|
uint32_t nonce;
|
||||||
@@ -424,6 +430,9 @@ bool CdmLicense::PrepareKeyUpdateRequest(bool is_renewal,
|
|||||||
else
|
else
|
||||||
license_request.set_type(LicenseRequest::RELEASE);
|
license_request.set_type(LicenseRequest::RELEASE);
|
||||||
|
|
||||||
|
Clock clock;
|
||||||
|
license_request.set_request_time(clock.GetCurrentTime());
|
||||||
|
|
||||||
LicenseRequest_ContentIdentification_ExistingLicense* current_license =
|
LicenseRequest_ContentIdentification_ExistingLicense* current_license =
|
||||||
license_request.mutable_content_id()->mutable_license();
|
license_request.mutable_content_id()->mutable_license();
|
||||||
LicenseIdentification license_id = policy_engine_->license_id();
|
LicenseIdentification license_id = policy_engine_->license_id();
|
||||||
@@ -432,8 +441,9 @@ bool CdmLicense::PrepareKeyUpdateRequest(bool is_renewal,
|
|||||||
if (!is_renewal) {
|
if (!is_renewal) {
|
||||||
if (license_id.has_provider_session_token()) {
|
if (license_id.has_provider_session_token()) {
|
||||||
std::string usage_report;
|
std::string usage_report;
|
||||||
if (!session_->GenerateUsageReport(license_id.provider_session_token(),
|
if (NO_ERROR !=
|
||||||
&usage_report)) {
|
session_->GenerateUsageReport(license_id.provider_session_token(),
|
||||||
|
&usage_report)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
current_license->set_session_usage_table_entry(usage_report);
|
current_license->set_session_usage_table_entry(usage_report);
|
||||||
@@ -560,7 +570,6 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
|||||||
return KEY_ERROR;
|
return KEY_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string provider_session_token;
|
|
||||||
if (license.id().has_provider_session_token())
|
if (license.id().has_provider_session_token())
|
||||||
provider_session_token_ = license.id().provider_session_token();
|
provider_session_token_ = license.id().provider_session_token();
|
||||||
|
|
||||||
@@ -575,7 +584,7 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
|||||||
mac_key_iv,
|
mac_key_iv,
|
||||||
mac_key,
|
mac_key,
|
||||||
key_array,
|
key_array,
|
||||||
provider_session_token);
|
provider_session_token_);
|
||||||
|
|
||||||
if (KEY_ADDED == resp) {
|
if (KEY_ADDED == resp) {
|
||||||
loaded_keys_.clear();
|
loaded_keys_.clear();
|
||||||
@@ -627,24 +636,23 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
|
|||||||
return KEY_ERROR;
|
return KEY_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_renewal) {
|
|
||||||
if (license.policy().has_renewal_server_url() &&
|
|
||||||
license.policy().renewal_server_url().size() > 0) {
|
|
||||||
server_url_ = license.policy().renewal_server_url();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (license.id().has_provider_session_token()) {
|
|
||||||
provider_session_token_ = license.id().provider_session_token();
|
|
||||||
session_->ReleaseUsageInformation(signed_response.msg(),
|
|
||||||
signed_response.signature(),
|
|
||||||
provider_session_token_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
policy_engine_->UpdateLicense(license);
|
policy_engine_->UpdateLicense(license);
|
||||||
|
|
||||||
if (!is_renewal) return KEY_ADDED;
|
if (!is_renewal) {
|
||||||
|
if (!license.id().has_provider_session_token()) return KEY_ADDED;
|
||||||
|
|
||||||
|
provider_session_token_ = license.id().provider_session_token();
|
||||||
|
CdmResponseType status =
|
||||||
|
session_->ReleaseUsageInformation(signed_response.msg(),
|
||||||
|
signed_response.signature(),
|
||||||
|
provider_session_token_);
|
||||||
|
return (NO_ERROR == status) ? KEY_ADDED : status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (license.policy().has_renewal_server_url() &&
|
||||||
|
license.policy().renewal_server_url().size() > 0) {
|
||||||
|
server_url_ = license.policy().renewal_server_url();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<CryptoKey> key_array = ExtractContentKeys(license);
|
std::vector<CryptoKey> key_array = ExtractContentKeys(license);
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ void PolicyEngine::Init(Clock* clock) {
|
|||||||
license_state_ = kLicenseStateInitial;
|
license_state_ = kLicenseStateInitial;
|
||||||
can_decrypt_ = false;
|
can_decrypt_ = false;
|
||||||
license_start_time_ = 0;
|
license_start_time_ = 0;
|
||||||
license_received_time_ = 0;
|
|
||||||
playback_start_time_ = 0;
|
playback_start_time_ = 0;
|
||||||
next_renewal_time_ = 0;
|
next_renewal_time_ = 0;
|
||||||
policy_max_duration_seconds_ = 0;
|
policy_max_duration_seconds_ = 0;
|
||||||
@@ -76,6 +75,14 @@ void PolicyEngine::OnTimerEvent(bool* event_occurred, CdmEventType* event) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case kLicenseStatePending: {
|
||||||
|
if (current_time >= license_start_time_) {
|
||||||
|
license_state_ = kLicenseStateCanPlay;
|
||||||
|
can_decrypt_ = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case kLicenseStateInitial:
|
case kLicenseStateInitial:
|
||||||
case kLicenseStateExpired: {
|
case kLicenseStateExpired: {
|
||||||
break;
|
break;
|
||||||
@@ -115,13 +122,11 @@ void PolicyEngine::UpdateLicense(
|
|||||||
policy_.MergeFrom(license.policy());
|
policy_.MergeFrom(license.policy());
|
||||||
|
|
||||||
// some basic license validation
|
// some basic license validation
|
||||||
if (license_state_ == kLicenseStateInitial) {
|
// license start time needs to be specified in the initial response
|
||||||
// license start time needs to be present in the initial response
|
if (!license.has_license_start_time()) return;
|
||||||
if (!license.has_license_start_time())
|
|
||||||
return;
|
// if renewal, discard license if version has not been updated
|
||||||
}
|
if (license_state_ != kLicenseStateInitial) {
|
||||||
else {
|
|
||||||
// if renewal, discard license if version has not been updated
|
|
||||||
if (license.id().version() > license_id_.version())
|
if (license.id().version() > license_id_.version())
|
||||||
license_id_.CopyFrom(license.id());
|
license_id_.CopyFrom(license.id());
|
||||||
else
|
else
|
||||||
@@ -129,12 +134,8 @@ void PolicyEngine::UpdateLicense(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update time information
|
// Update time information
|
||||||
int64_t current_time = clock_->GetCurrentTime();
|
license_start_time_ = license.license_start_time();
|
||||||
if (license.has_license_start_time())
|
next_renewal_time_ = license_start_time_ + policy_.renewal_delay_seconds();
|
||||||
license_start_time_ = license.license_start_time();
|
|
||||||
license_received_time_ = current_time;
|
|
||||||
next_renewal_time_ = current_time +
|
|
||||||
policy_.renewal_delay_seconds();
|
|
||||||
|
|
||||||
// Calculate policy_max_duration_seconds_. policy_max_duration_seconds_
|
// Calculate policy_max_duration_seconds_. policy_max_duration_seconds_
|
||||||
// will be set to the minimum of the following policies :
|
// will be set to the minimum of the following policies :
|
||||||
@@ -157,12 +158,18 @@ void PolicyEngine::UpdateLicense(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t current_time = clock_->GetCurrentTime();
|
||||||
if (IsLicenseDurationExpired(current_time)) return;
|
if (IsLicenseDurationExpired(current_time)) return;
|
||||||
if (IsPlaybackDurationExpired(current_time)) return;
|
if (IsPlaybackDurationExpired(current_time)) return;
|
||||||
|
|
||||||
// Update state
|
// Update state
|
||||||
license_state_ = kLicenseStateCanPlay;
|
if (current_time >= license_start_time_) {
|
||||||
can_decrypt_ = true;
|
license_state_ = kLicenseStateCanPlay;
|
||||||
|
can_decrypt_ = true;
|
||||||
|
} else {
|
||||||
|
license_state_ = kLicenseStatePending;
|
||||||
|
can_decrypt_ = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PolicyEngine::BeginDecryption() {
|
void PolicyEngine::BeginDecryption() {
|
||||||
@@ -178,6 +185,7 @@ void PolicyEngine::BeginDecryption() {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case kLicenseStateInitial:
|
case kLicenseStateInitial:
|
||||||
|
case kLicenseStatePending:
|
||||||
case kLicenseStateExpired:
|
case kLicenseStateExpired:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -221,7 +229,7 @@ void PolicyEngine::UpdateRenewalRequest(int64_t current_time) {
|
|||||||
// will always return false if the value is 0.
|
// will always return false if the value is 0.
|
||||||
bool PolicyEngine::IsLicenseDurationExpired(int64_t current_time) {
|
bool PolicyEngine::IsLicenseDurationExpired(int64_t current_time) {
|
||||||
return policy_max_duration_seconds_ &&
|
return policy_max_duration_seconds_ &&
|
||||||
license_received_time_ + policy_max_duration_seconds_ <=
|
license_start_time_ + policy_max_duration_seconds_ <=
|
||||||
current_time;
|
current_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,9 +237,12 @@ int64_t PolicyEngine::GetLicenseDurationRemaining(int64_t current_time) {
|
|||||||
if (0 == policy_max_duration_seconds_) return LLONG_MAX;
|
if (0 == policy_max_duration_seconds_) return LLONG_MAX;
|
||||||
|
|
||||||
int64_t remaining_time = policy_max_duration_seconds_
|
int64_t remaining_time = policy_max_duration_seconds_
|
||||||
+ license_received_time_ - current_time;
|
+ license_start_time_ - current_time;
|
||||||
|
|
||||||
if (remaining_time < 0) remaining_time = 0;
|
if (remaining_time < 0)
|
||||||
|
remaining_time = 0;
|
||||||
|
else if (remaining_time > policy_max_duration_seconds_)
|
||||||
|
remaining_time = policy_max_duration_seconds_;
|
||||||
return remaining_time;
|
return remaining_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,7 +267,7 @@ int64_t PolicyEngine::GetPlaybackDurationRemaining(int64_t current_time) {
|
|||||||
bool PolicyEngine::IsRenewalDelayExpired(int64_t current_time) {
|
bool PolicyEngine::IsRenewalDelayExpired(int64_t current_time) {
|
||||||
return policy_.can_renew() &&
|
return policy_.can_renew() &&
|
||||||
(policy_.renewal_delay_seconds() > 0) &&
|
(policy_.renewal_delay_seconds() > 0) &&
|
||||||
license_received_time_ + policy_.renewal_delay_seconds() <=
|
license_start_time_ + policy_.renewal_delay_seconds() <=
|
||||||
current_time;
|
current_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,7 +275,7 @@ bool PolicyEngine::IsRenewalRecoveryDurationExpired(
|
|||||||
int64_t current_time) {
|
int64_t current_time) {
|
||||||
// NOTE: Renewal Recovery Duration is currently not used.
|
// NOTE: Renewal Recovery Duration is currently not used.
|
||||||
return (policy_.renewal_recovery_duration_seconds() > 0) &&
|
return (policy_.renewal_recovery_duration_seconds() > 0) &&
|
||||||
license_received_time_ + policy_.renewal_recovery_duration_seconds() <=
|
license_start_time_ + policy_.renewal_recovery_duration_seconds() <=
|
||||||
current_time;
|
current_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
239
core/test/cdm_session_unittest.cpp
Normal file
239
core/test/cdm_session_unittest.cpp
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
#include "cdm_session.h"
|
||||||
|
#include "crypto_key.h"
|
||||||
|
#include "gmock/gmock.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "properties.h"
|
||||||
|
#include "string_conversions.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const std::string kToken = wvcdm::a2bs_hex(
|
||||||
|
"0AAE02080212107E0A892DEEB021E7AF696B938BB1D5B1188B85AD9D05228E023082010A02"
|
||||||
|
"82010100DBEDF2BFB0EC98213766E65049B9AB176FA4B1FBFBB2A0C96C87D9F2B895E0ED77"
|
||||||
|
"93BDA057E6BC3E0CA2348BC6831E03609445CA4D418CB98EAC98FFC87AB2364CE76BA26BEE"
|
||||||
|
"CDB0C45BD2A6FE9FD38CC5A1C26303AEEB7E9C3CAFAB0D10E46C07E50BEDAB42BF21F40BD2"
|
||||||
|
"E055DB0B455191D6B4CEEB11B3F1AFA42B5C0CE4C96B75A5283C0E3AE049AA7CF86D1C4EF6"
|
||||||
|
"6A9088B53BCF320ABC9B98A22C219DC109014EFEA72DA5FF2ED5D655DE7AE06EAC6C6B4191"
|
||||||
|
"523B2CD2DC1EBFF5F08B11CFE056F2826C1323F12704EC7EBBC1AF935129E5543804492AF9"
|
||||||
|
"23B848F4AF47B4BFB131C39DDDC99DBAEEE0F30AD2ADBBC63E60793D0876E37391008BB4DB"
|
||||||
|
"F7020301000128DD22128002A9E571776EA9D22A1BD14248DA88E12FD859989F613360B8D2"
|
||||||
|
"DA40AF31CC071C7A138466F0EB745E3FD664C0E1A5E4F01098B8D56C34A0158DF9916D192F"
|
||||||
|
"841ADCA17FD630E1C0CBE652CAC6A52B6A1581BE4029CE6FAE0E04D2D2C7861187AF8299D8"
|
||||||
|
"3E008DB9A2789672CA1DED903773D7E82B234CE2C799EB73CF80600C08F17EEDDDF369D2B8"
|
||||||
|
"4A08292F22D1F18FE89521905E713BA674F2217881DBD7711B8C48D5FDCE6FAB51F935E293"
|
||||||
|
"CB29191AB012B115FD2F5F23164B063D0A929C3E254BF0F4FA60051EB6B3498ED99FF77C19"
|
||||||
|
"68E8CD83A35CEB054D05433FD0EA6AAE43C87DDA377591D1DCC1831EE130BFFF6D139A5ADA"
|
||||||
|
"738B0F257CCE2649E71AB4050AAE020801121017DCBC27D11341D497135442A188DAA6188F"
|
||||||
|
"89809105228E023082010A0282010100D21ADD7549D2748B3494526A9C3FB86C79376BBE8C"
|
||||||
|
"8856F601B8D10461F77ACC7331B10DEBF365120056CDB5662D25907B74F12382F0F4A0CA47"
|
||||||
|
"5EEA9562815C6228F6F698ADA27879D8890F2A2D96A746DDEF5316301C003519C2A2250354"
|
||||||
|
"674169FDDA41CE14D3C52BEA7A20384515012D5952B38AA19E15E8563CC7AAA81C2122880A"
|
||||||
|
"A370A64FEA23C53FB83AC3DB5753214730A349E07F64BF32BE7EAD30D02612AF110BB44FB0"
|
||||||
|
"8E1D308173B327EF64D40C41639542B2D1A73C98A6607EC6C683B513A58470514106EF87AE"
|
||||||
|
"1E7B9C695B93A104DF7437BFC4167789748A43ED208F2C1FA710793C688885EAE732A8BFDF"
|
||||||
|
"5B423B23D75B88FC0ADC8FBDB5020301000128DD2212800372D2FB88098BA3B85B6B4354E0"
|
||||||
|
"3767DBE2D7724663FB0A62ABF7704EA910E01F221349EE16D0152C769384050CE78520668C"
|
||||||
|
"06CCFD3D789AF3EB69FF163615CD609169FDBE2E15A029D34AD2605625BC81844C9D1E2CE0"
|
||||||
|
"519039F3799ADAEF86641E20B033DC16DF2E5B9A1A2A417B8BB3B7A4D9AD1A99367448587D"
|
||||||
|
"A13DDE05A3ED9D62FA42078973B4AA40263D7BFA23F1072E94CDF323FA45F78408823E55C4"
|
||||||
|
"F4C5C723819CF44CE6D98E50C04EC24D93B1AAB8877B9108B9CA391308E1A3645EBB0E7CAC"
|
||||||
|
"BB40B5451560ED799421873BFB5ABB917FA60DB9C77CB8606AF7E3142626F5EA40E5CB8AA0"
|
||||||
|
"89D8E7D6A9361935C426A4450EA8BC2E57290D3BF0A0962991D2A91B752FC80C3E7E4E5503"
|
||||||
|
"3D71C94B325307A68815F026448F56A2741CEBEFC18E8C142F5F62BFAA67A291517DDE982D"
|
||||||
|
"8CD5A9DF6E3D3A99B806F6D60991358C5BE77117D4F3168F3348E9A048539F892F4D783152"
|
||||||
|
"C7A8095224AA56B78C5CF7BD1AB1B179C0C0D11E3C3BAC84C141A00191321E3ACC17242E68"
|
||||||
|
"3C");
|
||||||
|
const std::string kWrappedKey = wvcdm::a2bs_hex(
|
||||||
|
"3B84252DD84F1A710365014A114507FFFA3DD404625D61D1EEC7C3A39D72CB8D9318ADE9DA"
|
||||||
|
"05D69F9776DAFDA49A97BC30E84CA275925DFD98CA04F7DB23465103A224852192DE232902"
|
||||||
|
"99FF82024F5CCA7716ACA9BE0B56348BA16B9E3136D73789C842CB2ECA4820DDAAF59CCB9B"
|
||||||
|
"FCF2B4B0E2E5199FDCEC8DEBFFE50BB03041D8E767EA3FE6834C2E79E261ABF17B68EA66E1"
|
||||||
|
"45AD0A6B056F39C06531A9038C996BADD524E57AE7D5339F13C574E7A398C03D65FD730BAC"
|
||||||
|
"36F25347350DD2AD69EFA4DC040DC2D9DD4F53A729839FA3496CF580F2CBD51C3522DD67BC"
|
||||||
|
"BA4A91E89E2BD70449F28E026638920A6DF7B9A0B2C977ACC65AE845E76EF81CADAA746DAF"
|
||||||
|
"51D4D6FCBC083BE50DA1874D6EB1A30579B23C30881D94A8E5181FE20BF8F8C5F2522B1E7D"
|
||||||
|
"092B1E20BDE5373F40286DE15267247F88C564BD4EBF4F69B889A03C9892584DC340D87EE1"
|
||||||
|
"DFF2942D1B7E7EBD846349575F2DE6FDEF71BB005CFBEA845D87937BEBCAFEAC785A092C0A"
|
||||||
|
"76CE7F7A4FE2F8E43045DED5202A2A55F547BA5DE67AF9E6B2B7DC89EFAD34AC0B40BF4B8F"
|
||||||
|
"F82F8706B9A88FB9C7A0972E4A4B6CA970BF4F086573D595E5DB8ED0FDA4F9446ACD4B119C"
|
||||||
|
"1E949C194B042A5CFFC13043FF79F049068A67CC1EB671A10EF7DA927753C4D149E9D0000D"
|
||||||
|
"4307008BA0AED576ACCADF0CE6758F683087F26C2E38297B8C7D78DC3F1E8F24D7B3A0BED9"
|
||||||
|
"C066F8348FD19CDB54A92C4E944EE11E11B3B44344E0DB0E1B4BD6CF9295AB66C05454776A"
|
||||||
|
"8FE33AF659F67718AB43ACB52E83F8C29129DCE9654E8F1EBF9DAB9E933955E24389A37DBE"
|
||||||
|
"17BA89AC8C750B025CB2F65D5C8BF32FED87EF368F15751AA2114159B6C9C6C814D0720DA4"
|
||||||
|
"6E885BBB764ADC250D05F70306C3190991C31439BF273A33B6D1773E4FD089F32E753FA3C7"
|
||||||
|
"7B5ED7DB28407D87396F1F8C83B58176EDFE1F923BDB7DA0ADE58CA2BCD6E76F9463BE7A5A"
|
||||||
|
"909BE2731241BF1436F3E6A639FC7C717445D89AA5812E4532405B0FB368FE736E22D10FFD"
|
||||||
|
"15FACCF69FAC468B5552C7887763B96578038CCF154F333E2095BBFF71D5C1235E032174FB"
|
||||||
|
"44EAB4A753E7A917666A400EBE4F3D2C90100155C27F4B30C8ACFEDA6EFC763EF3556874E5"
|
||||||
|
"8A5AB0AEBBF39990F79EF4D65EC4697D7BBEEF4F32AE8C4A8A94814A9BE532B5AC902BC0C5"
|
||||||
|
"FB0A3E661AFF5961B6E79C82CC32FA7B7B48297347503FD58B110B93208167CC1FB96AD822"
|
||||||
|
"42F60B9D2BF9CCEE8E778A3D3A3302303FB4E33F607D46AACE49D3546A993EDC6FBEE6E19D"
|
||||||
|
"36831D85877013C57FE335F38D5CD9C3E09C1CEE28BC92C53A364663A7C031DF43B89BAAB4"
|
||||||
|
"AA8176900FD483AD70E3844BD15EE4F01D8BE72186BBF9E019FCEE5961166696854D1A901F"
|
||||||
|
"9D71B69B05F75FF233DB3C37F18DCADA640F68C4386F2E528CD77B93521A4574EF399375CD"
|
||||||
|
"2BE7B9FDC0AE62249717B7E0022BF55C0D023669DD09355EAA90E9DF9BEA309DF7561423BF"
|
||||||
|
"1DAD177F07A442E1591553924C0F67C2E86774009825490322A6B74319B4C77AA6195CA393"
|
||||||
|
"03A311F762FB0FD445278D9ACF26A9049C5031BE91F2C4A6BE994CA5A3CEBC2ACCF93AB1EB"
|
||||||
|
"993A6AA6DEB152DE8C9BB0E6B37B478393B50D1AAE99C086A0ED6D93BA7DD2DEEAB58EE34B"
|
||||||
|
"C5EE06BE238E8DE6CB44211097C5C90D5C04857918856F86B7036986C20A43153892ED9093"
|
||||||
|
"33EF70621A98184DDAB5E14BC971CF98CF6C91A37FFA83B00AD3BCABBAAB2DEF1C52F43003"
|
||||||
|
"E74C92B44F9205D22262FB47948654229DE1920F8EDF96A19A88A1CA1552F8856FB4CBF83B"
|
||||||
|
"AA3348419159D207F65FCE9C1A500C6818");
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace wvcdm {
|
||||||
|
|
||||||
|
// gmock methods
|
||||||
|
using ::testing::_;
|
||||||
|
using ::testing::Eq;
|
||||||
|
using ::testing::NotNull;
|
||||||
|
using ::testing::Return;
|
||||||
|
using ::testing::SetArgPointee;
|
||||||
|
using ::testing::StrEq;
|
||||||
|
|
||||||
|
class MockDeviceFiles : public DeviceFiles {
|
||||||
|
public:
|
||||||
|
MOCK_METHOD1(Init, bool(CdmSecurityLevel));
|
||||||
|
MOCK_METHOD2(RetrieveCertificate, bool(std::string*, std::string*));
|
||||||
|
};
|
||||||
|
|
||||||
|
class MockCryptoSession : public CryptoSession {
|
||||||
|
public:
|
||||||
|
MOCK_METHOD1(GetToken, bool(std::string*));
|
||||||
|
MOCK_METHOD0(GetSecurityLevel, CdmSecurityLevel());
|
||||||
|
MOCK_METHOD0(Open, CdmResponseType());
|
||||||
|
MOCK_METHOD1(Open, CdmResponseType(SecurityLevel));
|
||||||
|
MOCK_METHOD1(LoadCertificatePrivateKey, bool(std::string&));
|
||||||
|
};
|
||||||
|
|
||||||
|
class MockPolicyEngine : public PolicyEngine {
|
||||||
|
public:
|
||||||
|
// Leaving a place holder for when PolicyEngine methods need to be mocked
|
||||||
|
};
|
||||||
|
|
||||||
|
class MockCdmLicense : public CdmLicense {
|
||||||
|
public:
|
||||||
|
MOCK_METHOD3(Init, bool(const std::string&, CryptoSession*, PolicyEngine*));
|
||||||
|
};
|
||||||
|
|
||||||
|
class CdmSessionTest : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
virtual void SetUp() {
|
||||||
|
license_parser_ = new MockCdmLicense();
|
||||||
|
crypto_session_ = new MockCryptoSession();
|
||||||
|
policy_engine_ = new MockPolicyEngine();
|
||||||
|
file_handle_ = new MockDeviceFiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void TearDown() {
|
||||||
|
if (cdm_session_) delete cdm_session_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateSession() {
|
||||||
|
cdm_session_ = new CdmSession(license_parser_, crypto_session_,
|
||||||
|
policy_engine_, file_handle_, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateSession(const CdmClientPropertySet* cdm_client_property_set) {
|
||||||
|
cdm_session_ =
|
||||||
|
new CdmSession(license_parser_, crypto_session_, policy_engine_,
|
||||||
|
file_handle_, cdm_client_property_set);
|
||||||
|
}
|
||||||
|
|
||||||
|
CdmSession* cdm_session_;
|
||||||
|
MockCdmLicense* license_parser_;
|
||||||
|
MockCryptoSession* crypto_session_;
|
||||||
|
MockPolicyEngine* policy_engine_;
|
||||||
|
MockDeviceFiles* file_handle_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(CdmSessionTest, InitWithCertificate) {
|
||||||
|
CdmSecurityLevel level = kSecurityLevelL1;
|
||||||
|
EXPECT_CALL(*crypto_session_, GetSecurityLevel()).WillOnce(Return(level));
|
||||||
|
EXPECT_CALL(*crypto_session_, Open(Eq(kLevelDefault)))
|
||||||
|
.WillOnce(Return(NO_ERROR));
|
||||||
|
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
|
||||||
|
EXPECT_CALL(*file_handle_, RetrieveCertificate(NotNull(), NotNull()))
|
||||||
|
.WillOnce(DoAll(SetArgPointee<0>(kToken), SetArgPointee<1>(kWrappedKey),
|
||||||
|
Return(true)));
|
||||||
|
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey)))
|
||||||
|
.WillOnce(Return(true));
|
||||||
|
EXPECT_CALL(*license_parser_,
|
||||||
|
Init(Eq(kToken), Eq(crypto_session_), Eq(policy_engine_)))
|
||||||
|
.WillOnce(Return(true));
|
||||||
|
|
||||||
|
Properties::set_use_certificates_as_identification(true);
|
||||||
|
|
||||||
|
CreateSession();
|
||||||
|
ASSERT_EQ(NO_ERROR, cdm_session_->Init());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CdmSessionTest, InitWithKeybox) {
|
||||||
|
CdmSecurityLevel level = kSecurityLevelL1;
|
||||||
|
EXPECT_CALL(*crypto_session_, GetSecurityLevel()).WillOnce(Return(level));
|
||||||
|
EXPECT_CALL(*crypto_session_, Open(Eq(kLevelDefault)))
|
||||||
|
.WillOnce(Return(NO_ERROR));
|
||||||
|
EXPECT_CALL(*crypto_session_, GetToken(NotNull()))
|
||||||
|
.WillOnce(DoAll(SetArgPointee<0>(kToken), Return(true)));
|
||||||
|
EXPECT_CALL(*license_parser_,
|
||||||
|
Init(Eq(kToken), Eq(crypto_session_), Eq(policy_engine_)))
|
||||||
|
.WillOnce(Return(true));
|
||||||
|
|
||||||
|
Properties::set_use_certificates_as_identification(false);
|
||||||
|
|
||||||
|
CreateSession();
|
||||||
|
ASSERT_EQ(NO_ERROR, cdm_session_->Init());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CdmSessionTest, ReInitFail) {
|
||||||
|
CdmSecurityLevel level = kSecurityLevelL1;
|
||||||
|
EXPECT_CALL(*crypto_session_, GetSecurityLevel()).WillOnce(Return(level));
|
||||||
|
EXPECT_CALL(*crypto_session_, Open(Eq(kLevelDefault)))
|
||||||
|
.WillOnce(Return(NO_ERROR));
|
||||||
|
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
|
||||||
|
EXPECT_CALL(*file_handle_, RetrieveCertificate(NotNull(), NotNull()))
|
||||||
|
.WillOnce(DoAll(SetArgPointee<0>(kToken), SetArgPointee<1>(kWrappedKey),
|
||||||
|
Return(true)));
|
||||||
|
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey)))
|
||||||
|
.WillOnce(Return(true));
|
||||||
|
EXPECT_CALL(*license_parser_,
|
||||||
|
Init(Eq(kToken), Eq(crypto_session_), Eq(policy_engine_)))
|
||||||
|
.WillOnce(Return(true));
|
||||||
|
|
||||||
|
Properties::set_use_certificates_as_identification(true);
|
||||||
|
|
||||||
|
CreateSession();
|
||||||
|
ASSERT_EQ(NO_ERROR, cdm_session_->Init());
|
||||||
|
ASSERT_EQ(UNKNOWN_ERROR, cdm_session_->Init());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CdmSessionTest, InitFailCryptoError) {
|
||||||
|
CdmSecurityLevel level = kSecurityLevelL1;
|
||||||
|
EXPECT_CALL(*crypto_session_, GetSecurityLevel()).WillOnce(Return(level));
|
||||||
|
EXPECT_CALL(*crypto_session_, Open(Eq(kLevelDefault)))
|
||||||
|
.WillOnce(Return(UNKNOWN_ERROR));
|
||||||
|
|
||||||
|
Properties::set_use_certificates_as_identification(true);
|
||||||
|
|
||||||
|
CreateSession();
|
||||||
|
ASSERT_EQ(UNKNOWN_ERROR, cdm_session_->Init());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CdmSessionTest, InitNeedsProvisioning) {
|
||||||
|
CdmSecurityLevel level = kSecurityLevelL1;
|
||||||
|
EXPECT_CALL(*crypto_session_, GetSecurityLevel()).WillOnce(Return(level));
|
||||||
|
EXPECT_CALL(*crypto_session_, Open(Eq(kLevelDefault)))
|
||||||
|
.WillOnce(Return(NO_ERROR));
|
||||||
|
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
|
||||||
|
EXPECT_CALL(*file_handle_, RetrieveCertificate(NotNull(), NotNull()))
|
||||||
|
.WillOnce(Return(false));
|
||||||
|
|
||||||
|
Properties::set_use_certificates_as_identification(true);
|
||||||
|
|
||||||
|
CreateSession();
|
||||||
|
ASSERT_EQ(NEED_PROVISIONING, cdm_session_->Init());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // wvcdm
|
||||||
@@ -138,8 +138,7 @@ TEST_F(PolicyEngineTest, PlaybackFailed_CanPlayFalse) {
|
|||||||
policy->set_can_play(false);
|
policy->set_can_play(false);
|
||||||
|
|
||||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||||
.WillOnce(Return(kLicenseStartTime + 1))
|
.WillOnce(Return(kLicenseStartTime + 1));
|
||||||
.WillOnce(Return(kLicenseStartTime + 5));
|
|
||||||
|
|
||||||
policy_engine_->SetLicense(license_);
|
policy_engine_->SetLicense(license_);
|
||||||
EXPECT_FALSE(policy_engine_->can_decrypt());
|
EXPECT_FALSE(policy_engine_->can_decrypt());
|
||||||
@@ -163,8 +162,8 @@ TEST_F(PolicyEngineTest, PlaybackFails_RentalDurationExpired) {
|
|||||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||||
.WillOnce(Return(kLicenseStartTime + 1))
|
.WillOnce(Return(kLicenseStartTime + 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + 5))
|
.WillOnce(Return(kLicenseStartTime + 5))
|
||||||
.WillOnce(Return(kLicenseStartTime + min_duration))
|
.WillOnce(Return(kLicenseStartTime + min_duration - 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + min_duration + 1));
|
.WillOnce(Return(kLicenseStartTime + min_duration));
|
||||||
|
|
||||||
policy_engine_->SetLicense(license_);
|
policy_engine_->SetLicense(license_);
|
||||||
|
|
||||||
@@ -220,8 +219,8 @@ TEST_F(PolicyEngineTest, PlaybackFails_LicenseDurationExpired) {
|
|||||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||||
.WillOnce(Return(kLicenseStartTime + 1))
|
.WillOnce(Return(kLicenseStartTime + 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + 5))
|
.WillOnce(Return(kLicenseStartTime + 5))
|
||||||
.WillOnce(Return(kLicenseStartTime + min_duration))
|
.WillOnce(Return(kLicenseStartTime + min_duration - 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + 1 + min_duration));
|
.WillOnce(Return(kLicenseStartTime + min_duration));
|
||||||
|
|
||||||
policy_engine_->SetLicense(license_);
|
policy_engine_->SetLicense(license_);
|
||||||
|
|
||||||
@@ -248,8 +247,8 @@ TEST_F(PolicyEngineTest, PlaybackFails_ExpiryBeforeRenewalDelay) {
|
|||||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||||
.WillOnce(Return(kLicenseStartTime + 1))
|
.WillOnce(Return(kLicenseStartTime + 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + 5))
|
.WillOnce(Return(kLicenseStartTime + 5))
|
||||||
.WillOnce(Return(kLicenseStartTime + min_duration))
|
.WillOnce(Return(kLicenseStartTime + min_duration - 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + 1 + min_duration));
|
.WillOnce(Return(kLicenseStartTime + min_duration));
|
||||||
|
|
||||||
policy_engine_->SetLicense(license_);
|
policy_engine_->SetLicense(license_);
|
||||||
|
|
||||||
@@ -277,10 +276,10 @@ TEST_F(PolicyEngineTest, PlaybackOk_RentalDuration0) {
|
|||||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||||
.WillOnce(Return(kLicenseStartTime + 1))
|
.WillOnce(Return(kLicenseStartTime + 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + 5))
|
.WillOnce(Return(kLicenseStartTime + 5))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay - 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + license_renewal_delay))
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay))
|
||||||
.WillOnce(Return(kLicenseStartTime + 1 + license_renewal_delay))
|
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration - 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration))
|
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration));
|
||||||
.WillOnce(Return(kLicenseStartTime + 1 + kStreamingLicenseDuration));
|
|
||||||
|
|
||||||
policy_engine_->SetLicense(license_);
|
policy_engine_->SetLicense(license_);
|
||||||
|
|
||||||
@@ -357,8 +356,8 @@ TEST_F(PolicyEngineTest, PlaybackOk_LicenseDuration0) {
|
|||||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||||
.WillOnce(Return(kLicenseStartTime + 1))
|
.WillOnce(Return(kLicenseStartTime + 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + 5))
|
.WillOnce(Return(kLicenseStartTime + 5))
|
||||||
.WillOnce(Return(kLicenseStartTime + min_duration))
|
.WillOnce(Return(kLicenseStartTime + min_duration - 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + 1 + min_duration));
|
.WillOnce(Return(kLicenseStartTime + min_duration));
|
||||||
|
|
||||||
policy_engine_->SetLicense(license_);
|
policy_engine_->SetLicense(license_);
|
||||||
|
|
||||||
@@ -387,8 +386,8 @@ TEST_F(PolicyEngineTest, PlaybackOk_Durations0) {
|
|||||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||||
.WillOnce(Return(kLicenseStartTime + 1))
|
.WillOnce(Return(kLicenseStartTime + 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + 5))
|
.WillOnce(Return(kLicenseStartTime + 5))
|
||||||
.WillOnce(Return(kLicenseStartTime + kHighDuration))
|
.WillOnce(Return(kLicenseStartTime + kHighDuration - 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + kHighDuration + 10));
|
.WillOnce(Return(kLicenseStartTime + kHighDuration));
|
||||||
|
|
||||||
policy_engine_->SetLicense(license_);
|
policy_engine_->SetLicense(license_);
|
||||||
|
|
||||||
@@ -406,6 +405,29 @@ TEST_F(PolicyEngineTest, PlaybackOk_Durations0) {
|
|||||||
EXPECT_TRUE(policy_engine_->can_decrypt());
|
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(PolicyEngineTest, PlaybackOk_LicenseWithFutureStartTime) {
|
||||||
|
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||||
|
.WillOnce(Return(kLicenseStartTime - 100))
|
||||||
|
.WillOnce(Return(kLicenseStartTime - 50))
|
||||||
|
.WillOnce(Return(kLicenseStartTime))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + 10));
|
||||||
|
|
||||||
|
policy_engine_->SetLicense(license_);
|
||||||
|
|
||||||
|
bool event_occurred;
|
||||||
|
CdmEventType event;
|
||||||
|
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||||
|
EXPECT_FALSE(event_occurred);
|
||||||
|
EXPECT_FALSE(policy_engine_->can_decrypt());
|
||||||
|
|
||||||
|
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||||
|
EXPECT_FALSE(event_occurred);
|
||||||
|
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||||
|
|
||||||
|
policy_engine_->BeginDecryption();
|
||||||
|
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(PolicyEngineTest, PlaybackFailed_CanRenewFalse) {
|
TEST_F(PolicyEngineTest, PlaybackFailed_CanRenewFalse) {
|
||||||
License_Policy* policy = license_.mutable_policy();
|
License_Policy* policy = license_.mutable_policy();
|
||||||
policy->set_can_renew(false);
|
policy->set_can_renew(false);
|
||||||
@@ -480,6 +502,49 @@ TEST_F(PolicyEngineTest, PlaybackOk_RenewSuccess) {
|
|||||||
EXPECT_TRUE(policy_engine_->can_decrypt());
|
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(PolicyEngineTest, PlaybackOk_RenewSuccess_WithFutureStartTime) {
|
||||||
|
int64_t license_renewal_delay =
|
||||||
|
GetLicenseRenewalDelay(kStreamingLicenseDuration);
|
||||||
|
|
||||||
|
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||||
|
.WillOnce(Return(kLicenseStartTime + 1))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + 5))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay - 15))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 10))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 20))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 30))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 60));
|
||||||
|
|
||||||
|
policy_engine_->SetLicense(license_);
|
||||||
|
|
||||||
|
policy_engine_->BeginDecryption();
|
||||||
|
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||||
|
|
||||||
|
bool event_occurred;
|
||||||
|
CdmEventType event;
|
||||||
|
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||||
|
EXPECT_FALSE(event_occurred);
|
||||||
|
|
||||||
|
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||||
|
EXPECT_TRUE(event_occurred);
|
||||||
|
EXPECT_EQ(LICENSE_RENEWAL_NEEDED_EVENT, event);
|
||||||
|
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||||
|
|
||||||
|
license_.set_license_start_time(kLicenseStartTime + license_renewal_delay +
|
||||||
|
50);
|
||||||
|
LicenseIdentification* id = license_.mutable_id();
|
||||||
|
id->set_version(2);
|
||||||
|
policy_engine_->UpdateLicense(license_);
|
||||||
|
|
||||||
|
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||||
|
EXPECT_FALSE(event_occurred);
|
||||||
|
EXPECT_FALSE(policy_engine_->can_decrypt());
|
||||||
|
|
||||||
|
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||||
|
EXPECT_FALSE(event_occurred);
|
||||||
|
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(PolicyEngineTest, PlaybackFailed_RenewFailedVersionNotUpdated) {
|
TEST_F(PolicyEngineTest, PlaybackFailed_RenewFailedVersionNotUpdated) {
|
||||||
int64_t license_renewal_delay =
|
int64_t license_renewal_delay =
|
||||||
GetLicenseRenewalDelay(kStreamingLicenseDuration);
|
GetLicenseRenewalDelay(kStreamingLicenseDuration);
|
||||||
@@ -790,7 +855,7 @@ TEST_F(PolicyEngineTest, QuerySuccess) {
|
|||||||
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
|
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
|
||||||
ss >> remaining_time;
|
ss >> remaining_time;
|
||||||
ss.clear();
|
ss.clear();
|
||||||
EXPECT_EQ(kStreamingLicenseDuration - 99, remaining_time);
|
EXPECT_EQ(kStreamingLicenseDuration - 100, remaining_time);
|
||||||
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
|
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
|
||||||
ss >> remaining_time;
|
ss >> remaining_time;
|
||||||
EXPECT_EQ(kPlaybackDuration, remaining_time);
|
EXPECT_EQ(kPlaybackDuration, remaining_time);
|
||||||
@@ -816,7 +881,7 @@ TEST_F(PolicyEngineTest, QuerySuccess_PlaybackNotBegun) {
|
|||||||
std::istringstream ss;
|
std::istringstream ss;
|
||||||
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
|
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
|
||||||
ss >> remaining_time;
|
ss >> remaining_time;
|
||||||
EXPECT_EQ(kStreamingLicenseDuration - 99, remaining_time);
|
EXPECT_EQ(kStreamingLicenseDuration - 100, remaining_time);
|
||||||
ss.clear();
|
ss.clear();
|
||||||
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
|
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
|
||||||
ss >> remaining_time;
|
ss >> remaining_time;
|
||||||
@@ -832,7 +897,7 @@ TEST_F(PolicyEngineTest, QuerySuccess_PlaybackNotBegun) {
|
|||||||
ss.clear();
|
ss.clear();
|
||||||
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
|
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
|
||||||
ss >> remaining_time;
|
ss >> remaining_time;
|
||||||
EXPECT_EQ(kStreamingLicenseDuration - 199, remaining_time);
|
EXPECT_EQ(kStreamingLicenseDuration - 200, remaining_time);
|
||||||
ss.clear();
|
ss.clear();
|
||||||
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
|
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
|
||||||
ss >> remaining_time;
|
ss >> remaining_time;
|
||||||
@@ -861,7 +926,7 @@ TEST_F(PolicyEngineTest, QuerySuccess_PlaybackBegun) {
|
|||||||
std::istringstream ss;
|
std::istringstream ss;
|
||||||
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
|
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
|
||||||
ss >> remaining_time;
|
ss >> remaining_time;
|
||||||
EXPECT_EQ(kStreamingLicenseDuration - 49, remaining_time);
|
EXPECT_EQ(kStreamingLicenseDuration - 50, remaining_time);
|
||||||
ss.clear();
|
ss.clear();
|
||||||
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
|
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
|
||||||
ss >> remaining_time;
|
ss >> remaining_time;
|
||||||
@@ -885,7 +950,7 @@ TEST_F(PolicyEngineTest, QuerySuccess_PlaybackBegun) {
|
|||||||
ss.clear();
|
ss.clear();
|
||||||
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
|
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
|
||||||
ss >> remaining_time;
|
ss >> remaining_time;
|
||||||
EXPECT_EQ(kStreamingLicenseDuration - 199, remaining_time);
|
EXPECT_EQ(kStreamingLicenseDuration - 200, remaining_time);
|
||||||
ss.clear();
|
ss.clear();
|
||||||
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
|
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
|
||||||
ss >> remaining_time;
|
ss >> remaining_time;
|
||||||
@@ -931,7 +996,7 @@ TEST_F(PolicyEngineTest, QuerySuccess_Offline) {
|
|||||||
std::istringstream ss;
|
std::istringstream ss;
|
||||||
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
|
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
|
||||||
ss >> remaining_time;
|
ss >> remaining_time;
|
||||||
EXPECT_EQ(kOfflineLicenseDuration - 299, remaining_time);
|
EXPECT_EQ(kOfflineLicenseDuration - 300, remaining_time);
|
||||||
ss.clear();
|
ss.clear();
|
||||||
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
|
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
|
||||||
ss >> remaining_time;
|
ss >> remaining_time;
|
||||||
@@ -952,8 +1017,7 @@ TEST_F(PolicyEngineTest, QuerySuccess_CanPlayFalse) {
|
|||||||
|
|
||||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||||
.WillOnce(Return(kLicenseStartTime + 1))
|
.WillOnce(Return(kLicenseStartTime + 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + 100))
|
.WillOnce(Return(kLicenseStartTime + 100));
|
||||||
.WillOnce(Return(kLicenseStartTime + 200));
|
|
||||||
|
|
||||||
policy_engine_->SetLicense(license_);
|
policy_engine_->SetLicense(license_);
|
||||||
EXPECT_FALSE(policy_engine_->can_decrypt());
|
EXPECT_FALSE(policy_engine_->can_decrypt());
|
||||||
@@ -977,7 +1041,7 @@ TEST_F(PolicyEngineTest, QuerySuccess_CanPlayFalse) {
|
|||||||
std::istringstream ss;
|
std::istringstream ss;
|
||||||
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
|
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
|
||||||
ss >> remaining_time;
|
ss >> remaining_time;
|
||||||
EXPECT_EQ(kOfflineLicenseDuration - 199, remaining_time);
|
EXPECT_EQ(kOfflineLicenseDuration - 100, remaining_time);
|
||||||
ss.clear();
|
ss.clear();
|
||||||
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
|
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
|
||||||
ss >> remaining_time;
|
ss >> remaining_time;
|
||||||
@@ -995,8 +1059,8 @@ TEST_F(PolicyEngineTest, QuerySuccess_RentalDurationExpired) {
|
|||||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||||
.WillOnce(Return(kLicenseStartTime + 1))
|
.WillOnce(Return(kLicenseStartTime + 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + 5))
|
.WillOnce(Return(kLicenseStartTime + 5))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + min_duration - 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + min_duration))
|
.WillOnce(Return(kLicenseStartTime + min_duration))
|
||||||
.WillOnce(Return(kLicenseStartTime + min_duration + 1))
|
|
||||||
.WillOnce(Return(kLicenseStartTime + min_duration + 5));
|
.WillOnce(Return(kLicenseStartTime + min_duration + 5));
|
||||||
|
|
||||||
policy_engine_->SetLicense(license_);
|
policy_engine_->SetLicense(license_);
|
||||||
@@ -1076,7 +1140,7 @@ TEST_F(PolicyEngineTest, QuerySuccess_PlaybackDurationExpired) {
|
|||||||
std::istringstream ss;
|
std::istringstream ss;
|
||||||
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
|
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
|
||||||
ss >> remaining_time;
|
ss >> remaining_time;
|
||||||
EXPECT_EQ(kHighDuration - 10004 - min_duration, remaining_time);
|
EXPECT_EQ(kHighDuration - 10005 - min_duration, remaining_time);
|
||||||
ss.clear();
|
ss.clear();
|
||||||
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
|
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
|
||||||
ss >> remaining_time;
|
ss >> remaining_time;
|
||||||
@@ -1092,9 +1156,9 @@ TEST_F(PolicyEngineTest, QuerySuccess_LicenseDurationExpired) {
|
|||||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||||
.WillOnce(Return(kLicenseStartTime + 1))
|
.WillOnce(Return(kLicenseStartTime + 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + 5))
|
.WillOnce(Return(kLicenseStartTime + 5))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + min_duration - 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + min_duration))
|
.WillOnce(Return(kLicenseStartTime + min_duration))
|
||||||
.WillOnce(Return(kLicenseStartTime + 1 + min_duration))
|
.WillOnce(Return(kLicenseStartTime + min_duration + 5));
|
||||||
.WillOnce(Return(kLicenseStartTime + 5 + min_duration));
|
|
||||||
|
|
||||||
policy_engine_->SetLicense(license_);
|
policy_engine_->SetLicense(license_);
|
||||||
|
|
||||||
@@ -1140,11 +1204,11 @@ TEST_F(PolicyEngineTest, QuerySuccess_RentalDuration0) {
|
|||||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||||
.WillOnce(Return(kLicenseStartTime + 1))
|
.WillOnce(Return(kLicenseStartTime + 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + 5))
|
.WillOnce(Return(kLicenseStartTime + 5))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay - 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + license_renewal_delay))
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay))
|
||||||
.WillOnce(Return(kLicenseStartTime + 1 + license_renewal_delay))
|
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration - 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration))
|
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration))
|
||||||
.WillOnce(Return(kLicenseStartTime + 1 + kStreamingLicenseDuration))
|
.WillOnce(Return(kLicenseStartTime + kStreamingLicenseDuration + 5));
|
||||||
.WillOnce(Return(kLicenseStartTime + 5 + kStreamingLicenseDuration));
|
|
||||||
|
|
||||||
policy_engine_->SetLicense(license_);
|
policy_engine_->SetLicense(license_);
|
||||||
|
|
||||||
@@ -1275,9 +1339,9 @@ TEST_F(PolicyEngineTest, QuerySuccess_LicenseDuration0) {
|
|||||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||||
.WillOnce(Return(kLicenseStartTime + 1))
|
.WillOnce(Return(kLicenseStartTime + 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + 5))
|
.WillOnce(Return(kLicenseStartTime + 5))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + min_duration - 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + min_duration))
|
.WillOnce(Return(kLicenseStartTime + min_duration))
|
||||||
.WillOnce(Return(kLicenseStartTime + 1 + min_duration))
|
.WillOnce(Return(kLicenseStartTime + min_duration + 5));
|
||||||
.WillOnce(Return(kLicenseStartTime + 5 + min_duration));
|
|
||||||
|
|
||||||
policy_engine_->SetLicense(license_);
|
policy_engine_->SetLicense(license_);
|
||||||
|
|
||||||
@@ -1325,7 +1389,7 @@ TEST_F(PolicyEngineTest, QuerySuccess_Durations0) {
|
|||||||
.WillOnce(Return(kLicenseStartTime + 1))
|
.WillOnce(Return(kLicenseStartTime + 1))
|
||||||
.WillOnce(Return(kLicenseStartTime + 5))
|
.WillOnce(Return(kLicenseStartTime + 5))
|
||||||
.WillOnce(Return(kLicenseStartTime + kHighDuration))
|
.WillOnce(Return(kLicenseStartTime + kHighDuration))
|
||||||
.WillOnce(Return(kLicenseStartTime + kHighDuration + 10))
|
.WillOnce(Return(kLicenseStartTime + kHighDuration + 9))
|
||||||
.WillOnce(Return(kLicenseStartTime + kHighDuration + 15));
|
.WillOnce(Return(kLicenseStartTime + kHighDuration + 15));
|
||||||
|
|
||||||
policy_engine_->SetLicense(license_);
|
policy_engine_->SetLicense(license_);
|
||||||
@@ -1361,4 +1425,213 @@ TEST_F(PolicyEngineTest, QuerySuccess_Durations0) {
|
|||||||
EXPECT_EQ(LLONG_MAX, remaining_time);
|
EXPECT_EQ(LLONG_MAX, remaining_time);
|
||||||
EXPECT_EQ(kRenewalServerUrl, query_info[QUERY_KEY_RENEWAL_SERVER_URL]);
|
EXPECT_EQ(kRenewalServerUrl, query_info[QUERY_KEY_RENEWAL_SERVER_URL]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(PolicyEngineTest, QuerySuccess_LicenseWithFutureStartTime) {
|
||||||
|
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||||
|
.WillOnce(Return(kLicenseStartTime - 100))
|
||||||
|
.WillOnce(Return(kLicenseStartTime - 50))
|
||||||
|
.WillOnce(Return(kLicenseStartTime - 10))
|
||||||
|
.WillOnce(Return(kLicenseStartTime))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + 10))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + 25));
|
||||||
|
|
||||||
|
policy_engine_->SetLicense(license_);
|
||||||
|
|
||||||
|
bool event_occurred;
|
||||||
|
CdmEventType event;
|
||||||
|
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||||
|
EXPECT_FALSE(event_occurred);
|
||||||
|
EXPECT_FALSE(policy_engine_->can_decrypt());
|
||||||
|
|
||||||
|
CdmQueryMap query_info;
|
||||||
|
EXPECT_EQ(NO_ERROR, policy_engine_->Query(&query_info));
|
||||||
|
EXPECT_EQ(QUERY_VALUE_STREAMING, query_info[QUERY_KEY_LICENSE_TYPE]);
|
||||||
|
EXPECT_EQ(QUERY_VALUE_TRUE, query_info[QUERY_KEY_PLAY_ALLOWED]);
|
||||||
|
EXPECT_EQ(QUERY_VALUE_FALSE, query_info[QUERY_KEY_PERSIST_ALLOWED]);
|
||||||
|
EXPECT_EQ(QUERY_VALUE_TRUE, query_info[QUERY_KEY_RENEW_ALLOWED]);
|
||||||
|
|
||||||
|
int64_t remaining_time;
|
||||||
|
std::istringstream ss;
|
||||||
|
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
|
||||||
|
ss >> remaining_time;
|
||||||
|
EXPECT_EQ(kStreamingLicenseDuration, remaining_time);
|
||||||
|
ss.clear();
|
||||||
|
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
|
||||||
|
ss >> remaining_time;
|
||||||
|
EXPECT_EQ(kPlaybackDuration, remaining_time);
|
||||||
|
EXPECT_EQ(kRenewalServerUrl, query_info[QUERY_KEY_RENEWAL_SERVER_URL]);
|
||||||
|
|
||||||
|
EXPECT_FALSE(policy_engine_->can_decrypt());
|
||||||
|
|
||||||
|
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||||
|
EXPECT_FALSE(event_occurred);
|
||||||
|
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||||
|
policy_engine_->BeginDecryption();
|
||||||
|
|
||||||
|
EXPECT_EQ(NO_ERROR, policy_engine_->Query(&query_info));
|
||||||
|
EXPECT_EQ(QUERY_VALUE_STREAMING, query_info[QUERY_KEY_LICENSE_TYPE]);
|
||||||
|
EXPECT_EQ(QUERY_VALUE_TRUE, query_info[QUERY_KEY_PLAY_ALLOWED]);
|
||||||
|
EXPECT_EQ(QUERY_VALUE_FALSE, query_info[QUERY_KEY_PERSIST_ALLOWED]);
|
||||||
|
EXPECT_EQ(QUERY_VALUE_TRUE, query_info[QUERY_KEY_RENEW_ALLOWED]);
|
||||||
|
|
||||||
|
ss.clear();
|
||||||
|
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
|
||||||
|
ss >> remaining_time;
|
||||||
|
EXPECT_EQ(kStreamingLicenseDuration - 25, remaining_time);
|
||||||
|
ss.clear();
|
||||||
|
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
|
||||||
|
ss >> remaining_time;
|
||||||
|
EXPECT_EQ(kPlaybackDuration - 15, remaining_time);
|
||||||
|
EXPECT_EQ(kRenewalServerUrl, query_info[QUERY_KEY_RENEWAL_SERVER_URL]);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PolicyEngineTest, QuerySuccess_Renew) {
|
||||||
|
int64_t license_renewal_delay =
|
||||||
|
GetLicenseRenewalDelay(kStreamingLicenseDuration);
|
||||||
|
|
||||||
|
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||||
|
.WillOnce(Return(kLicenseStartTime + 1))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + 5))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay - 25))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 10))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 20))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay +
|
||||||
|
kLicenseRenewalRetryInterval + 10))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay +
|
||||||
|
kLicenseRenewalRetryInterval + 15));
|
||||||
|
|
||||||
|
policy_engine_->SetLicense(license_);
|
||||||
|
|
||||||
|
policy_engine_->BeginDecryption();
|
||||||
|
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||||
|
|
||||||
|
bool event_occurred;
|
||||||
|
CdmEventType event;
|
||||||
|
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||||
|
EXPECT_FALSE(event_occurred);
|
||||||
|
|
||||||
|
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||||
|
EXPECT_TRUE(event_occurred);
|
||||||
|
EXPECT_EQ(LICENSE_RENEWAL_NEEDED_EVENT, event);
|
||||||
|
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||||
|
|
||||||
|
license_.set_license_start_time(kLicenseStartTime + license_renewal_delay +
|
||||||
|
15);
|
||||||
|
LicenseIdentification* id = license_.mutable_id();
|
||||||
|
id->set_version(2);
|
||||||
|
policy_engine_->UpdateLicense(license_);
|
||||||
|
|
||||||
|
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||||
|
EXPECT_FALSE(event_occurred);
|
||||||
|
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||||
|
|
||||||
|
CdmQueryMap query_info;
|
||||||
|
EXPECT_EQ(NO_ERROR, policy_engine_->Query(&query_info));
|
||||||
|
EXPECT_EQ(QUERY_VALUE_STREAMING, query_info[QUERY_KEY_LICENSE_TYPE]);
|
||||||
|
EXPECT_EQ(QUERY_VALUE_TRUE, query_info[QUERY_KEY_PLAY_ALLOWED]);
|
||||||
|
EXPECT_EQ(QUERY_VALUE_FALSE, query_info[QUERY_KEY_PERSIST_ALLOWED]);
|
||||||
|
EXPECT_EQ(QUERY_VALUE_TRUE, query_info[QUERY_KEY_RENEW_ALLOWED]);
|
||||||
|
|
||||||
|
int64_t remaining_time;
|
||||||
|
std::istringstream ss;
|
||||||
|
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
|
||||||
|
ss >> remaining_time;
|
||||||
|
EXPECT_EQ(kStreamingLicenseDuration - kLicenseRenewalRetryInterval,
|
||||||
|
remaining_time);
|
||||||
|
ss.clear();
|
||||||
|
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
|
||||||
|
ss >> remaining_time;
|
||||||
|
EXPECT_EQ(kPlaybackDuration + 5 - license_renewal_delay -
|
||||||
|
kLicenseRenewalRetryInterval - 15,
|
||||||
|
remaining_time);
|
||||||
|
EXPECT_EQ(kRenewalServerUrl, query_info[QUERY_KEY_RENEWAL_SERVER_URL]);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PolicyEngineTest, QuerySuccess_RenewWithFutureStartTime) {
|
||||||
|
int64_t license_renewal_delay =
|
||||||
|
GetLicenseRenewalDelay(kStreamingLicenseDuration);
|
||||||
|
|
||||||
|
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||||
|
.WillOnce(Return(kLicenseStartTime + 1))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + 5))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay - 25))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 10))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 20))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay +
|
||||||
|
kLicenseRenewalRetryInterval + 10))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay +
|
||||||
|
kLicenseRenewalRetryInterval + 20))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay +
|
||||||
|
kLicenseRenewalRetryInterval + 30))
|
||||||
|
.WillOnce(Return(kLicenseStartTime + license_renewal_delay +
|
||||||
|
kLicenseRenewalRetryInterval + 40));
|
||||||
|
|
||||||
|
policy_engine_->SetLicense(license_);
|
||||||
|
|
||||||
|
policy_engine_->BeginDecryption();
|
||||||
|
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||||
|
|
||||||
|
bool event_occurred;
|
||||||
|
CdmEventType event;
|
||||||
|
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||||
|
EXPECT_FALSE(event_occurred);
|
||||||
|
|
||||||
|
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||||
|
EXPECT_TRUE(event_occurred);
|
||||||
|
EXPECT_EQ(LICENSE_RENEWAL_NEEDED_EVENT, event);
|
||||||
|
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||||
|
|
||||||
|
license_.set_license_start_time(kLicenseStartTime + license_renewal_delay +
|
||||||
|
kLicenseRenewalRetryInterval + 20);
|
||||||
|
LicenseIdentification* id = license_.mutable_id();
|
||||||
|
id->set_version(2);
|
||||||
|
policy_engine_->UpdateLicense(license_);
|
||||||
|
|
||||||
|
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||||
|
EXPECT_FALSE(event_occurred);
|
||||||
|
EXPECT_FALSE(policy_engine_->can_decrypt());
|
||||||
|
|
||||||
|
CdmQueryMap query_info;
|
||||||
|
EXPECT_EQ(NO_ERROR, policy_engine_->Query(&query_info));
|
||||||
|
EXPECT_EQ(QUERY_VALUE_STREAMING, query_info[QUERY_KEY_LICENSE_TYPE]);
|
||||||
|
EXPECT_EQ(QUERY_VALUE_TRUE, query_info[QUERY_KEY_PLAY_ALLOWED]);
|
||||||
|
EXPECT_EQ(QUERY_VALUE_FALSE, query_info[QUERY_KEY_PERSIST_ALLOWED]);
|
||||||
|
EXPECT_EQ(QUERY_VALUE_TRUE, query_info[QUERY_KEY_RENEW_ALLOWED]);
|
||||||
|
|
||||||
|
int64_t remaining_time;
|
||||||
|
std::istringstream ss;
|
||||||
|
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
|
||||||
|
ss >> remaining_time;
|
||||||
|
EXPECT_EQ(kStreamingLicenseDuration, remaining_time);
|
||||||
|
ss.clear();
|
||||||
|
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
|
||||||
|
ss >> remaining_time;
|
||||||
|
EXPECT_EQ(kPlaybackDuration + 5 - license_renewal_delay -
|
||||||
|
kLicenseRenewalRetryInterval - 20,
|
||||||
|
remaining_time);
|
||||||
|
EXPECT_EQ(kRenewalServerUrl, query_info[QUERY_KEY_RENEWAL_SERVER_URL]);
|
||||||
|
|
||||||
|
policy_engine_->OnTimerEvent(&event_occurred, &event);
|
||||||
|
EXPECT_FALSE(event_occurred);
|
||||||
|
EXPECT_TRUE(policy_engine_->can_decrypt());
|
||||||
|
|
||||||
|
EXPECT_EQ(NO_ERROR, policy_engine_->Query(&query_info));
|
||||||
|
EXPECT_EQ(QUERY_VALUE_STREAMING, query_info[QUERY_KEY_LICENSE_TYPE]);
|
||||||
|
EXPECT_EQ(QUERY_VALUE_TRUE, query_info[QUERY_KEY_PLAY_ALLOWED]);
|
||||||
|
EXPECT_EQ(QUERY_VALUE_FALSE, query_info[QUERY_KEY_PERSIST_ALLOWED]);
|
||||||
|
EXPECT_EQ(QUERY_VALUE_TRUE, query_info[QUERY_KEY_RENEW_ALLOWED]);
|
||||||
|
|
||||||
|
ss.clear();
|
||||||
|
ss.str(query_info[QUERY_KEY_LICENSE_DURATION_REMAINING]);
|
||||||
|
ss >> remaining_time;
|
||||||
|
EXPECT_EQ(kStreamingLicenseDuration - 20, remaining_time);
|
||||||
|
ss.clear();
|
||||||
|
ss.str(query_info[QUERY_KEY_PLAYBACK_DURATION_REMAINING]);
|
||||||
|
ss >> remaining_time;
|
||||||
|
EXPECT_EQ(kPlaybackDuration + 5 - license_renewal_delay -
|
||||||
|
kLicenseRenewalRetryInterval - 40,
|
||||||
|
remaining_time);
|
||||||
|
EXPECT_EQ(kRenewalServerUrl, query_info[QUERY_KEY_RENEWAL_SERVER_URL]);
|
||||||
|
}
|
||||||
|
|
||||||
} // wvcdm
|
} // wvcdm
|
||||||
|
|||||||
@@ -2880,7 +2880,7 @@ TEST_F(DISABLED_TestKeybox, RSASignature) {
|
|||||||
size_t signature_length = 0;
|
size_t signature_length = 0;
|
||||||
|
|
||||||
sts = OEMCrypto_GenerateRSASignature(s.session_id(), &licenseRequest[0],
|
sts = OEMCrypto_GenerateRSASignature(s.session_id(), &licenseRequest[0],
|
||||||
licenseRequest.size(), NULL,
|
licenseRequest.size(), signature,
|
||||||
&signature_length, kSign_RSASSA_PSS);
|
&signature_length, kSign_RSASSA_PSS);
|
||||||
|
|
||||||
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
|
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
'certificate_provision%': 'false',
|
'certificate_provision%': 'false',
|
||||||
'force_use_of_secure_buffers%': 'false',
|
'force_use_of_secure_buffers%': 'false',
|
||||||
'disable_privacy_crypto%': 'false',
|
'disable_privacy_crypto%': 'false',
|
||||||
|
'properties_source_file%': 'src/properties_common.cpp',
|
||||||
|
'protobuf_gyp%': '<(DEPTH)/third_party/protobuf.gyp',
|
||||||
}, # end variables
|
}, # end variables
|
||||||
|
|
||||||
'target_defaults': {
|
'target_defaults': {
|
||||||
|
|||||||
6
third_party/protoc.gypi
vendored
6
third_party/protoc.gypi
vendored
@@ -10,14 +10,14 @@
|
|||||||
'protoc_dir': '<(PRODUCT_DIR)',
|
'protoc_dir': '<(PRODUCT_DIR)',
|
||||||
},
|
},
|
||||||
'dependencies': [
|
'dependencies': [
|
||||||
'<(DEPTH)/third_party/protobuf.gyp:protoc#host',
|
'<(protobuf_gyp):protoc#host',
|
||||||
'<(DEPTH)/third_party/protobuf.gyp:protobuf_lite',
|
'<(protobuf_gyp):protobuf_lite',
|
||||||
],
|
],
|
||||||
'export_dependent_settings': [
|
'export_dependent_settings': [
|
||||||
# Direct dependents of protobuf_lite have the correct protobuf include
|
# Direct dependents of protobuf_lite have the correct protobuf include
|
||||||
# path, so export this as a dep to anyone who depends on the sources
|
# path, so export this as a dep to anyone who depends on the sources
|
||||||
# generated by this target.
|
# generated by this target.
|
||||||
'<(DEPTH)/third_party/protobuf.gyp:protobuf_lite',
|
'<(protobuf_gyp):protobuf_lite',
|
||||||
],
|
],
|
||||||
}],
|
}],
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user