From 6d617e2be4f78692964f37ff7036872a4e5ccd41 Mon Sep 17 00:00:00 2001 From: Rahul Frias Date: Sat, 4 Feb 2017 00:08:55 -0800 Subject: [PATCH 1/2] Implement Cdm::listStoredLicenses() [ Merge of http://go/wvgerrit/23600 ] This adds a new entry to IStorage:: - bool list(std::vector file_names) It returns the name of each file in the (origin-specific) file system. b/34628115 Uses the current file system (origin-specific) bound to the CDM. Returns the list of stored licenses (key_set_ids) in vector output parameter. Test: verified by unittests on angler. Change-Id: I988556b27c2a4b75f52b59bcd78cfeaddd649acd --- libwvdrmengine/cdm/core/include/cdm_engine.h | 13 ++++- libwvdrmengine/cdm/core/include/cdm_session.h | 2 + .../cdm/core/include/device_files.h | 3 + libwvdrmengine/cdm/core/include/file_store.h | 5 ++ .../cdm/core/include/wv_cdm_types.h | 3 + libwvdrmengine/cdm/core/src/cdm_engine.cpp | 17 ++++++ libwvdrmengine/cdm/core/src/device_files.cpp | 44 ++++++++++++++- .../cdm/core/test/device_files_unittest.cpp | 1 + .../cdm/core/test/file_store_unittest.cpp | 55 +++++++++++++++++++ .../cdm/core/test/test_printers.cpp | 10 +++- libwvdrmengine/cdm/src/file_store.cpp | 5 ++ libwvdrmengine/include/WVErrors.h | 5 +- libwvdrmengine/include/mapErrors-inl.h | 10 +++- 13 files changed, 166 insertions(+), 7 deletions(-) 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: From db6df99db124107bed9d7230f33974ef33b4dac4 Mon Sep 17 00:00:00 2001 From: Rahul Frias Date: Mon, 6 Feb 2017 17:49:37 -0800 Subject: [PATCH 2/2] Add usage support query method [ Merge of http://go/wvgerrit/23522 ] A helper method has been added to CryptoSession to determine whether the TEE supports usage tables, usage table headers+entries or does not provide any support for persistent licenses. In addition * CryptoSession now supports deletion of multiple usage entries rather than a single one. * Typedefs have been added for usage table headers and entries b/34327459 Test: Verified by unit/integration tests on angler. Change-Id: I634d3b7b81ce94d1deccd2a7aaf26b9efde414a8 --- .../cdm/core/include/crypto_session.h | 19 +++-- .../cdm/core/include/device_files.h | 14 ++-- .../cdm/core/include/wv_cdm_types.h | 18 +++++ .../cdm/core/src/crypto_session.cpp | 81 ++++++++++++++----- libwvdrmengine/cdm/core/src/device_files.cpp | 16 ++-- .../cdm/core/test/test_printers.cpp | 9 +++ libwvdrmengine/include/WVErrors.h | 5 +- libwvdrmengine/include/mapErrors-inl.h | 6 ++ 8 files changed, 125 insertions(+), 43 deletions(-) diff --git a/libwvdrmengine/cdm/core/include/crypto_session.h b/libwvdrmengine/cdm/core/include/crypto_session.h index 1473c000..22f3c2e9 100644 --- a/libwvdrmengine/cdm/core/include/crypto_session.h +++ b/libwvdrmengine/cdm/core/include/crypto_session.h @@ -141,17 +141,19 @@ class CryptoSession { const std::string& signature); // Usage table header and usage entry related methods + virtual CdmResponseType GetUsageSupportType(CdmUsageSupportType* type); virtual CdmResponseType CreateUsageTableHeader( - std::string* usage_table_header); + CdmUsageTableHeader* usage_table_header); virtual CdmResponseType LoadUsageTableHeader( - const std::string& usage_table_header); + const CdmUsageTableHeader& usage_table_header); virtual CdmResponseType CreateUsageEntry(uint32_t* entry_number); virtual CdmResponseType LoadUsageEntry(uint32_t entry_number, - const std::string& usage_entry); - virtual CdmResponseType UpdateUsageEntry(std::string* usage_table_header, - std::string* usage_entry); - virtual CdmResponseType DecrementUsageTableHeaderSize( - uint32_t current_usage_table_size, std::string* usage_table_header); + const CdmUsageEntry& usage_entry); + virtual CdmResponseType UpdateUsageEntry( + CdmUsageTableHeader* usage_table_header, + CdmUsageEntry* usage_entry); + virtual CdmResponseType ShrinkUsageTableHeader( + uint32_t new_entry_count, CdmUsageTableHeader* usage_table_header); virtual CdmResponseType MoveUsageEntry(uint32_t new_entry_number); virtual CdmResponseType CopyOldUsageEntry( const std::string& provider_session_token); @@ -212,6 +214,9 @@ class CryptoSession { KeyId cached_key_id_; + bool is_usage_support_type_valid_; + CdmUsageSupportType usage_support_type_; + uint64_t request_id_base_; static uint64_t request_id_index_; diff --git a/libwvdrmengine/cdm/core/include/device_files.h b/libwvdrmengine/cdm/core/include/device_files.h index 2ce212d8..8a669a13 100644 --- a/libwvdrmengine/cdm/core/include/device_files.h +++ b/libwvdrmengine/cdm/core/include/device_files.h @@ -69,7 +69,7 @@ class DeviceFiles { int64_t last_playback_time, int64_t grace_period_end_time, const CdmAppParameterMap& app_parameters, - const std::string& usage_entry); + const CdmUsageEntry& usage_entry); virtual bool RetrieveLicense( const std::string& key_set_id, LicenseState* state, CdmInitData* pssh_data, CdmKeyMessage* key_request, @@ -77,7 +77,7 @@ class DeviceFiles { CdmKeyResponse* key_renewal_response, std::string* release_server_url, int64_t* playback_start_time, int64_t* last_playback_time, int64_t* grace_period_end_time, CdmAppParameterMap* app_parameters, - std::string* usage_entry); + CdmUsageEntry* usage_entry); virtual bool DeleteLicense(const std::string& key_set_id); virtual bool ListLicenses(std::vector* key_set_ids); virtual bool DeleteAllFiles(); @@ -91,7 +91,7 @@ class DeviceFiles { const CdmKeyResponse& key_response, const std::string& app_id, const std::string& key_set_id, - const std::string& usage_entry); + const CdmUsageEntry& usage_entry); virtual bool DeleteUsageInfo(const std::string& app_id, const std::string& provider_session_token); // Delete usage information from the file system. Puts a list of all the @@ -110,14 +110,14 @@ class DeviceFiles { const std::string& provider_session_token, CdmKeyMessage* license_request, CdmKeyResponse* license_response, - std::string* usage_entry); + CdmUsageEntry* usage_entry); // Retrieve the usage info entry specified by |key_set_id|. // Returns false if the entry could not be found. virtual bool RetrieveUsageInfoByKeySetId(const std::string& app_id, const std::string& key_set_id, CdmKeyMessage* license_request, CdmKeyResponse* license_response, - std::string* usage_entry); + CdmUsageEntry* usage_entry); virtual bool StoreHlsAttributes(const std::string& key_set_id, const CdmHlsMethod method, @@ -128,11 +128,11 @@ class DeviceFiles { virtual bool DeleteHlsAttributes(const std::string& key_set_id); virtual bool StoreUsageTableInfo( - const std::string& usage_table_header, + const CdmUsageTableHeader& usage_table_header, const std::vector& usage_entry_info); virtual bool RetrieveUsageTableInfo( - std::string* usage_table_header, + CdmUsageTableHeader* usage_table_header, std::vector* usage_entry_info); private: diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_types.h b/libwvdrmengine/cdm/core/include/wv_cdm_types.h index 115d24c8..045b3fa6 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_types.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_types.h @@ -28,6 +28,8 @@ typedef std::vector CdmUsageInfo; typedef std::string CdmUsageInfoReleaseMessage; typedef std::string CdmProvisioningRequest; typedef std::string CdmProvisioningResponse; +typedef std::string CdmUsageTableHeader; +typedef std::string CdmUsageEntry; enum CdmKeyRequestType { kKeyRequestTypeUnknown, @@ -274,6 +276,9 @@ enum CdmResponseType { INVALID_PARAMETERS_ENG_22, STORE_LICENSE_ERROR_4, /* 235 */ LIST_LICENSES_ERROR, + INVALID_PARAMETERS_ENG_23, + USAGE_INFORMATION_SUPPORT_FAILED, + USAGE_SUPPORT_GET_API_FAILED, }; enum CdmKeyStatus { @@ -346,6 +351,19 @@ enum CdmClientTokenType { kClientTokenOemCert }; +// kNonSecureUsageSupport - TEE does not provide any support for usage +// information. +// kUsageTableSupport - TEE persists usage information securely in a fixed +// size table, commonly 50 entries. (OEMCrypto v9+) +// kUsageEntrySupport - usage information (table headers and entries) are +// persisted in non-secure storage but are loaded and unloaded from +// the TEE during use (OEMCrypto v13+) +enum CdmUsageSupportType { + kNonSecureUsageSupport, + kUsageTableSupport, + kUsageEntrySupport, +}; + class CdmKeyAllowedUsage { public: CdmKeyAllowedUsage() { diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index 2ea19f4b..0b630b8c 100644 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -31,6 +31,7 @@ std::string EncodeUint32(unsigned int u) { const uint32_t kRsaSignatureLength = 256; const size_t kMaximumChunkSize = 100 * 1024; // 100 KiB const size_t kEstimatedInitialUsageTableHeader = 40; +const size_t kOemCryptoApiVersionSupportsBigUsageTables = 13; } namespace wvcdm { @@ -46,6 +47,8 @@ CryptoSession::CryptoSession(metrics::MetricsGroup* metrics) update_usage_table_after_close_session_(false), is_destination_buffer_type_valid_(false), requested_security_level_(kLevelDefault), + is_usage_support_type_valid_(false), + usage_support_type_(kNonSecureUsageSupport), request_id_base_(0), cipher_mode_(kCipherModeCtr) { Init(); @@ -120,24 +123,23 @@ void CryptoSession::Terminate() { } bool CryptoSession::GetTokenFromKeybox(std::string* token) { - OEMCryptoResult status; std::string temp_buffer(KEYBOX_KEY_DATA_SIZE, '\0'); // lock is held by caller size_t buf_size = temp_buffer.size(); uint8_t* buf = reinterpret_cast(&temp_buffer[0]); - OEMCryptoResult sts; + OEMCryptoResult status; M_TIME( - sts = OEMCrypto_GetKeyData( + status = OEMCrypto_GetKeyData( buf, &buf_size, requested_security_level_), metrics_, oemcrypto_get_key_data_, - sts, + status, metrics::Pow2Bucket(buf_size), requested_security_level_); - if (OEMCrypto_SUCCESS == sts) { + if (OEMCrypto_SUCCESS == status) { token->swap(temp_buffer); return true; } @@ -1811,8 +1813,47 @@ CdmResponseType CryptoSession::GenericVerify(const std::string& message, return NO_ERROR; } +CdmResponseType CryptoSession::GetUsageSupportType( + CdmUsageSupportType* usage_support_type) { + LOGV("GetUsageSupportType: id=%ld", (uint32_t)oec_session_id_); + + if (usage_support_type == NULL) { + LOGE("GetUsageSupportType: usage_support_type param not provided"); + return INVALID_PARAMETERS_ENG_23; + } + + if (is_usage_support_type_valid_) { + *usage_support_type = usage_support_type_; + return NO_ERROR; + } + + bool has_support = false; + if (!UsageInformationSupport(&has_support)) { + LOGE("GetUsageSupportType: UsageInformationSupport failed"); + return USAGE_INFORMATION_SUPPORT_FAILED; + } + + if (!has_support) { + *usage_support_type = usage_support_type_ = kNonSecureUsageSupport; + is_usage_support_type_valid_ = true; + return NO_ERROR; + } + + uint32_t api_version = 0; + if (!GetApiVersion(&api_version)) { + LOGE("GetUsageSupportType: GetApiVersion failed"); + return USAGE_SUPPORT_GET_API_FAILED; + } + + *usage_support_type = usage_support_type_ = + (api_version >= kOemCryptoApiVersionSupportsBigUsageTables) ? + kUsageEntrySupport : kUsageTableSupport; + is_usage_support_type_valid_ = true; + return NO_ERROR; +} + CdmResponseType CryptoSession::CreateUsageTableHeader( - std::string* usage_table_header) { + CdmUsageTableHeader* usage_table_header) { LOGV("CreateUsageTableHeader: id=%ld", (uint32_t)oec_session_id_); if (usage_table_header == NULL) { @@ -1848,7 +1889,7 @@ CdmResponseType CryptoSession::CreateUsageTableHeader( } CdmResponseType CryptoSession::LoadUsageTableHeader( - const std::string& usage_table_header) { + const CdmUsageTableHeader& usage_table_header) { LOGV("LoadUsageTableHeader: id=%ld", (uint32_t)oec_session_id_); OEMCryptoResult result = OEMCrypto_LoadUsageTableHeader( @@ -1908,8 +1949,9 @@ CdmResponseType CryptoSession::CreateUsageEntry(uint32_t* entry_number) { } } -CdmResponseType CryptoSession::LoadUsageEntry(uint32_t entry_number, - const std::string& usage_entry) { +CdmResponseType CryptoSession::LoadUsageEntry( + uint32_t entry_number, + const CdmUsageEntry& usage_entry) { LOGV("LoadUsageEntry: id=%ld", (uint32_t)oec_session_id_); OEMCryptoResult result = OEMCrypto_LoadUsageEntry( @@ -1937,8 +1979,9 @@ CdmResponseType CryptoSession::LoadUsageEntry(uint32_t entry_number, } } -CdmResponseType CryptoSession::UpdateUsageEntry(std::string* usage_table_header, - std::string* usage_entry) { +CdmResponseType CryptoSession::UpdateUsageEntry( + CdmUsageTableHeader* usage_table_header, + CdmUsageEntry* usage_entry) { LOGV("UpdateUsageEntry: id=%ld", (uint32_t)oec_session_id_); if (usage_table_header == NULL) { @@ -1979,27 +2022,26 @@ CdmResponseType CryptoSession::UpdateUsageEntry(std::string* usage_table_header, return NO_ERROR; } -CdmResponseType CryptoSession::DecrementUsageTableHeaderSize( - uint32_t current_usage_table_size, std::string* usage_table_header) { - LOGV("DecrementUsageTableHeaderSize: id=%ld", (uint32_t)oec_session_id_); +CdmResponseType CryptoSession::ShrinkUsageTableHeader( + uint32_t new_entry_count, CdmUsageTableHeader* usage_table_header) { + LOGV("ShrinkUsageTableHeader: id=%ld", (uint32_t)oec_session_id_); if (usage_table_header == NULL) { LOGE( - "DecrementUsageTableHeaderSize: usage_table_header param not " - "provided"); + "ShrinkUsageTableHeader: usage_table_header param not provided"); return INVALID_PARAMETERS_ENG_21; } size_t usage_table_header_len = 0; OEMCryptoResult result = OEMCrypto_ShrinkUsageTableHeader( - requested_security_level_, current_usage_table_size, NULL, + requested_security_level_, new_entry_count, NULL, &usage_table_header_len); if (result == OEMCrypto_ERROR_SHORT_BUFFER) { usage_table_header->resize(usage_table_header_len); result = OEMCrypto_ShrinkUsageTableHeader( - requested_security_level_, --current_usage_table_size, + requested_security_level_, new_entry_count, reinterpret_cast( const_cast(usage_table_header->data())), &usage_table_header_len); @@ -2007,8 +2049,7 @@ CdmResponseType CryptoSession::DecrementUsageTableHeaderSize( if (result != OEMCrypto_SUCCESS) { LOGE( - "DecrementUsageTableHeaderSize: OEMCrypto_ShrinkUsageTableHeader " - "error: %d", + "ShrinkUsageTableHeader: OEMCrypto_ShrinkUsageTableHeader error: %d", result); return SHRINK_USAGE_TABLER_HEADER_UNKNOWN_ERROR; } diff --git a/libwvdrmengine/cdm/core/src/device_files.cpp b/libwvdrmengine/cdm/core/src/device_files.cpp index 30d8c303..eff98e2c 100644 --- a/libwvdrmengine/cdm/core/src/device_files.cpp +++ b/libwvdrmengine/cdm/core/src/device_files.cpp @@ -177,7 +177,7 @@ bool DeviceFiles::StoreLicense( const std::string& release_server_url, int64_t playback_start_time, int64_t last_playback_time, int64_t grace_period_end_time, const CdmAppParameterMap& app_parameters, - const std::string& usage_entry) { + const CdmUsageEntry& usage_entry) { if (!initialized_) { LOGW("DeviceFiles::StoreLicense: not initialized"); return false; @@ -233,7 +233,7 @@ bool DeviceFiles::RetrieveLicense( CdmKeyMessage* license_renewal_request, CdmKeyResponse* license_renewal, std::string* release_server_url, int64_t* playback_start_time, int64_t* last_playback_time, int64_t* grace_period_end_time, - CdmAppParameterMap* app_parameters, std::string* usage_entry) { + CdmAppParameterMap* app_parameters, CdmUsageEntry* usage_entry) { if (!initialized_) { LOGW("DeviceFiles::RetrieveLicense: not initialized"); return false; @@ -319,7 +319,7 @@ bool DeviceFiles::ListLicenses(std::vector* key_set_ids) { // 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++) { + for (size_t i = 0; i < filenames.size(); i++) { std::string* name = &filenames[i]; std::size_t pos = name->find(kLicenseFileNameExt); if (pos == std::string::npos) { @@ -384,7 +384,7 @@ bool DeviceFiles::StoreUsageInfo(const std::string& provider_session_token, const CdmKeyResponse& key_response, const std::string& app_id, const std::string& key_set_id, - const std::string& usage_entry) { + const CdmUsageEntry& usage_entry) { if (!initialized_) { LOGW("DeviceFiles::StoreUsageInfo: not initialized"); return false; @@ -525,7 +525,7 @@ bool DeviceFiles::RetrieveUsageInfo(const std::string& app_id, const std::string& provider_session_token, CdmKeyMessage* license_request, CdmKeyResponse* license_response, - std::string* usage_entry) { + CdmUsageEntry* usage_entry) { if (!initialized_) { LOGW("DeviceFiles::RetrieveUsageInfo: not initialized"); return false; @@ -555,7 +555,7 @@ bool DeviceFiles::RetrieveUsageInfoByKeySetId( const std::string& key_set_id, CdmKeyMessage* license_request, CdmKeyResponse* license_response, - std::string* usage_entry) { + CdmUsageEntry* usage_entry) { if (!initialized_) { LOGW("DeviceFiles::RetrieveUsageInfoByKeySetId: not initialized"); return false; @@ -678,7 +678,7 @@ bool DeviceFiles::DeleteHlsAttributes(const std::string& key_set_id) { } bool DeviceFiles::StoreUsageTableInfo( - const std::string& usage_table_header, + const CdmUsageTableHeader& usage_table_header, const std::vector& usage_entry_info) { if (!initialized_) { LOGW("DeviceFiles::StoreUsageTableHeader: not initialized"); @@ -723,7 +723,7 @@ bool DeviceFiles::StoreUsageTableInfo( } bool DeviceFiles::RetrieveUsageTableInfo( - std::string* usage_table_header, + CdmUsageTableHeader* usage_table_header, std::vector* usage_entry_info) { if (!initialized_) { LOGW("DeviceFiles::RetrieveUsageTableInfo: not initialized"); diff --git a/libwvdrmengine/cdm/core/test/test_printers.cpp b/libwvdrmengine/cdm/core/test/test_printers.cpp index a77930eb..aea9bf6d 100644 --- a/libwvdrmengine/cdm/core/test/test_printers.cpp +++ b/libwvdrmengine/cdm/core/test/test_printers.cpp @@ -519,6 +519,15 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) { break; case LIST_LICENSES_ERROR: *os << "LIST_LICENSES_ERROR"; break; + case INVALID_PARAMETERS_ENG_23: + *os << "INVALID_PARAMETERS_ENG_23"; + break; + case USAGE_INFORMATION_SUPPORT_FAILED: + *os << "USAGE_INFORMATION_SUPPORT_FAILED"; + break; + case USAGE_SUPPORT_GET_API_FAILED: + *os << "USAGE_SUPPORT_GET_API_FAILED"; + break; default: *os << "Unknown CdmResponseType"; diff --git a/libwvdrmengine/include/WVErrors.h b/libwvdrmengine/include/WVErrors.h index bbe74d80..552979cd 100644 --- a/libwvdrmengine/include/WVErrors.h +++ b/libwvdrmengine/include/WVErrors.h @@ -241,10 +241,13 @@ enum { kInvalidParametersEng22 = ERROR_DRM_VENDOR_MIN + 227, kStoreLicenseError4 = ERROR_DRM_VENDOR_MIN + 228, kListLicensesError = ERROR_DRM_VENDOR_MIN + 229, + kInvalidParametersEng23 = ERROR_DRM_VENDOR_MIN + 230, + kUsageInformationSupportFailed = ERROR_DRM_VENDOR_MIN + 231, + kUsageSupportGetApiFailed = ERROR_DRM_VENDOR_MIN + 232, // 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 + 229, + kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 232, // 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 344645c5..d9ff873c 100644 --- a/libwvdrmengine/include/mapErrors-inl.h +++ b/libwvdrmengine/include/mapErrors-inl.h @@ -473,6 +473,12 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { return kStoreLicenseError4; case wvcdm::LIST_LICENSES_ERROR: return kListLicensesError; + case wvcdm::INVALID_PARAMETERS_ENG_23: + return kInvalidParametersEng23; + case wvcdm::USAGE_INFORMATION_SUPPORT_FAILED: + return kUsageInformationSupportFailed; + case wvcdm::USAGE_SUPPORT_GET_API_FAILED: + return kUsageSupportGetApiFailed; case wvcdm::UNUSED_1: case wvcdm::UNUSED_2: