Merge "Store key set ID with usage info"

This commit is contained in:
Rahul Frias
2016-01-19 22:32:16 +00:00
committed by Android (Google) Code Review
9 changed files with 140 additions and 15 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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: