Merge "Store key set ID with usage info"
This commit is contained in:
@@ -146,6 +146,8 @@ class CdmEngine {
|
||||
virtual CdmResponseType ReleaseAllUsageInfo(const std::string& app_id);
|
||||
virtual CdmResponseType ReleaseUsageInfo(
|
||||
const CdmUsageInfoReleaseMessage& message);
|
||||
virtual CdmResponseType LoadUsageSession(const CdmKeySetId& key_set_id,
|
||||
CdmKeyMessage* release_message);
|
||||
|
||||
// Decryption and key related methods
|
||||
// Accept encrypted buffer and return decrypted data.
|
||||
|
||||
@@ -72,7 +72,8 @@ class DeviceFiles {
|
||||
virtual bool StoreUsageInfo(const std::string& provider_session_token,
|
||||
const CdmKeyMessage& key_request,
|
||||
const CdmKeyResponse& key_response,
|
||||
const std::string& app_id);
|
||||
const std::string& app_id,
|
||||
const std::string& key_set_id);
|
||||
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
|
||||
@@ -91,6 +92,12 @@ class DeviceFiles {
|
||||
const std::string& provider_session_token,
|
||||
CdmKeyMessage* license_request,
|
||||
CdmKeyResponse* license_response);
|
||||
// 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);
|
||||
|
||||
private:
|
||||
// Helpers that wrap the File interface and automatically handle hashing, as
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "cdm_engine.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <iostream>
|
||||
@@ -934,6 +935,66 @@ CdmResponseType CdmEngine::ReleaseUsageInfo(
|
||||
return status;
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::LoadUsageSession(const CdmKeySetId& key_set_id,
|
||||
CdmKeyMessage* release_message) {
|
||||
LOGI("CdmEngine::LoadUsageSession");
|
||||
// This method is currently only used by the CE CDM, in which all session IDs
|
||||
// are key set IDs.
|
||||
assert(Properties::AlwaysUseKeySetIds());
|
||||
|
||||
if (key_set_id.empty()) {
|
||||
LOGE("CdmEngine::LoadUsageSession: invalid key set id");
|
||||
return EMPTY_KEYSET_ID_ENG_5;
|
||||
}
|
||||
|
||||
CdmSessionMap::iterator iter = sessions_.find(key_set_id);
|
||||
if (iter == sessions_.end()) {
|
||||
LOGE("CdmEngine::LoadUsageSession: session_id not found = %s ",
|
||||
key_set_id.c_str());
|
||||
return SESSION_NOT_FOUND_11;
|
||||
}
|
||||
|
||||
DeviceFiles handle;
|
||||
if (!handle.Init(iter->second->GetSecurityLevel())) {
|
||||
LOGE("CdmEngine::LoadUsageSession: unable to initialize device files");
|
||||
return LOAD_USAGE_INFO_FILE_ERROR;
|
||||
}
|
||||
|
||||
std::string app_id;
|
||||
iter->second->GetApplicationId(&app_id);
|
||||
|
||||
CdmKeyMessage key_message;
|
||||
CdmKeyResponse key_response;
|
||||
if (!handle.RetrieveUsageInfoByKeySetId(app_id, key_set_id, &key_message,
|
||||
&key_response)) {
|
||||
LOGE("CdmEngine::LoadUsageSession: unable to find usage information");
|
||||
return LOAD_USAGE_INFO_MISSING;
|
||||
}
|
||||
|
||||
CdmResponseType status =
|
||||
iter->second->RestoreUsageSession(key_message, key_response);
|
||||
if (KEY_ADDED != status) {
|
||||
LOGE("CdmEngine::LoadUsageSession: usage session error %ld", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
std::string server_url;
|
||||
status = iter->second->GenerateReleaseRequest(release_message, &server_url);
|
||||
|
||||
switch (status) {
|
||||
case KEY_MESSAGE:
|
||||
break;
|
||||
case KEY_CANCELED: // usage information not present in
|
||||
iter->second->DeleteLicense(); // OEMCrypto, delete and try again
|
||||
break;
|
||||
default:
|
||||
LOGE("CdmEngine::LoadUsageSession: generate release request error: %d",
|
||||
status);
|
||||
break;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::Decrypt(const CdmSessionId& session_id,
|
||||
const CdmDecryptionParameters& parameters) {
|
||||
if (parameters.key_id == NULL) {
|
||||
|
||||
@@ -541,7 +541,7 @@ CdmResponseType CdmSession::StoreLicense() {
|
||||
std::string app_id;
|
||||
GetApplicationId(&app_id);
|
||||
if (!file_handle_->StoreUsageInfo(provider_session_token, key_request_,
|
||||
key_response_, app_id)) {
|
||||
key_response_, app_id, key_set_id_)) {
|
||||
LOGE("CdmSession::StoreLicense: Unable to store usage info");
|
||||
return STORE_USAGE_INFO_ERROR;
|
||||
}
|
||||
|
||||
@@ -355,7 +355,8 @@ bool DeviceFiles::UnreserveLicenseId(const std::string& key_set_id) {
|
||||
bool DeviceFiles::StoreUsageInfo(const std::string& provider_session_token,
|
||||
const CdmKeyMessage& key_request,
|
||||
const CdmKeyResponse& key_response,
|
||||
const std::string& app_id) {
|
||||
const std::string& app_id,
|
||||
const std::string& key_set_id) {
|
||||
if (!initialized_) {
|
||||
LOGW("DeviceFiles::StoreUsageInfo: not initialized");
|
||||
return false;
|
||||
@@ -381,6 +382,7 @@ bool DeviceFiles::StoreUsageInfo(const std::string& provider_session_token,
|
||||
provider_session_token.size());
|
||||
provider_session->set_license_request(key_request.data(), key_request.size());
|
||||
provider_session->set_license(key_response.data(), key_response.size());
|
||||
provider_session->set_key_set_id(key_set_id.data(), key_set_id.size());
|
||||
|
||||
file.SerializeToString(&serialized_file);
|
||||
return StoreFileWithHash(file_name, serialized_file);
|
||||
@@ -522,22 +524,48 @@ bool DeviceFiles::RetrieveUsageInfo(const std::string& app_id,
|
||||
LOGW("DeviceFiles::RetrieveUsageInfo: Unable to parse file");
|
||||
return false;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
bool found = false;
|
||||
for (; index < file.usage_info().sessions_size(); ++index) {
|
||||
if (file.usage_info().sessions(index).token() == provider_session_token) {
|
||||
found = true;
|
||||
break;
|
||||
*license_request = file.usage_info().sessions(index).license_request();
|
||||
*license_response = file.usage_info().sessions(index).license();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeviceFiles::RetrieveUsageInfoByKeySetId(
|
||||
const std::string& app_id,
|
||||
const std::string& key_set_id,
|
||||
CdmKeyMessage* license_request,
|
||||
CdmKeyResponse* license_response) {
|
||||
if (!initialized_) {
|
||||
LOGW("DeviceFiles::RetrieveUsageInfoByKeySetId: not initialized");
|
||||
return false;
|
||||
}
|
||||
std::string serialized_file;
|
||||
std::string file_name = GetUsageInfoFileName(app_id);
|
||||
if (!RetrieveHashedFile(file_name, &serialized_file)) return false;
|
||||
|
||||
video_widevine_client::sdk::File file;
|
||||
if (!file.ParseFromString(serialized_file)) {
|
||||
LOGW("DeviceFiles::RetrieveUsageInfoByKeySetId: Unable to parse file");
|
||||
return false;
|
||||
}
|
||||
|
||||
*license_request = file.usage_info().sessions(index).license_request();
|
||||
*license_response = file.usage_info().sessions(index).license();
|
||||
return true;
|
||||
int index = 0;
|
||||
for (; index < file.usage_info().sessions_size(); ++index) {
|
||||
if (file.usage_info().sessions(index).key_set_id() == key_set_id) {
|
||||
*license_request = file.usage_info().sessions(index).license_request();
|
||||
*license_response = file.usage_info().sessions(index).license();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeviceFiles::StoreFileWithHash(const std::string& name,
|
||||
|
||||
@@ -46,6 +46,7 @@ message UsageInfo {
|
||||
optional bytes token = 1;
|
||||
optional bytes license_request = 2;
|
||||
optional bytes license = 3;
|
||||
optional bytes key_set_id = 4;
|
||||
}
|
||||
|
||||
repeated ProviderSession sessions = 1;
|
||||
|
||||
@@ -21,6 +21,7 @@ const uint32_t kProtobufEstimatedOverhead = 75;
|
||||
const uint32_t kLicenseRequestLen = 300;
|
||||
const uint32_t kLicenseLen = 500;
|
||||
const uint32_t kProviderSessionTokenLen = 128;
|
||||
const uint32_t kKeySetIdLen = 20;
|
||||
|
||||
// Structurally valid test certificate.
|
||||
// The data elements in this module are used to test the storage and
|
||||
@@ -1536,6 +1537,16 @@ MATCHER_P4(Contains, str1, str2, str3, size, "") {
|
||||
data.find(str2) != std::string::npos &&
|
||||
data.find(str3) != std::string::npos);
|
||||
}
|
||||
MATCHER_P5(Contains, str1, str2, str3, str4, size, "") {
|
||||
// Estimating the length of data. We can have gmock provide length
|
||||
// as well as pointer to data but that will introduce a dependency on tr1
|
||||
std::string data(arg, size + str1.size() + str2.size() + str3.size() +
|
||||
str4.size() + kProtobufEstimatedOverhead);
|
||||
return (data.find(str1) != std::string::npos &&
|
||||
data.find(str2) != std::string::npos &&
|
||||
data.find(str3) != std::string::npos &&
|
||||
data.find(str4) != std::string::npos);
|
||||
}
|
||||
MATCHER_P6(Contains, str1, str2, str3, str4, str5, str6, "") {
|
||||
// Estimating the length of data. We can have gmock provide length
|
||||
// as well as pointer to data but that will introduce a dependency on tr1
|
||||
@@ -1549,7 +1560,6 @@ MATCHER_P6(Contains, str1, str2, str3, str4, str5, str6, "") {
|
||||
data.find(str5) != std::string::npos &&
|
||||
data.find(str6) != std::string::npos);
|
||||
}
|
||||
|
||||
MATCHER_P7(Contains, str1, str2, str3, str4, str5, str6, map7, "") {
|
||||
// Estimating the length of data. We can have gmock provide length
|
||||
// as well as pointer to data but that will introduce a dependency on tr1
|
||||
@@ -2207,6 +2217,7 @@ TEST_P(DeviceFilesUsageInfoTest, Store) {
|
||||
std::string pst(GenerateRandomData(kProviderSessionTokenLen));
|
||||
std::string license_request(GenerateRandomData(kLicenseRequestLen));
|
||||
std::string license(GenerateRandomData(kLicenseLen));
|
||||
std::string key_set_id(GenerateRandomData(kKeySetIdLen));
|
||||
std::string path =
|
||||
device_base_path_ + DeviceFiles::GetUsageInfoFileName(app_id);
|
||||
|
||||
@@ -2236,8 +2247,10 @@ TEST_P(DeviceFilesUsageInfoTest, Store) {
|
||||
}
|
||||
|
||||
EXPECT_CALL(file,
|
||||
Write(Contains(pst, license_request, license, data.size()),
|
||||
Gt(pst.size() + license_request.size() + license.size())))
|
||||
Write(Contains(pst, license_request, license, key_set_id,
|
||||
data.size()),
|
||||
Gt(pst.size() + license_request.size() + license.size() +
|
||||
key_set_id.size())))
|
||||
.WillOnce(ReturnArg<1>());
|
||||
|
||||
DeviceFiles device_files;
|
||||
@@ -2245,7 +2258,8 @@ TEST_P(DeviceFilesUsageInfoTest, Store) {
|
||||
device_files.SetTestFile(&file);
|
||||
|
||||
ASSERT_TRUE(
|
||||
device_files.StoreUsageInfo(pst, license_request, license, app_id));
|
||||
device_files.StoreUsageInfo(pst, license_request, license, app_id,
|
||||
key_set_id));
|
||||
}
|
||||
|
||||
TEST_P(DeviceFilesUsageInfoTest, Delete) {
|
||||
|
||||
@@ -179,7 +179,11 @@ enum {
|
||||
kLicenseRenewalProhibited = ERROR_DRM_VENDOR_MIN + 165,
|
||||
kOfflineLicenseProhibited = ERROR_DRM_VENDOR_MIN + 166,
|
||||
kStorageProhibited = ERROR_DRM_VENDOR_MIN + 167,
|
||||
kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 167,
|
||||
kEmptyKeySetIdEng5 = ERROR_DRM_VENDOR_MIN + 168,
|
||||
kSessionNotFound11 = ERROR_DRM_VENDOR_MIN + 169,
|
||||
kLoadUsageInfoFileError = ERROR_DRM_VENDOR_MIN + 170,
|
||||
kLoadUsageInfoMissing = ERROR_DRM_VENDOR_MIN + 171,
|
||||
kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 171,
|
||||
|
||||
// Used by crypto test mode
|
||||
kErrorTestMode = ERROR_DRM_VENDOR_MAX,
|
||||
|
||||
@@ -347,6 +347,14 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) {
|
||||
return kOfflineLicenseProhibited;
|
||||
case wvcdm::STORAGE_PROHIBITED:
|
||||
return kStorageProhibited;
|
||||
case wvcdm::EMPTY_KEYSET_ID_ENG_5:
|
||||
return kEmptyKeySetIdEng5;
|
||||
case wvcdm::SESSION_NOT_FOUND_11:
|
||||
return kSessionNotFound11;
|
||||
case wvcdm::LOAD_USAGE_INFO_FILE_ERROR:
|
||||
return kLoadUsageInfoFileError;
|
||||
case wvcdm::LOAD_USAGE_INFO_MISSING:
|
||||
return kLoadUsageInfoMissing;
|
||||
case wvcdm::UNKNOWN_ERROR:
|
||||
return android::ERROR_DRM_UNKNOWN;
|
||||
case wvcdm::SECURE_BUFFER_REQUIRED:
|
||||
|
||||
Reference in New Issue
Block a user