[ Merge of http://go/wvgerrit/22900 ] Add GetClientToken(), GetProvisioningToken(), GetPreProvisionTokenType() to CryptoSession. They return the correct token bytes and token type for preparing the ClientIdentification message for provisioning and license server transactions. Also refactor service certificate handling. OEM certs are introduced in Provisioning 3.0 b/30811184 * Address build breaks [ Merge of http://go/wvgerrit/23162 ] This addresses issues introduced by http://go/wvgerrit/22900 b/30811184 * When http://go/wvgerrit/18012 was merged (ag/1446934) some changes were not merged for mapErrors-inl.h. These changes are included in this CL. * When ag/1678104 was reverse merged to http//go/wvgerrit/21981/ a variable was renamed and some comments were added to add clarity in cdm_engine.cpp. These changes are included in this CL. Test: All unittests other than some oemcrypto, request_license_test passed. Those tests failed with or without this CL. Change-Id: Ie0215509f2f985f2a610f5a4c865db47edec8662
326 lines
11 KiB
C++
326 lines
11 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 "service_certificate.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() {}
|
|
|
|
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();
|
|
}
|
|
|
|
bool WvContentDecryptionModule::IsHls(const std::string& init_data_type) {
|
|
return InitializationData(init_data_type).is_hls();
|
|
}
|
|
|
|
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());
|
|
}
|
|
|
|
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) {
|
|
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) {
|
|
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
|
|
return cdm_engine && 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,
|
|
CdmKeyRequest* key_request) {
|
|
CdmEngine* cdm_engine = EnsureCdmForOrigin(origin);
|
|
CdmResponseType sts;
|
|
if (license_type == kLicenseTypeRelease) {
|
|
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(
|
|
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);
|
|
cdm_by_session_id_.erase(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) {
|
|
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) {
|
|
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;
|
|
}
|
|
|
|
CdmResponseType WvContentDecryptionModule::RemoveKeys(
|
|
const CdmSessionId& 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) {
|
|
CdmEngine* cdm_engine = EnsureCdmForOrigin(EMPTY_ORIGIN);
|
|
return cdm_engine->QueryStatus(security_level, key, value);
|
|
}
|
|
|
|
CdmResponseType WvContentDecryptionModule::QuerySessionStatus(
|
|
const CdmSessionId& session_id, CdmQueryMap* 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) {
|
|
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
|
|
if (!cdm_engine) return SESSION_NOT_FOUND_9;
|
|
return cdm_engine->QueryKeyStatus(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(
|
|
CdmCertificateType cert_type,
|
|
const std::string& cert_authority,
|
|
const std::string& origin,
|
|
CdmProvisioningRequest* request,
|
|
std::string* default_url) {
|
|
CdmEngine* cdm_engine = EnsureCdmForOrigin(origin);
|
|
return cdm_engine->GetProvisioningRequest(cert_type, cert_authority, request,
|
|
default_url);
|
|
}
|
|
|
|
CdmResponseType WvContentDecryptionModule::HandleProvisioningResponse(
|
|
const std::string& origin,
|
|
CdmProvisioningResponse& response,
|
|
std::string* cert,
|
|
std::string* wrapped_key) {
|
|
CdmEngine* cdm_engine = EnsureCdmForOrigin(origin);
|
|
return cdm_engine->HandleProvisioningResponse(response, cert, wrapped_key);
|
|
}
|
|
|
|
CdmResponseType WvContentDecryptionModule::Unprovision(
|
|
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) {
|
|
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) {
|
|
CdmEngine* cdm_engine = EnsureCdmForOrigin(EMPTY_ORIGIN);
|
|
return cdm_engine->GetUsageInfo(app_id, ssid, usage_info);
|
|
}
|
|
|
|
CdmResponseType WvContentDecryptionModule::ReleaseAllUsageInfo(
|
|
const std::string& app_id) {
|
|
CdmEngine* cdm_engine = EnsureCdmForOrigin(EMPTY_ORIGIN);
|
|
return cdm_engine->ReleaseAllUsageInfo(app_id);
|
|
}
|
|
|
|
CdmResponseType WvContentDecryptionModule::ReleaseUsageInfo(
|
|
const CdmUsageInfoReleaseMessage& 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,
|
|
&local_session_id);
|
|
if (!status) {
|
|
LOGE("WvContentDecryptionModule::Decrypt: unable to find session");
|
|
return SESSION_NOT_FOUND_FOR_DECRYPT;
|
|
}
|
|
}
|
|
return cdm_engine->Decrypt(local_session_id, parameters);
|
|
}
|
|
|
|
void WvContentDecryptionModule::NotifyResolution(const CdmSessionId& session_id,
|
|
uint32_t width,
|
|
uint32_t height) {
|
|
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
|
|
if (!cdm_engine) return;
|
|
cdm_engine->NotifyResolution(session_id, width, height);
|
|
}
|
|
|
|
bool WvContentDecryptionModule::IsValidServiceCertificate(
|
|
const std::string& certificate) {
|
|
return ServiceCertificate::VerifySignedServiceCertificate(certificate) ==
|
|
NO_ERROR;
|
|
}
|
|
|
|
WvContentDecryptionModule::CdmInfo::CdmInfo()
|
|
: cdm_engine(new CdmEngine(&file_system)) {}
|
|
|
|
CdmEngine* WvContentDecryptionModule::EnsureCdmForOrigin(
|
|
const std::string& origin) {
|
|
AutoLock auto_lock(cdms_lock_);
|
|
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())
|
|
policy_timer_.Start(this, kCdmPolicyTimerDurationSeconds);
|
|
}
|
|
|
|
void WvContentDecryptionModule::DisablePolicyTimer(bool force) {
|
|
bool has_sessions = false;
|
|
{
|
|
AutoLock auto_lock(cdms_lock_);
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
AutoLock auto_lock(policy_timer_lock_);
|
|
if ((!has_sessions || force) && policy_timer_.IsRunning())
|
|
policy_timer_.Stop();
|
|
}
|
|
|
|
void WvContentDecryptionModule::OnTimerEvent() {
|
|
AutoLock auto_lock(cdms_lock_);
|
|
for (auto it = cdms_.begin(); it != cdms_.end(); ++it) {
|
|
it->second.cdm_engine->OnTimerEvent();
|
|
}
|
|
}
|
|
|
|
uint32_t WvContentDecryptionModule::GenerateSessionSharingId() {
|
|
static int next_session_sharing_id = 0;
|
|
return ++next_session_sharing_id;
|
|
}
|
|
|
|
} // namespace wvcdm
|