File util, generic crypto, and key query

This CL merges several CLs from the widevine repo:

http://go/wvgerrit/18012 Add support for querying allowed usage for key.
http://go/wvgerrit/17971 Add per-origin storage.
http://go/wvgerrit/18152 Add OEMCrypto's generic crypto operations to CDM.
http://go/wvgerrit/17911 QueryKeyControlInfo => QueryOemCryptoSessionId

Note: numbering in wv_cdm_types.h was added in this CL and will be
back ported to wvgerrit in a future CL.

Change-Id: Idb9e9a67e94f62f25dc16c5307f75a08b3430b64
This commit is contained in:
Fred Gylys-Colwell
2016-09-14 12:44:09 -07:00
parent 24124ea6e3
commit eb3f8b786a
56 changed files with 4632 additions and 2083 deletions

View File

@@ -19,8 +19,7 @@ namespace wvcdm {
Lock WvContentDecryptionModule::session_sharing_id_generation_lock_;
WvContentDecryptionModule::WvContentDecryptionModule()
: cdm_engine_(new CdmEngine()) {}
WvContentDecryptionModule::WvContentDecryptionModule() {}
WvContentDecryptionModule::~WvContentDecryptionModule() {
DisablePolicyTimer(true);
@@ -52,19 +51,31 @@ CdmResponseType WvContentDecryptionModule::OpenSession(
property_set->set_session_sharing_id(GenerateSessionSharingId());
}
return cdm_engine_->OpenSession(key_system, property_set, origin,
event_listener, session_id);
CdmEngine* cdm_engine = EnsureCdmForOrigin(origin);
CdmResponseType sts = cdm_engine->OpenSession(key_system, property_set,
event_listener, session_id);
if (sts == NO_ERROR) {
cdm_by_session_id_[*session_id] = cdm_engine;
}
return sts;
}
CdmResponseType WvContentDecryptionModule::CloseSession(
const CdmSessionId& session_id) {
CdmResponseType sts = cdm_engine_->CloseSession(session_id);
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
// TODO(rfrias): Avoid reusing the error codes from CdmEngine.
if (!cdm_engine) return SESSION_NOT_FOUND_1;
CdmResponseType sts = cdm_engine->CloseSession(session_id);
if (sts == NO_ERROR) {
cdm_by_session_id_.erase(session_id);
}
DisablePolicyTimer(false);
return sts;
}
bool WvContentDecryptionModule::IsOpenSession(const CdmSessionId& session_id) {
return cdm_engine_->IsOpenSession(session_id);
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
return cdm_engine && cdm_engine->IsOpenSession(session_id);
}
CdmResponseType WvContentDecryptionModule::GenerateKeyRequest(
@@ -73,21 +84,24 @@ CdmResponseType WvContentDecryptionModule::GenerateKeyRequest(
const CdmLicenseType license_type, CdmAppParameterMap& app_parameters,
CdmClientPropertySet* property_set, const std::string& origin,
CdmKeyRequest* key_request) {
CdmEngine* cdm_engine = EnsureCdmForOrigin(origin);
CdmResponseType sts;
if (license_type == kLicenseTypeRelease) {
sts = cdm_engine_->OpenKeySetSession(key_set_id, property_set, origin,
NULL);
sts = cdm_engine->OpenKeySetSession(key_set_id, property_set, NULL);
if (sts != NO_ERROR) return sts;
cdm_by_session_id_[key_set_id] = cdm_engine;
}
InitializationData initialization_data(init_data_type, init_data);
sts = cdm_engine_->GenerateKeyRequest(
sts = cdm_engine->GenerateKeyRequest(
session_id, key_set_id, initialization_data, license_type, app_parameters,
key_request);
switch(license_type) {
case kLicenseTypeRelease:
if (sts != KEY_MESSAGE)
cdm_engine_->CloseKeySetSession(key_set_id);
if (sts != KEY_MESSAGE) {
cdm_engine->CloseKeySetSession(key_set_id);
cdm_by_session_id_.erase(key_set_id);
}
break;
default:
if (sts == KEY_MESSAGE)
@@ -101,16 +115,23 @@ CdmResponseType WvContentDecryptionModule::AddKey(
const CdmSessionId& session_id,
const CdmKeyResponse& key_data,
CdmKeySetId* key_set_id) {
CdmResponseType sts = cdm_engine_->AddKey(session_id, key_data, key_set_id);
if (sts == KEY_ADDED && session_id.empty()) // license type release
cdm_engine_->CloseKeySetSession(*key_set_id);
CdmEngine* cdm_engine = session_id.empty() ? GetCdmForSessionId(*key_set_id)
: GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_3;
CdmResponseType sts = cdm_engine->AddKey(session_id, key_data, key_set_id);
if (sts == KEY_ADDED && session_id.empty()) { // license type release
cdm_engine->CloseKeySetSession(*key_set_id);
cdm_by_session_id_.erase(*key_set_id);
}
return sts;
}
CdmResponseType WvContentDecryptionModule::RestoreKey(
const CdmSessionId& session_id,
const CdmKeySetId& key_set_id) {
CdmResponseType sts = cdm_engine_->RestoreKey(session_id, key_set_id);
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_4;
CdmResponseType sts = cdm_engine->RestoreKey(session_id, key_set_id);
if (sts == KEY_ADDED)
EnablePolicyTimer();
return sts;
@@ -118,29 +139,38 @@ CdmResponseType WvContentDecryptionModule::RestoreKey(
CdmResponseType WvContentDecryptionModule::RemoveKeys(
const CdmSessionId& session_id) {
return cdm_engine_->RemoveKeys(session_id);
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_5;
return cdm_engine->RemoveKeys(session_id);
}
CdmResponseType WvContentDecryptionModule::QueryStatus(
SecurityLevel security_level,
const std::string& key,
std::string* value) {
return cdm_engine_->QueryStatus(security_level, key, value);
CdmEngine* cdm_engine = EnsureCdmForOrigin(EMPTY_ORIGIN);
return cdm_engine->QueryStatus(security_level, key, value);
}
CdmResponseType WvContentDecryptionModule::QuerySessionStatus(
const CdmSessionId& session_id, CdmQueryMap* key_info) {
return cdm_engine_->QuerySessionStatus(session_id, key_info);
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_8;
return cdm_engine->QuerySessionStatus(session_id, key_info);
}
CdmResponseType WvContentDecryptionModule::QueryKeyStatus(
const CdmSessionId& session_id, CdmQueryMap* key_info) {
return cdm_engine_->QueryKeyStatus(session_id, key_info);
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_9;
return cdm_engine->QueryKeyStatus(session_id, key_info);
}
CdmResponseType WvContentDecryptionModule::QueryKeyControlInfo(
const CdmSessionId& session_id, CdmQueryMap* key_info) {
return cdm_engine_->QueryKeyControlInfo(session_id, key_info);
CdmResponseType WvContentDecryptionModule::QueryOemCryptoSessionId(
const CdmSessionId& session_id, CdmQueryMap* response) {
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_10;
return cdm_engine->QueryOemCryptoSessionId(session_id, response);
}
CdmResponseType WvContentDecryptionModule::GetProvisioningRequest(
@@ -149,8 +179,9 @@ CdmResponseType WvContentDecryptionModule::GetProvisioningRequest(
const std::string& origin,
CdmProvisioningRequest* request,
std::string* default_url) {
return cdm_engine_->GetProvisioningRequest(cert_type, cert_authority, origin,
request, default_url);
CdmEngine* cdm_engine = EnsureCdmForOrigin(origin);
return cdm_engine->GetProvisioningRequest(cert_type, cert_authority, request,
default_url);
}
CdmResponseType WvContentDecryptionModule::HandleProvisioningResponse(
@@ -158,59 +189,70 @@ CdmResponseType WvContentDecryptionModule::HandleProvisioningResponse(
CdmProvisioningResponse& response,
std::string* cert,
std::string* wrapped_key) {
return cdm_engine_->HandleProvisioningResponse(origin, response, cert,
wrapped_key);
CdmEngine* cdm_engine = EnsureCdmForOrigin(origin);
return cdm_engine->HandleProvisioningResponse(response, cert, wrapped_key);
}
CdmResponseType WvContentDecryptionModule::Unprovision(
CdmSecurityLevel level,
const std::string& origin) {
return cdm_engine_->Unprovision(level, origin);
CdmSecurityLevel level, const std::string& origin) {
CdmEngine* cdm_engine = EnsureCdmForOrigin(origin);
return cdm_engine->Unprovision(level);
}
CdmResponseType WvContentDecryptionModule::GetUsageInfo(
const std::string& app_id, CdmUsageInfo* usage_info) {
return cdm_engine_->GetUsageInfo(app_id, usage_info);
CdmEngine* cdm_engine = EnsureCdmForOrigin(EMPTY_ORIGIN);
return cdm_engine->GetUsageInfo(app_id, usage_info);
}
CdmResponseType WvContentDecryptionModule::GetUsageInfo(
const std::string& app_id,
const CdmSecureStopId& ssid,
CdmUsageInfo* usage_info) {
return cdm_engine_->GetUsageInfo(app_id, ssid, usage_info);
CdmEngine* cdm_engine = EnsureCdmForOrigin(EMPTY_ORIGIN);
return cdm_engine->GetUsageInfo(app_id, ssid, usage_info);
}
CdmResponseType WvContentDecryptionModule::ReleaseAllUsageInfo(
const std::string& app_id) {
return cdm_engine_->ReleaseAllUsageInfo(app_id);
CdmEngine* cdm_engine = EnsureCdmForOrigin(EMPTY_ORIGIN);
return cdm_engine->ReleaseAllUsageInfo(app_id);
}
CdmResponseType WvContentDecryptionModule::ReleaseUsageInfo(
const CdmUsageInfoReleaseMessage& message) {
return cdm_engine_->ReleaseUsageInfo(message);
CdmEngine* cdm_engine = EnsureCdmForOrigin(EMPTY_ORIGIN);
return cdm_engine->ReleaseUsageInfo(message);
}
CdmResponseType WvContentDecryptionModule::Decrypt(
const CdmSessionId& session_id,
bool validate_key_id,
const CdmDecryptionParameters& parameters) {
// First find the CdmEngine that has the given session_id. If we are using
// key sharing, the shared session will still be in the same CdmEngine.
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_FOR_DECRYPT;
CdmSessionId local_session_id = session_id;
if (validate_key_id &&
Properties::GetSessionSharingId(session_id) != 0) {
bool status = cdm_engine_->FindSessionForKey(*parameters.key_id,
bool status = cdm_engine->FindSessionForKey(*parameters.key_id,
&local_session_id);
if (!status) {
LOGE("WvContentDecryptionModule::Decrypt: unable to find session");
return NEED_KEY;
return SESSION_NOT_FOUND_FOR_DECRYPT;
}
}
return cdm_engine_->Decrypt(local_session_id, parameters);
return cdm_engine->Decrypt(local_session_id, parameters);
}
void WvContentDecryptionModule::NotifyResolution(const CdmSessionId& session_id,
uint32_t width,
uint32_t height) {
cdm_engine_->NotifyResolution(session_id, width, height);
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) return;
cdm_engine->NotifyResolution(session_id, width, height);
}
bool WvContentDecryptionModule::IsValidServiceCertificate(
@@ -218,6 +260,27 @@ bool WvContentDecryptionModule::IsValidServiceCertificate(
return CdmLicense::VerifySignedServiceCertificate(certificate) == NO_ERROR;
}
WvContentDecryptionModule::CdmInfo::CdmInfo()
: cdm_engine(new CdmEngine(&file_system)) {}
CdmEngine* WvContentDecryptionModule::EnsureCdmForOrigin(
const std::string& origin) {
if (cdms_.find(origin) == cdms_.end()) {
// Will create a new instance using the default constructor.
cdms_[origin].file_system.SetOrigin(origin);
}
return cdms_[origin].cdm_engine.get();
}
CdmEngine* WvContentDecryptionModule::GetCdmForSessionId(
const std::string& session_id) {
// Use find to avoid creating empty entries when not found.
auto it = cdm_by_session_id_.find(session_id);
if (it == cdm_by_session_id_.end()) return NULL;
return it->second;
}
void WvContentDecryptionModule::EnablePolicyTimer() {
AutoLock auto_lock(policy_timer_lock_);
if (!policy_timer_.IsRunning())
@@ -226,12 +289,25 @@ void WvContentDecryptionModule::EnablePolicyTimer() {
void WvContentDecryptionModule::DisablePolicyTimer(bool force) {
AutoLock auto_lock(policy_timer_lock_);
if ((cdm_engine_->SessionSize() == 0 || force) && policy_timer_.IsRunning())
bool has_sessions = false;
for (auto it = cdms_.begin(); it != cdms_.end();) {
if (it->second.cdm_engine->SessionSize() != 0) {
has_sessions = true;
++it;
} else {
// The CDM is no longer used for this origin, delete it.
it = cdms_.erase(it);
}
}
if ((!has_sessions || force) && policy_timer_.IsRunning())
policy_timer_.Stop();
}
void WvContentDecryptionModule::OnTimerEvent() {
cdm_engine_->OnTimerEvent();
for (auto it = cdms_.begin(); it != cdms_.end(); ++it) {
it->second.cdm_engine->OnTimerEvent();
}
}
uint32_t WvContentDecryptionModule::GenerateSessionSharingId() {