Revert "Core CDM: Removed secure stop support."

This reverts commit b039f31b27.

Reason for revert: Feature rejected by Android

Bug: 242289743
Change-Id: I8cd6014b4e2de93b3c574d407d6c8885863fed4f
This commit is contained in:
Alex Dale
2022-12-03 00:46:22 +00:00
committed by Android (Google) Code Review
parent b039f31b27
commit 16a4c2690a
6 changed files with 660 additions and 139 deletions

View File

@@ -78,6 +78,10 @@ CdmSession::CdmSession(wvutil::FileSystem* file_system,
is_temporary_(false),
security_level_(kSecurityLevelUninitialized),
requested_security_level_(kLevelDefault),
is_initial_usage_update_(true),
is_usage_update_needed_(false),
usage_table_header_(nullptr),
usage_entry_number_(0),
mock_license_parser_in_use_(false),
mock_policy_engine_in_use_(false) {
assert(metrics_); // metrics_ must not be null.
@@ -87,7 +91,7 @@ CdmSession::CdmSession(wvutil::FileSystem* file_system,
}
CdmSession::~CdmSession() {
if (HasUsageEntry() && !is_release_) {
if (has_provider_session_token() && supports_usage_info() && !is_release_) {
UpdateUsageEntryInformation();
}
@@ -265,9 +269,9 @@ CdmResponseType CdmSession::RestoreOfflineSession(const CdmKeySetId& key_set_id,
return GET_RELEASED_LICENSE_ERROR;
}
std::string provider_session_token;
bool sign_fake_request = false; // TODO(b/169483174): remove this variable.
if (SupportsUsageEntries()) {
std::string provider_session_token;
if (supports_usage_info()) {
if (!license_parser_->ExtractProviderSessionToken(
key_response_, &provider_session_token)) {
provider_session_token.clear();
@@ -284,7 +288,6 @@ CdmResponseType CdmSession::RestoreOfflineSession(const CdmKeySetId& key_set_id,
IdToString(key_set_id));
return USAGE_ENTRY_ALREADY_LOADED;
}
provider_session_token_ = std::move(provider_session_token);
if (sts != NO_ERROR) {
LOGE("Failed to load usage entry: status = %d", static_cast<int>(sts));
return sts;
@@ -293,10 +296,6 @@ CdmResponseType CdmSession::RestoreOfflineSession(const CdmKeySetId& key_set_id,
} else {
sign_fake_request = true; // TODO(b/169483174): remove this block.
}
// Must be set before updating the usage entry. CdmLicense will attempt
// to update the usage info when restoring.
is_offline_ = true;
// TODO(b/169483174): remove this code in v17. For OEMCrypto v16, an offline
// license would not work because the rental clock in OEMCrypto is only
// started when the license request is signed. We will sign a fake license
@@ -333,7 +332,7 @@ CdmResponseType CdmSession::RestoreOfflineSession(const CdmKeySetId& key_set_id,
}
}
if (HasUsageEntry()) {
if (!provider_session_token.empty() && supports_usage_info()) {
CdmResponseType sts = usage_table_header_->UpdateEntry(
usage_entry_number_, crypto_session_.get(), &usage_entry_);
if (sts != NO_ERROR) {
@@ -341,16 +340,74 @@ CdmResponseType CdmSession::RestoreOfflineSession(const CdmKeySetId& key_set_id,
return sts;
}
if (!StoreLicense(license_data.state, error_detail)) {
LOGW("Unable to save updated license");
LOGW("Unable to save updated usage info");
}
}
license_received_ = true;
is_offline_ = true;
is_release_ = license_type == kLicenseTypeRelease;
has_license_been_restored_ = true;
return KEY_ADDED;
}
CdmResponseType CdmSession::RestoreUsageSession(
const DeviceFiles::CdmUsageData& usage_data, int* error_detail) {
if (!initialized_) {
LOGE("CDM session not initialized");
return NOT_INITIALIZED_ERROR;
}
if (!key_set_id_.empty()) {
file_handle_->UnreserveLicenseId(key_set_id_);
}
key_set_id_ = usage_data.key_set_id;
key_request_ = usage_data.license_request;
key_response_ = usage_data.license;
usage_entry_ = usage_data.usage_entry;
usage_entry_number_ = usage_data.usage_entry_number;
usage_provider_session_token_ = usage_data.provider_session_token;
CdmResponseType status = LoadPrivateOrLegacyKey(
usage_data.drm_certificate, usage_data.wrapped_private_key);
if (status != NO_ERROR) return status;
CdmResponseType sts = NO_ERROR;
if (supports_usage_info()) {
sts = usage_table_header_->LoadEntry(crypto_session_.get(), usage_entry_,
usage_entry_number_);
crypto_metrics_->usage_table_header_load_entry_.Increment(sts);
if (sts != NO_ERROR) {
LOGE("Failed to load usage entry: status = %d", static_cast<int>(sts));
return sts;
}
}
sts = license_parser_->RestoreLicenseForRelease(usage_data.drm_certificate,
key_request_, key_response_);
if (sts != NO_ERROR) {
SetErrorDetail(error_detail, sts);
return RELEASE_LICENSE_ERROR_2;
}
if (supports_usage_info()) {
sts = usage_table_header_->UpdateEntry(
usage_entry_number_, crypto_session_.get(), &usage_entry_);
if (sts != NO_ERROR) {
LOGE("Failed to update usage entry: status = %d", static_cast<int>(sts));
return sts;
}
if (!UpdateUsageInfo()) {
LOGW("Unable to save updated usage info");
}
}
license_received_ = true;
is_offline_ = false;
is_release_ = true;
return KEY_ADDED;
}
// This is a thin wrapper that initiates the latency metric.
CdmResponseType CdmSession::GenerateKeyRequest(
const InitializationData& init_data, CdmLicenseType license_type,
@@ -475,21 +532,19 @@ CdmResponseType CdmSession::AddKeyInternal(const CdmKeyResponse& key_response) {
// to see if it has a provider session token. If so a new entry needs
// to be created.
CdmResponseType sts;
if (SupportsUsageEntries()) {
std::string provider_session_token;
std::string provider_session_token;
if (supports_usage_info()) {
if (license_parser_->ExtractProviderSessionToken(key_response,
&provider_session_token) &&
!provider_session_token.empty()) {
if (!is_offline_) {
LOGE("CDM does not support secure stop licenses");
return ADD_KEY_ERROR;
}
std::string app_id;
GetApplicationId(&app_id);
sts = usage_table_header_->AddEntry(
crypto_session_.get(), /* is_persistent */ true, key_set_id_,
/* usage_info_filename */ "", key_response, &usage_entry_number_);
crypto_session_.get(), is_offline_, key_set_id_,
DeviceFiles::GetUsageInfoFileName(app_id), key_response,
&usage_entry_number_);
crypto_metrics_->usage_table_header_add_entry_.Increment(sts);
if (sts != NO_ERROR) return sts;
provider_session_token_ = std::move(provider_session_token);
}
}
sts =
@@ -502,14 +557,13 @@ CdmResponseType CdmSession::AddKeyInternal(const CdmKeyResponse& key_response) {
version_info.license_service_version());
// Update or invalidate entry if usage table header+entries are supported
if (HasUsageEntry()) {
if (!provider_session_token.empty() && supports_usage_info()) {
if (sts != KEY_ADDED) {
const CdmResponseType invalidate_sts =
usage_table_header_->InvalidateEntry(
usage_entry_number_, true, file_handle_.get(), crypto_metrics_);
crypto_metrics_->usage_table_header_delete_entry_.Increment(
invalidate_sts);
provider_session_token_.clear();
if (invalidate_sts != NO_ERROR) {
LOGW("Invalidate usage entry failed: status = %d",
static_cast<int>(invalidate_sts));
@@ -526,11 +580,15 @@ CdmResponseType CdmSession::AddKeyInternal(const CdmKeyResponse& key_response) {
IdToString(license_parser_->provider_session_token()),
license_parser_->provider_session_token().size());
if (is_offline_ && !is_temporary_) {
if (HasUsageEntry()) {
if ((is_offline_ || has_provider_session_token()) && !is_temporary_) {
if (has_provider_session_token() && supports_usage_info()) {
usage_table_header_->UpdateEntry(usage_entry_number_,
crypto_session_.get(), &usage_entry_);
}
if (!is_offline_)
usage_provider_session_token_ = license_parser_->provider_session_token();
sts = StoreLicense();
if (sts != NO_ERROR) return sts;
}
@@ -642,7 +700,7 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParametersV16& params) {
}
has_decrypted_since_last_report_ = true;
if (!is_usage_update_needed_) {
is_usage_update_needed_ = HasUsageEntry();
is_usage_update_needed_ = has_provider_session_token();
}
last_decrypt_failed_ = false;
} else {
@@ -728,7 +786,7 @@ CdmResponseType CdmSession::GenerateReleaseRequest(CdmKeyRequest* key_request) {
if (KEY_MESSAGE != status) return status;
if (HasUsageEntry()) {
if (has_provider_session_token() && supports_usage_info()) {
status = usage_table_header_->UpdateEntry(
usage_entry_number_, crypto_session_.get(), &usage_entry_);
@@ -741,6 +799,10 @@ CdmResponseType CdmSession::GenerateReleaseRequest(CdmKeyRequest* key_request) {
if (is_offline_) { // Mark license as being released
if (!StoreLicense(kLicenseStateReleasing, nullptr))
return RELEASE_KEY_REQUEST_ERROR;
} else if (!usage_provider_session_token_.empty()) {
if (supports_usage_info()) {
if (!UpdateUsageInfo()) return RELEASE_USAGE_INFO_FAILED;
}
}
key_request_type_ = key_request->type;
@@ -771,7 +833,7 @@ CdmResponseType CdmSession::DeleteUsageEntry(uint32_t usage_entry_number) {
LOGE("CDM session not initialized");
return NOT_INITIALIZED_ERROR;
}
if (!SupportsUsageEntries()) {
if (!supports_usage_info()) {
LOGE("Cannot delete entry, usage table not supported");
return INCORRECT_USAGE_SUPPORT_TYPE_1;
}
@@ -800,7 +862,6 @@ CdmResponseType CdmSession::DeleteUsageEntry(uint32_t usage_entry_number) {
sts = usage_table_header_->InvalidateEntry(
usage_entry_number, true, file_handle_.get(), crypto_metrics_);
crypto_metrics_->usage_table_header_delete_entry_.Increment(sts);
provider_session_token_.clear();
return sts;
}
@@ -847,23 +908,54 @@ bool CdmSession::GenerateKeySetId(bool atsc_mode_enabled,
}
CdmResponseType CdmSession::StoreLicense() {
if (is_temporary_ || !is_offline_) {
if (is_temporary_) {
LOGE("Session type prohibits storage");
return STORAGE_PROHIBITED;
}
if (key_set_id_.empty()) {
LOGE("No key set ID");
return EMPTY_KEYSET_ID;
if (is_offline_) {
if (key_set_id_.empty()) {
LOGE("No key set ID");
return EMPTY_KEYSET_ID;
}
if (!license_parser_->is_offline()) {
LOGE("License policy prohibits storage");
return OFFLINE_LICENSE_PROHIBITED;
}
if (!StoreLicense(kLicenseStateActive, nullptr)) {
LOGE("Unable to store license");
return STORE_LICENSE_ERROR_1;
}
return NO_ERROR;
} // if (is_offline_)
std::string provider_session_token =
license_parser_->provider_session_token();
if (provider_session_token.empty()) {
LOGE("No provider session token and not offline");
return STORE_LICENSE_ERROR_2;
}
if (!license_parser_->is_offline()) {
LOGE("License policy prohibits storage");
return OFFLINE_LICENSE_PROHIBITED;
}
std::string app_id;
GetApplicationId(&app_id);
if (!file_handle_->StoreUsageInfo(
provider_session_token, key_request_, key_response_,
DeviceFiles::GetUsageInfoFileName(app_id), key_set_id_, usage_entry_,
usage_entry_number_, drm_certificate_, wrapped_private_key_)) {
LOGE("Unable to store usage info");
// Usage info file is corrupt. Delete current usage entry and file.
if (supports_usage_info()) {
DeleteUsageEntry(usage_entry_number_);
} else {
LOGW("Cannot store, usage table not supported");
}
std::vector<std::string> provider_session_tokens;
file_handle_->DeleteAllUsageInfoForApp(
DeviceFiles::GetUsageInfoFileName(app_id), &provider_session_tokens);
if (!StoreLicense(kLicenseStateActive, nullptr)) {
LOGE("Unable to store license");
return STORE_LICENSE_ERROR_1;
return STORE_USAGE_INFO_ERROR;
}
return NO_ERROR;
}
@@ -907,8 +999,8 @@ CdmResponseType CdmSession::RemoveKeys() {
}
CdmResponseType CdmSession::RemoveLicense() {
if (is_offline_) {
if (HasUsageEntry()) {
if (is_offline_ || has_provider_session_token()) {
if (has_provider_session_token() && supports_usage_info()) {
DeleteUsageEntry(usage_entry_number_);
}
DeleteLicenseFile();
@@ -917,8 +1009,17 @@ CdmResponseType CdmSession::RemoveLicense() {
}
bool CdmSession::DeleteLicenseFile() {
if (!is_offline_) return false;
return file_handle_->DeleteLicense(key_set_id_);
if (!is_offline_ && !has_provider_session_token()) return false;
if (is_offline_) {
return file_handle_->DeleteLicense(key_set_id_);
} else {
std::string app_id;
GetApplicationId(&app_id);
return file_handle_->DeleteUsageInfo(
DeviceFiles::GetUsageInfoFileName(app_id),
license_parser_->provider_session_token());
}
}
void CdmSession::NotifyResolution(uint32_t width, uint32_t height) {
@@ -949,14 +1050,16 @@ void CdmSession::GetApplicationId(std::string* app_id) {
}
CdmResponseType CdmSession::UpdateUsageEntryInformation() {
if (!HasUsageEntry()) {
LOGE("Session does not have a usage entry");
if (!has_provider_session_token() || !supports_usage_info()) {
LOGE("Unexpected state: usage_support = %s, PST present = %s, ",
supports_usage_info() ? "true" : "false",
has_provider_session_token() ? "yes" : "no");
return INCORRECT_USAGE_SUPPORT_TYPE_2;
}
CdmResponseType sts = NO_ERROR;
// TODO(blueeyes): Add measurements to all UpdateEntry calls in a way that
// allows us to isolate this particular use case within
// allos us to isolate this particular use case within
// UpdateUsageEntryInformation.
M_TIME(sts = usage_table_header_->UpdateEntry(
usage_entry_number_, crypto_session_.get(), &usage_entry_),
@@ -964,8 +1067,11 @@ CdmResponseType CdmSession::UpdateUsageEntryInformation() {
if (sts != NO_ERROR) return sts;
StoreLicense(is_release_ ? kLicenseStateReleasing : kLicenseStateActive,
nullptr);
if (is_offline_)
StoreLicense(is_release_ ? kLicenseStateReleasing : kLicenseStateActive,
nullptr);
else if (!usage_provider_session_token_.empty())
UpdateUsageInfo();
return NO_ERROR;
}
@@ -1032,6 +1138,23 @@ CdmResponseType CdmSession::GetDecryptHashError(std::string* error_string) {
return crypto_session_->GetDecryptHashError(error_string);
}
bool CdmSession::UpdateUsageInfo() {
std::string app_id;
GetApplicationId(&app_id);
DeviceFiles::CdmUsageData usage_data;
usage_data.provider_session_token = usage_provider_session_token_;
usage_data.license_request = key_request_;
usage_data.license = key_response_;
usage_data.key_set_id = key_set_id_;
usage_data.usage_entry = usage_entry_;
usage_data.usage_entry_number = usage_entry_number_;
return file_handle_->UpdateUsageInfo(
DeviceFiles::GetUsageInfoFileName(app_id), usage_provider_session_token_,
usage_data);
}
void CdmSession::UpdateRequestLatencyTiming(CdmResponseType sts) {
if (sts == KEY_ADDED && license_request_latency_.IsStarted()) {
metrics_->cdm_session_license_request_latency_ms_.Record(