Merge changes Ie4a63ac2,I8523ef28 into pi-dev

* changes:
  Recovery from usage info corruption
  Correct segfault in WvCdmRequestLicenseTest.UsageRemoveSecureStopTest
This commit is contained in:
Rahul Frias
2018-04-03 18:12:34 +00:00
committed by Android (Google) Code Review
8 changed files with 300 additions and 18 deletions

View File

@@ -289,7 +289,7 @@ enum CdmResponseType {
USAGE_STORE_LICENSE_FAILED = 247,
USAGE_STORE_USAGE_INFO_FAILED = 248,
USAGE_INVALID_LOAD_ENTRY = 249,
REMOVE_ALL_USAGE_INFO_ERROR_4 = 250,
/* previously REMOVE_ALL_USAGE_INFO_ERROR_4 = 250, */
REMOVE_ALL_USAGE_INFO_ERROR_5 = 251,
RELEASE_USAGE_INFO_FAILED = 252,
INCORRECT_USAGE_SUPPORT_TYPE_1 = 253,

View File

@@ -1223,24 +1223,29 @@ CdmResponseType CdmEngine::RemoveAllUsageInfo(const std::string& app_id) {
if (!handle.RetrieveUsageInfo(
DeviceFiles::GetUsageInfoFileName(app_id),
&usage_data)) {
status = REMOVE_ALL_USAGE_INFO_ERROR_4;
LOGW("CdmEngine::RemoveAllUsageInfo: failed to retrieve usage info");
break;
}
if (usage_data.empty()) break;
status = usage_session_->DeleteUsageEntry(
CdmResponseType res = usage_session_->DeleteUsageEntry(
usage_data[0].usage_entry_number);
if (status != NO_ERROR) break;
if (res != NO_ERROR) {
LOGW("CdmEngine::RemoveAllUsageInfo: failed to delete usage "
"entry: error: %d", res);
break;
}
if (!handle.DeleteUsageInfo(
DeviceFiles::GetUsageInfoFileName(app_id),
usage_data[0].provider_session_token)) {
status = REMOVE_ALL_USAGE_INFO_ERROR_6;
LOGW("CdmEngine::RemoveAllUsageInfo: failed to delete usage "
"info");
break;
}
} while (status == NO_ERROR && !usage_data.empty());
} while (!usage_data.empty());
std::vector<std::string> provider_session_tokens;
if (!handle.DeleteAllUsageInfoForApp(
@@ -1315,8 +1320,7 @@ CdmResponseType CdmEngine::RemoveUsageInfo(
switch (usage_session_->get_usage_support_type()) {
case kUsageEntrySupport: {
status = usage_session_->DeleteUsageEntry(
usage_data[0].usage_entry_number);
status = usage_session_->DeleteUsageEntry(usage_entry_number);
if (!handle.DeleteUsageInfo(
DeviceFiles::GetUsageInfoFileName(app_id),

View File

@@ -841,6 +841,25 @@ CdmResponseType CdmSession::StoreLicense() {
key_set_id_, usage_entry_,
usage_entry_number_)) {
LOGE("CdmSession::StoreLicense: Unable to store usage info");
// Usage info file is corrupt. Delete current usage entry and file.
switch (usage_support_type_) {
case kUsageEntrySupport:
DeleteUsageEntry(usage_entry_number_);
break;
case kUsageTableSupport:
crypto_session_->DeleteUsageInformation(provider_session_token);
crypto_session_->UpdateUsageInformation();
break;
default:
LOGW("CdmSession::StoreLicense: unexpected usage support type: %d",
usage_support_type_);
break;
}
std::vector<std::string> provider_session_tokens;
file_handle_->DeleteAllUsageInfoForApp(
DeviceFiles::GetUsageInfoFileName(app_id),
&provider_session_tokens);
return STORE_USAGE_INFO_ERROR;
}
return NO_ERROR;

View File

@@ -227,9 +227,6 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
case REMOVE_ALL_USAGE_INFO_ERROR_2:
*os << "REMOVE_ALL_USAGE_INFO_ERROR_2";
break;
case REMOVE_ALL_USAGE_INFO_ERROR_4:
*os << "REMOVE_ALL_USAGE_INFO_ERROR_4";
break;
case REMOVE_ALL_USAGE_INFO_ERROR_5:
*os << "REMOVE_ALL_USAGE_INFO_ERROR_5";
break;

View File

@@ -1475,13 +1475,11 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
void VerifyKeyRequestResponse(const std::string& server_url,
const std::string& client_auth) {
std::string response;
VerifyKeyRequestResponse(server_url, client_auth, false);
}
void VerifyUsageKeyRequestResponse(const std::string& server_url,
const std::string& client_auth) {
std::string response;
VerifyKeyRequestResponse(server_url, client_auth, true);
}
@@ -1496,10 +1494,19 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
const std::string& client_auth,
bool is_usage,
std::string* response) {
VerifyKeyRequestResponse(wvcdm::KEY_ADDED, server_url, client_auth,
is_usage, response);
}
void VerifyKeyRequestResponse(CdmResponseType expected_response,
const std::string& server_url,
const std::string& client_auth,
bool is_usage,
std::string* response) {
*response = GetKeyRequestResponse(server_url, client_auth);
EXPECT_EQ(decryptor_.AddKey(session_id_, *response, &key_set_id_),
wvcdm::KEY_ADDED);
expected_response);
EXPECT_EQ(is_usage || license_type_ == kLicenseTypeOffline,
key_set_id_.size() > 0);
}
@@ -3116,6 +3123,156 @@ TEST_F(WvCdmRequestLicenseTest, UsageRemoveAllTest) {
EXPECT_TRUE(usage_info.empty());
}
TEST_F(WvCdmRequestLicenseTest, RemoveCorruptedUsageInfoTest) {
Unprovision();
std::string app_id_empty = "";
std::string app_id_not_empty = "not empty";
TestWvCdmClientPropertySet property_set;
Provision(kLevelDefault);
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
FileSystem file_system;
DeviceFiles handle(&file_system);
EXPECT_TRUE(handle.Init(security_level));
std::vector<std::string> psts;
EXPECT_TRUE(handle.DeleteAllUsageInfoForApp(
DeviceFiles::GetUsageInfoFileName(""), &psts));
for (size_t i = 0; i < N_ELEM(usage_info_sub_samples_icp); ++i) {
SubSampleInfo* data = usage_info_sub_samples_icp + i;
property_set.set_app_id(i % 2 == 0 ? app_id_empty : app_id_not_empty);
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
NULL, &session_id_);
std::string key_id = a2bs_hex(
"000000427073736800000000" // blob size and pssh
"EDEF8BA979D64ACEA3C827DCD51D21ED00000022" // Widevine system id
"08011a0d7769646576696e655f74657374220f73" // pssh data
"747265616d696e675f636c6970");
char ch = 0x33 + i;
key_id.append(1, ch);
GenerateKeyRequest(key_id, kLicenseTypeStreaming, &property_set);
// TODO(rfrias): streaming_clip6 is a streaming license without a pst
if (ch == '6')
VerifyKeyRequestResponse(g_license_server, g_client_auth, false);
else
VerifyUsageKeyRequestResponse(g_license_server, g_client_auth);
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
CdmDecryptionParameters decryption_parameters(
&data->key_id, &data->encrypt_data.front(), data->encrypt_data.size(),
&data->iv, data->block_offset, &decrypt_buffer[0]);
decryption_parameters.is_encrypted = data->is_encrypted;
decryption_parameters.is_secure = data->is_secure;
decryption_parameters.subsample_flags = data->subsample_flags;
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_, data->validate_key_id,
decryption_parameters));
EXPECT_TRUE(std::equal(data->decrypt_data.begin(), data->decrypt_data.end(),
decrypt_buffer.begin()));
decryptor_.CloseSession(session_id_);
}
CdmUsageInfo usage_info;
EXPECT_EQ(
KEY_MESSAGE,
decryptor_.GetUsageInfo(app_id_empty, kDefaultCdmIdentifier,
&usage_info));
EXPECT_TRUE(usage_info.size() > 0);
EXPECT_EQ(
KEY_MESSAGE,
decryptor_.GetUsageInfo(app_id_not_empty, kDefaultCdmIdentifier,
&usage_info));
EXPECT_TRUE(usage_info.size() > 0);
// Read in usage info file
std::string path;
EXPECT_TRUE(Properties::GetDeviceFilesBasePath(security_level, &path));
std::string usage_info_not_empty_app_id_file_name =
path + DeviceFiles::GetUsageInfoFileName(app_id_not_empty);
ssize_t file_size =
file_system.FileSize(usage_info_not_empty_app_id_file_name);
EXPECT_LT(4, file_size);
File* file =
file_system.Open(usage_info_not_empty_app_id_file_name,
FileSystem::kReadOnly);
EXPECT_TRUE(NULL != file);
std::string file_data;
file_data.resize(file_size);
ssize_t bytes = file->Read(&file_data[0], file_data.size());
EXPECT_EQ(file_size, bytes);
file->Close();
// Corrupt the hash of the usage info file with non-empty app id and write
// it back out
memset(&file_data[0]+bytes-4, 0, 4);
file = file_system.Open(usage_info_not_empty_app_id_file_name,
FileSystem::kCreate | FileSystem::kTruncate);
EXPECT_TRUE(NULL != file);
bytes = file->Write(file_data.data(), file_data.size());
EXPECT_EQ(file_size, bytes);
file->Close();
EXPECT_EQ(
NO_ERROR,
decryptor_.RemoveAllUsageInfo(app_id_not_empty, kDefaultCdmIdentifier));
EXPECT_EQ(
NO_ERROR,
decryptor_.GetUsageInfo(app_id_not_empty, kDefaultCdmIdentifier,
&usage_info));
EXPECT_TRUE(usage_info.empty());
EXPECT_EQ(
KEY_MESSAGE,
decryptor_.GetUsageInfo(app_id_empty, kDefaultCdmIdentifier,
&usage_info));
EXPECT_TRUE(usage_info.size() > 0);
// Read in usage info file
std::string usage_info_empty_app_id_file_name =
path + DeviceFiles::GetUsageInfoFileName(app_id_empty);
file_size = file_system.FileSize(usage_info_empty_app_id_file_name);
EXPECT_LT(4, file_size);
file = file_system.Open(usage_info_empty_app_id_file_name,
FileSystem::kReadOnly);
EXPECT_TRUE(NULL != file);
file_data.resize(file_size);
bytes = file->Read(&file_data[0], file_data.size());
EXPECT_EQ(file_size, bytes);
file->Close();
// Corrupt the hash of the usage info file with empty app id and write it
// back out
memset(&file_data[0]+bytes-4, 0, 4);
file = file_system.Open(usage_info_empty_app_id_file_name,
FileSystem::kCreate | FileSystem::kTruncate);
EXPECT_TRUE(NULL != file);
bytes = file->Write(file_data.data(), file_data.size());
EXPECT_EQ(file_size, bytes);
file->Close();
EXPECT_EQ(
NO_ERROR,
decryptor_.RemoveAllUsageInfo(app_id_empty, kDefaultCdmIdentifier));
EXPECT_EQ(
NO_ERROR,
decryptor_.GetUsageInfo(app_id_not_empty, kDefaultCdmIdentifier,
&usage_info));
EXPECT_TRUE(usage_info.empty());
EXPECT_EQ(
NO_ERROR,
decryptor_.GetUsageInfo(app_id_empty, kDefaultCdmIdentifier,
&usage_info));
EXPECT_TRUE(usage_info.empty());
}
TEST_F(WvCdmRequestLicenseTest, GetSecureStopIdsTest) {
Unprovision();
@@ -3276,6 +3433,115 @@ TEST_F(WvCdmRequestLicenseTest, GetSecureStopIdsTest) {
EXPECT_TRUE(retrieved_secure_stop_ids.empty());
}
TEST_F(WvCdmRequestLicenseTest, UsageRecoveryTest) {
Unprovision();
std::string app_id_empty = "";
TestWvCdmClientPropertySet property_set;
Provision(kLevelDefault);
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
FileSystem file_system;
DeviceFiles handle(&file_system);
EXPECT_TRUE(handle.Init(security_level));
std::vector<std::string> psts;
EXPECT_TRUE(handle.DeleteAllUsageInfoForApp(
DeviceFiles::GetUsageInfoFileName(""), &psts));
// Fetch a usage license
SubSampleInfo* data = kUsageLicenseTestVector1[0].sub_sample;
property_set.set_app_id(app_id_empty);
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
NULL, &session_id_);
GenerateKeyRequest(kUsageLicenseTestVector1[0].pssh, kLicenseTypeStreaming,
&property_set);
VerifyUsageKeyRequestResponse(g_license_server, g_client_auth);
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
CdmDecryptionParameters decryption_parameters(
&data->key_id, &data->encrypt_data.front(), data->encrypt_data.size(),
&data->iv, data->block_offset, &decrypt_buffer[0]);
decryption_parameters.is_encrypted = data->is_encrypted;
decryption_parameters.is_secure = data->is_secure;
decryption_parameters.subsample_flags = data->subsample_flags;
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_, data->validate_key_id,
decryption_parameters));
EXPECT_TRUE(std::equal(data->decrypt_data.begin(), data->decrypt_data.end(),
decrypt_buffer.begin()));
decryptor_.CloseSession(session_id_);
std::string path;
EXPECT_TRUE(Properties::GetDeviceFilesBasePath(security_level, &path));
std::string usage_info_file_name =
path + DeviceFiles::GetUsageInfoFileName(app_id_empty);
// Read in usage info file
ssize_t file_size = file_system.FileSize(usage_info_file_name);
EXPECT_LT(4, file_size);
File* file =
file_system.Open(usage_info_file_name, FileSystem::kReadOnly);
EXPECT_TRUE(NULL != file);
std::string file_data;
file_data.resize(file_size);
ssize_t bytes = file->Read(&file_data[0], file_data.size());
EXPECT_EQ(file_size, bytes);
file->Close();
// Corrupt the hash of the usage info file and write it back out
memset(&file_data[0]+bytes-4, 0, 4);
file = file_system.Open(usage_info_file_name,
FileSystem::kCreate | FileSystem::kTruncate);
EXPECT_TRUE(NULL != file);
bytes = file->Write(file_data.data(), file_data.size());
EXPECT_EQ(file_size, bytes);
file->Close();
// Fetch a second usage license, this should fail as the usage table is
// corrupt
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
NULL, &session_id_);
GenerateKeyRequest(kUsageLicenseTestVector1[1].pssh, kLicenseTypeStreaming,
&property_set);
std::string response;
VerifyKeyRequestResponse(wvcdm::STORE_USAGE_INFO_ERROR, g_license_server,
g_client_auth, true, &response);
decryptor_.CloseSession(session_id_);
// Fetch the second usage license and verify that it is usable
decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier,
NULL, &session_id_);
GenerateKeyRequest(kUsageLicenseTestVector1[1].pssh, kLicenseTypeStreaming,
&property_set);
VerifyUsageKeyRequestResponse(g_license_server, g_client_auth);
data = kUsageLicenseTestVector1[1].sub_sample;
decrypt_buffer.resize(data->encrypt_data.size());
decryption_parameters.key_id = &data->key_id;
decryption_parameters.encrypt_buffer = &data->encrypt_data.front();
decryption_parameters.encrypt_length = data->encrypt_data.size();
decryption_parameters.iv = &data->iv;
decryption_parameters.block_offset = data->block_offset;
decryption_parameters.decrypt_buffer = &decrypt_buffer[0];
decryption_parameters.decrypt_buffer_length = data->encrypt_data.size();
decryption_parameters.is_encrypted = data->is_encrypted;
decryption_parameters.is_secure = data->is_secure;
decryption_parameters.subsample_flags = data->subsample_flags;
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_, data->validate_key_id,
decryption_parameters));
EXPECT_TRUE(std::equal(data->decrypt_data.begin(), data->decrypt_data.end(),
decrypt_buffer.begin()));
decryptor_.CloseSession(session_id_);
}
TEST_F(WvCdmRequestLicenseTest, UsageRemoveSecureStopTest) {
Unprovision();

View File

@@ -231,7 +231,6 @@ enum {
kUsageStoreLicenseFailed = ERROR_DRM_VENDOR_MIN + 241,
kUsageStoreUsageInfoFailed = ERROR_DRM_VENDOR_MIN + 242,
kUsageInvalidLoadEntry = ERROR_DRM_VENDOR_MIN + 243,
kRemoveAllUsageInfoError4 = ERROR_DRM_VENDOR_MIN + 244,
kRemoveAllUsageInfoError5 = ERROR_DRM_VENDOR_MIN + 245,
kReleaseUsageInfoFailed = ERROR_DRM_VENDOR_MIN + 246,
kIncorrectUsageSupportType1 = ERROR_DRM_VENDOR_MIN + 247,

View File

@@ -447,8 +447,6 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) {
return kIncorrectUsageSupportType1;
case wvcdm::INCORRECT_USAGE_SUPPORT_TYPE_2:
return kIncorrectUsageSupportType2;
case wvcdm::REMOVE_ALL_USAGE_INFO_ERROR_4:
return kRemoveAllUsageInfoError4;
case wvcdm::REMOVE_ALL_USAGE_INFO_ERROR_5:
return kRemoveAllUsageInfoError5;
case wvcdm::NO_USAGE_ENTRIES:

View File

@@ -264,7 +264,6 @@ static Status mapCdmResponseType(wvcdm::CdmResponseType res) {
case wvcdm::USAGE_STORE_LICENSE_FAILED:
case wvcdm::USAGE_STORE_USAGE_INFO_FAILED:
case wvcdm::USAGE_INVALID_LOAD_ENTRY:
case wvcdm::REMOVE_ALL_USAGE_INFO_ERROR_4:
case wvcdm::REMOVE_ALL_USAGE_INFO_ERROR_5:
case wvcdm::REMOVE_ALL_USAGE_INFO_ERROR_6:
case wvcdm::REMOVE_ALL_USAGE_INFO_ERROR_7: