* Reject session clobbering. [ Merge of http://go/wvgerrit/14634 ] This fixes a bug in I17de92b3e682c9c731f755e69466bdae7f560393 in which sessions can be clobbered by a forced session ID. This bug manifested in subtle test failures which involved repeatedly creating sessions. This was traced to OEMCrypto not being terminated, then upward to a leaked CryptoSession and CdmSession, and then finally to clobbered session IDs. To avoid the bug in future, first, reject duplicate session IDs. Second, change the OpenSession API to make forced IDs explicit. * Fix unit test namespaces. [ Merge of http://go/wvgerrit/14622 ] This fixes some odd errors that occur when linking multiple test suites into one executable. When two object files both contain a definition of wvcdm::MockCryptoSession, for example, one will win silently and cause the other's tests to misbehave and/or crash. The solution is to put all mocks into an anonymous namespace, since each wvcdm::(anonymous)::MockCryptoSession is separate. In order to avoid lots of repetitions of wvcdm:: in the anonymous namespaces, all anonymous namespaces in unit tests now live inside or the wvcdm namespace. This has been done even for tests which are not currently using mocks. * Move timer and timer_unittest to Android. [ Merge of http://go/wvgerrit/14619 ] These are not used anywhere else. Change-Id: I234f31e9b5c79061205728783596ebaff65e0aff
240 lines
7.9 KiB
C++
240 lines
7.9 KiB
C++
// Copyright 2013 Google Inc. All Rights Reserved.
|
|
|
|
#include "wv_content_decryption_module.h"
|
|
|
|
#include "cdm_client_property_set.h"
|
|
#include "cdm_engine.h"
|
|
#include "initialization_data.h"
|
|
#include "license.h"
|
|
#include "log.h"
|
|
#include "properties.h"
|
|
#include "wv_cdm_constants.h"
|
|
#include "wv_cdm_event_listener.h"
|
|
|
|
namespace {
|
|
const int kCdmPolicyTimerDurationSeconds = 1;
|
|
}
|
|
|
|
namespace wvcdm {
|
|
|
|
Lock WvContentDecryptionModule::session_sharing_id_generation_lock_;
|
|
|
|
WvContentDecryptionModule::WvContentDecryptionModule()
|
|
: cdm_engine_(new CdmEngine()) {}
|
|
|
|
WvContentDecryptionModule::~WvContentDecryptionModule() {
|
|
DisablePolicyTimer(true);
|
|
}
|
|
|
|
bool WvContentDecryptionModule::IsSupported(const std::string& init_data_type) {
|
|
return InitializationData(init_data_type).is_supported();
|
|
}
|
|
|
|
bool WvContentDecryptionModule::IsCenc(const std::string& init_data_type) {
|
|
return InitializationData(init_data_type).is_cenc();
|
|
}
|
|
|
|
bool WvContentDecryptionModule::IsWebm(const std::string& init_data_type) {
|
|
return InitializationData(init_data_type).is_webm();
|
|
}
|
|
|
|
CdmResponseType WvContentDecryptionModule::OpenSession(
|
|
const CdmKeySystem& key_system, CdmClientPropertySet* property_set,
|
|
const std::string& origin, WvCdmEventListener* event_listener,
|
|
CdmSessionId* session_id) {
|
|
if (property_set && property_set->is_session_sharing_enabled()) {
|
|
AutoLock auto_lock(session_sharing_id_generation_lock_);
|
|
if (property_set->session_sharing_id() == 0)
|
|
property_set->set_session_sharing_id(GenerateSessionSharingId());
|
|
}
|
|
|
|
return cdm_engine_->OpenSession(key_system, property_set, origin,
|
|
event_listener, NULL /* forced_session_id */,
|
|
session_id);
|
|
}
|
|
|
|
CdmResponseType WvContentDecryptionModule::CloseSession(
|
|
const CdmSessionId& session_id) {
|
|
CdmResponseType sts = cdm_engine_->CloseSession(session_id);
|
|
DisablePolicyTimer(false);
|
|
return sts;
|
|
}
|
|
|
|
bool WvContentDecryptionModule::IsOpenSession(const CdmSessionId& session_id) {
|
|
return cdm_engine_->IsOpenSession(session_id);
|
|
}
|
|
|
|
CdmResponseType WvContentDecryptionModule::GenerateKeyRequest(
|
|
const CdmSessionId& session_id, const CdmKeySetId& key_set_id,
|
|
const std::string& init_data_type, const CdmInitData& init_data,
|
|
const CdmLicenseType license_type, CdmAppParameterMap& app_parameters,
|
|
CdmClientPropertySet* property_set, const std::string& origin,
|
|
CdmKeyMessage* key_request, CdmKeyRequestType* key_request_type,
|
|
std::string* server_url) {
|
|
CdmResponseType sts;
|
|
if (license_type == kLicenseTypeRelease) {
|
|
sts = cdm_engine_->OpenKeySetSession(key_set_id, property_set, origin,
|
|
NULL);
|
|
if (sts != NO_ERROR) return sts;
|
|
}
|
|
InitializationData initialization_data(init_data_type, init_data);
|
|
sts = cdm_engine_->GenerateKeyRequest(
|
|
session_id, key_set_id, initialization_data, license_type, app_parameters,
|
|
key_request, key_request_type, server_url, NULL);
|
|
|
|
switch(license_type) {
|
|
case kLicenseTypeRelease:
|
|
if (sts != KEY_MESSAGE)
|
|
cdm_engine_->CloseKeySetSession(key_set_id);
|
|
break;
|
|
default:
|
|
if (sts == KEY_MESSAGE)
|
|
EnablePolicyTimer();
|
|
break;
|
|
}
|
|
return sts;
|
|
}
|
|
|
|
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);
|
|
return sts;
|
|
}
|
|
|
|
CdmResponseType WvContentDecryptionModule::RestoreKey(
|
|
const CdmSessionId& session_id,
|
|
const CdmKeySetId& key_set_id) {
|
|
CdmResponseType sts = cdm_engine_->RestoreKey(session_id, key_set_id);
|
|
if (sts == KEY_ADDED)
|
|
EnablePolicyTimer();
|
|
return sts;
|
|
}
|
|
|
|
CdmResponseType WvContentDecryptionModule::RemoveKeys(
|
|
const CdmSessionId& session_id) {
|
|
return cdm_engine_->RemoveKeys(session_id);
|
|
}
|
|
|
|
CdmResponseType WvContentDecryptionModule::QueryStatus(
|
|
SecurityLevel security_level,
|
|
CdmQueryMap* key_info) {
|
|
return cdm_engine_->QueryStatus(security_level, key_info);
|
|
}
|
|
|
|
CdmResponseType WvContentDecryptionModule::QuerySessionStatus(
|
|
const CdmSessionId& session_id, CdmQueryMap* key_info) {
|
|
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);
|
|
}
|
|
|
|
CdmResponseType WvContentDecryptionModule::QueryKeyControlInfo(
|
|
const CdmSessionId& session_id, CdmQueryMap* key_info) {
|
|
return cdm_engine_->QueryKeyControlInfo(session_id, key_info);
|
|
}
|
|
|
|
CdmResponseType WvContentDecryptionModule::GetProvisioningRequest(
|
|
CdmCertificateType cert_type,
|
|
const std::string& cert_authority,
|
|
const std::string& origin,
|
|
CdmProvisioningRequest* request,
|
|
std::string* default_url) {
|
|
return cdm_engine_->GetProvisioningRequest(cert_type, cert_authority, origin,
|
|
request, default_url);
|
|
}
|
|
|
|
CdmResponseType WvContentDecryptionModule::HandleProvisioningResponse(
|
|
const std::string& origin,
|
|
CdmProvisioningResponse& response,
|
|
std::string* cert,
|
|
std::string* wrapped_key) {
|
|
return cdm_engine_->HandleProvisioningResponse(origin, response, cert,
|
|
wrapped_key);
|
|
}
|
|
|
|
CdmResponseType WvContentDecryptionModule::Unprovision(
|
|
CdmSecurityLevel level,
|
|
const std::string& origin) {
|
|
return cdm_engine_->Unprovision(level, origin);
|
|
}
|
|
|
|
CdmResponseType WvContentDecryptionModule::GetUsageInfo(
|
|
const std::string& app_id, CdmUsageInfo* usage_info) {
|
|
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);
|
|
}
|
|
|
|
CdmResponseType WvContentDecryptionModule::ReleaseAllUsageInfo(
|
|
const std::string& app_id) {
|
|
return cdm_engine_->ReleaseAllUsageInfo(app_id);
|
|
}
|
|
|
|
CdmResponseType WvContentDecryptionModule::ReleaseUsageInfo(
|
|
const CdmUsageInfoReleaseMessage& message) {
|
|
return cdm_engine_->ReleaseUsageInfo(message);
|
|
}
|
|
|
|
CdmResponseType WvContentDecryptionModule::Decrypt(
|
|
const CdmSessionId& session_id,
|
|
bool validate_key_id,
|
|
const CdmDecryptionParameters& parameters) {
|
|
CdmSessionId local_session_id = session_id;
|
|
if (validate_key_id &&
|
|
Properties::GetSessionSharingId(session_id) != 0) {
|
|
bool status = cdm_engine_->FindSessionForKey(*parameters.key_id,
|
|
&local_session_id);
|
|
if (!status) {
|
|
LOGE("WvContentDecryptionModule::Decrypt: unable to find session");
|
|
return NEED_KEY;
|
|
}
|
|
}
|
|
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);
|
|
}
|
|
|
|
bool WvContentDecryptionModule::IsValidServiceCertificate(
|
|
const std::string& certificate) {
|
|
return CdmLicense::VerifySignedServiceCertificate(certificate) == NO_ERROR;
|
|
}
|
|
|
|
void WvContentDecryptionModule::EnablePolicyTimer() {
|
|
AutoLock auto_lock(policy_timer_lock_);
|
|
if (!policy_timer_.IsRunning())
|
|
policy_timer_.Start(this, kCdmPolicyTimerDurationSeconds);
|
|
}
|
|
|
|
void WvContentDecryptionModule::DisablePolicyTimer(bool force) {
|
|
AutoLock auto_lock(policy_timer_lock_);
|
|
if ((cdm_engine_->SessionSize() == 0 || force) && policy_timer_.IsRunning())
|
|
policy_timer_.Stop();
|
|
}
|
|
|
|
void WvContentDecryptionModule::OnTimerEvent() {
|
|
cdm_engine_->OnTimerEvent();
|
|
}
|
|
|
|
uint32_t WvContentDecryptionModule::GenerateSessionSharingId() {
|
|
static int next_session_sharing_id = 0;
|
|
return ++next_session_sharing_id;
|
|
}
|
|
|
|
} // namespace wvcdm
|