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

@@ -31,8 +31,8 @@
namespace wvcdm {
namespace {
const uint64_t kReleaseSessionTimeToLive = 60; // seconds
const uint32_t kUpdateUsageInformationPeriod = 60; // seconds
constexpr uint64_t kReleaseSessionTimeToLive = 60; // seconds
constexpr uint32_t kUpdateUsageInfoPeriod = 60; // seconds
} // namespace
class UsagePropertySet : public CdmClientPropertySet {
@@ -67,16 +67,12 @@ CdmEngine::CdmEngine(wvutil::FileSystem* file_system,
: metrics_(metrics),
cert_provisioning_(),
file_system_(file_system),
spoid_(EMPTY_SPOID),
usage_session_(),
usage_property_set_(),
last_usage_information_update_time_(0) {
spoid_(EMPTY_SPOID) {
assert(file_system);
Properties::Init();
}
CdmEngine::~CdmEngine() {
usage_session_.reset();
std::unique_lock<std::recursive_mutex> lock(session_map_lock_);
session_map_.Terminate();
}
@@ -415,8 +411,7 @@ CdmResponseType CdmEngine::AddKey(const CdmSessionId& session_id,
}
if (key_set_id != nullptr) {
if ((session->is_offline() || session->has_provider_session_token()) &&
!license_type_release) {
if ((session->is_offline()) && !license_type_release) {
*key_set_id = session->key_set_id();
LOGI("key_set_id = %s", IdPtrToString(key_set_id));
} else {
@@ -1284,50 +1279,21 @@ CdmResponseType CdmEngine::ListStoredLicenses(
CdmResponseType CdmEngine::ListUsageIds(
const std::string& app_id, CdmSecurityLevel security_level,
std::vector<std::string>* ksids,
std::vector<std::string>* provider_session_tokens) {
if (!ksids && !provider_session_tokens) {
LOGE("Outputs |ksids| and |provider_session_tokens| are null");
return INVALID_PARAMETERS_ENG_23;
}
if (security_level == kSecurityLevelL1 && OkpIsInFallbackMode()) {
LOGD("OKP fallback to L3");
security_level = kSecurityLevelL3;
}
DeviceFiles handle(file_system_);
if (!handle.Init(security_level)) {
LOGE("Unable to initialize device files");
return LIST_USAGE_ERROR_1;
}
if (!handle.ListUsageIds(app_id, ksids, provider_session_tokens)) {
LOGE("Failed: app_id = %s, security_level = %s", IdToString(app_id),
CdmSecurityLevelToString(security_level));
return LIST_USAGE_ERROR_2;
}
return NO_ERROR;
std::vector<std::string>* /* ksids */,
std::vector<std::string>* /* provider_session_tokens */) {
LOGI("app_id = %s, security_level = %s", IdToString(app_id),
CdmSecurityLevelToString(security_level));
LOGW("API not supported");
return NOT_IMPLEMENTED_ERROR;
}
CdmResponseType CdmEngine::DeleteUsageRecord(const std::string& app_id,
CdmSecurityLevel security_level,
const std::string& key_set_id) {
LOGI("app_id = %s, key_set_id = %s", IdToString(app_id),
IdToString(key_set_id));
if (security_level == kSecurityLevelL1 && OkpIsInFallbackMode()) {
LOGD("OKP fallback to L3");
security_level = kSecurityLevelL3;
}
DeviceFiles handle(file_system_);
if (!handle.Init(security_level)) {
LOGE("Unable to initialize device files");
return DELETE_USAGE_ERROR_1;
}
std::string provider_session_token;
if (!handle.GetProviderSessionToken(app_id, key_set_id,
&provider_session_token)) {
LOGE("GetProviderSessionToken failed");
return DELETE_USAGE_ERROR_2;
}
return RemoveUsageInfo(app_id, provider_session_token);
LOGI("app_id = %s, security_level = %s, key_set_id = %s", IdToString(app_id),
CdmSecurityLevelToString(security_level), IdToString(key_set_id));
LOGW("API not supported");
return NOT_IMPLEMENTED_ERROR;
}
CdmResponseType CdmEngine::GetOfflineLicenseState(
@@ -1397,7 +1363,7 @@ CdmResponseType CdmEngine::RemoveOfflineLicense(
}
} else if (sts == LICENSE_USAGE_ENTRY_MISSING) {
// It is possible that the CDM is tracking a key set ID, but has
// removed the usage information associated with it. In this case,
// removed the usage entry associated with it. In this case,
// it will no longer be possible to load the license for release;
// and the file should simply be deleted.
LOGW("License usage entry is missing, deleting license file");
@@ -1415,415 +1381,66 @@ CdmResponseType CdmEngine::RemoveOfflineLicense(
CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
const CdmSecureStopId& ssid,
int* error_detail,
CdmUsageInfo* usage_info) {
// Try to find usage info at the default security level. If the
// security level is unprovisioned or we are unable to find it,
// try L3.
CdmResponseType status =
GetUsageInfo(app_id, ssid, kLevelDefault, error_detail, usage_info);
switch (status) {
case NEED_PROVISIONING:
case GET_USAGE_INFO_ERROR_1:
case GET_USAGE_INFO_ERROR_2:
case USAGE_INFO_NOT_FOUND:
status = GetUsageInfo(app_id, ssid, kLevel3, error_detail, usage_info);
return status;
default:
return status;
}
int* /* error_detail */,
CdmUsageInfo* /* usage_info */) {
LOGI("app_id = %s, ssid = %s", IdToString(app_id), IdToString(ssid));
LOGE("API not supported");
return NOT_IMPLEMENTED_ERROR;
}
CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
const CdmSecureStopId& ssid,
RequestedSecurityLevel security_level,
int* error_detail,
CdmUsageInfo* usage_info) {
LOGI("app_id = %s, ssid = %s", IdToString(app_id), IdToString(ssid));
if (!usage_property_set_) {
usage_property_set_.reset(new UsagePropertySet());
}
if (usage_info == nullptr) {
LOGE("Output |usage_info| is null");
return PARAMETER_NULL;
}
usage_property_set_->set_security_level(security_level);
usage_property_set_->set_app_id(app_id);
usage_session_.reset(new CdmSession(file_system_, metrics_->AddSession()));
CdmResponseType status = usage_session_->Init(usage_property_set_.get());
if (NO_ERROR != status) {
LOGE("Session init error: status = %d", static_cast<int>(status));
return status;
}
DeviceFiles handle(file_system_);
if (!handle.Init(usage_session_->GetSecurityLevel())) {
LOGE("Device file init error");
return GET_USAGE_INFO_ERROR_1;
}
DeviceFiles::CdmUsageData usage_data;
if (!handle.RetrieveUsageInfo(DeviceFiles::GetUsageInfoFileName(app_id), ssid,
&usage_data)) {
usage_property_set_->set_security_level(kLevel3);
usage_property_set_->set_app_id(app_id);
usage_session_.reset(new CdmSession(file_system_, metrics_->AddSession()));
status = usage_session_->Init(usage_property_set_.get());
if (NO_ERROR != status) {
LOGE("Session init error: status = %d", static_cast<int>(status));
return status;
}
if (!handle.Reset(usage_session_->GetSecurityLevel())) {
LOGE("Device file init error");
return GET_USAGE_INFO_ERROR_2;
}
if (!handle.RetrieveUsageInfo(DeviceFiles::GetUsageInfoFileName(app_id),
ssid, &usage_data)) {
// No entry found for that ssid.
return USAGE_INFO_NOT_FOUND;
}
}
status = usage_session_->RestoreUsageSession(usage_data, error_detail);
if (KEY_ADDED != status) {
LOGE("RestoreUsageSession failed: status = %d", static_cast<int>(status));
usage_info->clear();
return status;
}
CdmKeyRequest request;
status = usage_session_->GenerateReleaseRequest(&request);
usage_info->clear();
usage_info->push_back(request.message);
if (KEY_MESSAGE != status) {
LOGE("GenerateReleaseRequest failed: status = %d",
static_cast<int>(status));
usage_info->clear();
return status;
}
return KEY_MESSAGE;
int* /* error_detail */,
CdmUsageInfo* /* usage_info */) {
LOGI("app_id = %s, ssid = %s, security_level = %s", IdToString(app_id),
IdToString(ssid), RequestedSecurityLevelToString(security_level));
LOGE("API not supported");
return NOT_IMPLEMENTED_ERROR;
}
CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
int* error_detail,
CdmUsageInfo* usage_info) {
int* /* error_detail */,
CdmUsageInfo* /* usage_info */) {
LOGI("app_id = %s", IdToString(app_id));
if (usage_info == nullptr) {
LOGE("Output |usage_info| is null");
return PARAMETER_NULL;
}
// Return a random usage report from a random security level
RequestedSecurityLevel security_level =
wvutil::CdmRandom::RandomBool() ? kLevelDefault : kLevel3;
CdmResponseType status = UNKNOWN_ERROR;
do {
status = GetUsageInfo(app_id, security_level, error_detail, usage_info);
if (KEY_MESSAGE == status && !usage_info->empty()) {
return status;
}
} while (KEY_CANCELED == status);
security_level = (kLevel3 == security_level) ? kLevelDefault : kLevel3;
do {
status = GetUsageInfo(app_id, security_level, error_detail, usage_info);
if (NEED_PROVISIONING == status)
return NO_ERROR; // Valid scenario that one of the security
// levels has not been provisioned
} while (KEY_CANCELED == status);
return status;
}
CdmResponseType CdmEngine::GetUsageInfo(
const std::string& app_id, RequestedSecurityLevel requested_security_level,
int* error_detail, CdmUsageInfo* usage_info) {
LOGI("app_id = %s, security_level = %s", IdToString(app_id),
RequestedSecurityLevelToString(requested_security_level));
if (usage_info == nullptr) {
LOGE("Output |usage_info| is null");
return PARAMETER_NULL;
}
if (requested_security_level == kLevelDefault && OkpIsInFallbackMode()) {
LOGD("OKP fallback to L3");
requested_security_level = kLevel3;
}
if (!usage_property_set_) {
usage_property_set_.reset(new UsagePropertySet());
}
usage_property_set_->set_security_level(requested_security_level);
usage_property_set_->set_app_id(app_id);
usage_session_.reset(new CdmSession(file_system_, metrics_->AddSession()));
CdmResponseType status = usage_session_->Init(usage_property_set_.get());
if (NO_ERROR != status) {
LOGE("Session init error");
return status;
}
DeviceFiles handle(file_system_);
if (!handle.Init(usage_session_->GetSecurityLevel())) {
LOGE("Unable to initialize device files");
return GET_USAGE_INFO_ERROR_3;
}
std::vector<DeviceFiles::CdmUsageData> usage_data;
if (!handle.RetrieveUsageInfo(DeviceFiles::GetUsageInfoFileName(app_id),
&usage_data)) {
LOGE("Unable to read usage information");
return GET_USAGE_INFO_ERROR_4;
}
if (usage_data.empty()) {
usage_info->clear();
return NO_ERROR;
}
const size_t index = wvutil::CdmRandom::RandomInRange(usage_data.size() - 1);
status = usage_session_->RestoreUsageSession(usage_data[index], error_detail);
if (KEY_ADDED != status) {
// TODO(b/141704872): Make multiple attempts.
LOGE("RestoreUsageSession failed: index = %zu, status = %d", index,
static_cast<int>(status));
usage_info->clear();
return status;
}
CdmKeyRequest request;
status = usage_session_->GenerateReleaseRequest(&request);
usage_info->clear();
usage_info->push_back(request.message);
switch (status) {
case KEY_MESSAGE:
break;
case KEY_CANCELED: // usage information not present in
usage_session_->DeleteLicenseFile(); // OEMCrypto, delete and try again
usage_info->clear();
break;
default:
LOGE("GenerateReleaseRequest failed: status = %d",
static_cast<int>(status));
usage_info->clear();
break;
}
return status;
LOGE("API not supported");
return NOT_IMPLEMENTED_ERROR;
}
CdmResponseType CdmEngine::RemoveAllUsageInfo(
const std::string& app_id, CdmSecurityLevel cdm_security_level) {
LOGI("app_id = %s, security_level = %s", IdToString(app_id),
CdmSecurityLevelToString(cdm_security_level));
if (!usage_property_set_) {
usage_property_set_.reset(new UsagePropertySet());
}
usage_property_set_->set_app_id(app_id);
CdmResponseType status = NO_ERROR;
DeviceFiles handle(file_system_);
if (handle.Init(cdm_security_level)) {
const RequestedSecurityLevel security_level =
cdm_security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault;
usage_property_set_->set_security_level(security_level);
usage_session_.reset(new CdmSession(file_system_, metrics_->AddSession()));
usage_session_->Init(usage_property_set_.get());
if (usage_session_->supports_usage_info()) {
std::vector<DeviceFiles::CdmUsageData> usage_data;
// Retrieve all usage information but delete only one before
// refetching. This is because deleting the usage entry
// might cause other entries to be shifted and information updated.
do {
if (!handle.RetrieveUsageInfo(DeviceFiles::GetUsageInfoFileName(app_id),
&usage_data)) {
LOGW("Failed to retrieve usage info");
break;
}
if (usage_data.empty()) break;
CdmResponseType res =
usage_session_->DeleteUsageEntry(usage_data[0].usage_entry_number);
if (res != NO_ERROR) {
LOGW("Failed to delete usage entry: status = %d",
static_cast<int>(res));
break;
}
if (!handle.DeleteUsageInfo(DeviceFiles::GetUsageInfoFileName(app_id),
usage_data[0].provider_session_token)) {
LOGW("Failed to delete usage info");
break;
}
} while (!usage_data.empty());
std::vector<std::string> provider_session_tokens;
if (!handle.DeleteAllUsageInfoForApp(
DeviceFiles::GetUsageInfoFileName(app_id),
&provider_session_tokens)) {
status = REMOVE_ALL_USAGE_INFO_ERROR_5;
}
}
}
usage_session_.reset();
return status;
LOGE("API not supported");
return NOT_IMPLEMENTED_ERROR;
}
CdmResponseType CdmEngine::RemoveAllUsageInfo(const std::string& app_id) {
LOGI("app_id = %s", IdToString(app_id));
const CdmResponseType status_l1 =
RemoveAllUsageInfo(app_id, kSecurityLevelL1);
const CdmResponseType status_l3 =
RemoveAllUsageInfo(app_id, kSecurityLevelL3);
// Prioritizing L1 status.
if (status_l1 != NO_ERROR) {
return status_l1;
}
return status_l3;
LOGE("API not supported");
return NOT_IMPLEMENTED_ERROR;
}
CdmResponseType CdmEngine::RemoveUsageInfo(
const std::string& app_id, const CdmSecureStopId& provider_session_token) {
LOGI("app_id = %s, pst = %s", IdToString(app_id),
IdToString(provider_session_token));
if (!usage_property_set_) {
usage_property_set_.reset(new UsagePropertySet());
}
usage_property_set_->set_app_id(app_id);
CdmResponseType status = NO_ERROR;
for (int j = kSecurityLevelL1; j < kSecurityLevelUnknown; ++j) {
DeviceFiles handle(file_system_);
if (handle.Init(static_cast<CdmSecurityLevel>(j))) {
RequestedSecurityLevel security_level =
static_cast<CdmSecurityLevel>(j) == kSecurityLevelL3 ? kLevel3
: kLevelDefault;
usage_property_set_->set_security_level(security_level);
usage_session_.reset(
new CdmSession(file_system_, metrics_->AddSession()));
usage_session_->Init(usage_property_set_.get());
CdmKeyMessage license_request;
CdmKeyResponse license_response;
CdmUsageEntry usage_entry;
uint32_t usage_entry_number;
std::string drm_certificate;
CryptoWrappedKey wrapped_private_key;
if (!handle.RetrieveUsageInfo(
DeviceFiles::GetUsageInfoFileName(app_id), provider_session_token,
&license_request, &license_response, &usage_entry,
&usage_entry_number, &drm_certificate, &wrapped_private_key)) {
// Try other security level
continue;
}
if (usage_session_->supports_usage_info()) {
status = usage_session_->DeleteUsageEntry(usage_entry_number);
if (!handle.DeleteUsageInfo(DeviceFiles::GetUsageInfoFileName(app_id),
provider_session_token)) {
status = REMOVE_USAGE_INFO_ERROR_1;
}
usage_session_.reset();
return status;
}
} else {
LOGE("Failed to initialize L%d device files", j);
status = REMOVE_USAGE_INFO_ERROR_2;
}
}
usage_session_.reset();
return REMOVE_USAGE_INFO_ERROR_3;
LOGE("API not supported");
return NOT_IMPLEMENTED_ERROR;
}
CdmResponseType CdmEngine::ReleaseUsageInfo(
const CdmUsageInfoReleaseMessage& message) {
LOGI("message_size = %zu", message.size());
if (!usage_session_) {
LOGE("Usage session not initialized");
return RELEASE_USAGE_INFO_ERROR;
}
const CdmResponseType status = usage_session_->ReleaseKey(message);
usage_session_.reset();
if (NO_ERROR != status) {
LOGE("ReleaseKey failed: status = %d", status);
}
return status;
LOGE("API not supported");
return NOT_IMPLEMENTED_ERROR;
}
CdmResponseType CdmEngine::LoadUsageSession(const CdmKeySetId& key_set_id,
CdmKeyMessage* release_message) {
CdmResponseType CdmEngine::LoadUsageSession(
const CdmKeySetId& key_set_id, CdmKeyMessage* /* release_message */) {
LOGI("key_set_id = %s", IdToString(key_set_id));
// 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("Invalid key set ID");
return EMPTY_KEYSET_ID_ENG_5;
}
if (release_message == nullptr) {
LOGE("Output |release_message| is null");
return PARAMETER_NULL;
}
std::shared_ptr<CdmSession> session;
if (!session_map_.FindSession(key_set_id, &session)) {
LOGE("Session not found: key_set_id = %s", IdToString(key_set_id));
return SESSION_NOT_FOUND_11;
}
DeviceFiles handle(file_system_);
if (!handle.Init(session->GetSecurityLevel())) {
LOGE("Unable to initialize device files");
return LOAD_USAGE_INFO_FILE_ERROR;
}
std::string app_id;
session->GetApplicationId(&app_id);
DeviceFiles::CdmUsageData usage_data;
if (!handle.RetrieveUsageInfoByKeySetId(
DeviceFiles::GetUsageInfoFileName(app_id), key_set_id,
&(usage_data.provider_session_token), &(usage_data.license_request),
&(usage_data.license), &(usage_data.usage_entry),
&(usage_data.usage_entry_number), &(usage_data.drm_certificate),
&(usage_data.wrapped_private_key))) {
LOGE("Unable to find usage information");
return LOAD_USAGE_INFO_MISSING;
}
int error_detail = NO_ERROR;
usage_data.key_set_id = key_set_id;
CdmResponseType status =
session->RestoreUsageSession(usage_data, &error_detail);
session->GetMetrics()->cdm_session_restore_usage_session_.Increment(
status, error_detail);
if (KEY_ADDED != status) {
LOGE("Restore failed: key_set_id = %s, status = %d", IdToString(key_set_id),
static_cast<int>(status));
return status;
}
CdmKeyRequest request;
status = session->GenerateReleaseRequest(&request);
*release_message = std::move(request.message);
switch (status) {
case KEY_MESSAGE:
break;
case KEY_CANCELED:
// usage information not present in OEMCrypto, delete and try again
session->DeleteLicenseFile();
break;
default:
LOGE("GenerateReleaseRequest failed: status = %d",
static_cast<int>(status));
break;
}
return status;
LOGE("API not supported");
return NOT_IMPLEMENTED_ERROR;
}
CdmResponseType CdmEngine::DecryptV16(
@@ -2072,6 +1689,7 @@ bool CdmEngine::FindSessionForKey(const KeyId& key_id,
bool CdmEngine::NotifyResolution(const CdmSessionId& session_id, uint32_t width,
uint32_t height) {
std::unique_lock<std::recursive_mutex> lock(session_map_lock_);
std::shared_ptr<CdmSession> session;
if (session_map_.FindSession(session_id, &session)) {
session->NotifyResolution(width, height);
@@ -2088,10 +1706,9 @@ void CdmEngine::OnTimerEvent() {
wvutil::Clock clock;
const uint64_t current_time = clock.GetCurrentTime();
bool usage_update_period_expired = false;
if (current_time - last_usage_information_update_time_ >
kUpdateUsageInformationPeriod) {
if (current_time - last_usage_info_update_time_ > kUpdateUsageInfoPeriod) {
usage_update_period_expired = true;
last_usage_information_update_time_ = current_time;
last_usage_info_update_time_ = current_time;
}
bool is_initial_usage_update = false;
@@ -2101,27 +1718,24 @@ void CdmEngine::OnTimerEvent() {
CdmSessionList sessions;
session_map_.GetSessionList(sessions);
while (!sessions.empty()) {
is_initial_usage_update = is_initial_usage_update ||
sessions.front()->is_initial_usage_update();
for (auto& session : sessions) {
is_initial_usage_update =
is_initial_usage_update || session->is_initial_usage_update();
is_usage_update_needed =
is_usage_update_needed || sessions.front()->is_usage_update_needed();
sessions.front()->OnTimerEvent(usage_update_period_expired);
sessions.pop_front();
is_usage_update_needed || session->is_usage_update_needed();
session->OnTimerEvent(usage_update_period_expired);
}
if (is_usage_update_needed &&
(usage_update_period_expired || is_initial_usage_update)) {
// Session list may have changed. Rebuild.
sessions.clear();
session_map_.GetSessionList(sessions);
for (CdmSessionList::iterator iter = sessions.begin();
iter != sessions.end(); ++iter) {
(*iter)->reset_usage_flags();
if ((*iter)->supports_usage_info() &&
(*iter)->has_provider_session_token()) {
(*iter)->UpdateUsageEntryInformation();
for (auto& session : sessions) {
session->ResetUsageFlags();
if (session->SupportsUsageEntries() && session->HasUsageEntry()) {
session->UpdateUsageEntryInformation();
}
}
}