Migration from jb-mr2 to master for Widevine CDM

Android development of the widevine CDM has been done
on the jb-mr2 branch of the cdm code base.  This CL
contains a merge of that jb-mr2 work to CDM master, and
also reflects the evolution of the common Modular DRM
code base since jb-mr2 branched.

Change-Id: I1d7e1a12d092c00044a4298261146cb97808d4ef
This commit is contained in:
Jeff Tinker
2013-07-29 17:29:07 -07:00
parent edb987db07
commit 0190f99fb3
68 changed files with 4754 additions and 3601 deletions

View File

@@ -4,7 +4,7 @@
#include <vector>
#include "crypto_engine.h"
#include "crypto_key.h"
#include "crypto_session.h"
#include "log.h"
#include "policy_engine.h"
@@ -13,13 +13,13 @@
#include "wv_cdm_constants.h"
namespace {
std::string kCompanyNameKey = "company_name";
std::string kModelNameKey = "model_name";
std::string kArchitectureNameKey = "architecture_name";
std::string kDeviceNameKey = "device_name";
std::string kProductNameKey = "product_name";
std::string kBuildInfoKey = "build_info";
std::string kDeviceIdKey = "device_id";
std::string kCompanyNameKey = "company_name";
std::string kModelNameKey = "model_name";
std::string kArchitectureNameKey = "architecture_name";
std::string kDeviceNameKey = "device_name";
std::string kProductNameKey = "product_name";
std::string kBuildInfoKey = "build_info";
std::string kDeviceIdKey = "device_id";
}
namespace wvcdm {
@@ -30,13 +30,13 @@ using video_widevine_server::sdk::ClientIdentification_NameValue;
using video_widevine_server::sdk::LicenseRequest;
using video_widevine_server::sdk::LicenseRequest_ContentIdentification;
using video_widevine_server::sdk::LicenseRequest_ContentIdentification_CENC;
using video_widevine_server::sdk::LicenseRequest_ContentIdentification_ExistingLicense;
using video_widevine_server::sdk::
LicenseRequest_ContentIdentification_ExistingLicense;
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;
static std::vector<CryptoKey> ExtractContentKeys(const License& license) {
std::vector<CryptoKey> key_array;
@@ -50,7 +50,11 @@ static std::vector<CryptoKey> ExtractContentKeys(const License& license) {
key.set_key_id(license.key(i).id());
// Strip off PKCS#5 padding - since we know the key is 16 or 32 bytes,
// the padding will always be 16 bytes.
length = license.key(i).key().size() - 16;
if (license.key(i).key().size() > 16) {
length = license.key(i).key().size() - 16;
} else {
length = 0;
}
key.set_key_data(license.key(i).key().substr(0, length));
key.set_key_data_iv(license.key(i).iv());
if (license.key(i).has_key_control()) {
@@ -62,7 +66,9 @@ static std::vector<CryptoKey> ExtractContentKeys(const License& license) {
case License_KeyContainer::KEY_CONTROL:
if (license.key(i).has_key_control()) {
key.set_key_control(license.key(i).key_control().key_control_block());
key.set_key_control_iv(license.key(i).key_control().iv());
if (license.key(i).key_control().has_iv()) {
key.set_key_control_iv(license.key(i).key_control().iv());
}
key_array.push_back(key);
}
break;
@@ -75,17 +81,14 @@ static std::vector<CryptoKey> ExtractContentKeys(const License& license) {
return key_array;
}
CdmLicense::CdmLicense(): session_(NULL) {}
CdmLicense::CdmLicense() : session_(NULL) {}
CdmLicense::~CdmLicense() {}
bool CdmLicense::Init(const std::string& token,
CryptoSession* session,
bool CdmLicense::Init(const std::string& token, CryptoSession* session,
PolicyEngine* policy_engine) {
if (token.size() == 0)
return false;
if (session == NULL || !session->IsValid() || !session->IsOpen())
return false;
if (token.size() == 0) return false;
if (session == NULL || !session->IsOpen()) return false;
token_ = token;
session_ = session;
policy_engine_ = policy_engine;
@@ -97,8 +100,7 @@ bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data,
const CdmAppParameterMap& app_parameters,
CdmKeyMessage* signed_request,
std::string* server_url) {
if (!session_ ||
token_.empty()) {
if (!session_ || token_.empty()) {
return false;
}
if (init_data.empty()) {
@@ -109,10 +111,6 @@ bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data,
LOGE("CdmLicense::PrepareKeyRequest : No signed request provided.");
return false;
}
if (!server_url) {
LOGE("CdmLicense::PrepareKeyRequest : No server url provided.");
return false;
}
// TODO(gmorgan): Request ID owned by session?
std::string request_id;
@@ -135,38 +133,38 @@ bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data,
client_info->set_value(iter->second);
}
std::string value;
if (Properties::GetCompanyName(value)) {
if (Properties::GetCompanyName(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kCompanyNameKey);
client_info->set_value(value);
}
if (Properties::GetModelName(value)) {
if (Properties::GetModelName(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kModelNameKey);
client_info->set_value(value);
}
if (Properties::GetArchitectureName(value)) {
if (Properties::GetArchitectureName(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kArchitectureNameKey);
client_info->set_value(value);
}
if (Properties::GetDeviceName(value)) {
if (Properties::GetDeviceName(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kDeviceNameKey);
client_info->set_value(value);
}
if (Properties::GetProductName(value)) {
if (Properties::GetProductName(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kProductNameKey);
client_info->set_value(value);
}
if (Properties::GetBuildInfo(value)) {
if (Properties::GetBuildInfo(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kBuildInfoKey);
client_info->set_value(value);
}
if (CryptoEngine::GetInstance()->GetDeviceUniqueId(&value)) {
if (session_->GetDeviceUniqueId(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kDeviceIdKey);
client_info->set_value(value);
@@ -188,8 +186,8 @@ bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data,
cenc_content_id->set_license_type(video_widevine_server::sdk::STREAMING);
break;
default:
LOGD("CdmLicense::PrepareKeyRequest: Unknown license type = %u",
(int)license_type);
LOGD("CdmLicense::PrepareKeyRequest: Unknown license type = %d",
license_type);
return false;
break;
}
@@ -220,8 +218,8 @@ bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data,
// Derive signing and encryption keys and construct signature.
std::string license_request_signature;
if (!session_->PrepareRequest(serialized_license_req,
&license_request_signature, false)) {
if (!session_->PrepareRequest(serialized_license_req, false,
&license_request_signature)) {
signed_request->clear();
return false;
}
@@ -268,7 +266,7 @@ bool CdmLicense::PrepareKeyUpdateRequest(bool is_renewal,
LicenseRequest_ContentIdentification_ExistingLicense* current_license =
license_request.mutable_content_id()->mutable_license();
current_license->mutable_license_id()->CopyFrom(license_id_);
current_license->mutable_license_id()->CopyFrom(policy_engine_->license_id());
// Get/set the nonce. This value will be reflected in the Key Control Block
// of the license response.
@@ -318,23 +316,19 @@ CdmResponseType CdmLicense::HandleKeyResponse(
}
SignedMessage signed_response;
if (!signed_response.ParseFromString(license_response))
return KEY_ERROR;
if (!signed_response.ParseFromString(license_response)) return KEY_ERROR;
if (signed_response.type() == SignedMessage::ERROR) {
return HandleKeyErrorResponse(signed_response);
}
if (!signed_response.has_signature())
return KEY_ERROR;
if (!signed_response.has_signature()) return KEY_ERROR;
License license;
if (!license.ParseFromString(signed_response.msg()))
return KEY_ERROR;
if (!license.ParseFromString(signed_response.msg())) return KEY_ERROR;
if (Properties::use_certificates_as_identification()) {
if (!signed_response.has_session_key())
return KEY_ERROR;
if (!signed_response.has_session_key()) return KEY_ERROR;
if (!session_->GenerateDerivedKeys(key_request_,
signed_response.session_key()))
@@ -344,8 +338,7 @@ CdmResponseType CdmLicense::HandleKeyResponse(
// Extract mac key
std::string mac_key_iv;
std::string mac_key;
if (license.policy().can_renew())
{
if (license.policy().can_renew()) {
for (int i = 0; i < license.key_size(); ++i) {
if (license.key(i).type() == License_KeyContainer::SIGNING) {
mac_key_iv.assign(license.key(i).iv());
@@ -355,15 +348,9 @@ CdmResponseType CdmLicense::HandleKeyResponse(
}
}
if (mac_key_iv.size() != KEY_IV_SIZE ||
mac_key.size() != MAC_KEY_SIZE) {
if (mac_key_iv.size() != KEY_IV_SIZE || mac_key.size() != MAC_KEY_SIZE) {
return KEY_ERROR;
}
// License Id should not be empty for renewable license
if (!license.has_id()) return KEY_ERROR;
license_id_.CopyFrom(license.id());
}
std::vector<CryptoKey> key_array = ExtractContentKeys(license);
@@ -376,17 +363,16 @@ CdmResponseType CdmLicense::HandleKeyResponse(
server_url_ = license.policy().renewal_server_url();
}
// TODO(kqyang, jfore, gmorgan): change SetLicense function signature to
// be able to return true/false to accept/reject the license. (Pending code
// merge from Eureka)
policy_engine_->SetLicense(license);
if (session_->LoadKeys(signed_response.msg(),
signed_response.signature(),
mac_key_iv,
mac_key,
key_array.size(),
if (session_->LoadKeys(signed_response.msg(), signed_response.signature(),
mac_key_iv, mac_key, key_array.size(),
&key_array[0])) {
return KEY_ADDED;
}
else {
} else {
return KEY_ERROR;
}
}
@@ -429,41 +415,31 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
return KEY_ERROR;
}
if (license.id().version() > license_id_.version()) {
// This is the normal case.
license_id_.CopyFrom(license.id());
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(),
signed_response.signature(),
key_array.size(),
&key_array[0])) {
return KEY_ADDED;
}
else {
return KEY_ERROR;
if (is_renewal) {
if (license.policy().has_renewal_server_url() &&
license.policy().renewal_server_url().size() > 0) {
server_url_ = license.policy().renewal_server_url();
}
}
// 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;
// TODO(kqyang, jfore, gmorgan): change UpdateLicense function signature to
// be able to return true/false to accept/reject the license. (Pending code
// merge from Eureka)
policy_engine_->UpdateLicense(license);
if (!is_renewal)
return KEY_ADDED;
std::vector<CryptoKey> key_array = ExtractContentKeys(license);
if (session_->RefreshKeys(signed_response.msg(),
signed_response.signature(),
key_array.size(),
&key_array[0])) {
return KEY_ADDED;
} else {
return KEY_ERROR;
}
}
bool CdmLicense::RestoreOfflineLicense(