diff --git a/libwvdrmengine/cdm/core/include/crypto_session.h b/libwvdrmengine/cdm/core/include/crypto_session.h index 1db0999d..bf75cd5d 100644 --- a/libwvdrmengine/cdm/core/include/crypto_session.h +++ b/libwvdrmengine/cdm/core/include/crypto_session.h @@ -22,17 +22,9 @@ class CryptoSession { CryptoSession(); ~CryptoSession(); - typedef enum { - kSecurityLevelUninitialized, - kSecurityLevelL1, - kSecurityLevelL2, - kSecurityLevelL3, - kSecurityLevelUnknown - } SecurityLevel; - bool ValidateKeybox(); bool GetToken(std::string* token); - SecurityLevel GetSecurityLevel(); + CdmSecurityLevel GetSecurityLevel(); bool GetDeviceUniqueId(std::string* device_id); bool GetSystemId(uint32_t* system_id); bool GetProvisioningId(std::string* provisioning_id); @@ -96,6 +88,7 @@ class CryptoSession { OEMCryptoBufferType destination_buffer_type_; bool is_destination_buffer_type_valid_; + CdmSecurityLevel security_level_; CORE_DISALLOW_COPY_AND_ASSIGN(CryptoSession); }; diff --git a/libwvdrmengine/cdm/core/include/device_files.h b/libwvdrmengine/cdm/core/include/device_files.h index 0ac90043..692da784 100644 --- a/libwvdrmengine/cdm/core/include/device_files.h +++ b/libwvdrmengine/cdm/core/include/device_files.h @@ -17,10 +17,11 @@ class DeviceFiles { kLicenseStateUnknown, } LicenseState; - DeviceFiles() {} + DeviceFiles(): file_(NULL), security_level_(kSecurityLevelUninitialized), + initialized_(false) {} virtual ~DeviceFiles() {} - virtual bool Init(File* handle); + virtual bool Init(const File* handle, CdmSecurityLevel security_level); virtual bool StoreCertificate(const std::string& certificate, const std::string& wrapped_private_key); @@ -44,6 +45,7 @@ class DeviceFiles { CdmKeyResponse* key_renewal_response, std::string* release_server_url); virtual bool DeleteLicense(const std::string& key_set_id); + virtual bool DeleteAllLicenses(); virtual bool LicenseExists(const std::string& key_set_id); // For testing only @@ -57,6 +59,8 @@ class DeviceFiles { private: File* file_; + CdmSecurityLevel security_level_; + bool initialized_; CORE_DISALLOW_COPY_AND_ASSIGN(DeviceFiles); }; diff --git a/libwvdrmengine/cdm/core/include/properties.h b/libwvdrmengine/cdm/core/include/properties.h index f6ad36a5..f5b3fd26 100644 --- a/libwvdrmengine/cdm/core/include/properties.h +++ b/libwvdrmengine/cdm/core/include/properties.h @@ -46,7 +46,8 @@ class Properties { static bool GetDeviceName(std::string* device_name); static bool GetProductName(std::string* product_name); static bool GetBuildInfo(std::string* build_info); - static bool GetDeviceFilesBasePath(std::string* base_path); + static bool GetDeviceFilesBasePath(CdmSecurityLevel security_level, + std::string* base_path); static bool GetFactoryKeyboxPath(std::string* keybox); private: diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_types.h b/libwvdrmengine/cdm/core/include/wv_cdm_types.h index 0be6a9e7..ad418081 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_types.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_types.h @@ -56,6 +56,14 @@ enum CdmLicenseType { kLicenseTypeRelease }; +enum CdmSecurityLevel { + kSecurityLevelUninitialized, + kSecurityLevelL1, + kSecurityLevelL2, + kSecurityLevelL3, + kSecurityLevelUnknown +}; + struct CdmDecryptionParameters { bool is_encrypted; bool is_secure; diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index 9b61ff3c..fc7ec340 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -347,17 +347,17 @@ CdmResponseType CdmEngine::QueryStatus(CdmQueryMap* key_info) { LOGI("CdmEngine::QueryStatus"); CryptoSession crypto_session; switch (crypto_session.GetSecurityLevel()) { - case CryptoSession::kSecurityLevelL1: + case kSecurityLevelL1: (*key_info)[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L1; break; - case CryptoSession::kSecurityLevelL2: + case kSecurityLevelL2: (*key_info)[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L2; break; - case CryptoSession::kSecurityLevelL3: + case kSecurityLevelL3: (*key_info)[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L3; break; - case CryptoSession::kSecurityLevelUninitialized: - case CryptoSession::kSecurityLevelUnknown: + case kSecurityLevelUninitialized: + case kSecurityLevelUnknown: (*key_info)[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_Unknown; break; default: diff --git a/libwvdrmengine/cdm/core/src/cdm_session.cpp b/libwvdrmengine/cdm/core/src/cdm_session.cpp index 688216d7..a69e40b8 100644 --- a/libwvdrmengine/cdm/core/src/cdm_session.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_session.cpp @@ -54,7 +54,8 @@ CdmResponseType CdmSession::RestoreOfflineSession( // Retrieve license information from persistent store File file; DeviceFiles handle; - if (!handle.Init(&file)) return UNKNOWN_ERROR; + if (!handle.Init(&file, crypto_session_->GetSecurityLevel())) + return UNKNOWN_ERROR; DeviceFiles::LicenseState license_state; @@ -302,7 +303,8 @@ CdmResponseType CdmSession::ReleaseKey(const CdmKeyResponse& key_response) { license_parser_.HandleKeyUpdateResponse(false, key_response); File file; DeviceFiles handle; - if (handle.Init(&file)) handle.DeleteLicense(key_set_id_); + if (handle.Init(&file, crypto_session_->GetSecurityLevel())) + handle.DeleteLicense(key_set_id_); return sts; } @@ -331,7 +333,8 @@ bool CdmSession::GenerateKeySetId(CdmKeySetId* key_set_id) { File file; DeviceFiles handle; - if (!handle.Init(&file)) return false; + if (!handle.Init(&file, crypto_session_->GetSecurityLevel())) + return false; while (key_set_id->empty()) { if (!crypto_session_->GetRandom(&random_data[0], random_data.size())) @@ -351,7 +354,8 @@ bool CdmSession::LoadDeviceCertificate(std::string* certificate, std::string* wrapped_key) { File file; DeviceFiles handle; - if (!handle.Init(&file)) return false; + if (!handle.Init(&file, crypto_session_->GetSecurityLevel())) + return false; return handle.RetrieveCertificate(certificate, wrapped_key); } @@ -359,7 +363,8 @@ bool CdmSession::LoadDeviceCertificate(std::string* certificate, bool CdmSession::StoreLicense(DeviceFiles::LicenseState state) { File file; DeviceFiles handle; - if (!handle.Init(&file)) return false; + if (!handle.Init(&file, crypto_session_->GetSecurityLevel())) + return false; return handle.StoreLicense( key_set_id_, state, offline_pssh_data_, offline_key_request_, diff --git a/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp b/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp index fd034ad4..1bdfaa28 100644 --- a/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp +++ b/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp @@ -215,7 +215,7 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse( File file; DeviceFiles handle; - if (!handle.Init(&file)) { + if (!handle.Init(&file, crypto_session_.GetSecurityLevel())) { LOGE("HandleProvisioningResponse: failed to init DeviceFiles"); return UNKNOWN_ERROR; } @@ -223,6 +223,7 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse( LOGE("HandleProvisioningResponse: failed to save provisioning certificate"); return UNKNOWN_ERROR; } + handle.DeleteAllLicenses(); return NO_ERROR; } diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index 7896c2ad..13be31cd 100755 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -35,7 +35,9 @@ bool CryptoSession::initialized_ = false; int CryptoSession::session_count_ = 0; CryptoSession::CryptoSession() - : open_(false), is_destination_buffer_type_valid_(false) { + : open_(false), + is_destination_buffer_type_valid_(false), + security_level_(kSecurityLevelUninitialized) { Init(); } @@ -101,12 +103,22 @@ bool CryptoSession::GetToken(std::string* token) { return true; } -CryptoSession::SecurityLevel CryptoSession::GetSecurityLevel() { +CdmSecurityLevel CryptoSession::GetSecurityLevel() { LOGV("CryptoSession::GetSecurityLevel: Lock"); AutoLock auto_lock(crypto_lock_); if (!initialized_) { return kSecurityLevelUninitialized; } + + switch (security_level_) { + case kSecurityLevelL1: + case kSecurityLevelL2: + case kSecurityLevelL3: + return security_level_; + default: + break; + } + std::string security_level = OEMCrypto_SecurityLevel(); if ((security_level.size() != 2) || (security_level.at(0) != 'L')) { @@ -115,16 +127,20 @@ CryptoSession::SecurityLevel CryptoSession::GetSecurityLevel() { switch (security_level.at(1)) { case '1': - return kSecurityLevelL1; + security_level_ = kSecurityLevelL1; + break; case '2': - return kSecurityLevelL2; + security_level_ = kSecurityLevelL2; + break; case '3': - return kSecurityLevelL3; + security_level_ = kSecurityLevelL3; + break; default: - return kSecurityLevelUnknown; + security_level_ = kSecurityLevelUnknown; + break; } - return kSecurityLevelUnknown; + return security_level_; } bool CryptoSession::GetDeviceUniqueId(std::string* device_id) { @@ -552,7 +568,8 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) { switch (buffer_descriptor.type) { case OEMCrypto_BufferType_Clear: buffer_descriptor.buffer.clear.address = - static_cast(params.decrypt_buffer) + params.decrypt_buffer_offset; + static_cast(params.decrypt_buffer) + + params.decrypt_buffer_offset; buffer_descriptor.buffer.clear.max_length = params.decrypt_buffer_length; break; case OEMCrypto_BufferType_Secure: @@ -567,14 +584,9 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) { } OEMCryptoResult sts = OEMCrypto_DecryptCTR( - oec_session_id_, - params.encrypt_buffer, - params.encrypt_length, - params.is_encrypted, - &(*params.iv).front(), - params.block_offset, - &buffer_descriptor, - params.subsample_flags); + oec_session_id_, params.encrypt_buffer, params.encrypt_length, + params.is_encrypted, &(*params.iv).front(), params.block_offset, + &buffer_descriptor, params.subsample_flags); if (OEMCrypto_ERROR_INSUFFICIENT_RESOURCES == sts) { return INSUFFICIENT_CRYPTO_RESOURCES; @@ -598,7 +610,7 @@ bool CryptoSession::GenerateNonce(uint32_t* nonce) { bool CryptoSession::SetDestinationBufferType() { if (Properties::oem_crypto_use_secure_buffers()) { - if (GetSecurityLevel() == CryptoSession::kSecurityLevelL1) { + if (GetSecurityLevel() == kSecurityLevelL1) { destination_buffer_type_ = OEMCrypto_BufferType_Secure; } else { destination_buffer_type_ = OEMCrypto_BufferType_Clear; diff --git a/libwvdrmengine/cdm/core/src/device_files.cpp b/libwvdrmengine/cdm/core/src/device_files.cpp index e76ec528..f861c602 100644 --- a/libwvdrmengine/cdm/core/src/device_files.cpp +++ b/libwvdrmengine/cdm/core/src/device_files.cpp @@ -21,22 +21,38 @@ using video_widevine_client::sdk::License_LicenseState_RELEASING; namespace { const char kCertificateFileName[] = "cert.bin"; const char kLicenseFileNameExt[] = ".lic"; -} // namespace +const char kWildcard[] = "*"; +} // namespace namespace wvcdm { - -bool DeviceFiles::Init(File* handle) { - file_ = handle; +bool DeviceFiles::Init(const File* handle, CdmSecurityLevel security_level) { if (handle == NULL) { LOGW("DeviceFiles::Init: Invalid file handle parameter"); return false; } + switch (security_level) { + case kSecurityLevelL1: + case kSecurityLevelL2: + case kSecurityLevelL3: + break; + default: + LOGW("DeviceFiles::Init: Unsupported security level %d", security_level); + return false; + } + file_ = const_cast(handle); + security_level_ = security_level; + initialized_ = true; return true; } bool DeviceFiles::StoreCertificate(const std::string& certificate, const std::string& wrapped_private_key) { + if (!initialized_) { + LOGW("DeviceFiles::StoreCertificate: not initialized"); + return false; + } + // Fill in file information video_widevine_client::sdk::File file; @@ -69,6 +85,11 @@ bool DeviceFiles::StoreCertificate(const std::string& certificate, bool DeviceFiles::RetrieveCertificate(std::string* certificate, std::string* wrapped_private_key) { + if (!initialized_) { + LOGW("DeviceFiles::RetrieveCertificate: not initialized"); + return false; + } + std::string serialized_hashed_file; if (!RetrieveFile(kCertificateFileName, &serialized_hashed_file)) return false; @@ -118,15 +139,19 @@ bool DeviceFiles::RetrieveCertificate(std::string* certificate, return true; } -bool DeviceFiles::StoreLicense( - const std::string& key_set_id, - const LicenseState state, - const CdmInitData& pssh_data, - const CdmKeyMessage& license_request, - const CdmKeyResponse& license_message, - const CdmKeyMessage& license_renewal_request, - const CdmKeyResponse& license_renewal, - const std::string& release_server_url) { +bool DeviceFiles::StoreLicense(const std::string& key_set_id, + const LicenseState state, + const CdmInitData& pssh_data, + const CdmKeyMessage& license_request, + const CdmKeyResponse& license_message, + const CdmKeyMessage& license_renewal_request, + const CdmKeyResponse& license_renewal, + const std::string& release_server_url) { + if (!initialized_) { + LOGW("DeviceFiles::StoreLicense: not initialized"); + return false; + } + // Fill in file information video_widevine_client::sdk::File file; @@ -134,7 +159,7 @@ bool DeviceFiles::StoreLicense( file.set_version(video_widevine_client::sdk::File::VERSION_1); License* license = file.mutable_license(); - switch(state) { + switch (state) { case kLicenseStateActive: license->set_state(License_LicenseState_ACTIVE); break; @@ -174,19 +199,21 @@ bool DeviceFiles::StoreLicense( return StoreFile(file_name.c_str(), serialized_string); } -bool DeviceFiles::RetrieveLicense( - const std::string& key_set_id, - LicenseState* state, - CdmInitData* pssh_data, - CdmKeyMessage* license_request, - CdmKeyResponse* license_message, - CdmKeyMessage* license_renewal_request, - CdmKeyResponse* license_renewal, - std::string* release_server_url) { +bool DeviceFiles::RetrieveLicense(const std::string& key_set_id, + LicenseState* state, CdmInitData* pssh_data, + CdmKeyMessage* license_request, + CdmKeyResponse* license_message, + CdmKeyMessage* license_renewal_request, + CdmKeyResponse* license_renewal, + std::string* release_server_url) { + if (!initialized_) { + LOGW("DeviceFiles::RetrieveLicense: not initialized"); + return false; + } + std::string serialized_hashed_file; std::string file_name = key_set_id + kLicenseFileNameExt; - if (!RetrieveFile(file_name.c_str(), &serialized_hashed_file)) - return false; + if (!RetrieveFile(file_name.c_str(), &serialized_hashed_file)) return false; HashedFile hashed_file; if (!hashed_file.ParseFromString(serialized_hashed_file)) { @@ -228,7 +255,7 @@ bool DeviceFiles::RetrieveLicense( License license = file.license(); - switch(license.state()) { + switch (license.state()) { case License_LicenseState_ACTIVE: *state = kLicenseStateActive; break; @@ -237,7 +264,7 @@ bool DeviceFiles::RetrieveLicense( break; default: LOGW("DeviceFiles::RetrieveLicense: Unrecognized license state: %u", - kLicenseStateUnknown); + kLicenseStateUnknown); *state = kLicenseStateUnknown; break; } @@ -251,13 +278,13 @@ bool DeviceFiles::RetrieveLicense( } bool DeviceFiles::DeleteLicense(const std::string& key_set_id) { - if (!file_) { - LOGW("DeviceFiles::DeleteLicense: Invalid file handle"); + if (!initialized_) { + LOGW("DeviceFiles::DeleteLicense: not initialized"); return false; } std::string path; - if (!Properties::GetDeviceFilesBasePath(&path)) { + if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) { LOGW("DeviceFiles::StoreFile: Unable to get base path"); return false; } @@ -267,14 +294,31 @@ bool DeviceFiles::DeleteLicense(const std::string& key_set_id) { return file_->Remove(path); } -bool DeviceFiles::LicenseExists(const std::string& key_set_id) { - if (!file_) { - LOGW("DeviceFiles::LicenseExists: Invalid file handle"); +bool DeviceFiles::DeleteAllLicenses() { + if (!initialized_) { + LOGW("DeviceFiles::DeleteLicense: not initialized"); return false; } std::string path; - if (!Properties::GetDeviceFilesBasePath(&path)) { + if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) { + LOGW("DeviceFiles::StoreFile: Unable to get base path"); + return false; + } + path.append(kWildcard); + path.append(kLicenseFileNameExt); + + return file_->Remove(path); +} + +bool DeviceFiles::LicenseExists(const std::string& key_set_id) { + if (!initialized_) { + LOGW("DeviceFiles::LicenseExists: not initialized"); + return false; + } + + std::string path; + if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) { LOGW("DeviceFiles::StoreFile: Unable to get base path"); return false; } @@ -307,7 +351,7 @@ bool DeviceFiles::StoreFile(const char* name, const std::string& data) { } std::string path; - if (!Properties::GetDeviceFilesBasePath(&path)) { + if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) { LOGW("DeviceFiles::StoreFile: Unable to get base path"); return false; } @@ -352,7 +396,7 @@ bool DeviceFiles::RetrieveFile(const char* name, std::string* data) { } std::string path; - if (!Properties::GetDeviceFilesBasePath(&path)) { + if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) { LOGW("DeviceFiles::StoreFile: Unable to get base path"); return false; } @@ -385,7 +429,7 @@ bool DeviceFiles::RetrieveFile(const char* name, std::string* data) { } LOGV("DeviceFiles::RetrieveFile: success: %s (%db)", path.c_str(), - data->size()); + data->size()); return true; } diff --git a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp index 096ea3e1..087d09c7 100644 --- a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp @@ -6,6 +6,7 @@ #include "gtest/gtest.h" #include "properties.h" #include "string_conversions.h" +#include "wv_cdm_types.h" namespace wvcdm { @@ -995,7 +996,8 @@ class MockFile : public File { class DeviceFilesTest : public ::testing::Test { protected: virtual void SetUp() { - ASSERT_TRUE(Properties::GetDeviceFilesBasePath(&device_base_path_)); + ASSERT_TRUE(Properties::GetDeviceFilesBasePath(kSecurityLevelL1, + &device_base_path_)); } std::string GenerateRandomData(uint32_t len) { @@ -1073,7 +1075,7 @@ TEST_P(DeviceFilesStoreTest, StoreCertificate) { EXPECT_CALL(file, Read(_, _)).Times(0); DeviceFiles device_files; - EXPECT_TRUE(device_files.Init(&file)); + EXPECT_TRUE(device_files.Init(&file, kSecurityLevelL1)); EXPECT_TRUE(device_files.StoreCertificate(certificate, wrapped_private_key)); } @@ -1098,7 +1100,7 @@ TEST_F(DeviceFilesTest, ReadCertificate) { EXPECT_CALL(file, Write(_, _)).Times(0); DeviceFiles device_files; - EXPECT_TRUE(device_files.Init(&file)); + EXPECT_TRUE(device_files.Init(&file, kSecurityLevelL1)); std::string certificate, wrapped_private_key; ASSERT_TRUE( @@ -1140,7 +1142,7 @@ TEST_P(DeviceFilesStoreTest, StoreLicense) { EXPECT_CALL(file, Read(_, _)).Times(0); DeviceFiles device_files; - EXPECT_TRUE(device_files.Init(&file)); + EXPECT_TRUE(device_files.Init(&file, kSecurityLevelL1)); EXPECT_TRUE(device_files.StoreLicense( license_test_data[license_num].key_set_id, license_test_data[license_num].license_state, @@ -1183,7 +1185,7 @@ TEST_F(DeviceFilesTest, StoreLicenses) { EXPECT_CALL(file, Read(_, _)).Times(0); DeviceFiles device_files; - EXPECT_TRUE(device_files.Init(&file)); + EXPECT_TRUE(device_files.Init(&file, kSecurityLevelL1)); for (size_t i = 0; i < kNumberOfLicenses; i++) { EXPECT_TRUE(device_files.StoreLicense( license_test_data[i].key_set_id, license_test_data[i].license_state, @@ -1218,7 +1220,7 @@ TEST_F(DeviceFilesTest, RetrieveLicenses) { EXPECT_CALL(file, Write(_, _)).Times(0); DeviceFiles device_files; - EXPECT_TRUE(device_files.Init(&file)); + EXPECT_TRUE(device_files.Init(&file, kSecurityLevelL1)); DeviceFiles::LicenseState license_state; CdmInitData pssh_data; CdmKeyMessage key_request; @@ -1264,7 +1266,7 @@ TEST_F(DeviceFilesTest, UpdateLicenseState) { EXPECT_CALL(file, Read(_, _)).Times(0); DeviceFiles device_files; - EXPECT_TRUE(device_files.Init(&file)); + EXPECT_TRUE(device_files.Init(&file, kSecurityLevelL1)); EXPECT_TRUE(device_files.StoreLicense( license_update_test_data[0].key_set_id, license_update_test_data[0].license_state, @@ -1308,7 +1310,7 @@ TEST_F(DeviceFilesTest, DeleteLicense) { EXPECT_CALL(file, Write(_, _)).Times(0); DeviceFiles device_files; - EXPECT_TRUE(device_files.Init(&file)); + EXPECT_TRUE(device_files.Init(&file, kSecurityLevelL1)); DeviceFiles::LicenseState license_state; CdmInitData pssh_data; CdmKeyMessage key_request; diff --git a/libwvdrmengine/cdm/core/test/file_store_unittest.cpp b/libwvdrmengine/cdm/core/test/file_store_unittest.cpp index c3b8d859..8faac410 100644 --- a/libwvdrmengine/cdm/core/test/file_store_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/file_store_unittest.cpp @@ -8,6 +8,9 @@ namespace { const std::string kTestFileName = "test.txt"; +const std::string kTestFileName2 = "test2.txt"; +const std::string kTestFileNameExt = ".txt"; +const std::string kWildcard = "*"; } // namespace namespace wvcdm { @@ -97,6 +100,24 @@ TEST_F(FileTest, RemoveDirAndFile) { EXPECT_FALSE(file.Exists(path)); } +TEST_F(FileTest, RemoveWildcardFiles) { + std::string path1 = test_vectors::kTestDir + kTestFileName; + std::string path2 = test_vectors::kTestDir + kTestFileName2; + std::string wildcard_path = + test_vectors::kTestDir + kWildcard + kTestFileNameExt; + + File file; + EXPECT_TRUE(file.Open(path1, File::kCreate)); + file.Close(); + EXPECT_TRUE(file.Open(path2, File::kCreate)); + file.Close(); + EXPECT_TRUE(file.Exists(path1)); + EXPECT_TRUE(file.Exists(path2)); + EXPECT_TRUE(file.Remove(wildcard_path)); + EXPECT_FALSE(file.Exists(path1)); + EXPECT_FALSE(file.Exists(path2)); +} + TEST_F(FileTest, IsDir) { std::string path = test_vectors::kTestDir + kTestFileName; File file; diff --git a/libwvdrmengine/cdm/src/file_store.cpp b/libwvdrmengine/cdm/src/file_store.cpp index e8eec4fc..bd7fd357 100644 --- a/libwvdrmengine/cdm/src/file_store.cpp +++ b/libwvdrmengine/cdm/src/file_store.cpp @@ -14,9 +14,11 @@ #include "log.h" namespace { -const char* kCurrentDirectory = "."; -const char* kParentDirectory = ".."; -} // namespace +const char kCurrentDirectory[] = "."; +const char kParentDirectory[] = ".."; +const char kPathDelimiter[] = "/"; +const char kWildcard[] = "*"; +} // namespace namespace wvcdm { @@ -49,9 +51,9 @@ bool File::Open(const std::string& name, int flags) { } if (flags & File::kBinary) { - open_flags = (flags & File::kReadOnly)? "rb" : "rb+"; + open_flags = (flags & File::kReadOnly) ? "rb" : "rb+"; } else { - open_flags = (flags & File::kReadOnly)? "r" : "r+"; + open_flags = (flags & File::kReadOnly) ? "r" : "r+"; } impl_->file_ = fopen(name.c_str(), open_flags.c_str()); @@ -104,14 +106,15 @@ bool File::Exists(const std::string& path) { bool File::Remove(const std::string& path) { if (IsDirectory(path)) { + // Handle directory deletion DIR* dir; if ((dir = opendir(path.c_str())) != NULL) { // first remove files and dir within it struct dirent* entry; while ((entry = readdir(dir)) != NULL) { if (strcmp(entry->d_name, kCurrentDirectory) && - (strcmp(entry->d_name, kParentDirectory))) { - std::string path_to_remove = path + '/'; + (strcmp(entry->d_name, kParentDirectory))) { + std::string path_to_remove = path + kPathDelimiter; path_to_remove += entry->d_name; if (!Remove(path_to_remove)) { closedir(dir); @@ -127,9 +130,46 @@ bool File::Remove(const std::string& path) { } return true; } else { - if (unlink(path.c_str()) && (errno != ENOENT)) { - LOGW("File::Remove: unlink failed: %d", errno); - return false; + size_t wildcard_pos = path.find(kWildcard); + if (wildcard_pos == std::string::npos) { + // Handle file deletion + if (unlink(path.c_str()) && (errno != ENOENT)) { + LOGW("File::Remove: unlink failed: %d", errno); + return false; + } + } else { + // Handle wildcard specified file deletion + size_t delimiter_pos = path.rfind(kPathDelimiter, wildcard_pos); + if (delimiter_pos == std::string::npos) { + LOGW("File::Remove: unable to find path delimiter before wildcard"); + return false; + } + + DIR* dir; + std::string dir_path = path.substr(0, delimiter_pos); + if ((dir = opendir(dir_path.c_str())) == NULL) { + LOGW("File::Remove: directory open failed for wildcard"); + return false; + } + + struct dirent* entry; + std::string ext = path.substr(wildcard_pos + 1); + + while ((entry = readdir(dir)) != NULL) { + size_t filename_len = strlen(entry->d_name); + if (filename_len > ext.size()) { + if (strcmp(entry->d_name + filename_len - ext.size(), ext.c_str()) == + 0) { + std::string file_path_to_remove = + dir_path + kPathDelimiter + entry->d_name; + if (!Remove(file_path_to_remove)) { + closedir(dir); + return false; + } + } + } + } + closedir(dir); } return true; } @@ -137,13 +177,11 @@ bool File::Remove(const std::string& path) { bool File::CreateDirectory(std::string path) { size_t size = path.size(); - if ((size == 1) && (path[0] == '/')) - return true; + if ((size == 1) && (path[0] == '/')) return true; - if (size <= 1) - return false; + if (size <= 1) return false; - if (path.at(size-1) == '/') { + if (path.at(size - 1) == '/') { --size; path.resize(size); } @@ -158,7 +196,7 @@ bool File::CreateDirectory(std::string path) { } } path.at(pos) = '/'; - pos = path.find('/', pos+1); + pos = path.find('/', pos + 1); } if (mkdir(path.c_str(), 0775) != 0) { if (errno != EEXIST) { diff --git a/libwvdrmengine/cdm/src/properties_android.cpp b/libwvdrmengine/cdm/src/properties_android.cpp index f35fc8e8..40a34e77 100644 --- a/libwvdrmengine/cdm/src/properties_android.cpp +++ b/libwvdrmengine/cdm/src/properties_android.cpp @@ -11,6 +11,12 @@ namespace { +const char kBasePathPrefix[] = "/data/mediadrm/IDM"; +const char kL1Dir[] = "/L1"; +const char kL2Dir[] = "/L2"; +const char kL3Dir[] = "/L3"; +const char kFactoryKeyboxPath[] = "/factory/wv.keys"; + bool GetAndroidProperty(const char* key, std::string* value) { char val[PROPERTY_VALUE_MAX]; if (!key) { @@ -81,13 +87,24 @@ bool Properties::GetBuildInfo(std::string* build_info) { return GetAndroidProperty("ro.build.fingerprint", build_info); } -bool Properties::GetDeviceFilesBasePath(std::string* base_path) { +bool Properties::GetDeviceFilesBasePath(CdmSecurityLevel security_level, + std::string* base_path) { if (!base_path) { LOGW("Properties::GetDeviceFilesBasePath: Invalid parameter"); return false; } std::stringstream ss; - ss << "/data/mediadrm/IDM" << getuid() << "/"; + ss << kBasePathPrefix << getuid(); + switch (security_level) { + case kSecurityLevelL1: ss << kL1Dir; break; + case kSecurityLevelL2: ss << kL2Dir; break; + case kSecurityLevelL3: ss << kL3Dir; break; + default: + LOGW("Properties::GetDeviceFilesBasePath: Unknown security level: %d", + security_level); + return false; + } + *base_path = ss.str(); return true; } @@ -97,7 +114,7 @@ bool Properties::GetFactoryKeyboxPath(std::string* keybox) { LOGW("Properties::GetFactoryKeyboxPath: Invalid parameter"); return false; } - *keybox = "/factory/wv.keys"; + *keybox = kFactoryKeyboxPath; return true; }