Support Offline Licenses
Bug: 8621588 Merge of the following CLs from the Widevine CDM repository: https://widevine-internal-review.googlesource.com/#/c/5602/ https://widevine-internal-review.googlesource.com/#/c/5431/ https://widevine-internal-review.googlesource.com/#/c/5660/ Change-Id: If37940e2535e1a1eca95e4394d8cf9bf689e9c3a
This commit is contained in:
@@ -36,8 +36,6 @@ using video_widevine_server::sdk::License;
|
||||
using video_widevine_server::sdk::License_KeyContainer;
|
||||
using video_widevine_server::sdk::LicenseError;
|
||||
using video_widevine_server::sdk::SignedMessage;
|
||||
using video_widevine_server::sdk::STREAMING;
|
||||
using video_widevine_server::sdk::VERSION_2_1;
|
||||
|
||||
|
||||
static std::vector<CryptoKey> ExtractContentKeys(const License& license) {
|
||||
@@ -97,7 +95,7 @@ bool CdmLicense::Init(const std::string& token,
|
||||
|
||||
bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data,
|
||||
const CdmLicenseType license_type,
|
||||
CdmAppParameterMap& app_parameters,
|
||||
const CdmAppParameterMap& app_parameters,
|
||||
CdmKeyMessage* signed_request,
|
||||
std::string* server_url) {
|
||||
if (!session_ ||
|
||||
@@ -180,7 +178,20 @@ bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data,
|
||||
LicenseRequest_ContentIdentification_CENC* cenc_content_id =
|
||||
content_id->mutable_cenc_id();
|
||||
cenc_content_id->add_pssh(init_data);
|
||||
cenc_content_id->set_license_type(STREAMING);
|
||||
|
||||
switch (license_type) {
|
||||
case kLicenseTypeOffline:
|
||||
cenc_content_id->set_license_type(video_widevine_server::sdk::OFFLINE);
|
||||
break;
|
||||
case kLicenseTypeStreaming:
|
||||
cenc_content_id->set_license_type(video_widevine_server::sdk::STREAMING);
|
||||
break;
|
||||
default:
|
||||
LOGD("CdmLicense::PrepareKeyRequest: Unknown license type = %u",
|
||||
(int)license_type);
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
cenc_content_id->set_request_id(request_id);
|
||||
|
||||
// TODO(jfore): The time field will be updated once the cdm wrapper
|
||||
@@ -197,7 +208,7 @@ bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data,
|
||||
}
|
||||
license_request.set_key_control_nonce(UintToString(nonce));
|
||||
LOGD("PrepareKeyRequest: nonce=%u", nonce);
|
||||
license_request.set_protocol_version(VERSION_2_1);
|
||||
license_request.set_protocol_version(video_widevine_server::sdk::VERSION_2_1);
|
||||
|
||||
// License request is complete. Serialize it.
|
||||
std::string serialized_license_req;
|
||||
@@ -215,6 +226,7 @@ bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data,
|
||||
}
|
||||
|
||||
if (license_request_signature.empty()) {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: License request signature empty");
|
||||
signed_request->clear();
|
||||
return false;
|
||||
}
|
||||
@@ -231,22 +243,27 @@ bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CdmLicense::PrepareKeyRenewalRequest(CdmKeyMessage* signed_request,
|
||||
std::string* server_url) {
|
||||
bool CdmLicense::PrepareKeyUpdateRequest(bool is_renewal,
|
||||
CdmKeyMessage* signed_request,
|
||||
std::string* server_url) {
|
||||
if (!session_) {
|
||||
LOGE("CdmLicense::PrepareKeyUpdateRequest: Invalid crypto session");
|
||||
return false;
|
||||
}
|
||||
if (!signed_request) {
|
||||
LOGE("CdmLicense::PrepareKeyRenewalRequest : No signed request provided.");
|
||||
LOGE("CdmLicense::PrepareKeyUpdateRequest: No signed request provided");
|
||||
return false;
|
||||
}
|
||||
if (!server_url) {
|
||||
LOGE("CdmLicense::PrepareKeyRenewalRequest : No server url provided.");
|
||||
LOGE("CdmLicense::PrepareKeyUpdateRequest: No server url provided");
|
||||
return false;
|
||||
}
|
||||
|
||||
LicenseRequest license_request;
|
||||
license_request.set_type(LicenseRequest::RENEWAL);
|
||||
if (is_renewal)
|
||||
license_request.set_type(LicenseRequest::RENEWAL);
|
||||
else
|
||||
license_request.set_type(LicenseRequest::RELEASE);
|
||||
|
||||
LicenseRequest_ContentIdentification_ExistingLicense* current_license =
|
||||
license_request.mutable_content_id()->mutable_license();
|
||||
@@ -259,8 +276,8 @@ bool CdmLicense::PrepareKeyRenewalRequest(CdmKeyMessage* signed_request,
|
||||
return false;
|
||||
}
|
||||
license_request.set_key_control_nonce(UintToString(nonce));
|
||||
LOGD("PrepareKeyRenewalRequest: nonce=%u", nonce);
|
||||
license_request.set_protocol_version(VERSION_2_1);
|
||||
LOGD("PrepareKeyUpdateRequest: nonce=%u", nonce);
|
||||
license_request.set_protocol_version(video_widevine_server::sdk::VERSION_2_1);
|
||||
|
||||
// License request is complete. Serialize it.
|
||||
std::string serialized_license_req;
|
||||
@@ -272,7 +289,11 @@ bool CdmLicense::PrepareKeyRenewalRequest(CdmKeyMessage* signed_request,
|
||||
&license_request_signature))
|
||||
return false;
|
||||
|
||||
if (license_request_signature.empty()) return false;
|
||||
if (license_request_signature.empty()) {
|
||||
LOGE("CdmLicense::PrepareKeyUpdateRequest: empty license request"
|
||||
" signature");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Put serialize license request and signature together
|
||||
SignedMessage signed_message;
|
||||
@@ -369,44 +390,60 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
||||
}
|
||||
}
|
||||
|
||||
CdmResponseType CdmLicense::HandleKeyRenewalResponse(
|
||||
CdmResponseType CdmLicense::HandleKeyUpdateResponse(
|
||||
bool is_renewal,
|
||||
const CdmKeyResponse& license_response) {
|
||||
if (!session_) {
|
||||
return KEY_ERROR;
|
||||
}
|
||||
if (license_response.empty()) {
|
||||
LOGE("CdmLicense::HandleKeyRenewalResponse : Empty license response.");
|
||||
LOGE("CdmLicense::HandleKeyUpdateResponse : Empty license response.");
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
SignedMessage signed_response;
|
||||
if (!signed_response.ParseFromString(license_response))
|
||||
if (!signed_response.ParseFromString(license_response)) {
|
||||
LOGE("CdmLicense::HandleKeyUpdateResponse: Unable to parse signed message");
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
if (signed_response.type() == SignedMessage::ERROR) {
|
||||
return HandleKeyErrorResponse(signed_response);
|
||||
}
|
||||
|
||||
if (!signed_response.has_signature())
|
||||
if (!signed_response.has_signature()) {
|
||||
LOGE("CdmLicense::HandleKeyUpdateResponse: signature missing");
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
License license;
|
||||
if (!license.ParseFromString(signed_response.msg()))
|
||||
if (!license.ParseFromString(signed_response.msg())) {
|
||||
LOGE("CdmLicense::HandleKeyUpdateResponse: Unable to parse license"
|
||||
" from signed message");
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
if (!license.has_id()) return KEY_ERROR;
|
||||
if (!license.has_id()) {
|
||||
LOGE("CdmLicense::HandleKeyUpdateResponse: license id not present");
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
if (license.id().version() > license_id_.version()) {
|
||||
// This is the normal case.
|
||||
license_id_.CopyFrom(license.id());
|
||||
|
||||
if (license.policy().has_renewal_server_url() &&
|
||||
license.policy().renewal_server_url().size() > 0) {
|
||||
server_url_ = license.policy().renewal_server_url();
|
||||
if (is_renewal) {
|
||||
if (license.policy().has_renewal_server_url() &&
|
||||
license.policy().renewal_server_url().size() > 0) {
|
||||
server_url_ = license.policy().renewal_server_url();
|
||||
}
|
||||
}
|
||||
|
||||
policy_engine_->UpdateLicense(license);
|
||||
|
||||
if (!is_renewal)
|
||||
return KEY_ADDED;
|
||||
|
||||
std::vector<CryptoKey> key_array = ExtractContentKeys(license);
|
||||
|
||||
if (session_->RefreshKeys(signed_response.msg(),
|
||||
@@ -423,15 +460,67 @@ CdmResponseType CdmLicense::HandleKeyRenewalResponse(
|
||||
// This isn't supposed to happen.
|
||||
// TODO(jfore): Handle wrap? We can miss responses and that should be
|
||||
// considered normal until retries are exhausted.
|
||||
LOGE("CdmLicense::HandleKeyUpdateResponse: license version: expected > %u,"
|
||||
" actual = %u", license_id_.version(), license.id().version());
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
bool CdmLicense::RestoreOfflineLicense(
|
||||
CdmKeyMessage& license_request,
|
||||
CdmKeyResponse& license_response,
|
||||
CdmKeyResponse& license_renewal_response) {
|
||||
|
||||
if (license_request.empty() || license_response.empty()) {
|
||||
LOGE("CdmLicense::RestoreOfflineLicense: key_request or response empty: "
|
||||
"%u %u", license_request.size(), license_response.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
SignedMessage signed_request;
|
||||
if (!signed_request.ParseFromString(license_request)) {
|
||||
LOGE("CdmLicense::RestoreOfflineLicense: license_request parse failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (signed_request.type() != SignedMessage::LICENSE_REQUEST) {
|
||||
LOGE("CdmLicense::RestoreOfflineLicense: license request type: expected = "
|
||||
"%d, actual = %d",
|
||||
SignedMessage::LICENSE_REQUEST,
|
||||
signed_request.type());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Properties::use_certificates_as_identification()) {
|
||||
key_request_ = signed_request.msg();
|
||||
}
|
||||
else {
|
||||
if (!session_->GenerateDerivedKeys(signed_request.msg()))
|
||||
return false;
|
||||
}
|
||||
|
||||
CdmResponseType sts = HandleKeyResponse(license_response);
|
||||
|
||||
if (sts != KEY_ADDED)
|
||||
return false;
|
||||
|
||||
if (!license_renewal_response.empty()) {
|
||||
sts = HandleKeyUpdateResponse(true, license_renewal_response);
|
||||
|
||||
if (sts != KEY_ADDED)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CdmResponseType CdmLicense::HandleKeyErrorResponse(
|
||||
const SignedMessage& signed_message) {
|
||||
|
||||
LicenseError license_error;
|
||||
if (!license_error.ParseFromString(signed_message.msg()))
|
||||
if (!license_error.ParseFromString(signed_message.msg())) {
|
||||
LOGE("CdmLicense::HandleKeyErrorResponse: Unable to parse license error");
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
switch (license_error.error_code()) {
|
||||
case LicenseError::INVALID_CREDENTIALS:
|
||||
@@ -440,6 +529,8 @@ CdmResponseType CdmLicense::HandleKeyErrorResponse(
|
||||
return DEVICE_REVOKED;
|
||||
case LicenseError::SERVICE_UNAVAILABLE:
|
||||
default:
|
||||
LOGW("CdmLicense::HandleKeyErrorResponse: Unknwon error type = %d",
|
||||
license_error.error_code());
|
||||
return KEY_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user