Source release v2.1.4-0-804 + third_party libs

Change-Id: I1db8582efba613fa8a2b91a9c2697c5dfb2a8abf
This commit is contained in:
Joey Parrish
2014-07-02 09:27:29 -07:00
parent 84acd5a15e
commit 334525c8a5
22 changed files with 1090 additions and 271 deletions

117
README.upgrading Normal file
View 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.

View File

@@ -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',

View File

@@ -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"

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}; };

View File

@@ -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);

View File

@@ -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_;

View File

@@ -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_;

View File

@@ -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_;

View File

@@ -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) {
status = usage_session_->RestoreUsageSession(license_info[i].first,
license_info[i].second);
if (KEY_ADDED != status) { if (KEY_ADDED != status) {
LOGE("CdmEngine::GetUsageInfo: restore usage session error: %ld", LOGE("CdmEngine::GetUsageInfo: restore usage session (%d) error %ld",
status); index, status);
usage_info->clear(); usage_info->clear();
return status; return status;
} }
status = usage_session_->GenerateReleaseRequest(&(*usage_info)[i],
&server_url); status = usage_session_->GenerateReleaseRequest(&(*usage_info)[0], &server_url);
if (KEY_MESSAGE != status) { if (KEY_MESSAGE != status) {
LOGE("CdmEngine::GetUsageInfo: generate release request error: %ld", LOGE("CdmEngine::GetUsageInfo: generate release request error: %ld",
status); status);
usage_info->clear(); usage_info->clear();
return status; 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(

View File

@@ -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,13 +120,13 @@ 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,
&offline_init_data_,
&key_request_, &key_response_, &key_request_, &key_response_,
&offline_key_renewal_request_, &offline_key_renewal_request_,
&offline_key_renewal_response_, &offline_key_renewal_response_,
@@ -95,16 +141,7 @@ 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_ ||
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_)) { 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,22 +203,12 @@ 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_ ||
crypto_session_->LoadCertificatePrivateKey(wrapped_key_)) {
is_certificate_loaded_ = true;
} else {
reinitialize_session_ = true;
return NEED_PROVISIONING;
}
}
if (!license_parser_.PrepareKeyRequest(init_data, license_type,
app_parameters, session_id_, app_parameters, session_id_,
key_request, server_url)) { 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,19 +452,19 @@ 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();

View File

@@ -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.");

View File

@@ -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;
} }

View File

@@ -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,7 +441,8 @@ 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 !=
session_->GenerateUsageReport(license_id.provider_session_token(),
&usage_report)) { &usage_report)) {
return false; return false;
} }
@@ -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) { policy_engine_->UpdateLicense(license);
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() && if (license.policy().has_renewal_server_url() &&
license.policy().renewal_server_url().size() > 0) { license.policy().renewal_server_url().size() > 0) {
server_url_ = license.policy().renewal_server_url(); server_url_ = license.policy().renewal_server_url();
} }
}
else {
if (license.id().has_provider_session_token()) {
provider_session_token_ = license.id().provider_session_token();
session_->ReleaseUsageInformation(signed_response.msg(),
signed_response.signature(),
provider_session_token_);
}
}
policy_engine_->UpdateLicense(license);
if (!is_renewal) return KEY_ADDED;
std::vector<CryptoKey> key_array = ExtractContentKeys(license); std::vector<CryptoKey> key_array = ExtractContentKeys(license);

View File

@@ -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;
}
else {
// if renewal, discard license if version has not been updated // if renewal, discard license if version has not been updated
if (license_state_ != kLicenseStateInitial) {
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();
if (license.has_license_start_time())
license_start_time_ = license.license_start_time(); license_start_time_ = license.license_start_time();
license_received_time_ = current_time; next_renewal_time_ = license_start_time_ + policy_.renewal_delay_seconds();
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
if (current_time >= license_start_time_) {
license_state_ = kLicenseStateCanPlay; license_state_ = kLicenseStateCanPlay;
can_decrypt_ = true; 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;
} }

View 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

View File

@@ -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

View File

@@ -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);

View File

@@ -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': {

View File

@@ -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',
], ],
}], }],
], ],