diff --git a/libwvdrmengine/cdm/core/include/cdm_engine.h b/libwvdrmengine/cdm/core/include/cdm_engine.h index 375982c2..633e0616 100644 --- a/libwvdrmengine/cdm/core/include/cdm_engine.h +++ b/libwvdrmengine/cdm/core/include/cdm_engine.h @@ -4,6 +4,7 @@ #define WVCDM_CORE_CDM_ENGINE_H_ #include +#include #include "certificate_provisioning.h" #include "clock.h" @@ -128,19 +129,29 @@ class CdmEngine { virtual CdmResponseType QueryOemCryptoSessionId( const CdmSessionId& session_id, CdmQueryMap* query_response); - // Provisioning related methods + // Generate and return a valid provisioning request. virtual CdmResponseType GetProvisioningRequest( CdmCertificateType cert_type, const std::string& cert_authority, CdmProvisioningRequest* request, std::string* default_url); + // Verify and process a provisioning response. virtual CdmResponseType HandleProvisioningResponse( const CdmProvisioningResponse& response, std::string* cert, std::string* wrapped_key); + // Return true if there is a device certificate on the current + // (origin-specific) file system. virtual bool IsProvisioned(CdmSecurityLevel security_level); + // Remove DRM certificate from the current (origin-specific) + // file system. This will force the device to reprovision itself. virtual CdmResponseType Unprovision(CdmSecurityLevel security_level); + // Return the list of key_set_ids stored on the current (origin-specific) + // file system. + virtual CdmResponseType ListStoredLicenses( + CdmSecurityLevel security_level, std::vector* key_set_ids); + // Usage related methods for streaming licenses // Retrieve a random usage info from the list of all usage infos for this app // id. diff --git a/libwvdrmengine/cdm/core/include/cdm_session.h b/libwvdrmengine/cdm/core/include/cdm_session.h index ec6ad0ef..d5fcb6d3 100644 --- a/libwvdrmengine/cdm/core/include/cdm_session.h +++ b/libwvdrmengine/cdm/core/include/cdm_session.h @@ -5,6 +5,7 @@ #include #include +#include #include "crypto_session.h" #include "device_files.h" @@ -119,6 +120,7 @@ class CdmSession { // release the underlying crypto session) rather than call this method. virtual CdmResponseType ReleaseCrypto(); + // Delete current license and matching usage record bool DeleteLicense(); // Generate unique ID for each new session. diff --git a/libwvdrmengine/cdm/core/include/device_files.h b/libwvdrmengine/cdm/core/include/device_files.h index 1b97754d..2ce212d8 100644 --- a/libwvdrmengine/cdm/core/include/device_files.h +++ b/libwvdrmengine/cdm/core/include/device_files.h @@ -7,6 +7,7 @@ #include #include +#include #include "device_files.pb.h" #include "scoped_ptr.h" @@ -78,6 +79,7 @@ class DeviceFiles { int64_t* grace_period_end_time, CdmAppParameterMap* app_parameters, std::string* usage_entry); virtual bool DeleteLicense(const std::string& key_set_id); + virtual bool ListLicenses(std::vector* key_set_ids); virtual bool DeleteAllFiles(); virtual bool DeleteAllLicenses(); virtual bool LicenseExists(const std::string& key_set_id); @@ -143,6 +145,7 @@ class DeviceFiles { bool RetrieveHashedFile(const std::string& name, video_widevine_client::sdk::File* file); bool FileExists(const std::string& name); + bool ListFiles(std::vector* names); bool RemoveFile(const std::string& name); ssize_t GetFileSize(const std::string& name); diff --git a/libwvdrmengine/cdm/core/include/file_store.h b/libwvdrmengine/cdm/core/include/file_store.h index 5b207ce3..fd27e788 100644 --- a/libwvdrmengine/cdm/core/include/file_store.h +++ b/libwvdrmengine/cdm/core/include/file_store.h @@ -55,6 +55,11 @@ class FileSystem { virtual bool Remove(const std::string& file_path); virtual ssize_t FileSize(const std::string& file_path); + // Return the filenames stored at dir_path. + // dir_path will be stripped from the returned names. + virtual bool List(const std::string& dir_path, + std::vector* names); + const std::string& origin() const { return origin_; } void SetOrigin(const std::string& origin); diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_types.h b/libwvdrmengine/cdm/core/include/wv_cdm_types.h index 31d29e75..115d24c8 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_types.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_types.h @@ -271,6 +271,9 @@ enum CdmResponseType { SHRINK_USAGE_TABLER_HEADER_UNKNOWN_ERROR, MOVE_USAGE_ENTRY_UNKNOWN_ERROR, COPY_OLD_USAGE_ENTRY_UNKNOWN_ERROR, + INVALID_PARAMETERS_ENG_22, + STORE_LICENSE_ERROR_4, /* 235 */ + LIST_LICENSES_ERROR, }; enum CdmKeyStatus { diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index ea5d81e3..f81d4c69 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -1011,6 +1011,23 @@ CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) { } } +CdmResponseType CdmEngine::ListStoredLicenses( + CdmSecurityLevel security_level, std::vector* key_set_ids) { + DeviceFiles handle(file_system_); + if (!key_set_ids) { + LOGE("CdmEngine::QueryStoredLicenses: no response destination"); + return INVALID_PARAMETERS_ENG_22; + } + if (!handle.Init(security_level)) { + LOGE("CdmEngine::ListStoredLicenses: unable to initialize device files"); + return STORE_LICENSE_ERROR_4; + } + if (!handle.ListLicenses(key_set_ids)) { + return LIST_LICENSES_ERROR; + } + return NO_ERROR; +} + CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id, const CdmSecureStopId& ssid, CdmUsageInfo* usage_info) { diff --git a/libwvdrmengine/cdm/core/src/device_files.cpp b/libwvdrmengine/cdm/core/src/device_files.cpp index 291c9143..30d8c303 100644 --- a/libwvdrmengine/cdm/core/src/device_files.cpp +++ b/libwvdrmengine/cdm/core/src/device_files.cpp @@ -299,6 +299,39 @@ bool DeviceFiles::DeleteLicense(const std::string& key_set_id) { return RemoveFile(key_set_id + kLicenseFileNameExt); } +bool DeviceFiles::ListLicenses(std::vector* key_set_ids) { + if (!initialized_) { + LOGW("DeviceFiles::ListLicenses: not initialized"); + return false; + } + + if (key_set_ids == NULL) { + LOGW("DeviceFiles::ListLicenses: key_set_ids parameter not provided"); + return false; + } + + // Get list of filenames + std::vector filenames; + if (!ListFiles(&filenames)) { + return false; + } + + // Scan list of returned filenames, remove extension, and return + // as a list of key_set_ids. + key_set_ids->clear(); + for (int i = 0; i < filenames.size(); i++) { + std::string* name = &filenames[i]; + std::size_t pos = name->find(kLicenseFileNameExt); + if (pos == std::string::npos) { + // Skip this file - extension does not match + continue; + } + // Store filename (minus extension). This should be a key set ID. + key_set_ids->push_back(name->substr(0, pos)); + } + return true; +} + bool DeviceFiles::DeleteAllLicenses() { if (!initialized_) { LOGW("DeviceFiles::DeleteAllLicenses: not initialized"); @@ -821,7 +854,7 @@ bool DeviceFiles::RetrieveHashedFile( std::string path; if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) { - LOGW("DeviceFiles::StoreFileWithHash: Unable to get base path"); + LOGW("DeviceFiles::RetrieveHashedFile: Unable to get base path"); return false; } @@ -898,6 +931,15 @@ bool DeviceFiles::FileExists(const std::string& name) { return file_system_->Exists(path); } +bool DeviceFiles::ListFiles(std::vector* names) { + std::string path; + if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) { + LOGW("DeviceFiles::RemoveFile: Unable to get base path"); + return false; + } + return file_system_->List(path, names); +} + bool DeviceFiles::RemoveFile(const std::string& name) { std::string path; if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) { diff --git a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp index c198ebb3..0f751d0a 100644 --- a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp @@ -1570,6 +1570,7 @@ class MockFileSystem : public FileSystem { MOCK_METHOD1(Exists, bool(const std::string&)); MOCK_METHOD1(Remove, bool(const std::string&)); MOCK_METHOD1(FileSize, ssize_t(const std::string&)); + MOCK_METHOD2(List, bool(const std::string&, std::vector*)); }; } // namespace diff --git a/libwvdrmengine/cdm/core/test/file_store_unittest.cpp b/libwvdrmengine/cdm/core/test/file_store_unittest.cpp index 48bfcd17..fe5d9694 100644 --- a/libwvdrmengine/cdm/core/test/file_store_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/file_store_unittest.cpp @@ -1,5 +1,6 @@ // Copyright 2013 Google Inc. All Rights Reserved. +#include #include #include "file_store.h" @@ -11,7 +12,9 @@ namespace { const std::string kTestDirName = "test_dir"; const std::string kTestFileName = "test.txt"; const std::string kTestFileName2 = "test2.txt"; +const std::string kTestFileName3 = "test3.other"; const std::string kTestFileNameExt = ".txt"; +const std::string kTestFileNameExt3 = ".other"; const std::string kWildcard = "*"; } // namespace @@ -135,4 +138,56 @@ TEST_F(FileTest, WriteReadBinaryFile) { EXPECT_EQ(write_data, read_data); } +TEST_F(FileTest, ListFiles) { + std::vector names; + + std::string not_path("zzz"); + std::string path1 = test_vectors::kTestDir + kTestFileName; + std::string path2 = test_vectors::kTestDir + kTestFileName2; + std::string path3 = test_vectors::kTestDir + kTestFileName3; + std::string path_dir = test_vectors::kTestDir; + + File* file = file_system.Open(path1, FileSystem::kCreate); + ASSERT_TRUE(file); + file->Close(); + file = file_system.Open(path2, FileSystem::kCreate); + ASSERT_TRUE(file); + file->Close(); + file = file_system.Open(path3, FileSystem::kCreate); + ASSERT_TRUE(file); + file->Close(); + + EXPECT_TRUE(file_system.Exists(path1)); + EXPECT_TRUE(file_system.Exists(path2)); + EXPECT_TRUE(file_system.Exists(path3)); + + // Ask for non-existent path. + EXPECT_FALSE(file_system.List(not_path, &names)); + + // Valid path, but no way to return names. + EXPECT_FALSE(file_system.List(path_dir, NULL)); + + // Valid path, valid return. + EXPECT_TRUE(file_system.List(path_dir, &names)); + + // Should find three files. Order not important. + EXPECT_EQ(3, names.size()); + EXPECT_THAT(names, ::testing::UnorderedElementsAre(kTestFileName, + kTestFileName2, + kTestFileName3)); + + std::string wild_card_path = path_dir + kWildcard + kTestFileNameExt; + EXPECT_TRUE(file_system.Remove(wild_card_path)); + EXPECT_TRUE(file_system.List(path_dir, &names)); + + EXPECT_EQ(1, names.size()); + EXPECT_TRUE(names[0].compare(kTestFileName3) == 0); + + std::string wild_card_path2 = path_dir + kWildcard + kTestFileNameExt3; + EXPECT_TRUE(file_system.Remove(wild_card_path2)); + EXPECT_TRUE(file_system.List(path_dir, &names)); + + EXPECT_EQ(0, names.size()); +} + } // namespace wvcdm diff --git a/libwvdrmengine/cdm/core/test/test_printers.cpp b/libwvdrmengine/cdm/core/test/test_printers.cpp index 61d8b3f9..a77930eb 100644 --- a/libwvdrmengine/cdm/core/test/test_printers.cpp +++ b/libwvdrmengine/cdm/core/test/test_printers.cpp @@ -304,6 +304,8 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) { break; case STORE_LICENSE_ERROR_2: *os << "STORE_LICENSE_ERROR_2"; break; + case STORE_LICENSE_ERROR_4: *os << "STORE_LICENSE_ERROR_4"; + break; case STORE_USAGE_INFO_ERROR: *os << "STORE_USAGE_INFO_ERROR"; break; case UNPROVISION_ERROR_1: *os << "UNPROVISION_ERROR_1"; @@ -448,6 +450,8 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) { break; case INVALID_PARAMETERS_ENG_16: *os << "INVALID_PARAMETERS_ENG_16"; break; + case INVALID_PARAMETERS_ENG_17: *os << "INVALID_PARAMETERS_ENG_17"; + break; case CERT_PROVISIONING_CLIENT_TOKEN_ERROR_1: *os << "CERT_PROVISIONING_CLIENT_TOKEN_ERROR_1"; break; @@ -476,8 +480,6 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) { case LOAD_USAGE_HEADER_UNKNOWN_ERROR: *os << "LOAD_USAGE_HEADER_UNKNOWN_ERROR"; break; - case INVALID_PARAMETERS_ENG_17: *os << "INVALID_PARAMETERS_ENG_17"; - break; case INVALID_PARAMETERS_ENG_18: *os << "INVALID_PARAMETERS_ENG_18"; break; case INSUFFICIENT_CRYPTO_RESOURCES_3: @@ -504,6 +506,8 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) { break; case INVALID_PARAMETERS_ENG_21: *os << "INVALID_PARAMETERS_ENG_21"; break; + case INVALID_PARAMETERS_ENG_22: *os << "INVALID_PARAMETERS_ENG_22"; + break; case SHRINK_USAGE_TABLER_HEADER_UNKNOWN_ERROR: *os << "SHRINK_USAGE_TABLER_HEADER_UNKNOWN_ERROR"; break; @@ -513,6 +517,8 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) { case COPY_OLD_USAGE_ENTRY_UNKNOWN_ERROR: *os << "COPY_OLD_USAGE_ENTRY_UNKNOWN_ERROR"; break; + case LIST_LICENSES_ERROR: *os << "LIST_LICENSES_ERROR"; + break; default: *os << "Unknown CdmResponseType"; diff --git a/libwvdrmengine/cdm/src/file_store.cpp b/libwvdrmengine/cdm/src/file_store.cpp index 9a278473..844d808f 100644 --- a/libwvdrmengine/cdm/src/file_store.cpp +++ b/libwvdrmengine/cdm/src/file_store.cpp @@ -171,6 +171,11 @@ ssize_t FileSystem::FileSize(const std::string& in_path) { return -1; } +bool FileSystem::List(const std::string& path, + std::vector* filenames) { + return FileUtils::List(GetFileNameForIdentifier(path, origin_), filenames); +} + void FileSystem::SetOrigin(const std::string& origin) { origin_ = origin; } void FileSystem::SetIdentifier(const std::string& identifier) { diff --git a/libwvdrmengine/include/WVErrors.h b/libwvdrmengine/include/WVErrors.h index 53e6b16d..bbe74d80 100644 --- a/libwvdrmengine/include/WVErrors.h +++ b/libwvdrmengine/include/WVErrors.h @@ -238,10 +238,13 @@ enum { kShrinkUsageTablerHeaderUnknownError = ERROR_DRM_VENDOR_MIN + 224, kMoveUsageEntryUnknownError = ERROR_DRM_VENDOR_MIN + 225, kCopyOldUsageEntryUnknownError = ERROR_DRM_VENDOR_MIN + 226, + kInvalidParametersEng22 = ERROR_DRM_VENDOR_MIN + 227, + kStoreLicenseError4 = ERROR_DRM_VENDOR_MIN + 228, + kListLicensesError = ERROR_DRM_VENDOR_MIN + 229, // This should always follow the last error code. // The offset value should be updated each time a new error code is added. - kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 226, + kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 229, // Used by crypto test mode kErrorTestMode = ERROR_DRM_VENDOR_MAX, diff --git a/libwvdrmengine/include/mapErrors-inl.h b/libwvdrmengine/include/mapErrors-inl.h index 674f23f6..344645c5 100644 --- a/libwvdrmengine/include/mapErrors-inl.h +++ b/libwvdrmengine/include/mapErrors-inl.h @@ -419,6 +419,8 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { return kInvalidParametersEng15; case wvcdm::INVALID_PARAMETERS_ENG_16: return kInvalidParametersEng16; + case wvcdm::INVALID_PARAMETERS_ENG_17: + return kInvalidParametersEng17; case wvcdm::CERT_PROVISIONING_CLIENT_TOKEN_ERROR_1: return kCertProvisioningClientTokenError1; case wvcdm::CERT_PROVISIONING_CLIENT_TOKEN_ERROR_2: @@ -439,8 +441,6 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { return kLoadUsageHeaderBadMagic; case wvcdm::LOAD_USAGE_HEADER_UNKNOWN_ERROR: return kLoadUsageHeaderUnknownError; - case wvcdm::INVALID_PARAMETERS_ENG_17: - return kInvalidParametersEng17; case wvcdm::INVALID_PARAMETERS_ENG_18: return kInvalidParametersEng18; case wvcdm::INSUFFICIENT_CRYPTO_RESOURCES_3: @@ -461,12 +461,18 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { return kUpdateUsageEntryUnknownError; case wvcdm::INVALID_PARAMETERS_ENG_21: return kInvalidParametersEng21; + case wvcdm::INVALID_PARAMETERS_ENG_22: + return kInvalidParametersEng22; case wvcdm::SHRINK_USAGE_TABLER_HEADER_UNKNOWN_ERROR: return kShrinkUsageTablerHeaderUnknownError; case wvcdm::MOVE_USAGE_ENTRY_UNKNOWN_ERROR: return kMoveUsageEntryUnknownError; case wvcdm::COPY_OLD_USAGE_ENTRY_UNKNOWN_ERROR: return kCopyOldUsageEntryUnknownError; + case wvcdm::STORE_LICENSE_ERROR_4: + return kStoreLicenseError4; + case wvcdm::LIST_LICENSES_ERROR: + return kListLicensesError; case wvcdm::UNUSED_1: case wvcdm::UNUSED_2: