Refactoring to cache service certs and initialization data
* Extend CdmLicense's stored_init_data_ [ Merge of http://go/wvgerrit/14661 ] CdmLicense will store init data when a server cert must be provisioned. After provisioning, the original init data can be used to generate the originally-intended license request. To do this before, the caller had to call CdmSession's GenerateKeyRequest with an empty InitializationData object. However, the init data's type still had to be set, as did the license type. This CL allows the caller to use a truly empty InitializationData without a type. To permit this, CdmLicense now stores a full InitializationData object, rather than just a copy of it's data field. With this CL, the caller also avoid storing the original license type. To accomplish this, CdmSession uses the already-set is_offline_ and is_release_ flags from the original call to reconstruct the intended license type. The caller uses the new type kLicenseTypeDeferred. To facilitate storing whole InitializationData objects, they are now copyable. This ultimately simplifies server cert code for the new CE CDM. * Store service certs in Properties [ Merge of http://go/wvgerrit/14664 ] This allows CE devices to mimic the Chrome CDM's behavior of sharing server certs between sessions. This also affects Android behavior. Previously, provisioned service certificates were per-session, while explicitly-set service certs were per-DRM-plugin. Now, both are per-DRM-plugin. A DRM plugin is associated with a mediaDrm object. Content providers will still be able to retrieve and use different certificates. The change here requires an app, that wishes to use different provisioned service certificates will have to use multiple mediaDrm objects. This is an unlikely scenario. Change-Id: If2586932784ed046ecab72b5720ff30547e84b97
This commit is contained in:
@@ -38,6 +38,7 @@ class UsagePropertySet : public CdmClientPropertySet {
|
||||
virtual const std::string& security_level() const { return security_level_; }
|
||||
virtual bool use_privacy_mode() const { return false; }
|
||||
virtual const std::string& service_certificate() const { return empty_; }
|
||||
virtual void set_service_certificate(const std::string&) {}
|
||||
virtual bool is_session_sharing_enabled() const { return false; }
|
||||
virtual uint32_t session_sharing_id() const { return 0; }
|
||||
virtual void set_session_sharing_id(uint32_t /* id */) {}
|
||||
@@ -75,7 +76,7 @@ CdmEngine::~CdmEngine() {
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system,
|
||||
const CdmClientPropertySet* property_set,
|
||||
CdmClientPropertySet* property_set,
|
||||
const std::string& origin,
|
||||
WvCdmEventListener* event_listener,
|
||||
const CdmSessionId* forced_session_id,
|
||||
@@ -122,7 +123,7 @@ CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system,
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::OpenKeySetSession(
|
||||
const CdmKeySetId& key_set_id, const CdmClientPropertySet* property_set,
|
||||
const CdmKeySetId& key_set_id, CdmClientPropertySet* property_set,
|
||||
const std::string& origin, WvCdmEventListener* event_listener) {
|
||||
LOGI("CdmEngine::OpenKeySetSession");
|
||||
|
||||
@@ -630,7 +631,6 @@ CdmResponseType CdmEngine::HandleProvisioningResponse(
|
||||
"missing.");
|
||||
return EMPTY_PROVISIONING_CERTIFICATE_1;
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
CdmResponseType ret = cert_provisioning_->HandleProvisioningResponse(
|
||||
@@ -865,8 +865,8 @@ CdmResponseType CdmEngine::ReleaseAllUsageInfo(const std::string& app_id) {
|
||||
: kLevelDefault;
|
||||
usage_property_set_->set_security_level(security_level);
|
||||
usage_session_.reset(
|
||||
new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL,
|
||||
NULL));
|
||||
new CdmSession(usage_property_set_.get(),
|
||||
EMPTY_ORIGIN, NULL, NULL));
|
||||
CdmResponseType status2 = usage_session_->
|
||||
DeleteMultipleUsageInformation(provider_session_tokens);
|
||||
if (status2 != NO_ERROR) {
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
#include "cdm_session.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
@@ -23,14 +25,13 @@ const size_t kKeySetIdLength = 14;
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set,
|
||||
CdmSession::CdmSession(CdmClientPropertySet* cdm_client_property_set,
|
||||
const std::string& origin,
|
||||
WvCdmEventListener* event_listener,
|
||||
const CdmSessionId* forced_session_id)
|
||||
: initialized_(false),
|
||||
session_id_(GenerateSessionId()),
|
||||
origin_(origin),
|
||||
license_parser_(new CdmLicense),
|
||||
crypto_session_(new CryptoSession),
|
||||
file_handle_(new DeviceFiles),
|
||||
license_received_(false),
|
||||
@@ -51,6 +52,7 @@ CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set,
|
||||
}
|
||||
session_id_ = key_set_id_;
|
||||
}
|
||||
license_parser_.reset(new CdmLicense(session_id_));
|
||||
policy_engine_.reset(new PolicyEngine(
|
||||
session_id_, event_listener, crypto_session_.get()));
|
||||
if (cdm_client_property_set) {
|
||||
@@ -166,7 +168,7 @@ CdmResponseType CdmSession::RestoreUsageSession(
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::GenerateKeyRequest(
|
||||
const InitializationData& init_data, const CdmLicenseType license_type,
|
||||
const InitializationData& init_data, CdmLicenseType license_type,
|
||||
const CdmAppParameterMap& app_parameters, CdmKeyMessage* key_request,
|
||||
CdmKeyRequestType* key_request_type, std::string* server_url,
|
||||
CdmKeySetId* key_set_id) {
|
||||
@@ -190,6 +192,24 @@ CdmResponseType CdmSession::GenerateKeyRequest(
|
||||
case kLicenseTypeRelease:
|
||||
is_release_ = true;
|
||||
break;
|
||||
case kLicenseTypeDeferred:
|
||||
// If you're going to pass Deferred, you must have empty init data in
|
||||
// this call and stored init data from the previous call.
|
||||
if (!init_data.IsEmpty() || !license_parser_->HasInitData()) {
|
||||
return INVALID_LICENSE_TYPE;
|
||||
}
|
||||
// The arguments check out.
|
||||
// The is_release_ and is_offline_ flags were already set last time based
|
||||
// on the original license type. Do not change them, and use them to
|
||||
// re-derive the original license type.
|
||||
if (is_release_) {
|
||||
license_type = kLicenseTypeRelease;
|
||||
} else if (is_offline_) {
|
||||
license_type = kLicenseTypeOffline;
|
||||
} else {
|
||||
license_type = kLicenseTypeStreaming;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOGE("CdmSession::GenerateKeyRequest: unrecognized license type: %ld",
|
||||
license_type);
|
||||
@@ -204,14 +224,16 @@ CdmResponseType CdmSession::GenerateKeyRequest(
|
||||
return GenerateRenewalRequest(key_request, server_url);
|
||||
} else {
|
||||
if (key_request_type) *key_request_type = kKeyRequestTypeInitial;
|
||||
if (!init_data.is_supported()) {
|
||||
LOGW("CdmSession::GenerateKeyRequest: unsupported init data type (%s)",
|
||||
init_data.type().c_str());
|
||||
return UNSUPPORTED_INIT_DATA;
|
||||
}
|
||||
if (init_data.IsEmpty() && !license_parser_->HasInitData()) {
|
||||
LOGW("CdmSession::GenerateKeyRequest: init data absent");
|
||||
return INIT_DATA_NOT_FOUND;
|
||||
if (!license_parser_->HasInitData()) {
|
||||
if (!init_data.is_supported()) {
|
||||
LOGW("CdmSession::GenerateKeyRequest: unsupported init data type (%s)",
|
||||
init_data.type().c_str());
|
||||
return UNSUPPORTED_INIT_DATA;
|
||||
}
|
||||
if (init_data.IsEmpty()) {
|
||||
LOGW("CdmSession::GenerateKeyRequest: init data absent");
|
||||
return INIT_DATA_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
if (is_offline_ && key_set_id_.empty() &&
|
||||
!GenerateKeySetId(&key_set_id_)) {
|
||||
@@ -222,8 +244,7 @@ CdmResponseType CdmSession::GenerateKeyRequest(
|
||||
app_parameters_ = app_parameters;
|
||||
CdmResponseType status = license_parser_->PrepareKeyRequest(
|
||||
init_data, license_type,
|
||||
app_parameters, session_id_,
|
||||
key_request, server_url);
|
||||
app_parameters, key_request, server_url);
|
||||
|
||||
if (KEY_MESSAGE != status) return status;
|
||||
|
||||
@@ -374,7 +395,7 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
|
||||
CdmResponseType CdmSession::GenerateRenewalRequest(CdmKeyMessage* key_request,
|
||||
std::string* server_url) {
|
||||
CdmResponseType status = license_parser_->PrepareKeyUpdateRequest(
|
||||
true, app_parameters_, session_id_, key_request, server_url);
|
||||
true, app_parameters_, key_request, server_url);
|
||||
|
||||
if (KEY_MESSAGE != status) return status;
|
||||
|
||||
@@ -402,7 +423,7 @@ CdmResponseType CdmSession::GenerateReleaseRequest(CdmKeyMessage* key_request,
|
||||
std::string* server_url) {
|
||||
is_release_ = true;
|
||||
CdmResponseType status = license_parser_->PrepareKeyUpdateRequest(
|
||||
false, app_parameters_, session_id_, key_request, server_url);
|
||||
false, app_parameters_, key_request, server_url);
|
||||
|
||||
if (KEY_MESSAGE != status) return status;
|
||||
|
||||
|
||||
@@ -126,13 +126,20 @@ static std::vector<CryptoKey> ExtractContentKeys(const License& license) {
|
||||
return key_array;
|
||||
}
|
||||
|
||||
CdmLicense::CdmLicense()
|
||||
CdmLicense::CdmLicense(const CdmSessionId& session_id)
|
||||
: session_(NULL),
|
||||
policy_engine_(NULL),
|
||||
session_id_(session_id),
|
||||
initialized_(false),
|
||||
renew_with_client_id_(false),
|
||||
clock_(new Clock()) {}
|
||||
|
||||
CdmLicense::CdmLicense(Clock* clock) : session_(NULL), initialized_(false) {
|
||||
CdmLicense::CdmLicense(const CdmSessionId& session_id, Clock* clock)
|
||||
: session_(NULL),
|
||||
policy_engine_(NULL),
|
||||
session_id_(session_id),
|
||||
initialized_(false),
|
||||
renew_with_client_id_(false) {
|
||||
if (NULL == clock) {
|
||||
LOGE("CdmLicense::CdmLicense: clock parameter not provided");
|
||||
return;
|
||||
@@ -144,6 +151,14 @@ CdmLicense::~CdmLicense() {}
|
||||
|
||||
bool CdmLicense::Init(const std::string& token, CryptoSession* session,
|
||||
PolicyEngine* policy_engine) {
|
||||
if (clock_.get() == NULL) {
|
||||
LOGE("CdmLicense::Init: clock parameter not provided");
|
||||
return false;
|
||||
}
|
||||
if (session_id_.empty()) {
|
||||
LOGE("CdmLicense::Init: empty session id provided");
|
||||
return false;
|
||||
}
|
||||
if (token.size() == 0) {
|
||||
LOGE("CdmLicense::Init: empty token provided");
|
||||
return false;
|
||||
@@ -165,25 +180,27 @@ bool CdmLicense::Init(const std::string& token, CryptoSession* session,
|
||||
|
||||
CdmResponseType CdmLicense::PrepareKeyRequest(
|
||||
const InitializationData& init_data, const CdmLicenseType license_type,
|
||||
const CdmAppParameterMap& app_parameters, const CdmSessionId& session_id,
|
||||
CdmKeyMessage* signed_request, std::string* server_url) {
|
||||
const CdmAppParameterMap& app_parameters, CdmKeyMessage* signed_request,
|
||||
std::string* server_url) {
|
||||
if (!initialized_) {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: not initialized");
|
||||
return LICENSE_PARSER_NOT_INITIALIZED_4;
|
||||
}
|
||||
if (init_data.IsEmpty() && stored_init_data_.get()) {
|
||||
InitializationData restored_init_data = *stored_init_data_;
|
||||
stored_init_data_.reset();
|
||||
return PrepareKeyRequest(restored_init_data, license_type, app_parameters,
|
||||
signed_request, server_url);
|
||||
}
|
||||
if (!init_data.is_supported()) {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: unsupported init data type (%s)",
|
||||
init_data.type().c_str());
|
||||
return INVALID_PARAMETERS_LIC_3;
|
||||
}
|
||||
if (init_data.IsEmpty() && stored_init_data_.empty()) {
|
||||
if (init_data.IsEmpty()) {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: empty init data provided");
|
||||
return INVALID_PARAMETERS_LIC_4;
|
||||
}
|
||||
if (session_id.empty()) {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: empty session id provided");
|
||||
return INVALID_PARAMETERS_LIC_5;
|
||||
}
|
||||
if (!signed_request) {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: no signed request provided");
|
||||
return INVALID_PARAMETERS_LIC_6;
|
||||
@@ -194,10 +211,10 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
|
||||
}
|
||||
|
||||
std::string service_certificate;
|
||||
bool privacy_mode_enabled = Properties::UsePrivacyMode(session_id);
|
||||
bool privacy_mode_enabled = Properties::UsePrivacyMode(session_id_);
|
||||
if (privacy_mode_enabled) {
|
||||
if (!GetServiceCertificate(session_id, &service_certificate)) {
|
||||
stored_init_data_ = init_data.data();
|
||||
if (!GetServiceCertificate(&service_certificate)) {
|
||||
stored_init_data_.reset(new InitializationData(init_data));
|
||||
return PrepareServiceCertificateRequest(signed_request, server_url)
|
||||
? KEY_MESSAGE
|
||||
: LICENSE_REQUEST_SERVICE_CERTIFICATE_GENERATION_ERROR;
|
||||
@@ -223,8 +240,6 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
|
||||
|
||||
if (!init_data.IsEmpty()) {
|
||||
cenc_content_id->add_pssh(init_data.data());
|
||||
} else if (privacy_mode_enabled && !stored_init_data_.empty()) {
|
||||
cenc_content_id->add_pssh(stored_init_data_);
|
||||
} else {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: ISO-CENC init data not available");
|
||||
return CENC_INIT_DATA_UNAVAILABLE;
|
||||
@@ -239,8 +254,6 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
|
||||
|
||||
if (!init_data.IsEmpty()) {
|
||||
webm_content_id->set_header(init_data.data());
|
||||
} else if (privacy_mode_enabled && !stored_init_data_.empty()) {
|
||||
webm_content_id->set_header(stored_init_data_);
|
||||
} else {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: WebM init data not available");
|
||||
return WEBM_INIT_DATA_UNAVAILABLE;
|
||||
@@ -304,8 +317,7 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
|
||||
|
||||
CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
|
||||
bool is_renewal, const CdmAppParameterMap& app_parameters,
|
||||
const CdmSessionId& session_id, CdmKeyMessage* signed_request,
|
||||
std::string* server_url) {
|
||||
CdmKeyMessage* signed_request, std::string* server_url) {
|
||||
if (!initialized_) {
|
||||
LOGE("CdmLicense::PrepareKeyUpdateRequest: not initialized");
|
||||
return LICENSE_PARSER_NOT_INITIALIZED_1;
|
||||
@@ -334,9 +346,9 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
|
||||
|
||||
if (renew_with_client_id_) {
|
||||
std::string service_certificate;
|
||||
bool privacy_mode_enabled = Properties::UsePrivacyMode(session_id);
|
||||
bool privacy_mode_enabled = Properties::UsePrivacyMode(session_id_);
|
||||
if (privacy_mode_enabled) {
|
||||
if (!GetServiceCertificate(session_id, &service_certificate)) {
|
||||
if (!GetServiceCertificate(&service_certificate)) {
|
||||
return PrepareServiceCertificateRequest(signed_request, server_url)
|
||||
? KEY_MESSAGE
|
||||
: LICENSE_RENEWAL_SERVICE_CERTIFICATE_GENERATION_ERROR;
|
||||
@@ -447,9 +459,13 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
||||
case SignedMessage::LICENSE:
|
||||
break;
|
||||
case SignedMessage::SERVICE_CERTIFICATE: {
|
||||
CdmResponseType status = VerifyAndExtractSignedServiceCertificate(
|
||||
signed_response.msg(), &service_certificate_);
|
||||
return status == NO_ERROR ? NEED_KEY : status;
|
||||
CdmResponseType status =
|
||||
VerifySignedServiceCertificate(signed_response.msg());
|
||||
if (status != NO_ERROR) {
|
||||
return status;
|
||||
}
|
||||
Properties::SetServiceCertificate(session_id_, signed_response.msg());
|
||||
return NEED_KEY;
|
||||
}
|
||||
case SignedMessage::ERROR_RESPONSE:
|
||||
return HandleKeyErrorResponse(signed_response);
|
||||
@@ -558,9 +574,13 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
|
||||
case SignedMessage::LICENSE:
|
||||
break;
|
||||
case SignedMessage::SERVICE_CERTIFICATE: {
|
||||
CdmResponseType status = VerifyAndExtractSignedServiceCertificate(
|
||||
signed_response.msg(), &service_certificate_);
|
||||
return status == NO_ERROR ? NEED_KEY : status;
|
||||
CdmResponseType status =
|
||||
VerifySignedServiceCertificate(signed_response.msg());
|
||||
if (status != NO_ERROR) {
|
||||
return status;
|
||||
}
|
||||
Properties::SetServiceCertificate(session_id_, signed_response.msg());
|
||||
return NEED_KEY;
|
||||
}
|
||||
case SignedMessage::ERROR_RESPONSE:
|
||||
return HandleKeyErrorResponse(signed_response);
|
||||
@@ -1067,19 +1087,14 @@ CdmResponseType CdmLicense::PrepareClientId(
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
bool CdmLicense::GetServiceCertificate(const CdmSessionId& session_id,
|
||||
std::string* service_certificate) {
|
||||
bool CdmLicense::GetServiceCertificate(std::string* service_certificate) {
|
||||
std::string signed_service_certificate;
|
||||
if (!Properties::GetServiceCertificate(session_id,
|
||||
&signed_service_certificate) ||
|
||||
signed_service_certificate.empty() ||
|
||||
NO_ERROR != VerifyAndExtractSignedServiceCertificate(
|
||||
signed_service_certificate, service_certificate)) {
|
||||
*service_certificate = service_certificate_;
|
||||
}
|
||||
|
||||
if (service_certificate->size() > 0) return true;
|
||||
return false;
|
||||
return Properties::GetServiceCertificate(session_id_,
|
||||
&signed_service_certificate) &&
|
||||
!signed_service_certificate.empty() &&
|
||||
NO_ERROR == VerifyAndExtractSignedServiceCertificate(
|
||||
signed_service_certificate, service_certificate) &&
|
||||
!service_certificate->empty();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -17,13 +17,13 @@ bool Properties::security_level_path_backward_compatibility_support_;
|
||||
scoped_ptr<CdmClientPropertySetMap> Properties::session_property_set_;
|
||||
|
||||
bool Properties::AddSessionPropertySet(
|
||||
const CdmSessionId& session_id, const CdmClientPropertySet* property_set) {
|
||||
const CdmSessionId& session_id, CdmClientPropertySet* property_set) {
|
||||
if (NULL == session_property_set_.get()) {
|
||||
return false;
|
||||
}
|
||||
std::pair<CdmClientPropertySetMap::iterator, bool> result =
|
||||
session_property_set_->insert(
|
||||
std::pair<const CdmSessionId, const CdmClientPropertySet*>(
|
||||
std::pair<const CdmSessionId, CdmClientPropertySet*>(
|
||||
session_id, property_set));
|
||||
return result.second;
|
||||
}
|
||||
@@ -35,10 +35,10 @@ bool Properties::RemoveSessionPropertySet(const CdmSessionId& session_id) {
|
||||
return (1 == session_property_set_->erase(session_id));
|
||||
}
|
||||
|
||||
const CdmClientPropertySet* Properties::GetCdmClientPropertySet(
|
||||
CdmClientPropertySet* Properties::GetCdmClientPropertySet(
|
||||
const CdmSessionId& session_id) {
|
||||
if (NULL != session_property_set_.get()) {
|
||||
CdmClientPropertySetMap::const_iterator it =
|
||||
CdmClientPropertySetMap::iterator it =
|
||||
session_property_set_->find(session_id);
|
||||
if (it != session_property_set_->end()) {
|
||||
return it->second;
|
||||
@@ -69,6 +69,17 @@ bool Properties::GetServiceCertificate(const CdmSessionId& session_id,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Properties::SetServiceCertificate(const CdmSessionId& session_id,
|
||||
const std::string& service_certificate) {
|
||||
CdmClientPropertySet* property_set =
|
||||
GetCdmClientPropertySet(session_id);
|
||||
if (NULL == property_set) {
|
||||
return false;
|
||||
}
|
||||
property_set->set_service_certificate(service_certificate);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Properties::UsePrivacyMode(const CdmSessionId& session_id) {
|
||||
const CdmClientPropertySet* property_set =
|
||||
GetCdmClientPropertySet(session_id);
|
||||
|
||||
Reference in New Issue
Block a user