Source release 16.3.0
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
@@ -62,6 +63,7 @@ class UsagePropertySet : public CdmClientPropertySet {
|
||||
void set_session_sharing_id(uint32_t /* id */) override {}
|
||||
const std::string& app_id() const override { return app_id_; }
|
||||
void set_app_id(const std::string& appId) { app_id_ = appId; }
|
||||
bool use_atsc_mode() const override { return false; }
|
||||
|
||||
private:
|
||||
std::string app_id_;
|
||||
@@ -73,7 +75,6 @@ CdmEngine::CdmEngine(FileSystem* file_system,
|
||||
std::shared_ptr<metrics::EngineMetrics> metrics)
|
||||
: metrics_(metrics),
|
||||
cert_provisioning_(),
|
||||
cert_provisioning_requested_security_level_(kLevelDefault),
|
||||
file_system_(file_system),
|
||||
spoid_(EMPTY_SPOID),
|
||||
usage_session_(),
|
||||
@@ -136,8 +137,6 @@ CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system,
|
||||
new_session->Init(property_set, forced_session_id, event_listener);
|
||||
if (sts != NO_ERROR) {
|
||||
if (sts == NEED_PROVISIONING) {
|
||||
cert_provisioning_requested_security_level_ =
|
||||
new_session->GetRequestedSecurityLevel();
|
||||
// Reserve a session ID so the CDM can return success.
|
||||
if (session_id) *session_id = new_session->GenerateSessionId();
|
||||
} else {
|
||||
@@ -172,10 +171,13 @@ CdmResponseType CdmEngine::OpenKeySetSession(
|
||||
key_set_in_use =
|
||||
release_key_sets_.find(key_set_id) != release_key_sets_.end();
|
||||
}
|
||||
if (key_set_in_use) CloseKeySetSession(key_set_id);
|
||||
if (key_set_in_use) {
|
||||
LOGD("Reopening existing key session");
|
||||
CloseKeySetSession(key_set_id);
|
||||
}
|
||||
|
||||
CdmSessionId session_id;
|
||||
CdmResponseType sts =
|
||||
const CdmResponseType sts =
|
||||
OpenSession(KEY_SYSTEM, property_set, event_listener,
|
||||
nullptr /* forced_session_id */, &session_id);
|
||||
|
||||
@@ -294,10 +296,6 @@ CdmResponseType CdmEngine::GenerateKeyRequest(
|
||||
if (KEY_ADDED == sts) {
|
||||
return sts;
|
||||
} else if (KEY_MESSAGE != sts) {
|
||||
if (sts == NEED_PROVISIONING) {
|
||||
cert_provisioning_requested_security_level_ =
|
||||
session->GetRequestedSecurityLevel();
|
||||
}
|
||||
LOGE("Key request generation failed, status = %d", static_cast<int>(sts));
|
||||
return sts;
|
||||
}
|
||||
@@ -414,10 +412,6 @@ CdmResponseType CdmEngine::RestoreKey(const CdmSessionId& session_id,
|
||||
&error_detail);
|
||||
session->GetMetrics()->cdm_session_restore_offline_session_.Increment(
|
||||
sts, error_detail);
|
||||
if (sts == NEED_PROVISIONING) {
|
||||
cert_provisioning_requested_security_level_ =
|
||||
session->GetRequestedSecurityLevel();
|
||||
}
|
||||
if (sts != KEY_ADDED && sts != GET_RELEASED_LICENSE_ERROR) {
|
||||
LOGE("Restore offline session failed: status = %d", static_cast<int>(sts));
|
||||
}
|
||||
@@ -703,6 +697,12 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
LOGW("GetMaxUsageTableEntries failed");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
if (max_number_of_usage_entries == 0) {
|
||||
// Zero indicates that the table is dynamically allocated and does
|
||||
// not have a defined limit. Setting to max value of int32_t to
|
||||
// be able to fit into a Java int.
|
||||
max_number_of_usage_entries = std::numeric_limits<int32_t>::max();
|
||||
}
|
||||
*query_response = std::to_string(max_number_of_usage_entries);
|
||||
return NO_ERROR;
|
||||
} else if (query_token == QUERY_KEY_OEMCRYPTO_API_MINOR_VERSION) {
|
||||
@@ -895,7 +895,8 @@ bool CdmEngine::IsSecurityLevelSupported(CdmSecurityLevel level) {
|
||||
*/
|
||||
CdmResponseType CdmEngine::GetProvisioningRequest(
|
||||
CdmCertificateType cert_type, const std::string& cert_authority,
|
||||
const std::string& service_certificate, CdmProvisioningRequest* request,
|
||||
const std::string& service_certificate,
|
||||
SecurityLevel requested_security_level, CdmProvisioningRequest* request,
|
||||
std::string* default_url) {
|
||||
LOGI("Getting provisioning request");
|
||||
if (!request) {
|
||||
@@ -915,7 +916,7 @@ CdmResponseType CdmEngine::GetProvisioningRequest(
|
||||
if (status != NO_ERROR) return status;
|
||||
}
|
||||
CdmResponseType ret = cert_provisioning_->GetProvisioningRequest(
|
||||
cert_provisioning_requested_security_level_, cert_type, cert_authority,
|
||||
requested_security_level, cert_type, cert_authority,
|
||||
file_system_->origin(), spoid_, request, default_url);
|
||||
if (ret != NO_ERROR) {
|
||||
cert_provisioning_.reset(); // Release resources.
|
||||
@@ -931,7 +932,8 @@ CdmResponseType CdmEngine::GetProvisioningRequest(
|
||||
* Returns NO_ERROR for success and CdmResponseType error code if fails.
|
||||
*/
|
||||
CdmResponseType CdmEngine::HandleProvisioningResponse(
|
||||
const CdmProvisioningResponse& response, std::string* cert,
|
||||
const CdmProvisioningResponse& response,
|
||||
SecurityLevel requested_security_level, std::string* cert,
|
||||
std::string* wrapped_key) {
|
||||
LOGI("Handling provision request");
|
||||
if (response.empty()) {
|
||||
@@ -955,10 +957,9 @@ CdmResponseType CdmEngine::HandleProvisioningResponse(
|
||||
std::unique_ptr<CryptoSession> crypto_session(
|
||||
CryptoSession::MakeCryptoSession(metrics_->GetCryptoMetrics()));
|
||||
CdmResponseType status;
|
||||
M_TIME(status = crypto_session->Open(
|
||||
cert_provisioning_requested_security_level_),
|
||||
M_TIME(status = crypto_session->Open(requested_security_level),
|
||||
metrics_->GetCryptoMetrics(), crypto_session_open_, status,
|
||||
cert_provisioning_requested_security_level_);
|
||||
requested_security_level);
|
||||
if (NO_ERROR != status) {
|
||||
LOGE("Provisioning object missing and crypto session open failed");
|
||||
return EMPTY_PROVISIONING_CERTIFICATE_2;
|
||||
@@ -1124,14 +1125,19 @@ CdmResponseType CdmEngine::RemoveOfflineLicense(
|
||||
property_set.set_security_level(
|
||||
security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault);
|
||||
DeviceFiles handle(file_system_);
|
||||
|
||||
if (!handle.Init(security_level)) {
|
||||
LOGE("Cannot initialize device files: security_level = %s",
|
||||
security_level == kSecurityLevelL3 ? "L3" : "Default");
|
||||
return REMOVE_OFFLINE_LICENSE_ERROR_1;
|
||||
}
|
||||
|
||||
CdmResponseType sts = OpenKeySetSession(key_set_id, &property_set,
|
||||
nullptr /* event listener */);
|
||||
if (sts != NO_ERROR) {
|
||||
if (!handle.Init(security_level)) {
|
||||
LOGE("Cannot initialize device files");
|
||||
}
|
||||
LOGE("Failed to open key set session: status = %d", static_cast<int>(sts));
|
||||
handle.DeleteLicense(key_set_id);
|
||||
return REMOVE_OFFLINE_LICENSE_ERROR_1;
|
||||
return sts;
|
||||
}
|
||||
|
||||
CdmSessionId session_id;
|
||||
@@ -1151,6 +1157,14 @@ CdmResponseType CdmEngine::RemoveOfflineLicense(
|
||||
session_id = iter->second.first;
|
||||
sts = RemoveLicense(session_id);
|
||||
}
|
||||
} 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,
|
||||
// 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");
|
||||
handle.DeleteLicense(key_set_id);
|
||||
sts = NO_ERROR;
|
||||
}
|
||||
|
||||
if (sts != NO_ERROR) {
|
||||
|
||||
@@ -159,8 +159,12 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set,
|
||||
// License server client ID token is a stored certificate. Stage it or
|
||||
// indicate that provisioning is needed. Get token from stored certificate
|
||||
std::string wrapped_key;
|
||||
if (!file_handle_->RetrieveCertificate(&client_token, &wrapped_key,
|
||||
&serial_number, nullptr)) {
|
||||
bool atsc_mode_enabled = false;
|
||||
if (cdm_client_property_set != nullptr)
|
||||
atsc_mode_enabled = cdm_client_property_set->use_atsc_mode();
|
||||
if (!file_handle_->RetrieveCertificate(atsc_mode_enabled, &client_token,
|
||||
&wrapped_key, &serial_number,
|
||||
nullptr)) {
|
||||
return NEED_PROVISIONING;
|
||||
}
|
||||
CdmResponseType load_cert_sts;
|
||||
@@ -186,7 +190,7 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set,
|
||||
if (forced_session_id) {
|
||||
key_set_id_ = *forced_session_id;
|
||||
} else {
|
||||
bool ok = GenerateKeySetId(&key_set_id_);
|
||||
bool ok = GenerateKeySetId(atsc_mode_enabled, &key_set_id_);
|
||||
(void)ok; // ok is now used when assertions are turned off.
|
||||
assert(ok);
|
||||
}
|
||||
@@ -282,6 +286,17 @@ CdmResponseType CdmSession::RestoreOfflineSession(const CdmKeySetId& key_set_id,
|
||||
key_response_, &provider_session_token) ||
|
||||
usage_table_header_ == nullptr) {
|
||||
provider_session_token.clear();
|
||||
std::string fake_message("empty message");
|
||||
std::string core_message;
|
||||
std::string license_request_signature;
|
||||
// Sign a fake message so that OEMCrypto will start the rental clock. The
|
||||
// signature and generated core message are ignored.
|
||||
CdmResponseType status = crypto_session_->PrepareAndSignLicenseRequest(
|
||||
fake_message, &core_message, &license_request_signature);
|
||||
if (status != NO_ERROR) return status;
|
||||
} else if (!VerifyOfflineUsageEntry()) {
|
||||
LOGE("License usage entry is invalid, cannot restore");
|
||||
return LICENSE_USAGE_ENTRY_MISSING;
|
||||
} else {
|
||||
CdmResponseType sts = usage_table_header_->LoadEntry(
|
||||
crypto_session_.get(), usage_entry_, usage_entry_number_);
|
||||
@@ -529,16 +544,18 @@ CdmResponseType CdmSession::AddKeyInternal(const CdmKeyResponse& key_response) {
|
||||
metrics_->license_sdk_version_.Record(
|
||||
version_info.license_service_version());
|
||||
|
||||
// Update or delete entry if usage table header+entries are supported
|
||||
// Update or invalidate entry if usage table header+entries are supported
|
||||
if (usage_support_type_ == kUsageEntrySupport &&
|
||||
!provider_session_token.empty() && usage_table_header_ != nullptr) {
|
||||
if (sts != KEY_ADDED) {
|
||||
CdmResponseType delete_sts = usage_table_header_->DeleteEntry(
|
||||
usage_entry_number_, file_handle_.get(), crypto_metrics_);
|
||||
crypto_metrics_->usage_table_header_delete_entry_.Increment(delete_sts);
|
||||
if (delete_sts != NO_ERROR) {
|
||||
LOGW("Delete usage entry failed: status = %d",
|
||||
static_cast<int>(delete_sts));
|
||||
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);
|
||||
if (invalidate_sts != NO_ERROR) {
|
||||
LOGW("Invalidate usage entry failed: status = %d",
|
||||
static_cast<int>(invalidate_sts));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -824,8 +841,8 @@ CdmResponseType CdmSession::DeleteUsageEntry(uint32_t usage_entry_number) {
|
||||
return INCORRECT_USAGE_SUPPORT_TYPE_1;
|
||||
}
|
||||
|
||||
sts = usage_table_header_->DeleteEntry(usage_entry_number, file_handle_.get(),
|
||||
crypto_metrics_);
|
||||
sts = usage_table_header_->InvalidateEntry(
|
||||
usage_entry_number, true, file_handle_.get(), crypto_metrics_);
|
||||
crypto_metrics_->usage_table_header_delete_entry_.Increment(sts);
|
||||
return sts;
|
||||
}
|
||||
@@ -844,7 +861,8 @@ CdmSessionId CdmSession::GenerateSessionId() {
|
||||
return SESSION_ID_PREFIX + IntToString(++session_num);
|
||||
}
|
||||
|
||||
bool CdmSession::GenerateKeySetId(CdmKeySetId* key_set_id) {
|
||||
bool CdmSession::GenerateKeySetId(bool atsc_mode_enabled,
|
||||
CdmKeySetId* key_set_id) {
|
||||
RETURN_FALSE_IF_NULL(key_set_id);
|
||||
|
||||
std::vector<uint8_t> random_data(
|
||||
@@ -856,7 +874,10 @@ bool CdmSession::GenerateKeySetId(CdmKeySetId* key_set_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*key_set_id = KEY_SET_ID_PREFIX + b2a_hex(random_data);
|
||||
if (atsc_mode_enabled)
|
||||
*key_set_id = ATSC_KEY_SET_ID_PREFIX + b2a_hex(random_data);
|
||||
else
|
||||
*key_set_id = KEY_SET_ID_PREFIX + b2a_hex(random_data);
|
||||
|
||||
// key set collision
|
||||
if (file_handle_->LicenseExists(*key_set_id)) {
|
||||
@@ -960,11 +981,10 @@ CdmResponseType CdmSession::RemoveKeys() {
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::RemoveLicense() {
|
||||
CdmResponseType sts = NO_ERROR;
|
||||
if (is_offline_ || has_provider_session_token()) {
|
||||
if (usage_support_type_ == kUsageEntrySupport &&
|
||||
has_provider_session_token()) {
|
||||
sts = DeleteUsageEntry(usage_entry_number_);
|
||||
DeleteUsageEntry(usage_entry_number_);
|
||||
}
|
||||
DeleteLicenseFile();
|
||||
}
|
||||
@@ -1131,6 +1151,25 @@ void CdmSession::UpdateRequestLatencyTiming(CdmResponseType sts) {
|
||||
license_request_latency_.Clear();
|
||||
}
|
||||
|
||||
bool CdmSession::VerifyOfflineUsageEntry() {
|
||||
// Check that the current license is the same as the expected
|
||||
// entry in the usage table. It is possible that the license has
|
||||
// been removed from the usage table but the license file remains.
|
||||
if (usage_entry_number_ >= usage_table_header_->size()) {
|
||||
LOGD("License usage entry does not exist: entry_number = %u, size = %zu",
|
||||
usage_entry_number_, usage_table_header_->size());
|
||||
return false;
|
||||
}
|
||||
const CdmUsageEntryInfo& usage_entry_info =
|
||||
usage_table_header_->usage_entry_info().at(usage_entry_number_);
|
||||
if (usage_entry_info.storage_type != kStorageLicense ||
|
||||
usage_entry_info.key_set_id != key_set_id_) {
|
||||
LOGD("License usage entry does not match");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// For testing only - takes ownership of pointers
|
||||
|
||||
void CdmSession::set_license_parser(CdmLicense* license_parser) {
|
||||
|
||||
@@ -708,12 +708,10 @@ uint8_t CryptoSession::GetSecurityPatchLevel() {
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
|
||||
LOGD(
|
||||
"Opening crypto session: requested_security_level: "
|
||||
"requested_security_level = %s",
|
||||
requested_security_level == kLevel3
|
||||
? QUERY_VALUE_SECURITY_LEVEL_L3.c_str()
|
||||
: QUERY_VALUE_SECURITY_LEVEL_DEFAULT.c_str());
|
||||
LOGD("Opening crypto session: requested_security_level = %s",
|
||||
requested_security_level == kLevel3
|
||||
? QUERY_VALUE_SECURITY_LEVEL_L3.c_str()
|
||||
: QUERY_VALUE_SECURITY_LEVEL_DEFAULT.c_str());
|
||||
RETURN_IF_UNINITIALIZED(UNKNOWN_ERROR);
|
||||
if (open_) return NO_ERROR;
|
||||
|
||||
@@ -750,12 +748,13 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
|
||||
open_ = true;
|
||||
|
||||
// Get System ID and save it.
|
||||
if (GetSystemIdInternal(&system_id_) == NO_ERROR) {
|
||||
result = GetSystemIdInternal(&system_id_);
|
||||
if (result == NO_ERROR) {
|
||||
metrics_->crypto_session_system_id_.Record(system_id_);
|
||||
} else {
|
||||
LOGE("Failed to fetch system ID");
|
||||
metrics_->crypto_session_system_id_.SetError(LOAD_SYSTEM_ID_ERROR);
|
||||
return LOAD_SYSTEM_ID_ERROR;
|
||||
metrics_->crypto_session_system_id_.SetError(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Set up request ID
|
||||
@@ -802,35 +801,33 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
|
||||
CdmSecurityLevel security_level = GetSecurityLevel();
|
||||
if (security_level == kSecurityLevelL1 ||
|
||||
security_level == kSecurityLevelL3) {
|
||||
{
|
||||
// This block cannot use |WithStaticFieldWriteLock| because it needs
|
||||
// to unlock the lock partway through.
|
||||
LOGV("Static field write lock: Open() initializing usage table");
|
||||
std::unique_lock<shared_mutex> auto_lock(static_field_mutex_);
|
||||
// This block cannot use |WithStaticFieldWriteLock| because it needs
|
||||
// to unlock the lock partway through.
|
||||
LOGV("Static field write lock: Open() initializing usage table");
|
||||
std::unique_lock<shared_mutex> auto_lock(static_field_mutex_);
|
||||
|
||||
UsageTableHeader** header = security_level == kSecurityLevelL1
|
||||
? &usage_table_header_l1_
|
||||
: &usage_table_header_l3_;
|
||||
if (*header == nullptr) {
|
||||
*header = new UsageTableHeader();
|
||||
// Ignore errors since we do not know when a session is opened,
|
||||
// if it is intended to be used for offline/usage session related
|
||||
// or otherwise.
|
||||
auto_lock.unlock();
|
||||
bool is_usage_table_header_inited =
|
||||
(*header)->Init(security_level, this);
|
||||
auto_lock.lock();
|
||||
if (!is_usage_table_header_inited) {
|
||||
delete *header;
|
||||
*header = nullptr;
|
||||
usage_table_header_ = nullptr;
|
||||
return NO_ERROR;
|
||||
}
|
||||
UsageTableHeader** header = security_level == kSecurityLevelL1
|
||||
? &usage_table_header_l1_
|
||||
: &usage_table_header_l3_;
|
||||
if (*header == nullptr) {
|
||||
*header = new UsageTableHeader();
|
||||
// Ignore errors since we do not know when a session is opened,
|
||||
// if it is intended to be used for offline/usage session related
|
||||
// or otherwise.
|
||||
auto_lock.unlock();
|
||||
bool is_usage_table_header_inited =
|
||||
(*header)->Init(security_level, this);
|
||||
auto_lock.lock();
|
||||
if (!is_usage_table_header_inited) {
|
||||
delete *header;
|
||||
*header = nullptr;
|
||||
usage_table_header_ = nullptr;
|
||||
return NO_ERROR;
|
||||
}
|
||||
usage_table_header_ = *header;
|
||||
metrics_->usage_table_header_initial_size_.Record((*header)->size());
|
||||
}
|
||||
}
|
||||
usage_table_header_ = *header;
|
||||
metrics_->usage_table_header_initial_size_.Record((*header)->size());
|
||||
} // End |static_field_mutex_| block.
|
||||
}
|
||||
} else {
|
||||
metrics_->oemcrypto_usage_table_support_.SetError(result);
|
||||
@@ -943,7 +940,7 @@ CdmResponseType CryptoSession::LoadKeys(
|
||||
update_usage_table_after_close_session_ = true;
|
||||
return KEY_ADDED;
|
||||
case OEMCrypto_ERROR_TOO_MANY_KEYS:
|
||||
return INSUFFICIENT_CRYPTO_RESOURCES_4;
|
||||
return INSUFFICIENT_CRYPTO_RESOURCES;
|
||||
case OEMCrypto_ERROR_USAGE_TABLE_UNRECOVERABLE:
|
||||
// Handle vendor specific error
|
||||
return NEED_PROVISIONING;
|
||||
@@ -983,7 +980,7 @@ CdmResponseType CryptoSession::LoadLicense(const std::string& signed_message,
|
||||
return LOAD_LICENSE_ERROR;
|
||||
case OEMCrypto_ERROR_TOO_MANY_KEYS:
|
||||
LOGE("Too many keys in license");
|
||||
return INSUFFICIENT_CRYPTO_RESOURCES_4;
|
||||
return INSUFFICIENT_CRYPTO_RESOURCES;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1185,16 +1182,15 @@ CdmResponseType CryptoSession::PrepareAndSignProvisioningRequest(
|
||||
|
||||
CdmResponseType CryptoSession::LoadEntitledContentKeys(
|
||||
const std::vector<CryptoKey>& key_array) {
|
||||
OEMCryptoResult sts;
|
||||
WithOecSessionLock("LoadEntitledContentKeys", [&] {
|
||||
sts = key_session_->LoadEntitledContentKeys(key_array);
|
||||
});
|
||||
const OEMCryptoResult sts = WithOecSessionLock(
|
||||
"LoadEntitledContentKeys",
|
||||
[&] { return key_session_->LoadEntitledContentKeys(key_array); });
|
||||
|
||||
switch (sts) {
|
||||
case OEMCrypto_SUCCESS:
|
||||
return KEY_ADDED;
|
||||
case OEMCrypto_ERROR_INSUFFICIENT_RESOURCES:
|
||||
return INSUFFICIENT_CRYPTO_RESOURCES_6;
|
||||
return INSUFFICIENT_CRYPTO_RESOURCES;
|
||||
case OEMCrypto_ERROR_INVALID_CONTEXT:
|
||||
return NOT_AN_ENTITLEMENT_SESSION;
|
||||
case OEMCrypto_KEY_NOT_ENTITLED:
|
||||
@@ -1243,39 +1239,46 @@ CdmResponseType CryptoSession::LoadCertificatePrivateKey(
|
||||
// Private.
|
||||
CdmResponseType CryptoSession::SelectKey(const std::string& key_id,
|
||||
CdmCipherMode cipher_mode) {
|
||||
OEMCryptoResult sts;
|
||||
WithOecSessionLock(
|
||||
"SelectKey", [&] { sts = key_session_->SelectKey(key_id, cipher_mode); });
|
||||
const OEMCryptoResult sts = WithOecSessionLock("SelectKey", [&] {
|
||||
return key_session_->SelectKey(key_id, cipher_mode);
|
||||
});
|
||||
|
||||
switch (sts) {
|
||||
// SelectKey errors.
|
||||
case OEMCrypto_SUCCESS:
|
||||
return NO_ERROR;
|
||||
case OEMCrypto_ERROR_KEY_EXPIRED:
|
||||
return NEED_KEY;
|
||||
case OEMCrypto_ERROR_INSUFFICIENT_HDCP:
|
||||
return INSUFFICIENT_OUTPUT_PROTECTION;
|
||||
case OEMCrypto_ERROR_ANALOG_OUTPUT:
|
||||
return ANALOG_OUTPUT_ERROR;
|
||||
case OEMCrypto_ERROR_INVALID_SESSION:
|
||||
return INVALID_SESSION_1;
|
||||
case OEMCrypto_ERROR_NO_DEVICE_KEY:
|
||||
return NO_DEVICE_KEY_1;
|
||||
case OEMCrypto_ERROR_NO_CONTENT_KEY:
|
||||
return NO_CONTENT_KEY_2;
|
||||
case OEMCrypto_KEY_NOT_LOADED: // obsolete.
|
||||
return NO_CONTENT_KEY_3;
|
||||
case OEMCrypto_ERROR_INSUFFICIENT_RESOURCES:
|
||||
return INSUFFICIENT_CRYPTO_RESOURCES_2;
|
||||
case OEMCrypto_ERROR_UNKNOWN_FAILURE:
|
||||
return UNKNOWN_SELECT_KEY_ERROR_1;
|
||||
case OEMCrypto_ERROR_SESSION_LOST_STATE:
|
||||
return SESSION_LOST_STATE_ERROR;
|
||||
case OEMCrypto_ERROR_SYSTEM_INVALIDATED:
|
||||
return SYSTEM_INVALIDATED_ERROR;
|
||||
case OEMCrypto_ERROR_CONTROL_INVALID:
|
||||
case OEMCrypto_ERROR_KEYBOX_INVALID:
|
||||
default:
|
||||
return UNKNOWN_SELECT_KEY_ERROR_2;
|
||||
case OEMCrypto_ERROR_INSUFFICIENT_RESOURCES:
|
||||
return INSUFFICIENT_CRYPTO_RESOURCES;
|
||||
case OEMCrypto_ERROR_UNKNOWN_FAILURE:
|
||||
return UNKNOWN_SELECT_KEY_ERROR_1;
|
||||
case OEMCrypto_ERROR_ANALOG_OUTPUT:
|
||||
return ANALOG_OUTPUT_ERROR;
|
||||
case OEMCrypto_ERROR_INSUFFICIENT_HDCP:
|
||||
return INSUFFICIENT_OUTPUT_PROTECTION;
|
||||
// LoadEntitledContentKeys errors.
|
||||
// |key_session_| may make calls to OEMCrypto_LoadEntitledContentKeys
|
||||
// if the key selected has not yet been loaded.
|
||||
case OEMCrypto_ERROR_INVALID_CONTEXT:
|
||||
return NOT_AN_ENTITLEMENT_SESSION;
|
||||
case OEMCrypto_KEY_NOT_ENTITLED:
|
||||
return NO_MATCHING_ENTITLEMENT_KEY;
|
||||
// Obsolete errors.
|
||||
case OEMCrypto_KEY_NOT_LOADED:
|
||||
return NO_CONTENT_KEY_3;
|
||||
// Catch all else.
|
||||
default:
|
||||
return MapOEMCryptoResult(sts, UNKNOWN_SELECT_KEY_ERROR_2, "SelectKey");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1530,7 +1533,7 @@ CdmResponseType CryptoSession::Decrypt(
|
||||
case OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION:
|
||||
return NO_ERROR;
|
||||
case OEMCrypto_ERROR_INSUFFICIENT_RESOURCES:
|
||||
return INSUFFICIENT_CRYPTO_RESOURCES_5;
|
||||
return INSUFFICIENT_CRYPTO_RESOURCES;
|
||||
case OEMCrypto_ERROR_KEY_EXPIRED:
|
||||
return NEED_KEY;
|
||||
case OEMCrypto_ERROR_INVALID_SESSION:
|
||||
@@ -2005,6 +2008,11 @@ bool CryptoSession::GetMaximumUsageTableEntries(SecurityLevel security_level,
|
||||
metrics_->oemcrypto_maximum_usage_table_header_size_.Record(
|
||||
*number_of_entries);
|
||||
|
||||
if (*number_of_entries == 0) {
|
||||
// Special value, indicating that the table size is not directly
|
||||
// limited.
|
||||
return true;
|
||||
}
|
||||
return *number_of_entries >= kMinimumUsageTableEntriesSupported;
|
||||
}
|
||||
|
||||
@@ -2349,18 +2357,20 @@ CdmResponseType CryptoSession::GetUsageSupportType(
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::CreateUsageTableHeader(
|
||||
SecurityLevel requested_security_level,
|
||||
CdmUsageTableHeader* usage_table_header) {
|
||||
LOGV("Creating usage table header: id = %u", oec_session_id_);
|
||||
|
||||
LOGV("Creating usage table header: requested_security_level = %s",
|
||||
requested_security_level == kLevel3
|
||||
? QUERY_VALUE_SECURITY_LEVEL_L3.c_str()
|
||||
: QUERY_VALUE_SECURITY_LEVEL_DEFAULT.c_str());
|
||||
RETURN_IF_NULL(usage_table_header, PARAMETER_NULL);
|
||||
|
||||
usage_table_header->resize(kEstimatedInitialUsageTableHeader);
|
||||
|
||||
size_t usage_table_header_size = usage_table_header->size();
|
||||
OEMCryptoResult result;
|
||||
WithOecWriteLock("CreateUsageTableHeader Attempt 1", [&] {
|
||||
result = OEMCrypto_CreateUsageTableHeader(
|
||||
requested_security_level_,
|
||||
requested_security_level,
|
||||
reinterpret_cast<uint8_t*>(
|
||||
const_cast<char*>(usage_table_header->data())),
|
||||
&usage_table_header_size);
|
||||
@@ -2371,7 +2381,7 @@ CdmResponseType CryptoSession::CreateUsageTableHeader(
|
||||
usage_table_header->resize(usage_table_header_size);
|
||||
WithOecWriteLock("CreateUsageTableHeader Attempt 2", [&] {
|
||||
result = OEMCrypto_CreateUsageTableHeader(
|
||||
requested_security_level_,
|
||||
requested_security_level,
|
||||
reinterpret_cast<uint8_t*>(
|
||||
const_cast<char*>(usage_table_header->data())),
|
||||
&usage_table_header_size);
|
||||
@@ -2379,22 +2389,28 @@ CdmResponseType CryptoSession::CreateUsageTableHeader(
|
||||
});
|
||||
}
|
||||
|
||||
if (result == OEMCrypto_SUCCESS) {
|
||||
usage_table_header->resize(usage_table_header_size);
|
||||
switch (result) {
|
||||
case OEMCrypto_SUCCESS:
|
||||
usage_table_header->resize(usage_table_header_size);
|
||||
return NO_ERROR;
|
||||
default:
|
||||
return MapOEMCryptoResult(result, CREATE_USAGE_TABLE_ERROR,
|
||||
"CreateUsageTableHeader");
|
||||
}
|
||||
|
||||
return MapOEMCryptoResult(result, CREATE_USAGE_TABLE_ERROR,
|
||||
"CreateUsageTableHeader");
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::LoadUsageTableHeader(
|
||||
SecurityLevel requested_security_level,
|
||||
const CdmUsageTableHeader& usage_table_header) {
|
||||
LOGV("Loading usage table header: id = %u", oec_session_id_);
|
||||
LOGV("Loading usage table header: requested_security_level = %s",
|
||||
requested_security_level == kLevel3
|
||||
? QUERY_VALUE_SECURITY_LEVEL_L3.c_str()
|
||||
: QUERY_VALUE_SECURITY_LEVEL_DEFAULT.c_str());
|
||||
|
||||
OEMCryptoResult result;
|
||||
WithOecWriteLock("LoadUsageTableHeader", [&] {
|
||||
result = OEMCrypto_LoadUsageTableHeader(
|
||||
requested_security_level_,
|
||||
requested_security_level,
|
||||
reinterpret_cast<const uint8_t*>(usage_table_header.data()),
|
||||
usage_table_header.size());
|
||||
metrics_->oemcrypto_load_usage_table_header_.Increment(result);
|
||||
@@ -2427,6 +2443,48 @@ CdmResponseType CryptoSession::LoadUsageTableHeader(
|
||||
}
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::ShrinkUsageTableHeader(
|
||||
SecurityLevel requested_security_level, uint32_t new_entry_count,
|
||||
CdmUsageTableHeader* usage_table_header) {
|
||||
LOGV("Shrinking usage table header: requested_security_level = %s",
|
||||
requested_security_level == kLevel3
|
||||
? QUERY_VALUE_SECURITY_LEVEL_L3.c_str()
|
||||
: QUERY_VALUE_SECURITY_LEVEL_DEFAULT.c_str());
|
||||
RETURN_IF_NULL(usage_table_header, PARAMETER_NULL);
|
||||
|
||||
size_t usage_table_header_len = 0;
|
||||
OEMCryptoResult result;
|
||||
WithOecWriteLock("ShrinkUsageTableHeader Attempt 1", [&] {
|
||||
result = OEMCrypto_ShrinkUsageTableHeader(requested_security_level,
|
||||
new_entry_count, nullptr,
|
||||
&usage_table_header_len);
|
||||
metrics_->oemcrypto_shrink_usage_table_header_.Increment(result);
|
||||
});
|
||||
|
||||
if (result == OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||
usage_table_header->resize(usage_table_header_len);
|
||||
WithOecWriteLock("ShrinkUsageTableHeader Attempt 2", [&] {
|
||||
result = OEMCrypto_ShrinkUsageTableHeader(
|
||||
requested_security_level, new_entry_count,
|
||||
reinterpret_cast<uint8_t*>(
|
||||
const_cast<char*>(usage_table_header->data())),
|
||||
&usage_table_header_len);
|
||||
metrics_->oemcrypto_shrink_usage_table_header_.Increment(result);
|
||||
});
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
case OEMCrypto_SUCCESS:
|
||||
usage_table_header->resize(usage_table_header_len);
|
||||
return NO_ERROR;
|
||||
case OEMCrypto_ERROR_ENTRY_IN_USE:
|
||||
return SHRINK_USAGE_TABLE_HEADER_ENTRY_IN_USE;
|
||||
default:
|
||||
return MapOEMCryptoResult(result, SHRINK_USAGE_TABLE_HEADER_UNKNOWN_ERROR,
|
||||
"ShrinkUsageTableHeader");
|
||||
}
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::CreateUsageEntry(uint32_t* entry_number) {
|
||||
LOGV("Creating usage entry: id = %u", oec_session_id_);
|
||||
|
||||
@@ -2447,7 +2505,7 @@ CdmResponseType CryptoSession::CreateUsageEntry(uint32_t* entry_number) {
|
||||
case OEMCrypto_SUCCESS:
|
||||
return NO_ERROR;
|
||||
case OEMCrypto_ERROR_INSUFFICIENT_RESOURCES:
|
||||
return INSUFFICIENT_CRYPTO_RESOURCES_3;
|
||||
return INSUFFICIENT_CRYPTO_RESOURCES;
|
||||
case OEMCrypto_ERROR_SESSION_LOST_STATE:
|
||||
return SESSION_LOST_STATE_ERROR;
|
||||
case OEMCrypto_ERROR_SYSTEM_INVALIDATED:
|
||||
@@ -2483,18 +2541,19 @@ CdmResponseType CryptoSession::LoadUsageEntry(
|
||||
case OEMCrypto_SUCCESS:
|
||||
case OEMCrypto_WARNING_GENERATION_SKEW:
|
||||
return NO_ERROR;
|
||||
case OEMCrypto_ERROR_INVALID_SESSION:
|
||||
// This case is special, as it could imply that the provided
|
||||
// session ID is invalid (CDM internal bug), or that the entry
|
||||
// being loaded is already in use in a different session.
|
||||
// It is up to the caller to handle this.
|
||||
return LOAD_USAGE_ENTRY_INVALID_SESSION;
|
||||
case OEMCrypto_ERROR_GENERATION_SKEW:
|
||||
return LOAD_USAGE_ENTRY_GENERATION_SKEW;
|
||||
case OEMCrypto_ERROR_SIGNATURE_FAILURE:
|
||||
return LOAD_USAGE_ENTRY_SIGNATURE_FAILURE;
|
||||
case OEMCrypto_ERROR_INSUFFICIENT_RESOURCES:
|
||||
return INSUFFICIENT_CRYPTO_RESOURCES_3;
|
||||
case OEMCrypto_ERROR_SESSION_LOST_STATE:
|
||||
return SESSION_LOST_STATE_ERROR;
|
||||
case OEMCrypto_ERROR_SYSTEM_INVALIDATED:
|
||||
return SYSTEM_INVALIDATED_ERROR;
|
||||
default:
|
||||
return LOAD_USAGE_ENTRY_UNKNOWN_ERROR;
|
||||
return MapOEMCryptoResult(result, LOAD_USAGE_ENTRY_UNKNOWN_ERROR,
|
||||
"LoadUsageEntry");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2540,42 +2599,6 @@ CdmResponseType CryptoSession::UpdateUsageEntry(
|
||||
"UpdateUsageEntry");
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::ShrinkUsageTableHeader(
|
||||
uint32_t new_entry_count, CdmUsageTableHeader* usage_table_header) {
|
||||
LOGV("Shrinking usage table header: id = %u", oec_session_id_);
|
||||
|
||||
RETURN_IF_NULL(usage_table_header, PARAMETER_NULL);
|
||||
|
||||
size_t usage_table_header_len = 0;
|
||||
OEMCryptoResult result;
|
||||
WithOecWriteLock("ShrinkUsageTableHeader Attempt 1", [&] {
|
||||
result = OEMCrypto_ShrinkUsageTableHeader(requested_security_level_,
|
||||
new_entry_count, nullptr,
|
||||
&usage_table_header_len);
|
||||
metrics_->oemcrypto_shrink_usage_table_header_.Increment(result);
|
||||
});
|
||||
|
||||
if (result == OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||
usage_table_header->resize(usage_table_header_len);
|
||||
|
||||
WithOecWriteLock("ShrinkUsageTableHeader Attempt 2", [&] {
|
||||
result = OEMCrypto_ShrinkUsageTableHeader(
|
||||
requested_security_level_, new_entry_count,
|
||||
reinterpret_cast<uint8_t*>(
|
||||
const_cast<char*>(usage_table_header->data())),
|
||||
&usage_table_header_len);
|
||||
metrics_->oemcrypto_shrink_usage_table_header_.Increment(result);
|
||||
});
|
||||
}
|
||||
|
||||
if (result == OEMCrypto_SUCCESS) {
|
||||
usage_table_header->resize(usage_table_header_len);
|
||||
}
|
||||
|
||||
return MapOEMCryptoResult(result, SHRINK_USAGE_TABLER_HEADER_UNKNOWN_ERROR,
|
||||
"ShrinkUsageTableHeader");
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::MoveUsageEntry(uint32_t new_entry_number) {
|
||||
LOGV("Moving usage entry: id = %u", oec_session_id_);
|
||||
|
||||
@@ -2585,8 +2608,15 @@ CdmResponseType CryptoSession::MoveUsageEntry(uint32_t new_entry_number) {
|
||||
metrics_->oemcrypto_move_entry_.Increment(result);
|
||||
});
|
||||
|
||||
return MapOEMCryptoResult(result, MOVE_USAGE_ENTRY_UNKNOWN_ERROR,
|
||||
"MoveUsageEntry");
|
||||
switch (result) {
|
||||
case OEMCrypto_ERROR_ENTRY_IN_USE:
|
||||
LOGW("OEMCrypto_MoveEntry failed: Destination index in use: index = %u",
|
||||
new_entry_number);
|
||||
return MOVE_USAGE_ENTRY_DESTINATION_IN_USE;
|
||||
default:
|
||||
return MapOEMCryptoResult(result, MOVE_USAGE_ENTRY_UNKNOWN_ERROR,
|
||||
"MoveUsageEntry");
|
||||
}
|
||||
}
|
||||
|
||||
bool CryptoSession::GetAnalogOutputCapabilities(bool* can_support_output,
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "certificate_provisioning.h"
|
||||
@@ -70,6 +71,7 @@ using video_widevine_client::sdk::
|
||||
|
||||
namespace {
|
||||
|
||||
const char kAtscCertificateFileName[] = "atsccert.bin";
|
||||
const char kCertificateFileName[] = "cert.bin";
|
||||
const char kHlsAttributesFileNameExt[] = ".hal";
|
||||
const char kUsageInfoFileNamePrefix[] = "usage";
|
||||
@@ -126,19 +128,25 @@ bool DeviceFiles::StoreCertificate(const std::string& certificate,
|
||||
std::string serialized_file;
|
||||
file.SerializeToString(&serialized_file);
|
||||
|
||||
return StoreFileWithHash(GetCertificateFileName(), serialized_file) ==
|
||||
return StoreFileWithHash(GetCertificateFileName(false), serialized_file) ==
|
||||
kNoError;
|
||||
}
|
||||
|
||||
bool DeviceFiles::RetrieveCertificate(std::string* certificate,
|
||||
bool DeviceFiles::RetrieveCertificate(bool atsc_mode_enabled,
|
||||
std::string* certificate,
|
||||
std::string* wrapped_private_key,
|
||||
std::string* serial_number,
|
||||
uint32_t* system_id) {
|
||||
RETURN_FALSE_IF_UNINITIALIZED();
|
||||
|
||||
if (!HasCertificate(atsc_mode_enabled)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
video_widevine_client::sdk::File file;
|
||||
if (RetrieveHashedFile(GetCertificateFileName(), &file) != kNoError) {
|
||||
LOGE("Unable to retrieve certificate file");
|
||||
if (RetrieveHashedFile(GetCertificateFileName(atsc_mode_enabled), &file) !=
|
||||
kNoError) {
|
||||
LOGW("Unable to retrieve certificate file");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -166,14 +174,16 @@ bool DeviceFiles::RetrieveCertificate(std::string* certificate,
|
||||
device_certificate.certificate(), serial_number, system_id);
|
||||
}
|
||||
|
||||
bool DeviceFiles::HasCertificate() {
|
||||
bool DeviceFiles::HasCertificate(bool atsc_mode_enabled) {
|
||||
RETURN_FALSE_IF_UNINITIALIZED();
|
||||
return FileExists(GetCertificateFileName());
|
||||
|
||||
return FileExists(GetCertificateFileName(atsc_mode_enabled));
|
||||
}
|
||||
|
||||
bool DeviceFiles::RemoveCertificate() {
|
||||
RETURN_FALSE_IF_UNINITIALIZED()
|
||||
return RemoveFile(GetCertificateFileName());
|
||||
|
||||
return RemoveFile(GetCertificateFileName(false));
|
||||
}
|
||||
|
||||
bool DeviceFiles::StoreLicense(const CdmLicenseData& license_data,
|
||||
@@ -1103,7 +1113,7 @@ DeviceFiles::ResponseType DeviceFiles::RetrieveHashedFile(
|
||||
path += name;
|
||||
|
||||
if (!file_system_->Exists(path)) {
|
||||
LOGE("File does not exist: path = %s", path.c_str());
|
||||
LOGW("File does not exist: path = %s", path.c_str());
|
||||
return kFileNotFound;
|
||||
}
|
||||
|
||||
@@ -1214,8 +1224,8 @@ ssize_t DeviceFiles::GetFileSize(const std::string& name) {
|
||||
return file_system_->FileSize(path);
|
||||
}
|
||||
|
||||
std::string DeviceFiles::GetCertificateFileName() {
|
||||
return kCertificateFileName;
|
||||
std::string DeviceFiles::GetCertificateFileName(bool atsc_mode_enabled) {
|
||||
return atsc_mode_enabled ? kAtscCertificateFileName : kCertificateFileName;
|
||||
}
|
||||
|
||||
std::string DeviceFiles::GetUsageTableFileName() { return kUsageTableFileName; }
|
||||
|
||||
@@ -237,6 +237,7 @@ bool CdmLicense::Init(const std::string& client_token,
|
||||
crypto_session_ = session;
|
||||
policy_engine_ = policy_engine;
|
||||
use_privacy_mode_ = use_privacy_mode;
|
||||
license_nonce_ = 0;
|
||||
initialized_ = true;
|
||||
return true;
|
||||
}
|
||||
@@ -313,8 +314,7 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
|
||||
|
||||
// Get/set the nonce. This value will be reflected in the Key Control Block
|
||||
// of the license response.
|
||||
uint32_t nonce;
|
||||
status = crypto_session_->GenerateNonce(&nonce);
|
||||
status = crypto_session_->GenerateNonce(&license_nonce_);
|
||||
|
||||
switch (status) {
|
||||
case NO_ERROR:
|
||||
@@ -325,9 +325,7 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
|
||||
default:
|
||||
return LICENSE_REQUEST_NONCE_GENERATION_ERROR;
|
||||
}
|
||||
license_request.set_key_control_nonce(nonce);
|
||||
LOGD("nonce = %u", nonce);
|
||||
|
||||
license_request.set_key_control_nonce(license_nonce_);
|
||||
license_request.set_protocol_version(video_widevine::VERSION_2_1);
|
||||
|
||||
// License request is complete. Serialize it.
|
||||
@@ -462,11 +460,11 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
|
||||
LOGW("Unknown API Version");
|
||||
api_version = 15;
|
||||
}
|
||||
uint32_t nonce = 0;
|
||||
if (api_version < 16) {
|
||||
// For a pre-v16 license, get/set the nonce. This value will be reflected
|
||||
// in the Key Control Block of the license response.
|
||||
const CdmResponseType status = crypto_session_->GenerateNonce(&nonce);
|
||||
const CdmResponseType status =
|
||||
crypto_session_->GenerateNonce(&license_nonce_);
|
||||
switch (status) {
|
||||
case NO_ERROR:
|
||||
break;
|
||||
@@ -477,8 +475,7 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
|
||||
return LICENSE_RENEWAL_NONCE_GENERATION_ERROR;
|
||||
}
|
||||
}
|
||||
license_request.set_key_control_nonce(nonce);
|
||||
LOGD("nonce = %u", nonce);
|
||||
license_request.set_key_control_nonce(license_nonce_);
|
||||
license_request.set_protocol_version(video_widevine::VERSION_2_1);
|
||||
|
||||
// License request is complete. Serialize it.
|
||||
@@ -705,12 +702,13 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
|
||||
return INVALID_LICENSE_TYPE;
|
||||
}
|
||||
|
||||
// At this point of the license life-cycle (handling a renewal or
|
||||
// release), we should already know if the license is v15 or not.
|
||||
// If license is v16, then there should be a |core_message|
|
||||
// present; otherwise there might have beeen some tampering with the
|
||||
// request or response.
|
||||
if (supports_core_messages() &&
|
||||
// At this point of the license life-cycle (handling a renewal), we should
|
||||
// already know if the license is v15 or not. If license is v16, then a
|
||||
// renewal should have a |core_message| present; otherwise there might have
|
||||
// been some tampering with the request or response. On the other hand, a
|
||||
// release is processed without loading the license, so OEMCrypto does not
|
||||
// know if it is v15 or v16, and will not add a core message.
|
||||
if (is_renewal && supports_core_messages() &&
|
||||
(!signed_response.has_oemcrypto_core_message() ||
|
||||
signed_response.oemcrypto_core_message().empty())) {
|
||||
LOGE("Renewal response is missing |core_message| field");
|
||||
@@ -723,8 +721,9 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
|
||||
}
|
||||
const std::string& signed_message = signed_response.msg();
|
||||
const std::string core_message =
|
||||
supports_core_messages() ? signed_response.oemcrypto_core_message()
|
||||
: std::string();
|
||||
signed_response.has_oemcrypto_core_message()
|
||||
? signed_response.oemcrypto_core_message()
|
||||
: std::string();
|
||||
const std::string& signature = signed_response.signature();
|
||||
|
||||
License license;
|
||||
@@ -811,6 +810,13 @@ CdmResponseType CdmLicense::RestoreOfflineLicense(
|
||||
}
|
||||
|
||||
key_request_ = signed_request.msg();
|
||||
LicenseRequest original_license_request;
|
||||
if (!original_license_request.ParseFromString(key_request_)) {
|
||||
LOGW("Could not parse original request.");
|
||||
} else {
|
||||
license_nonce_ = original_license_request.key_control_nonce();
|
||||
}
|
||||
|
||||
CdmResponseType sts = HandleKeyResponse(license_response);
|
||||
|
||||
if (sts != KEY_ADDED) return sts;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user