diff --git a/libwvdrmengine/cdm/core/include/cdm_session.h b/libwvdrmengine/cdm/core/include/cdm_session.h index 4a96a576..9a727189 100644 --- a/libwvdrmengine/cdm/core/include/cdm_session.h +++ b/libwvdrmengine/cdm/core/include/cdm_session.h @@ -23,7 +23,8 @@ class WvCdmEventListener; class CdmSession { public: CdmSession(const CdmClientPropertySet* cdm_client_property_set, - const std::string& origin, WvCdmEventListener* event_listener); + const std::string& origin, WvCdmEventListener* event_listener, + CdmSessionId* forced_session_id); virtual ~CdmSession(); virtual CdmResponseType Init(); diff --git a/libwvdrmengine/cdm/core/include/device_files.h b/libwvdrmengine/cdm/core/include/device_files.h index 840a673a..57f29fe7 100644 --- a/libwvdrmengine/cdm/core/include/device_files.h +++ b/libwvdrmengine/cdm/core/include/device_files.h @@ -4,6 +4,7 @@ #define WVCDM_CORE_DEVICE_FILES_H_ #include +#include #include #include "scoped_ptr.h" @@ -110,7 +111,6 @@ class DeviceFiles { static std::string GetCertificateFileName(const std::string& origin); static std::string GetLicenseFileNameExtension(); static std::string GetUsageInfoFileName(const std::string& app_id); - static std::string GetBlankFileData(); static std::string GetFileNameSafeHash(const std::string& input); // For testing only: @@ -122,7 +122,7 @@ class DeviceFiles { FRIEND_TEST(DeviceCertificateTest, HasCertificate); FRIEND_TEST(DeviceFilesStoreTest, StoreLicense); FRIEND_TEST(DeviceFilesTest, DeleteLicense); - FRIEND_TEST(DeviceFilesTest, ReserveLicenseIds); + FRIEND_TEST(DeviceFilesTest, ReserveLicenseIdsDoesNotUseFileSystem); FRIEND_TEST(DeviceFilesTest, RetrieveLicenses); FRIEND_TEST(DeviceFilesTest, AppParametersBackwardCompatibility); FRIEND_TEST(DeviceFilesTest, SecurityLevelPathBackwardCompatibility); @@ -141,6 +141,8 @@ class DeviceFiles { FRIEND_TEST(WvCdmExtendedDurationTest, UsageOverflowTest); #endif + static std::set reserved_license_ids_; + scoped_ptr file_; CdmSecurityLevel security_level_; bool initialized_; diff --git a/libwvdrmengine/cdm/core/include/properties.h b/libwvdrmengine/cdm/core/include/properties.h index 8acf750c..a0890317 100644 --- a/libwvdrmengine/cdm/core/include/properties.h +++ b/libwvdrmengine/cdm/core/include/properties.h @@ -54,6 +54,7 @@ class Properties { std::string* base_path); static bool GetFactoryKeyboxPath(std::string* keybox); static bool GetOEMCryptoPath(std::string* library_name); + static bool AlwaysUseKeySetIds(); static bool GetSecurityLevelDirectories(std::vector* dirs); static bool GetApplicationId(const CdmSessionId& session_id, std::string* app_id); diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index 1bab8f63..3b7bf096 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -91,8 +91,13 @@ CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system, return INVALID_PARAMETERS_ENG_1; } + CdmSessionId* forced_session_id = NULL; + if (Properties::AlwaysUseKeySetIds() && !session_id->empty()) { + forced_session_id = session_id; + } + scoped_ptr new_session( - new CdmSession(property_set, origin, event_listener)); + new CdmSession(property_set, origin, event_listener, forced_session_id)); if (new_session->session_id().empty()) { LOGE("CdmEngine::OpenSession: failure to generate session ID"); return EMPTY_SESSION_ID; @@ -180,7 +185,10 @@ CdmResponseType CdmEngine::GenerateKeyRequest( CdmSessionId id = session_id; CdmResponseType sts; - if (license_type == kLicenseTypeRelease) { + // NOTE: If AlwaysUseKeySetIds() is true, there is no need to consult the + // release_key_sets_ map for release licenses. + if (license_type == kLicenseTypeRelease && + !Properties::AlwaysUseKeySetIds()) { if (key_set_id.empty()) { LOGE("CdmEngine::GenerateKeyRequest: invalid key set ID"); return EMPTY_KEYSET_ID_ENG_2; @@ -666,7 +674,7 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id, usage_property_set_->set_security_level(kLevelDefault); usage_property_set_->set_app_id(app_id); usage_session_.reset( - new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL)); + new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL, NULL)); CdmResponseType status = usage_session_->Init(); if (NO_ERROR != status) { LOGE("CdmEngine::GetUsageInfo: session init error"); @@ -685,7 +693,7 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id, usage_property_set_->set_security_level(kLevel3); usage_property_set_->set_app_id(app_id); usage_session_.reset( - new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL)); + new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL, NULL)); status = usage_session_->Init(); if (NO_ERROR != status) { LOGE("CdmEngine::GetUsageInfo: session init error"); @@ -754,7 +762,7 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id, usage_property_set_->set_app_id(app_id); usage_session_.reset( - new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL)); + new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL, NULL)); CdmResponseType status = usage_session_->Init(); if (NO_ERROR != status) { @@ -833,7 +841,8 @@ CdmResponseType CdmEngine::ReleaseAllUsageInfo(const std::string& app_id) { : kLevelDefault; usage_property_set_->set_security_level(security_level); usage_session_.reset( - new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL)); + new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL, + NULL)); CdmResponseType status2 = usage_session_-> DeleteMultipleUsageInformation(provider_session_tokens); if (status2 != NO_ERROR) { diff --git a/libwvdrmengine/cdm/core/src/cdm_session.cpp b/libwvdrmengine/cdm/core/src/cdm_session.cpp index a7c728ca..ddb8a662 100644 --- a/libwvdrmengine/cdm/core/src/cdm_session.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_session.cpp @@ -25,14 +25,13 @@ namespace wvcdm { CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set, const std::string& origin, - WvCdmEventListener* event_listener) + WvCdmEventListener* event_listener, + CdmSessionId* forced_session_id) : initialized_(false), session_id_(GenerateSessionId()), origin_(origin), license_parser_(new CdmLicense), crypto_session_(new CryptoSession), - policy_engine_( - new PolicyEngine(session_id_, event_listener, crypto_session_.get())), file_handle_(new DeviceFiles), license_received_(false), is_offline_(false), @@ -43,6 +42,17 @@ CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set, has_decrypted_since_last_report_(false), is_initial_usage_update_(true), is_usage_update_needed_(false) { + if (Properties::AlwaysUseKeySetIds()) { + if (forced_session_id) { + key_set_id_ = *forced_session_id; + } else { + bool ok = GenerateKeySetId(&key_set_id_); + assert(ok); + } + session_id_ = key_set_id_; + } + policy_engine_.reset(new PolicyEngine( + session_id_, event_listener, crypto_session_.get())); if (cdm_client_property_set) { if (cdm_client_property_set->security_level() == QUERY_VALUE_SECURITY_LEVEL_L3) { @@ -203,7 +213,8 @@ CdmResponseType CdmSession::GenerateKeyRequest( LOGW("CdmSession::GenerateKeyRequest: init data absent"); return INIT_DATA_NOT_FOUND; } - if (is_offline_ && !GenerateKeySetId(&key_set_id_)) { + if (is_offline_ && key_set_id_.empty() && + !GenerateKeySetId(&key_set_id_)) { LOGE("CdmSession::GenerateKeyRequest: Unable to generate key set ID"); return KEY_REQUEST_ERROR_1; } diff --git a/libwvdrmengine/cdm/core/src/device_files.cpp b/libwvdrmengine/cdm/core/src/device_files.cpp index df0bbb9c..bc8ab008 100644 --- a/libwvdrmengine/cdm/core/src/device_files.cpp +++ b/libwvdrmengine/cdm/core/src/device_files.cpp @@ -46,8 +46,6 @@ const char* kSecurityLevelPathCompatibilityExclusionList[] = { size_t kSecurityLevelPathCompatibilityExclusionListSize = sizeof(kSecurityLevelPathCompatibilityExclusionList) / sizeof(*kSecurityLevelPathCompatibilityExclusionList); -// Some platforms cannot store a truly blank file, so we use a W for Widevine. -const char kBlankFileData[] = "W"; bool Hash(const std::string& data, std::string* hash) { if (!hash) return false; @@ -64,6 +62,9 @@ bool Hash(const std::string& data, std::string* hash) { namespace wvcdm { +// static +std::set DeviceFiles::reserved_license_ids_; + DeviceFiles::DeviceFiles() : file_(NULL), security_level_(kSecurityLevelUninitialized), @@ -228,6 +229,7 @@ bool DeviceFiles::StoreLicense( std::string serialized_file; file.SerializeToString(&serialized_file); + reserved_license_ids_.erase(key_set_id); return StoreFileWithHash(key_set_id + kLicenseFileNameExt, serialized_file); } @@ -331,6 +333,8 @@ bool DeviceFiles::LicenseExists(const std::string& key_set_id) { return false; } return FileExists(key_set_id + kLicenseFileNameExt); + return reserved_license_ids_.count(key_set_id) || + FileExists(key_set_id + kLicenseFileNameExt); } bool DeviceFiles::ReserveLicenseId(const std::string& key_set_id) { @@ -338,7 +342,8 @@ bool DeviceFiles::ReserveLicenseId(const std::string& key_set_id) { LOGW("DeviceFiles::ReserveLicenseId: not initialized"); return false; } - return StoreFileRaw(key_set_id + kLicenseFileNameExt, kBlankFileData); + reserved_license_ids_.insert(key_set_id); + return true; } bool DeviceFiles::StoreUsageInfo(const std::string& provider_session_token, @@ -804,8 +809,6 @@ std::string DeviceFiles::GetUsageInfoFileName(const std::string& app_id) { return kUsageInfoFileNamePrefix + hash + kUsageInfoFileNameExt; } -std::string DeviceFiles::GetBlankFileData() { return kBlankFileData; } - std::string DeviceFiles::GetFileNameSafeHash(const std::string& input) { std::vector hash(MD5_DIGEST_LENGTH); const unsigned char* input_ptr = diff --git a/libwvdrmengine/cdm/core/src/properties.cpp b/libwvdrmengine/cdm/core/src/properties.cpp index fb0d4309..686f2e43 100644 --- a/libwvdrmengine/cdm/core/src/properties.cpp +++ b/libwvdrmengine/cdm/core/src/properties.cpp @@ -1,7 +1,7 @@ // Copyright 2013 Google Inc. All Rights Reserved. #include "log.h" -#include "properties_configuration.h" +#include "properties.h" #include "wv_cdm_constants.h" namespace { @@ -16,17 +16,6 @@ bool Properties::use_certificates_as_identification_; bool Properties::security_level_path_backward_compatibility_support_; scoped_ptr Properties::session_property_set_; -void Properties::Init() { - oem_crypto_use_secure_buffers_ = kPropertyOemCryptoUseSecureBuffers; - oem_crypto_use_fifo_ = kPropertyOemCryptoUseFifo; - oem_crypto_use_userspace_buffers_ = kPropertyOemCryptoUseUserSpaceBuffers; - use_certificates_as_identification_ = - kPropertyUseCertificatesAsIdentification; - security_level_path_backward_compatibility_support_ = - kSecurityLevelPathBackwardCompatibilitySupport; - session_property_set_.reset(new CdmClientPropertySetMap()); -} - bool Properties::AddSessionPropertySet( const CdmSessionId& session_id, const CdmClientPropertySet* property_set) { if (NULL == session_property_set_.get()) { diff --git a/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp b/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp index 1e4cd121..bcc8c953 100644 --- a/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp @@ -132,7 +132,7 @@ class MockCdmLicense : public CdmLicense { class CdmSessionTest : public ::testing::Test { protected: virtual void SetUp() { - cdm_session_.reset(new CdmSession(NULL, kTestOrigin, NULL)); + cdm_session_.reset(new CdmSession(NULL, kTestOrigin, NULL, NULL)); // Inject testing mocks. license_parser_ = new MockCdmLicense(); cdm_session_->set_license_parser(license_parser_); diff --git a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp index e2647104..ab81d77d 100644 --- a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp @@ -2118,26 +2118,15 @@ TEST_F(DeviceFilesTest, DeleteLicense) { EXPECT_FALSE(device_files.LicenseExists(license_test_data[0].key_set_id)); } -TEST_F(DeviceFilesTest, ReserveLicenseIds) { +TEST_F(DeviceFilesTest, ReserveLicenseIdsDoesNotUseFileSystem) { + // Validate that ReserveLicenseIds does not touch the file system. MockFile file; - EXPECT_CALL(file, IsDirectory(StrEq(device_base_path_))) - .Times(kNumberOfLicenses) - .WillRepeatedly(Return(true)); + EXPECT_CALL(file, IsDirectory(StrEq(device_base_path_))).Times(0); EXPECT_CALL(file, CreateDirectory(_)).Times(0); - for (size_t i = 0; i < kNumberOfLicenses; ++i) { - std::string license_path = device_base_path_ + - license_test_data[i].key_set_id + - DeviceFiles::GetLicenseFileNameExtension(); - InSequence calls; - EXPECT_CALL(file, Open(StrEq(license_path), - AllOf(IsCreateFileFlagSet(), IsBinaryFileFlagSet()))) - .WillOnce(Return(true)); - EXPECT_CALL(file, Write(StrEq(DeviceFiles::GetBlankFileData()), - DeviceFiles::GetBlankFileData().size())) - .WillOnce(ReturnArg<1>()); - EXPECT_CALL(file, Close()); - } + EXPECT_CALL(file, Open(_, _)).Times(0); + EXPECT_CALL(file, Write(_, _)).Times(0); + EXPECT_CALL(file, Close()).Times(0); EXPECT_CALL(file, Read(_, _)).Times(0); DeviceFiles device_files; @@ -2145,6 +2134,8 @@ TEST_F(DeviceFilesTest, ReserveLicenseIds) { device_files.SetTestFile(&file); for (size_t i = 0; i < kNumberOfLicenses; i++) { EXPECT_TRUE(device_files.ReserveLicenseId(license_test_data[i].key_set_id)); + // Validate that the license IDs are actually reserved. + EXPECT_TRUE(device_files.LicenseExists(license_test_data[i].key_set_id)); } } diff --git a/libwvdrmengine/cdm/src/properties_android.cpp b/libwvdrmengine/cdm/src/properties_android.cpp index 97567742..6753f39b 100644 --- a/libwvdrmengine/cdm/src/properties_android.cpp +++ b/libwvdrmengine/cdm/src/properties_android.cpp @@ -1,6 +1,7 @@ // Copyright 2013 Google Inc. All Rights Reserved. #include "properties.h" +#include "properties_configuration.h" #include #include @@ -42,6 +43,17 @@ bool GetAndroidProperty(const char* key, std::string* value) { namespace wvcdm { +void Properties::Init() { + oem_crypto_use_secure_buffers_ = kPropertyOemCryptoUseSecureBuffers; + oem_crypto_use_fifo_ = kPropertyOemCryptoUseFifo; + oem_crypto_use_userspace_buffers_ = kPropertyOemCryptoUseUserSpaceBuffers; + use_certificates_as_identification_ = + kPropertyUseCertificatesAsIdentification; + security_level_path_backward_compatibility_support_ = + kSecurityLevelPathBackwardCompatibilitySupport; + session_property_set_.reset(new CdmClientPropertySetMap()); +} + bool Properties::GetCompanyName(std::string* company_name) { if (!company_name) { LOGW("Properties::GetCompanyName: Invalid parameter"); @@ -139,4 +151,8 @@ bool Properties::GetOEMCryptoPath(std::string* library_name) { return true; } +bool Properties::AlwaysUseKeySetIds() { + return false; +} + } // namespace wvcdm