Core CDM: Removed secure stop support.

[ Merge of http://go/wvgerrit/158721 ]

This CL removes support for secure stop / usage info sessions from the
CDM engine and CDM session.  APIs for related to secure stop
operations will return NOT_IMPLEMENTED_ERROR.

New secure stop licenses will be rejected by the CDM when added.

Bug: 242289743
Test: run_x86_64_tests request_license_test
Change-Id: I30cd47e580d63014e001c903382a28238746f6d4
This commit is contained in:
Alex Dale
2022-10-12 18:10:13 -07:00
parent f5fbfa6176
commit b039f31b27
6 changed files with 139 additions and 660 deletions

View File

@@ -78,10 +78,6 @@ 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.
@@ -91,7 +87,7 @@ CdmSession::CdmSession(wvutil::FileSystem* file_system,
}
CdmSession::~CdmSession() {
if (has_provider_session_token() && supports_usage_info() && !is_release_) {
if (HasUsageEntry() && !is_release_) {
UpdateUsageEntryInformation();
}
@@ -269,9 +265,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 (supports_usage_info()) {
if (SupportsUsageEntries()) {
std::string provider_session_token;
if (!license_parser_->ExtractProviderSessionToken(
key_response_, &provider_session_token)) {
provider_session_token.clear();
@@ -288,6 +284,7 @@ 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;
@@ -296,6 +293,10 @@ 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
@@ -332,7 +333,7 @@ CdmResponseType CdmSession::RestoreOfflineSession(const CdmKeySetId& key_set_id,
}
}
if (!provider_session_token.empty() && supports_usage_info()) {
if (HasUsageEntry()) {
CdmResponseType sts = usage_table_header_->UpdateEntry(
usage_entry_number_, crypto_session_.get(), &usage_entry_);
if (sts != NO_ERROR) {
@@ -340,74 +341,16 @@ CdmResponseType CdmSession::RestoreOfflineSession(const CdmKeySetId& key_set_id,
return sts;
}
if (!StoreLicense(license_data.state, error_detail)) {
LOGW("Unable to save updated usage info");
LOGW("Unable to save updated license");
}
}
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,
@@ -532,19 +475,21 @@ 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;
std::string provider_session_token;
if (supports_usage_info()) {
if (SupportsUsageEntries()) {
std::string provider_session_token;
if (license_parser_->ExtractProviderSessionToken(key_response,
&provider_session_token) &&
!provider_session_token.empty()) {
std::string app_id;
GetApplicationId(&app_id);
if (!is_offline_) {
LOGE("CDM does not support secure stop licenses");
return ADD_KEY_ERROR;
}
sts = usage_table_header_->AddEntry(
crypto_session_.get(), is_offline_, key_set_id_,
DeviceFiles::GetUsageInfoFileName(app_id), key_response,
&usage_entry_number_);
crypto_session_.get(), /* is_persistent */ true, key_set_id_,
/* usage_info_filename */ "", 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 =
@@ -557,13 +502,14 @@ CdmResponseType CdmSession::AddKeyInternal(const CdmKeyResponse& key_response) {
version_info.license_service_version());
// Update or invalidate entry if usage table header+entries are supported
if (!provider_session_token.empty() && supports_usage_info()) {
if (HasUsageEntry()) {
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));
@@ -580,15 +526,11 @@ CdmResponseType CdmSession::AddKeyInternal(const CdmKeyResponse& key_response) {
IdToString(license_parser_->provider_session_token()),
license_parser_->provider_session_token().size());
if ((is_offline_ || has_provider_session_token()) && !is_temporary_) {
if (has_provider_session_token() && supports_usage_info()) {
if (is_offline_ && !is_temporary_) {
if (HasUsageEntry()) {
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;
}
@@ -700,7 +642,7 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParametersV16& params) {
}
has_decrypted_since_last_report_ = true;
if (!is_usage_update_needed_) {
is_usage_update_needed_ = has_provider_session_token();
is_usage_update_needed_ = HasUsageEntry();
}
last_decrypt_failed_ = false;
} else {
@@ -786,7 +728,7 @@ CdmResponseType CdmSession::GenerateReleaseRequest(CdmKeyRequest* key_request) {
if (KEY_MESSAGE != status) return status;
if (has_provider_session_token() && supports_usage_info()) {
if (HasUsageEntry()) {
status = usage_table_header_->UpdateEntry(
usage_entry_number_, crypto_session_.get(), &usage_entry_);
@@ -799,10 +741,6 @@ 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;
@@ -833,7 +771,7 @@ CdmResponseType CdmSession::DeleteUsageEntry(uint32_t usage_entry_number) {
LOGE("CDM session not initialized");
return NOT_INITIALIZED_ERROR;
}
if (!supports_usage_info()) {
if (!SupportsUsageEntries()) {
LOGE("Cannot delete entry, usage table not supported");
return INCORRECT_USAGE_SUPPORT_TYPE_1;
}
@@ -862,6 +800,7 @@ 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;
}
@@ -908,54 +847,23 @@ bool CdmSession::GenerateKeySetId(bool atsc_mode_enabled,
}
CdmResponseType CdmSession::StoreLicense() {
if (is_temporary_) {
if (is_temporary_ || !is_offline_) {
LOGE("Session type prohibits storage");
return STORAGE_PROHIBITED;
}
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 (key_set_id_.empty()) {
LOGE("No key set ID");
return EMPTY_KEYSET_ID;
}
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 (!license_parser_->is_offline()) {
LOGE("License policy prohibits storage");
return OFFLINE_LICENSE_PROHIBITED;
}
return STORE_USAGE_INFO_ERROR;
if (!StoreLicense(kLicenseStateActive, nullptr)) {
LOGE("Unable to store license");
return STORE_LICENSE_ERROR_1;
}
return NO_ERROR;
}
@@ -999,8 +907,8 @@ CdmResponseType CdmSession::RemoveKeys() {
}
CdmResponseType CdmSession::RemoveLicense() {
if (is_offline_ || has_provider_session_token()) {
if (has_provider_session_token() && supports_usage_info()) {
if (is_offline_) {
if (HasUsageEntry()) {
DeleteUsageEntry(usage_entry_number_);
}
DeleteLicenseFile();
@@ -1009,17 +917,8 @@ CdmResponseType CdmSession::RemoveLicense() {
}
bool CdmSession::DeleteLicenseFile() {
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());
}
if (!is_offline_) return false;
return file_handle_->DeleteLicense(key_set_id_);
}
void CdmSession::NotifyResolution(uint32_t width, uint32_t height) {
@@ -1050,16 +949,14 @@ void CdmSession::GetApplicationId(std::string* app_id) {
}
CdmResponseType CdmSession::UpdateUsageEntryInformation() {
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");
if (!HasUsageEntry()) {
LOGE("Session does not have a usage entry");
return INCORRECT_USAGE_SUPPORT_TYPE_2;
}
CdmResponseType sts = NO_ERROR;
// TODO(blueeyes): Add measurements to all UpdateEntry calls in a way that
// allos us to isolate this particular use case within
// allows us to isolate this particular use case within
// UpdateUsageEntryInformation.
M_TIME(sts = usage_table_header_->UpdateEntry(
usage_entry_number_, crypto_session_.get(), &usage_entry_),
@@ -1067,11 +964,8 @@ CdmResponseType CdmSession::UpdateUsageEntryInformation() {
if (sts != NO_ERROR) return sts;
if (is_offline_)
StoreLicense(is_release_ ? kLicenseStateReleasing : kLicenseStateActive,
nullptr);
else if (!usage_provider_session_token_.empty())
UpdateUsageInfo();
StoreLicense(is_release_ ? kLicenseStateReleasing : kLicenseStateActive,
nullptr);
return NO_ERROR;
}
@@ -1138,23 +1032,6 @@ 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(