Source release 14.2.0
This commit is contained in:
@@ -85,7 +85,10 @@ CdmEngine::CdmEngine(FileSystem* file_system, const std::string& spoid)
|
||||
}
|
||||
}
|
||||
|
||||
CdmEngine::~CdmEngine() {}
|
||||
CdmEngine::~CdmEngine() {
|
||||
AutoLock lock(session_map_lock_);
|
||||
session_map_.Terminate();
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::OpenSession(
|
||||
const CdmKeySystem& key_system, CdmClientPropertySet* property_set,
|
||||
@@ -143,6 +146,7 @@ CdmResponseType CdmEngine::OpenSession(
|
||||
CdmSessionId id = new_session->session_id();
|
||||
LOGI("CdmEngine::OpenSession: %s", id.c_str());
|
||||
|
||||
AutoLock lock(session_map_lock_);
|
||||
session_map_.Add(id, new_session.release());
|
||||
if (session_id) *session_id = id;
|
||||
return NO_ERROR;
|
||||
@@ -184,6 +188,7 @@ CdmResponseType CdmEngine::OpenKeySetSession(
|
||||
|
||||
CdmResponseType CdmEngine::CloseSession(const CdmSessionId& session_id) {
|
||||
LOGI("CdmEngine::CloseSession: %s", session_id.c_str());
|
||||
AutoLock lock(session_map_lock_);
|
||||
if (!session_map_.CloseSession(session_id)) {
|
||||
LOGE("CdmEngine::CloseSession: session not found = %s", session_id.c_str());
|
||||
return SESSION_NOT_FOUND_1;
|
||||
@@ -217,6 +222,7 @@ CdmResponseType CdmEngine::CloseKeySetSession(const CdmKeySetId& key_set_id) {
|
||||
}
|
||||
|
||||
bool CdmEngine::IsOpenSession(const CdmSessionId& session_id) {
|
||||
AutoLock lock(session_map_lock_);
|
||||
return session_map_.Exists(session_id);
|
||||
}
|
||||
|
||||
@@ -486,10 +492,11 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
const std::string& query_token,
|
||||
std::string* query_response) {
|
||||
LOGI("CdmEngine::QueryStatus");
|
||||
CryptoSession crypto_session(metrics_.GetCryptoMetrics());
|
||||
scoped_ptr<CryptoSession> crypto_session(
|
||||
CryptoSession::MakeCryptoSession(metrics_.GetCryptoMetrics()));
|
||||
CdmResponseType status;
|
||||
M_TIME(
|
||||
status = crypto_session.Open(
|
||||
status = crypto_session->Open(
|
||||
security_level),
|
||||
metrics_.GetCryptoMetrics(),
|
||||
crypto_session_open_,
|
||||
@@ -505,7 +512,7 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
|
||||
if (query_token == QUERY_KEY_SECURITY_LEVEL) {
|
||||
CdmSecurityLevel found_security_level =
|
||||
crypto_session.GetSecurityLevel();
|
||||
crypto_session->GetSecurityLevel();
|
||||
switch (found_security_level) {
|
||||
case kSecurityLevelL1:
|
||||
*query_response = QUERY_VALUE_SECURITY_LEVEL_L1;
|
||||
@@ -527,7 +534,7 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
}
|
||||
} else if (query_token == QUERY_KEY_DEVICE_ID) {
|
||||
std::string deviceId;
|
||||
bool got_id = crypto_session.GetExternalDeviceUniqueId(&deviceId);
|
||||
bool got_id = crypto_session->GetExternalDeviceUniqueId(&deviceId);
|
||||
metrics_.GetCryptoMetrics()->crypto_session_get_device_unique_id_
|
||||
.Increment(got_id);
|
||||
if (!got_id) {
|
||||
@@ -538,7 +545,7 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
*query_response = deviceId;
|
||||
} else if (query_token == QUERY_KEY_SYSTEM_ID) {
|
||||
uint32_t system_id;
|
||||
bool got_id = crypto_session.GetSystemId(&system_id);
|
||||
bool got_id = crypto_session->GetSystemId(&system_id);
|
||||
if (!got_id) {
|
||||
LOGW("CdmEngine::QueryStatus: QUERY_KEY_SYSTEM_ID unknown failure");
|
||||
return UNKNOWN_ERROR;
|
||||
@@ -549,7 +556,7 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
*query_response = system_id_stream.str();
|
||||
} else if (query_token == QUERY_KEY_PROVISIONING_ID) {
|
||||
std::string provisioning_id;
|
||||
if (!crypto_session.GetProvisioningId(&provisioning_id)) {
|
||||
if (!crypto_session->GetProvisioningId(&provisioning_id)) {
|
||||
LOGW("CdmEngine::QueryStatus: GetProvisioningId failed");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
@@ -559,7 +566,7 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
query_token == QUERY_KEY_MAX_HDCP_LEVEL) {
|
||||
CryptoSession::HdcpCapability current_hdcp;
|
||||
CryptoSession::HdcpCapability max_hdcp;
|
||||
if (!crypto_session.GetHdcpCapabilities(¤t_hdcp, &max_hdcp)) {
|
||||
if (!crypto_session->GetHdcpCapabilities(¤t_hdcp, &max_hdcp)) {
|
||||
LOGW("CdmEngine::QueryStatus: GetHdcpCapabilities failed");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
@@ -568,7 +575,7 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
current_hdcp : max_hdcp);
|
||||
} else if (query_token == QUERY_KEY_USAGE_SUPPORT) {
|
||||
bool supports_usage_reporting;
|
||||
bool got_info = crypto_session.UsageInformationSupport(
|
||||
bool got_info = crypto_session->UsageInformationSupport(
|
||||
&supports_usage_reporting);
|
||||
|
||||
if (!got_info) {
|
||||
@@ -584,7 +591,7 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
supports_usage_reporting ? QUERY_VALUE_TRUE : QUERY_VALUE_FALSE;
|
||||
} else if (query_token == QUERY_KEY_NUMBER_OF_OPEN_SESSIONS) {
|
||||
size_t number_of_open_sessions;
|
||||
if (!crypto_session.GetNumberOfOpenSessions(&number_of_open_sessions)) {
|
||||
if (!crypto_session->GetNumberOfOpenSessions(&number_of_open_sessions)) {
|
||||
LOGW("CdmEngine::QueryStatus: GetNumberOfOpenSessions failed");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
@@ -594,7 +601,7 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
*query_response = open_sessions_stream.str();
|
||||
} else if (query_token == QUERY_KEY_MAX_NUMBER_OF_SESSIONS) {
|
||||
size_t maximum_number_of_sessions = 0;
|
||||
if (!crypto_session.GetMaxNumberOfSessions(&maximum_number_of_sessions)) {
|
||||
if (!crypto_session->GetMaxNumberOfSessions(&maximum_number_of_sessions)) {
|
||||
LOGW("CdmEngine::QueryStatus: GetMaxNumberOfOpenSessions failed");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
@@ -604,7 +611,7 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
*query_response = max_sessions_stream.str();
|
||||
} else if (query_token == QUERY_KEY_OEMCRYPTO_API_VERSION) {
|
||||
uint32_t api_version;
|
||||
if (!crypto_session.GetApiVersion(&api_version)) {
|
||||
if (!crypto_session->GetApiVersion(&api_version)) {
|
||||
LOGW("CdmEngine::QueryStatus: GetApiVersion failed");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
@@ -614,7 +621,7 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
*query_response = api_version_stream.str();
|
||||
} else if (query_token == QUERY_KEY_CURRENT_SRM_VERSION) {
|
||||
uint16_t current_srm_version;
|
||||
if (!crypto_session.GetSrmVersion(¤t_srm_version)) {
|
||||
if (!crypto_session->GetSrmVersion(¤t_srm_version)) {
|
||||
LOGW("CdmEngine::QueryStatus: GetCurrentSRMVersion failed");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
@@ -623,7 +630,7 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
current_srm_version_stream << current_srm_version;
|
||||
*query_response = current_srm_version_stream.str();
|
||||
} else if (query_token == QUERY_KEY_SRM_UPDATE_SUPPORT) {
|
||||
bool is_srm_update_supported = crypto_session.IsSrmUpdateSupported();
|
||||
bool is_srm_update_supported = crypto_session->IsSrmUpdateSupported();
|
||||
*query_response =
|
||||
is_srm_update_supported ? QUERY_VALUE_TRUE : QUERY_VALUE_FALSE;
|
||||
} else if (query_token == QUERY_KEY_WVCDM_VERSION) {
|
||||
@@ -827,10 +834,11 @@ CdmResponseType CdmEngine::HandleProvisioningResponse(
|
||||
if (NULL == cert_provisioning_.get()) {
|
||||
// Certificate provisioning object has been released. Check if a concurrent
|
||||
// provisioning attempt has succeeded before declaring failure.
|
||||
CryptoSession crypto_session(metrics_.GetCryptoMetrics());
|
||||
scoped_ptr<CryptoSession> crypto_session(
|
||||
CryptoSession::MakeCryptoSession(metrics_.GetCryptoMetrics()));
|
||||
CdmResponseType status;
|
||||
M_TIME(
|
||||
status = crypto_session.Open(
|
||||
status = crypto_session->Open(
|
||||
cert_provisioning_requested_security_level_),
|
||||
metrics_.GetCryptoMetrics(),
|
||||
crypto_session_open_,
|
||||
@@ -842,7 +850,7 @@ CdmResponseType CdmEngine::HandleProvisioningResponse(
|
||||
"missing and crypto session open failed.");
|
||||
return EMPTY_PROVISIONING_CERTIFICATE_2;
|
||||
}
|
||||
CdmSecurityLevel security_level = crypto_session.GetSecurityLevel();
|
||||
CdmSecurityLevel security_level = crypto_session->GetSecurityLevel();
|
||||
if (!IsProvisioned(security_level)) {
|
||||
LOGE(
|
||||
"CdmEngine::HandleProvisioningResponse: provisioning object "
|
||||
@@ -882,9 +890,10 @@ bool CdmEngine::IsProvisioned(CdmSecurityLevel security_level) {
|
||||
CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) {
|
||||
// Devices with baked-in DRM certs cannot be reprovisioned and therefore must
|
||||
// not be unprovisioned.
|
||||
CryptoSession crypto_session(metrics_.GetCryptoMetrics());
|
||||
scoped_ptr<CryptoSession> crypto_session(
|
||||
CryptoSession::MakeCryptoSession(metrics_.GetCryptoMetrics()));
|
||||
CdmClientTokenType token_type = kClientTokenUninitialized;
|
||||
CdmResponseType res = crypto_session.GetProvisioningMethod(
|
||||
CdmResponseType res = crypto_session->GetProvisioningMethod(
|
||||
security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault,
|
||||
&token_type);
|
||||
if (res != NO_ERROR) {
|
||||
@@ -915,10 +924,11 @@ CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) {
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::DeleteUsageTable(CdmSecurityLevel security_level) {
|
||||
CryptoSession crypto_session(metrics_.GetCryptoMetrics());
|
||||
scoped_ptr<CryptoSession> crypto_session(
|
||||
CryptoSession::MakeCryptoSession(metrics_.GetCryptoMetrics()));
|
||||
CdmResponseType status;
|
||||
M_TIME(
|
||||
status = crypto_session.Open(
|
||||
status = crypto_session->Open(
|
||||
security_level == kSecurityLevelL3 ?
|
||||
kLevel3 :
|
||||
kLevelDefault),
|
||||
@@ -931,7 +941,7 @@ CdmResponseType CdmEngine::DeleteUsageTable(CdmSecurityLevel security_level) {
|
||||
status);
|
||||
return UNPROVISION_ERROR_4;
|
||||
}
|
||||
status = crypto_session.DeleteAllUsageReports();
|
||||
status = crypto_session->DeleteAllUsageReports();
|
||||
metrics_.GetCryptoMetrics()->crypto_session_delete_all_usage_reports_
|
||||
.Increment(status);
|
||||
if (status != NO_ERROR) {
|
||||
@@ -998,7 +1008,7 @@ CdmResponseType CdmEngine::DeleteUsageRecord(const std::string& app_id,
|
||||
|
||||
// Got provider token. Remove from OEMCrypto.
|
||||
scoped_ptr<CryptoSession> crypto_session(
|
||||
new CryptoSession(metrics_.GetCryptoMetrics()));
|
||||
CryptoSession::MakeCryptoSession(metrics_.GetCryptoMetrics()));
|
||||
CdmResponseType status = crypto_session->Open(
|
||||
security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault);
|
||||
if (status == NO_ERROR) {
|
||||
@@ -1207,7 +1217,7 @@ CdmResponseType CdmEngine::RemoveAllUsageInfo(
|
||||
|
||||
// Got at least one provider token. Remove from OEMCrypto.
|
||||
scoped_ptr<CryptoSession> crypto_session(
|
||||
new CryptoSession(metrics_.GetCryptoMetrics()));
|
||||
CryptoSession::MakeCryptoSession(metrics_.GetCryptoMetrics()));
|
||||
CdmResponseType status = crypto_session->Open(
|
||||
security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault);
|
||||
if (status == NO_ERROR) {
|
||||
@@ -1361,7 +1371,7 @@ CdmResponseType CdmEngine::RemoveUsageInfo(
|
||||
DeviceFiles::GetUsageInfoFileName(app_id),
|
||||
provider_session_token);
|
||||
scoped_ptr<CryptoSession> crypto_session(
|
||||
new CryptoSession(metrics_.GetCryptoMetrics()));
|
||||
CryptoSession::MakeCryptoSession(metrics_.GetCryptoMetrics()));
|
||||
status = crypto_session->Open(
|
||||
static_cast<CdmSecurityLevel>(j) == kSecurityLevelL3
|
||||
? kLevel3 : kLevelDefault);
|
||||
@@ -1499,6 +1509,7 @@ CdmResponseType CdmEngine::Decrypt(const CdmSessionId& session_id,
|
||||
// else we must be level 1 direct and we don't need to return a buffer.
|
||||
}
|
||||
|
||||
AutoLock lock(session_map_lock_);
|
||||
shared_ptr<CdmSession> session;
|
||||
if (session_id.empty()) {
|
||||
CdmSessionList sessions;
|
||||
@@ -1619,6 +1630,7 @@ bool CdmEngine::FindSessionForKey(const KeyId& key_id,
|
||||
|
||||
uint32_t session_sharing_id = Properties::GetSessionSharingId(*session_id);
|
||||
|
||||
AutoLock lock(session_map_lock_);
|
||||
CdmSessionList sessions;
|
||||
session_map_.GetSessionList(sessions);
|
||||
|
||||
@@ -1664,9 +1676,6 @@ void CdmEngine::OnTimerEvent() {
|
||||
Clock clock;
|
||||
uint64_t current_time = clock.GetCurrentTime();
|
||||
|
||||
CdmSessionList sessions;
|
||||
session_map_.GetSessionList(sessions);
|
||||
|
||||
bool usage_update_period_expired = false;
|
||||
if (current_time - last_usage_information_update_time_ >
|
||||
kUpdateUsageInformationPeriod) {
|
||||
@@ -1677,47 +1686,54 @@ void CdmEngine::OnTimerEvent() {
|
||||
bool is_initial_usage_update = false;
|
||||
bool is_usage_update_needed = false;
|
||||
|
||||
while (!sessions.empty()) {
|
||||
is_initial_usage_update =
|
||||
is_initial_usage_update || sessions.front()->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();
|
||||
}
|
||||
|
||||
if (is_usage_update_needed &&
|
||||
(usage_update_period_expired || is_initial_usage_update)) {
|
||||
bool has_usage_been_updated = false;
|
||||
|
||||
// Session list may have changed. Rebuild.
|
||||
{
|
||||
AutoLock lock(session_map_lock_);
|
||||
CdmSessionList sessions;
|
||||
session_map_.GetSessionList(sessions);
|
||||
|
||||
for (CdmSessionList::iterator iter = sessions.begin();
|
||||
iter != sessions.end(); ++iter) {
|
||||
(*iter)->reset_usage_flags();
|
||||
switch ((*iter)->get_usage_support_type()) {
|
||||
case kUsageEntrySupport:
|
||||
if ((*iter)->has_provider_session_token()) {
|
||||
(*iter)->UpdateUsageEntryInformation();
|
||||
}
|
||||
break;
|
||||
case kUsageTableSupport:
|
||||
if (!has_usage_been_updated) {
|
||||
// usage is updated for all sessions so this needs to be
|
||||
// called only once per update usage information period
|
||||
CdmResponseType status = (*iter)->UpdateUsageTableInformation();
|
||||
if (NO_ERROR != status) {
|
||||
LOGW("Update usage information failed: %d", status);
|
||||
} else {
|
||||
has_usage_been_updated = true;
|
||||
while (!sessions.empty()) {
|
||||
is_initial_usage_update =
|
||||
is_initial_usage_update ||
|
||||
sessions.front()->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();
|
||||
}
|
||||
|
||||
if (is_usage_update_needed &&
|
||||
(usage_update_period_expired || is_initial_usage_update)) {
|
||||
bool has_usage_been_updated = false;
|
||||
|
||||
// Session list may have changed. Rebuild.
|
||||
session_map_.GetSessionList(sessions);
|
||||
|
||||
for (CdmSessionList::iterator iter = sessions.begin();
|
||||
iter != sessions.end(); ++iter) {
|
||||
(*iter)->reset_usage_flags();
|
||||
switch ((*iter)->get_usage_support_type()) {
|
||||
case kUsageEntrySupport:
|
||||
if ((*iter)->has_provider_session_token()) {
|
||||
(*iter)->UpdateUsageEntryInformation();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Ignore
|
||||
break;
|
||||
break;
|
||||
case kUsageTableSupport:
|
||||
if (!has_usage_been_updated) {
|
||||
// usage is updated for all sessions so this needs to be
|
||||
// called only once per update usage information period
|
||||
CdmResponseType status = (*iter)->UpdateUsageTableInformation();
|
||||
if (NO_ERROR != status) {
|
||||
LOGW("Update usage information failed: %d", status);
|
||||
} else {
|
||||
has_usage_been_updated = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Ignore
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1793,7 +1809,7 @@ void CdmEngine::DeleteAllUsageReportsUponFactoryReset() {
|
||||
if (!file_system_->Exists(device_base_path_level1) &&
|
||||
!file_system_->Exists(device_base_path_level3)) {
|
||||
scoped_ptr<CryptoSession> crypto_session(
|
||||
new CryptoSession(metrics_.GetCryptoMetrics()));
|
||||
CryptoSession::MakeCryptoSession(metrics_.GetCryptoMetrics()));
|
||||
CdmResponseType status;
|
||||
M_TIME(
|
||||
status = crypto_session->Open(
|
||||
|
||||
@@ -49,7 +49,7 @@ CdmSession::CdmSession(FileSystem* file_system,
|
||||
mock_policy_engine_in_use_(false) {
|
||||
assert(metrics_); // metrics_ must not be null.
|
||||
crypto_metrics_ = metrics_->GetCryptoMetrics();
|
||||
crypto_session_.reset(new CryptoSession(crypto_metrics_));
|
||||
crypto_session_.reset(CryptoSession::MakeCryptoSession(crypto_metrics_));
|
||||
life_span_.Start();
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set,
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::RestoreOfflineSession(
|
||||
const CdmKeySetId& key_set_id, const CdmLicenseType license_type) {
|
||||
const CdmKeySetId& key_set_id, CdmLicenseType license_type) {
|
||||
if (!initialized_) {
|
||||
LOGE("CdmSession::RestoreOfflineSession: not initialized");
|
||||
return NOT_INITIALIZED_ERROR;
|
||||
@@ -214,7 +214,14 @@ CdmResponseType CdmSession::RestoreOfflineSession(
|
||||
return GET_LICENSE_ERROR;
|
||||
}
|
||||
|
||||
// Do not restore a released offline license, unless a release retry
|
||||
// Attempts to restore a released offline license are treated as a release
|
||||
// retry.
|
||||
if (license_state == DeviceFiles::kLicenseStateReleasing) {
|
||||
license_type = kLicenseTypeRelease;
|
||||
}
|
||||
|
||||
// Only restore offline licenses if they are active or this is a release
|
||||
// retry.
|
||||
if (!(license_type == kLicenseTypeRelease ||
|
||||
license_state == DeviceFiles::kLicenseStateActive)) {
|
||||
LOGE(
|
||||
@@ -577,18 +584,21 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
|
||||
return NOT_INITIALIZED_ERROR;
|
||||
}
|
||||
|
||||
// Playback may not begin until either the start time passes or the license
|
||||
// is updated, so we treat this Decrypt call as invalid.
|
||||
if (params.is_encrypted &&
|
||||
!policy_engine_->CanDecryptContent(*params.key_id)) {
|
||||
if (policy_engine_->IsLicenseForFuture()) return DECRYPT_NOT_READY;
|
||||
if (!policy_engine_->IsSufficientOutputProtection(*params.key_id))
|
||||
return INSUFFICIENT_OUTPUT_PROTECTION;
|
||||
return NEED_KEY;
|
||||
}
|
||||
|
||||
if (!policy_engine_->CanUseKey(*params.key_id, security_level_)) {
|
||||
return KEY_PROHIBITED_FOR_SECURITY_LEVEL;
|
||||
// Encrypted playback may not begin until either the start time passes or the
|
||||
// license is updated, so we treat this Decrypt call as invalid.
|
||||
// For the clear lead, we allow playback even if the key_id is not found or if
|
||||
// the security level is not high enough yet.
|
||||
if (params.is_encrypted) {
|
||||
if (!policy_engine_->CanDecryptContent(*params.key_id)) {
|
||||
if (policy_engine_->IsLicenseForFuture()) return DECRYPT_NOT_READY;
|
||||
if (!policy_engine_->IsSufficientOutputProtection(*params.key_id))
|
||||
return INSUFFICIENT_OUTPUT_PROTECTION;
|
||||
return NEED_KEY;
|
||||
}
|
||||
if (!policy_engine_->CanUseKeyForSecurityLevel(*params.key_id,
|
||||
security_level_)) {
|
||||
return KEY_PROHIBITED_FOR_SECURITY_LEVEL;
|
||||
}
|
||||
}
|
||||
|
||||
CdmResponseType status = crypto_session_->Decrypt(params);
|
||||
@@ -732,7 +742,7 @@ CdmResponseType CdmSession::DeleteUsageEntry(uint32_t usage_entry_number) {
|
||||
// it, so close and reopen session.
|
||||
CdmResponseType sts;
|
||||
crypto_session_->Close();
|
||||
crypto_session_.reset(new CryptoSession(crypto_metrics_));
|
||||
crypto_session_.reset(CryptoSession::MakeCryptoSession(crypto_metrics_));
|
||||
M_TIME(sts = crypto_session_->Open(requested_security_level_),
|
||||
crypto_metrics_, crypto_session_open_, sts, requested_security_level_);
|
||||
if (sts != NO_ERROR) return sts;
|
||||
@@ -868,7 +878,7 @@ bool CdmSession::StoreLicense(DeviceFiles::LicenseState state) {
|
||||
|
||||
CdmResponseType CdmSession::RemoveKeys() {
|
||||
CdmResponseType sts;
|
||||
crypto_session_.reset(new CryptoSession(crypto_metrics_));
|
||||
crypto_session_.reset(CryptoSession::MakeCryptoSession(crypto_metrics_));
|
||||
// Ignore errors
|
||||
M_TIME(
|
||||
sts = crypto_session_->Open(requested_security_level_),
|
||||
|
||||
@@ -12,7 +12,10 @@
|
||||
namespace wvcdm {
|
||||
|
||||
CdmSessionMap::~CdmSessionMap() {
|
||||
AutoLock lock(lock_);
|
||||
Terminate();
|
||||
}
|
||||
|
||||
void CdmSessionMap::Terminate() {
|
||||
for (CdmIdToSessionMap::iterator i = sessions_.begin();
|
||||
i != sessions_.end(); ++i) {
|
||||
i->second->Close();
|
||||
@@ -22,12 +25,10 @@ CdmSessionMap::~CdmSessionMap() {
|
||||
}
|
||||
|
||||
void CdmSessionMap::Add(const std::string& id, CdmSession* session) {
|
||||
AutoLock lock(lock_);
|
||||
sessions_[id].reset(session);
|
||||
}
|
||||
|
||||
bool CdmSessionMap::CloseSession(const std::string& id) {
|
||||
AutoLock lock(lock_);
|
||||
shared_ptr<CdmSession> session;
|
||||
if (!FindSessionNoLock(id, &session)) {
|
||||
return false;
|
||||
@@ -38,13 +39,11 @@ bool CdmSessionMap::CloseSession(const std::string& id) {
|
||||
}
|
||||
|
||||
bool CdmSessionMap::Exists(const std::string& id) {
|
||||
AutoLock lock(lock_);
|
||||
return sessions_.find(id) != sessions_.end();
|
||||
}
|
||||
|
||||
bool CdmSessionMap::FindSession(const CdmSessionId& id,
|
||||
shared_ptr<CdmSession>* session) {
|
||||
AutoLock lock(lock_);
|
||||
return FindSessionNoLock(id, session);
|
||||
}
|
||||
|
||||
@@ -61,7 +60,6 @@ bool CdmSessionMap::FindSessionNoLock(const CdmSessionId& session_id,
|
||||
|
||||
void CdmSessionMap::GetSessionList(CdmSessionList& sessions) {
|
||||
sessions.clear();
|
||||
AutoLock lock(lock_);
|
||||
for (CdmIdToSessionMap::iterator iter = sessions_.begin();
|
||||
iter != sessions_.end(); ++iter) {
|
||||
if (!(iter->second)->IsClosed()) {
|
||||
|
||||
@@ -142,7 +142,7 @@ bool CertificateProvisioning::SetSpoidParameter(
|
||||
} else if (origin != EMPTY_ORIGIN) {
|
||||
// Legacy behavior - Concatenate Unique ID with Origin
|
||||
std::string device_unique_id;
|
||||
if (!crypto_session_.GetInternalDeviceUniqueId(&device_unique_id)) {
|
||||
if (!crypto_session_->GetInternalDeviceUniqueId(&device_unique_id)) {
|
||||
LOGE("CertificateProvisioning::SetSpoidParameter: Failure getting "
|
||||
"device unique ID");
|
||||
return false;
|
||||
@@ -158,7 +158,7 @@ bool CertificateProvisioning::SetSpoidParameter(
|
||||
*/
|
||||
SignedProvisioningMessage::ProtocolVersion
|
||||
CertificateProvisioning::GetProtocolVersion() {
|
||||
if (crypto_session_.GetPreProvisionTokenType() == kClientTokenOemCert)
|
||||
if (crypto_session_->GetPreProvisionTokenType() == kClientTokenOemCert)
|
||||
return SignedProvisioningMessage::VERSION_3;
|
||||
else
|
||||
return SignedProvisioningMessage::VERSION_2;
|
||||
@@ -183,7 +183,7 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequest(
|
||||
|
||||
default_url->assign(kProvisioningServerUrl);
|
||||
|
||||
CdmResponseType status = crypto_session_.Open(requested_security_level);
|
||||
CdmResponseType status = crypto_session_->Open(requested_security_level);
|
||||
if (NO_ERROR != status) {
|
||||
LOGE("GetProvisioningRequest: fails to create a crypto session");
|
||||
return status;
|
||||
@@ -193,7 +193,7 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequest(
|
||||
ProvisioningRequest provisioning_request;
|
||||
|
||||
wvcdm::ClientIdentification id;
|
||||
status = id.Init(&crypto_session_);
|
||||
status = id.Init(crypto_session_.get());
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
video_widevine::ClientIdentification* client_id =
|
||||
@@ -212,12 +212,12 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequest(
|
||||
// Encrypt client identification
|
||||
EncryptedClientIdentification* encrypted_client_id =
|
||||
provisioning_request.mutable_encrypted_client_id();
|
||||
status = service_certificate_->EncryptClientId(&crypto_session_, client_id,
|
||||
encrypted_client_id);
|
||||
status = service_certificate_->EncryptClientId(
|
||||
crypto_session_.get(), client_id, encrypted_client_id);
|
||||
provisioning_request.clear_client_id();
|
||||
|
||||
uint32_t nonce;
|
||||
if (!crypto_session_.GenerateNonce(&nonce)) {
|
||||
if (!crypto_session_->GenerateNonce(&nonce)) {
|
||||
LOGE("GetProvisioningRequest: fails to generate a nonce");
|
||||
return CERT_PROVISIONING_NONCE_GENERATION_ERROR;
|
||||
}
|
||||
@@ -254,7 +254,7 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequest(
|
||||
|
||||
// Derives signing and encryption keys and constructs signature.
|
||||
std::string request_signature;
|
||||
if (!crypto_session_.PrepareRequest(serialized_message, true,
|
||||
if (!crypto_session_->PrepareRequest(serialized_message, true,
|
||||
&request_signature)) {
|
||||
LOGE("GetProvisioningRequest: fails to prepare request");
|
||||
return CERT_PROVISIONING_REQUEST_ERROR_3;
|
||||
@@ -351,7 +351,7 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||
|
||||
// If Provisioning 3.0 (OEM Cert provisioned), verify that the
|
||||
// message is properly signed.
|
||||
if (crypto_session_.GetPreProvisionTokenType() == kClientTokenOemCert) {
|
||||
if (crypto_session_->GetPreProvisionTokenType() == kClientTokenOemCert) {
|
||||
if (service_certificate_->VerifySignedMessage(signed_message, signature)
|
||||
!= NO_ERROR) {
|
||||
// TODO(b/69562876): if the cert is bad, request a new one.
|
||||
@@ -369,14 +369,14 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||
|
||||
std::string wrapped_private_key;
|
||||
|
||||
if (!crypto_session_.RewrapCertificate(signed_message, signature, nonce,
|
||||
if (!crypto_session_->RewrapCertificate(signed_message, signature, nonce,
|
||||
new_private_key, iv, wrapping_key,
|
||||
&wrapped_private_key)) {
|
||||
LOGE("HandleProvisioningResponse: RewrapCertificate fails");
|
||||
return CERT_PROVISIONING_RESPONSE_ERROR_6;
|
||||
}
|
||||
|
||||
crypto_session_.Close();
|
||||
crypto_session_->Close();
|
||||
|
||||
if (cert_type_ == kCertificateX509) {
|
||||
*cert = provisioning_response.device_certificate();
|
||||
@@ -391,7 +391,7 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||
provisioning_response.device_certificate();
|
||||
|
||||
DeviceFiles handle(file_system);
|
||||
if (!handle.Init(crypto_session_.GetSecurityLevel())) {
|
||||
if (!handle.Init(crypto_session_->GetSecurityLevel())) {
|
||||
LOGE("HandleProvisioningResponse: failed to init DeviceFiles");
|
||||
return CERT_PROVISIONING_RESPONSE_ERROR_7;
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ void GenerateEncryptContext(const std::string& input_context,
|
||||
}
|
||||
|
||||
const std::string kEncryptionKeyLabel = "ENCRYPTION";
|
||||
const size_t kEncryptionKeySizeBits = wvcdm::KEY_SIZE * 8;
|
||||
const size_t kEncryptionKeySizeBits = wvcdm::CONTENT_KEY_SIZE * 8;
|
||||
|
||||
deriv_context->assign(kEncryptionKeyLabel);
|
||||
deriv_context->append(1, '\0');
|
||||
@@ -981,6 +981,8 @@ CdmResponseType CryptoSession::SelectKey(const std::string& key_id,
|
||||
return NO_DEVICE_KEY_1;
|
||||
case OEMCrypto_ERROR_NO_CONTENT_KEY:
|
||||
return NO_CONTENT_KEY_2;
|
||||
case OEMCrypto_KEY_NOT_LOADED:
|
||||
return NO_CONTENT_KEY_3;
|
||||
case OEMCrypto_ERROR_INSUFFICIENT_RESOURCES:
|
||||
return INSUFFICIENT_CRYPTO_RESOURCES_2;
|
||||
case OEMCrypto_ERROR_UNKNOWN_FAILURE:
|
||||
@@ -2115,6 +2117,8 @@ CdmResponseType CryptoSession::LoadUsageEntry(
|
||||
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;
|
||||
default:
|
||||
return LOAD_USAGE_ENTRY_UNKNOWN_ERROR;
|
||||
}
|
||||
@@ -2572,4 +2576,20 @@ void CryptoSession::IncrementIV(uint64_t increase_by,
|
||||
(*counter_buffer) = htonll64(ntohll64(*counter_buffer) + increase_by);
|
||||
}
|
||||
|
||||
// The factory will either be set by WvCdmTestBase, or a default factory is
|
||||
// created on the first call to MakeCryptoSession.
|
||||
scoped_ptr<CryptoSessionFactory> CryptoSession::factory_(NULL);
|
||||
|
||||
CryptoSession* CryptoSession::MakeCryptoSession(
|
||||
metrics::CryptoMetrics* crypto_metrics) {
|
||||
// If the factory_ has not been set, then use a default factory.
|
||||
if (factory_.get() == NULL) factory_.reset(new CryptoSessionFactory());
|
||||
return factory_->MakeCryptoSession(crypto_metrics);
|
||||
}
|
||||
|
||||
CryptoSession* CryptoSessionFactory::MakeCryptoSession(
|
||||
metrics::CryptoMetrics* crypto_metrics) {
|
||||
return new CryptoSession(crypto_metrics);
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
@@ -611,6 +611,15 @@ bool DeviceFiles::DeleteAllUsageInfoForApp(
|
||||
return RemoveFile(usage_info_file_name);
|
||||
}
|
||||
|
||||
bool DeviceFiles::DeleteAllUsageInfo() {
|
||||
if (!initialized_) {
|
||||
LOGW("DeviceFiles::DeleteAllUsageInfo: not initialized");
|
||||
return false;
|
||||
}
|
||||
return RemoveFile(kUsageInfoFileNamePrefix + std::string(kWildcard) +
|
||||
kUsageInfoFileNameExt);
|
||||
}
|
||||
|
||||
bool DeviceFiles::RetrieveUsageInfo(
|
||||
const std::string& usage_info_file_name,
|
||||
std::vector<std::pair<CdmKeyMessage, CdmKeyResponse> >* usage_info) {
|
||||
@@ -1105,6 +1114,14 @@ bool DeviceFiles::RetrieveUsageTableInfo(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceFiles::DeleteUsageTableInfo() {
|
||||
if (!initialized_) {
|
||||
LOGW("DeviceFiles::DeleteUsageTableInfo: not initialized");
|
||||
return false;
|
||||
}
|
||||
return RemoveFile(GetUsageTableFileName());
|
||||
}
|
||||
|
||||
bool DeviceFiles::StoreFileWithHash(const std::string& name,
|
||||
const std::string& serialized_file) {
|
||||
// calculate SHA hash
|
||||
|
||||
@@ -66,7 +66,7 @@ InitializationData::InitializationData(const std::string& type,
|
||||
is_hls_ = true;
|
||||
}
|
||||
|
||||
if (is_supported()) {
|
||||
if (data.size() && is_supported()) {
|
||||
if (is_cenc()) {
|
||||
bool oec_prefers_entitlements = DetectEntitlementPreference(oec_version);
|
||||
if (!SelectWidevinePssh(data, oec_prefers_entitlements, &data_)) {
|
||||
|
||||
@@ -143,6 +143,7 @@ static std::vector<CryptoKey> ExtractContentKeys(const License& license) {
|
||||
key.set_key_id(license.key(i).id());
|
||||
// Strip off PKCS#5 padding - since we know the key is 16 or 32 bytes,
|
||||
// the padding will always be 16 bytes.
|
||||
// TODO(b/111069024): remove this!
|
||||
if (license.key(i).key().size() > 16) {
|
||||
length = license.key(i).key().size() - 16;
|
||||
} else {
|
||||
@@ -632,7 +633,7 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
||||
"CdmLicense::HandleKeyResponse: mac key/iv size error"
|
||||
"(key/iv size expected: %d/%d, actual: %d/%d",
|
||||
MAC_KEY_SIZE, KEY_IV_SIZE, mac_key.size(), mac_key_iv.size());
|
||||
return KEY_SIZE_ERROR;
|
||||
return KEY_SIZE_ERROR_1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1125,11 +1126,11 @@ CdmResponseType CdmLicense::HandleEntitlementKeyResponse(
|
||||
CdmResponseType CdmLicense::HandleNewEntitledKeys(
|
||||
const std::vector<WidevinePsshData_EntitledKey>& wrapped_keys) {
|
||||
std::vector<CryptoKey> entitled_key_array;
|
||||
entitled_key_array.reserve(entitlement_keys_.size());
|
||||
entitled_key_array.reserve(wrapped_keys.size());
|
||||
|
||||
for (RepeatedPtrField<License_KeyContainer>::const_iterator kc =
|
||||
entitlement_keys_.begin();
|
||||
kc != entitlement_keys_.end(); kc++) {
|
||||
kc != entitlement_keys_.end(); ++kc) {
|
||||
if (kc->type() != video_widevine::License::KeyContainer::ENTITLEMENT) {
|
||||
continue;
|
||||
}
|
||||
@@ -1142,8 +1143,11 @@ CdmResponseType CdmLicense::HandleNewEntitledKeys(
|
||||
|
||||
// Strip PKCS#5 padding from entitled content keys.
|
||||
std::string content_key = wk->key();
|
||||
if (content_key.size() > KEY_SIZE) {
|
||||
content_key.resize(KEY_SIZE);
|
||||
if (content_key.size() < CONTENT_KEY_SIZE) {
|
||||
LOGE("Entitled Key too small, %lu bytes", content_key.size());
|
||||
return KEY_SIZE_ERROR_2;
|
||||
} else if (content_key.size() > CONTENT_KEY_SIZE) {
|
||||
content_key.resize(CONTENT_KEY_SIZE);
|
||||
}
|
||||
|
||||
CryptoKey& this_entry = entitled_key_array.back();
|
||||
@@ -1192,8 +1196,8 @@ CdmResponseType CdmLicense::HandleSubLicense(
|
||||
|
||||
// Strip PKCS#5 padding from sublicense content keys.
|
||||
// TODO(jfore): Refactor this to use ExtractContentKeys.
|
||||
if (keyc.key().size() > KEY_SIZE) {
|
||||
length = keyc.key().size() - KEY_SIZE;
|
||||
if (keyc.key().size() > CONTENT_KEY_SIZE) {
|
||||
length = keyc.key().size() - CONTENT_KEY_SIZE;
|
||||
} else {
|
||||
length = 0;
|
||||
}
|
||||
|
||||
@@ -66,8 +66,8 @@ VideoResolutionConstraint* GetConstraintForRes(
|
||||
namespace wvcdm {
|
||||
|
||||
bool LicenseKeys::IsContentKey(const std::string& key_id) {
|
||||
if (keys_.count(key_id) > 0) {
|
||||
return keys_[key_id]->IsContentKey();
|
||||
if (key_statuses_.count(key_id) > 0) {
|
||||
return key_statuses_[key_id]->IsContentKey();
|
||||
} else if (content_keyid_to_entitlement_key_id_.count(key_id) > 0) {
|
||||
return true;
|
||||
} else {
|
||||
@@ -76,11 +76,11 @@ bool LicenseKeys::IsContentKey(const std::string& key_id) {
|
||||
}
|
||||
|
||||
bool LicenseKeys::CanDecryptContent(const std::string& key_id) {
|
||||
if (keys_.count(key_id) > 0) {
|
||||
return keys_[key_id]->CanDecryptContent();
|
||||
if (key_statuses_.count(key_id) > 0) {
|
||||
return key_statuses_[key_id]->CanDecryptContent();
|
||||
} else if (content_keyid_to_entitlement_key_id_.count(key_id) > 0) {
|
||||
if (keys_.count(content_keyid_to_entitlement_key_id_[key_id]) > 0) {
|
||||
return keys_[content_keyid_to_entitlement_key_id_[key_id]]
|
||||
if (key_statuses_.count(content_keyid_to_entitlement_key_id_[key_id]) > 0) {
|
||||
return key_statuses_[content_keyid_to_entitlement_key_id_[key_id]]
|
||||
->CanDecryptContent();
|
||||
}
|
||||
return false;
|
||||
@@ -91,11 +91,11 @@ bool LicenseKeys::CanDecryptContent(const std::string& key_id) {
|
||||
|
||||
bool LicenseKeys::GetAllowedUsage(const KeyId& key_id,
|
||||
CdmKeyAllowedUsage* allowed_usage) {
|
||||
if (keys_.count(key_id) > 0) {
|
||||
return keys_[key_id]->GetAllowedUsage(allowed_usage);
|
||||
if (key_statuses_.count(key_id) > 0) {
|
||||
return key_statuses_[key_id]->GetAllowedUsage(allowed_usage);
|
||||
} else if (content_keyid_to_entitlement_key_id_.count(key_id) > 0) {
|
||||
if (keys_.count(content_keyid_to_entitlement_key_id_[key_id]) > 0) {
|
||||
return keys_[content_keyid_to_entitlement_key_id_[key_id]]
|
||||
if (key_statuses_.count(content_keyid_to_entitlement_key_id_[key_id]) > 0) {
|
||||
return key_statuses_[content_keyid_to_entitlement_key_id_[key_id]]
|
||||
->CanDecryptContent();
|
||||
}
|
||||
return false;
|
||||
@@ -109,7 +109,8 @@ bool LicenseKeys::ApplyStatusChange(CdmKeyStatus new_status,
|
||||
bool keys_changed = false;
|
||||
bool newly_usable = false;
|
||||
*new_usable_keys = false;
|
||||
for (LicenseKeyStatusIterator it = keys_.begin(); it != keys_.end(); ++it) {
|
||||
for (LicenseKeyStatusIterator it = key_statuses_.begin();
|
||||
it != key_statuses_.end(); ++it) {
|
||||
bool usable;
|
||||
if (it->second->ApplyStatusChange(new_status, &usable)) {
|
||||
newly_usable |= usable;
|
||||
@@ -121,15 +122,16 @@ bool LicenseKeys::ApplyStatusChange(CdmKeyStatus new_status,
|
||||
}
|
||||
|
||||
CdmKeyStatus LicenseKeys::GetKeyStatus(const KeyId& key_id) {
|
||||
if (keys_.count(key_id) == 0) {
|
||||
if (key_statuses_.count(key_id) == 0) {
|
||||
return kKeyStatusKeyUnknown;
|
||||
}
|
||||
return keys_[key_id]->GetKeyStatus();
|
||||
return key_statuses_[key_id]->GetKeyStatus();
|
||||
}
|
||||
|
||||
void LicenseKeys::ExtractKeyStatuses(CdmKeyStatusMap* content_keys) {
|
||||
content_keys->clear();
|
||||
for (LicenseKeyStatusIterator it = keys_.begin(); it != keys_.end(); ++it) {
|
||||
for (LicenseKeyStatusIterator it = key_statuses_.begin();
|
||||
it != key_statuses_.end(); ++it) {
|
||||
if (it->second->IsContentKey()) {
|
||||
const KeyId key_id = it->first;
|
||||
CdmKeyStatus key_status = it->second->GetKeyStatus();
|
||||
@@ -139,8 +141,8 @@ void LicenseKeys::ExtractKeyStatuses(CdmKeyStatusMap* content_keys) {
|
||||
}
|
||||
|
||||
bool LicenseKeys::MeetsConstraints(const KeyId& key_id) {
|
||||
if (keys_.count(key_id) > 0) {
|
||||
return keys_[key_id]->MeetsConstraints();
|
||||
if (key_statuses_.count(key_id) > 0) {
|
||||
return key_statuses_[key_id]->MeetsConstraints();
|
||||
} else {
|
||||
// If a Key ID is unknown to us, we don't know of any constraints for it,
|
||||
// so never block decryption.
|
||||
@@ -150,7 +152,8 @@ bool LicenseKeys::MeetsConstraints(const KeyId& key_id) {
|
||||
|
||||
void LicenseKeys::ApplyConstraints(
|
||||
uint32_t new_resolution, CryptoSession::HdcpCapability new_hdcp_level) {
|
||||
for (LicenseKeyStatusIterator i = keys_.begin(); i != keys_.end(); ++i) {
|
||||
for (LicenseKeyStatusIterator i = key_statuses_.begin();
|
||||
i != key_statuses_.end(); ++i) {
|
||||
i->second->ApplyConstraints(new_resolution, new_hdcp_level);
|
||||
}
|
||||
}
|
||||
@@ -163,7 +166,7 @@ void LicenseKeys::SetFromLicense(const video_widevine::License& license) {
|
||||
key.type() == KeyContainer::OPERATOR_SESSION ||
|
||||
key.type() == KeyContainer::ENTITLEMENT)) {
|
||||
const KeyId& key_id = key.id();
|
||||
keys_[key_id] = new LicenseKeyStatus(key);
|
||||
key_statuses_[key_id] = new LicenseKeyStatus(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,8 +178,8 @@ void LicenseKeys::SetEntitledKeys(
|
||||
key != keys.end(); key++) {
|
||||
// Check to see if we have an entitlement key for this content key.
|
||||
std::map<KeyId, LicenseKeyStatus*>::iterator entitlement =
|
||||
keys_.find(key->entitlement_key_id());
|
||||
if (entitlement == keys_.end()) {
|
||||
key_statuses_.find(key->entitlement_key_id());
|
||||
if (entitlement == key_statuses_.end()) {
|
||||
continue;
|
||||
}
|
||||
// And set the new content key id.
|
||||
@@ -271,10 +274,11 @@ void LicenseKeyStatus::ParseOperatorSessionKey(const KeyContainer& key) {
|
||||
}
|
||||
|
||||
void LicenseKeys::Clear() {
|
||||
for (LicenseKeyStatusIterator i = keys_.begin(); i != keys_.end(); ++i) {
|
||||
for (LicenseKeyStatusIterator i = key_statuses_.begin();
|
||||
i != key_statuses_.end(); ++i) {
|
||||
delete i->second;
|
||||
}
|
||||
keys_.clear();
|
||||
key_statuses_.clear();
|
||||
}
|
||||
|
||||
bool LicenseKeyStatus::CanDecryptContent() {
|
||||
|
||||
@@ -21,8 +21,8 @@ OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox,
|
||||
return ::OEMCrypto_InstallKeybox(keybox, keyBoxLength);
|
||||
}
|
||||
|
||||
OEMCryptoResult OEMCrypto_IsKeyboxValid(SecurityLevel) {
|
||||
return ::OEMCrypto_IsKeyboxValid();
|
||||
OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(SecurityLevel) {
|
||||
return ::OEMCrypto_IsKeyboxOrOEMCertValid();
|
||||
}
|
||||
|
||||
OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID, size_t* idLength,
|
||||
|
||||
@@ -314,7 +314,7 @@ CdmResponseType PolicyEngine::QueryKeyAllowedUsage(
|
||||
return KEY_NOT_FOUND_1;
|
||||
}
|
||||
|
||||
bool PolicyEngine::CanUseKey(
|
||||
bool PolicyEngine::CanUseKeyForSecurityLevel(
|
||||
const KeyId& key_id,
|
||||
CdmSecurityLevel security_level) {
|
||||
|
||||
|
||||
@@ -189,9 +189,9 @@ bool RsaPublicKey::Encrypt(const std::string& clear_message,
|
||||
return true;
|
||||
}
|
||||
|
||||
// LogOpenSSLError is a callback from OpenSSL which is called with each error
|
||||
// LogBoringSSLError is a callback from BoringSSL which is called with each error
|
||||
// in the thread's error queue.
|
||||
static int LogOpenSSLError(const char* msg, size_t /* len */, void* /* ctx */) {
|
||||
static int LogBoringSSLError(const char* msg, size_t /* len */, void* /* ctx */) {
|
||||
LOGE(" %s", msg);
|
||||
return 1;
|
||||
}
|
||||
@@ -242,7 +242,7 @@ static bool VerifyPSSSignature(EVP_PKEY *pkey, const std::string &message,
|
||||
return true;
|
||||
|
||||
err:
|
||||
ERR_print_errors_cb(LogOpenSSLError, NULL);
|
||||
ERR_print_errors_cb(LogBoringSSLError, NULL);
|
||||
EVP_MD_CTX_free(evp_md_ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//
|
||||
// Description:
|
||||
// Dummy version of privacy crypto classes for systems which
|
||||
// can't tolerate OpenSSL as a dependency.
|
||||
// can't tolerate BoringSSL or OpenSSL as a dependency.
|
||||
//
|
||||
|
||||
#include "privacy_crypto.h"
|
||||
|
||||
@@ -226,7 +226,7 @@ CdmResponseType ServiceCertificate::EncryptClientId(
|
||||
encrypted_client_id->set_service_certificate_serial_number(serial_number_);
|
||||
|
||||
std::string iv(KEY_IV_SIZE, 0);
|
||||
std::string key(KEY_SIZE, 0);
|
||||
std::string key(SERVICE_KEY_SIZE, 0);
|
||||
|
||||
if (!crypto_session->GetRandom(key.size(),
|
||||
reinterpret_cast<uint8_t*>(&key[0])))
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
|
||||
namespace {
|
||||
std::string kEmptyString;
|
||||
size_t kMaxCryptoRetries = 3;
|
||||
size_t kMinUsageEntriesSupported = 200;
|
||||
wvcdm::CdmKeySetId kDummyKeySetId = "DummyKsid";
|
||||
uint64_t kOldUsageEntryTimeSinceLicenseReceived = 0;
|
||||
uint64_t kOldUsageEntryTimeSinceFirstDecrypt = 0;
|
||||
uint64_t kOldUsageEntryTimeSinceLastDecrypt = 0;
|
||||
@@ -58,14 +61,42 @@ bool UsageTableHeader::Init(CdmSecurityLevel security_level,
|
||||
}
|
||||
|
||||
CdmResponseType status = USAGE_INFO_NOT_FOUND;
|
||||
metrics::CryptoMetrics* metrics = crypto_session->GetCryptoMetrics();
|
||||
if (metrics == NULL) metrics = &alternate_crypto_metrics_;
|
||||
|
||||
if (file_handle_->RetrieveUsageTableInfo(&usage_table_header_,
|
||||
&usage_entry_info_)) {
|
||||
status = crypto_session->LoadUsageTableHeader(usage_table_header_);
|
||||
|
||||
// If the usage table header has been successfully loaded, and is at
|
||||
// minimum capacity (>200), we need to make sure we can still add and
|
||||
// remove entries. If not, clear files/data and recreate usage header table.
|
||||
if (status == NO_ERROR) {
|
||||
if (usage_entry_info_.size() > kMinUsageEntriesSupported) {
|
||||
uint32_t temporary_usage_entry_number;
|
||||
CdmResponseType result = AddEntry(crypto_session, true,
|
||||
kDummyKeySetId, kEmptyString,
|
||||
&temporary_usage_entry_number);
|
||||
if (result == NO_ERROR) {
|
||||
result = DeleteEntry(temporary_usage_entry_number,
|
||||
file_handle_.get(), metrics);
|
||||
}
|
||||
if (result != NO_ERROR) {
|
||||
LOGE("UsageTableHeader::Init: Unable to create/delete new entry. "
|
||||
"Clear usage entries, security level: %d, usage entries: %d",
|
||||
security_level, usage_entry_info_.size());
|
||||
status = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (status != NO_ERROR) {
|
||||
LOGE(
|
||||
"UsageTableHeader::Init: load usage table failed, security level: %d",
|
||||
security_level);
|
||||
file_handle_->DeleteAllLicenses();
|
||||
file_handle_->DeleteAllUsageInfo();
|
||||
file_handle_->DeleteUsageTableInfo();
|
||||
usage_entry_info_.clear();
|
||||
usage_table_header_.clear();
|
||||
status = crypto_session->CreateUsageTableHeader(&usage_table_header_);
|
||||
@@ -77,11 +108,6 @@ bool UsageTableHeader::Init(CdmSecurityLevel security_level,
|
||||
if (status != NO_ERROR) return false;
|
||||
file_handle_->StoreUsageTableInfo(usage_table_header_, usage_entry_info_);
|
||||
|
||||
metrics::CryptoMetrics alternate_metrics;
|
||||
metrics::CryptoMetrics* metrics =
|
||||
crypto_session->GetCryptoMetrics() != NULL ?
|
||||
crypto_session->GetCryptoMetrics() : &alternate_metrics;
|
||||
|
||||
UpgradeFromUsageTable(file_handle_.get(), metrics);
|
||||
file_handle_->StoreUsageTableInfo(usage_table_header_, usage_entry_info_);
|
||||
}
|
||||
@@ -95,11 +121,25 @@ CdmResponseType UsageTableHeader::AddEntry(
|
||||
const CdmKeySetId& key_set_id, const std::string& usage_info_file_name,
|
||||
uint32_t* usage_entry_number) {
|
||||
LOGV("UsageTableHeader::AddEntry: Lock");
|
||||
AutoLock auto_lock(usage_table_header_lock_);
|
||||
CdmResponseType status = crypto_session->CreateUsageEntry(usage_entry_number);
|
||||
|
||||
metrics::CryptoMetrics* metrics = crypto_session->GetCryptoMetrics();
|
||||
if (metrics == NULL) metrics = &alternate_crypto_metrics_;
|
||||
|
||||
uint32_t retry_count = 0;
|
||||
CdmResponseType status = NO_ERROR;
|
||||
do {
|
||||
{
|
||||
AutoLock auto_lock(usage_table_header_lock_);
|
||||
status = crypto_session->CreateUsageEntry(usage_entry_number);
|
||||
}
|
||||
if (status == INSUFFICIENT_CRYPTO_RESOURCES_3)
|
||||
DeleteEntry(retry_count, file_handle_.get(), metrics);
|
||||
} while (status == INSUFFICIENT_CRYPTO_RESOURCES_3 &&
|
||||
++retry_count < kMaxCryptoRetries);
|
||||
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
AutoLock auto_lock(usage_table_header_lock_);
|
||||
if (*usage_entry_number < usage_entry_info_.size()) {
|
||||
LOGE("UsageTableHeader::AddEntry: new entry %d smaller than table size: %d",
|
||||
*usage_entry_number, usage_entry_info_.size());
|
||||
@@ -134,17 +174,34 @@ CdmResponseType UsageTableHeader::AddEntry(
|
||||
CdmResponseType UsageTableHeader::LoadEntry(CryptoSession* crypto_session,
|
||||
const CdmUsageEntry& usage_entry,
|
||||
uint32_t usage_entry_number) {
|
||||
LOGV("UsageTableHeader::LoadEntry: Lock");
|
||||
AutoLock auto_lock(usage_table_header_lock_);
|
||||
{
|
||||
LOGV("UsageTableHeader::LoadEntry: Lock");
|
||||
AutoLock auto_lock(usage_table_header_lock_);
|
||||
|
||||
if (usage_entry_number >= usage_entry_info_.size()) {
|
||||
LOGE(
|
||||
"UsageTableHeader::LoadEntry: usage entry number %d larger than table "
|
||||
"size: %d",
|
||||
usage_entry_number, usage_entry_info_.size());
|
||||
return USAGE_INVALID_LOAD_ENTRY;
|
||||
if (usage_entry_number >= usage_entry_info_.size()) {
|
||||
LOGE(
|
||||
"UsageTableHeader::LoadEntry: usage entry number %d larger than "
|
||||
"table size: %d",
|
||||
usage_entry_number, usage_entry_info_.size());
|
||||
return USAGE_INVALID_LOAD_ENTRY;
|
||||
}
|
||||
}
|
||||
return crypto_session->LoadUsageEntry(usage_entry_number, usage_entry);
|
||||
metrics::CryptoMetrics* metrics = crypto_session->GetCryptoMetrics();
|
||||
if (metrics == NULL) metrics = &alternate_crypto_metrics_;
|
||||
|
||||
uint32_t retry_count = 0;
|
||||
CdmResponseType status = NO_ERROR;
|
||||
do {
|
||||
{
|
||||
AutoLock auto_lock(usage_table_header_lock_);
|
||||
status = crypto_session->LoadUsageEntry(usage_entry_number, usage_entry);
|
||||
}
|
||||
if (status == INSUFFICIENT_CRYPTO_RESOURCES_3)
|
||||
DeleteEntry(retry_count, file_handle_.get(), metrics);
|
||||
} while (status == INSUFFICIENT_CRYPTO_RESOURCES_3 &&
|
||||
++retry_count < kMaxCryptoRetries);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
CdmResponseType UsageTableHeader::UpdateEntry(CryptoSession* crypto_session,
|
||||
@@ -228,7 +285,7 @@ CdmResponseType UsageTableHeader::MoveEntry(
|
||||
scoped_ptr<CryptoSession> scoped_crypto_session;
|
||||
CryptoSession* crypto_session = test_crypto_session_.get();
|
||||
if (crypto_session == NULL) {
|
||||
scoped_crypto_session.reset((new CryptoSession(metrics)));
|
||||
scoped_crypto_session.reset((CryptoSession::MakeCryptoSession(metrics)));
|
||||
crypto_session = scoped_crypto_session.get();
|
||||
}
|
||||
|
||||
@@ -422,7 +479,7 @@ CdmResponseType UsageTableHeader::Shrink(
|
||||
scoped_ptr<CryptoSession> scoped_crypto_session;
|
||||
CryptoSession* crypto_session = test_crypto_session_.get();
|
||||
if (crypto_session == NULL) {
|
||||
scoped_crypto_session.reset((new CryptoSession(metrics)));
|
||||
scoped_crypto_session.reset((CryptoSession::MakeCryptoSession(metrics)));
|
||||
crypto_session = scoped_crypto_session.get();
|
||||
}
|
||||
|
||||
@@ -492,32 +549,33 @@ bool UsageTableHeader::UpgradeLicensesFromUsageTable(
|
||||
|
||||
if (provider_session_token.empty()) continue;
|
||||
|
||||
CryptoSession crypto_session(metrics);
|
||||
CdmResponseType status = crypto_session.Open(requested_security_level_);
|
||||
scoped_ptr<CryptoSession> crypto_session(
|
||||
CryptoSession::MakeCryptoSession(metrics));
|
||||
CdmResponseType status = crypto_session->Open(requested_security_level_);
|
||||
|
||||
if (status != NO_ERROR) continue;
|
||||
|
||||
// We create this entry since OEMCrypto_CopyOldUsageEntry needs the old
|
||||
// usage table to be loaded in order to copy an entry.
|
||||
if (!CreateDummyOldUsageEntry(&crypto_session)) continue;
|
||||
if (!CreateDummyOldUsageEntry(crypto_session.get())) continue;
|
||||
|
||||
status = AddEntry(&crypto_session, true /* persistent license */,
|
||||
status = AddEntry(crypto_session.get(), true /* persistent license */,
|
||||
key_set_ids[i], kEmptyString, &usage_entry_number);
|
||||
|
||||
if (status != NO_ERROR) continue;
|
||||
|
||||
status = crypto_session.CopyOldUsageEntry(provider_session_token);
|
||||
status = crypto_session->CopyOldUsageEntry(provider_session_token);
|
||||
|
||||
if (status != NO_ERROR) {
|
||||
crypto_session.Close();
|
||||
crypto_session->Close();
|
||||
Shrink(metrics, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
status = UpdateEntry(&crypto_session, &usage_entry);
|
||||
status = UpdateEntry(crypto_session.get(), &usage_entry);
|
||||
|
||||
if (status != NO_ERROR) {
|
||||
crypto_session.Close();
|
||||
crypto_session->Close();
|
||||
Shrink(metrics, 1);
|
||||
continue;
|
||||
}
|
||||
@@ -574,36 +632,37 @@ bool UsageTableHeader::UpgradeUsageInfoFromUsageTable(
|
||||
continue;
|
||||
}
|
||||
|
||||
CryptoSession crypto_session(metrics);
|
||||
CdmResponseType status = crypto_session.Open(requested_security_level_);
|
||||
scoped_ptr<CryptoSession> crypto_session(
|
||||
CryptoSession::MakeCryptoSession(metrics));
|
||||
CdmResponseType status = crypto_session->Open(requested_security_level_);
|
||||
|
||||
if (status != NO_ERROR) continue;
|
||||
|
||||
// We create this entry since OEMCrypto_CopyOldUsageEntry needs the old
|
||||
// usage table to be loaded in order to copy an entry.
|
||||
if (!CreateDummyOldUsageEntry(&crypto_session)) continue;
|
||||
if (!CreateDummyOldUsageEntry(crypto_session.get())) continue;
|
||||
|
||||
// TODO(rfrias): We need to fill in the app id, but it is hashed
|
||||
// and we have no way to extract. Use the hased filename instead?
|
||||
status = AddEntry(&crypto_session, false /* usage info */,
|
||||
status = AddEntry(crypto_session.get(), false /* usage info */,
|
||||
usage_data[j].key_set_id, usage_info_file_names[i],
|
||||
&(usage_data[j].usage_entry_number));
|
||||
|
||||
if (status != NO_ERROR) continue;
|
||||
|
||||
status = crypto_session.CopyOldUsageEntry(
|
||||
status = crypto_session->CopyOldUsageEntry(
|
||||
usage_data[j].provider_session_token);
|
||||
|
||||
if (status != NO_ERROR) {
|
||||
crypto_session.Close();
|
||||
crypto_session->Close();
|
||||
Shrink(metrics, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
status = UpdateEntry(&crypto_session, &(usage_data[j].usage_entry));
|
||||
status = UpdateEntry(crypto_session.get(), &(usage_data[j].usage_entry));
|
||||
|
||||
if (status != NO_ERROR) {
|
||||
crypto_session.Close();
|
||||
crypto_session->Close();
|
||||
Shrink(metrics, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user