Add initial support for key rotation through ce cdm interface.
Merge from Widevine repo of http://go/wvgerrit/42941 Bug: 72168544 Test: tested as part of http://go/ag/4674759 Change-Id: I1a2d0f49371e5b3edf1d9dff85b85593f981d1f5
This commit is contained in:
@@ -212,7 +212,8 @@ CdmLicense::CdmLicense(const CdmSessionId& session_id)
|
||||
renew_with_client_id_(false),
|
||||
is_offline_(false),
|
||||
use_privacy_mode_(false),
|
||||
clock_(new Clock()) {}
|
||||
clock_(new Clock()),
|
||||
license_key_type_(kLicenseKeyTypeContent) {}
|
||||
|
||||
CdmLicense::CdmLicense(const CdmSessionId& session_id, Clock* clock)
|
||||
: crypto_session_(NULL),
|
||||
@@ -221,7 +222,8 @@ CdmLicense::CdmLicense(const CdmSessionId& session_id, Clock* clock)
|
||||
initialized_(false),
|
||||
renew_with_client_id_(false),
|
||||
is_offline_(false),
|
||||
use_privacy_mode_(false) {
|
||||
use_privacy_mode_(false),
|
||||
license_key_type_(kLicenseKeyTypeContent) {
|
||||
clock_.reset(clock);
|
||||
}
|
||||
|
||||
@@ -638,6 +640,7 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
||||
LOGE("CdmLicense::HandleKeyResponse : No content keys.");
|
||||
return NO_CONTENT_KEY;
|
||||
}
|
||||
license_key_type_ = key_type;
|
||||
|
||||
if (license.has_srm_update()) crypto_session_->LoadSrm(license.srm_update());
|
||||
|
||||
@@ -661,6 +664,7 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
||||
|
||||
CdmResponseType resp = NO_CONTENT_KEY;
|
||||
if (kLicenseKeyTypeEntitlement == key_type) {
|
||||
entitlement_key_array_ = key_array;
|
||||
resp = HandleEntitlementKeyResponse(signed_response.msg(),
|
||||
signed_response.signature(), mac_key_iv,
|
||||
mac_key, key_array, license);
|
||||
@@ -752,55 +756,11 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
|
||||
}
|
||||
}
|
||||
|
||||
CdmResponseType CdmLicense::HandleSubLicense(
|
||||
CdmResponseType CdmLicense::HandleEmbeddedKeyData(
|
||||
const InitializationData& init_data) {
|
||||
std::vector<video_widevine::SubLicense> subkeys =
|
||||
init_data.ExtractSublicenseKeys();
|
||||
std::set<KeyId> loaded_keys;
|
||||
// Build a license with the rotated keys.
|
||||
License license;
|
||||
for (size_t i = 0; i < subkeys.size(); ++i) {
|
||||
SignedMessage sm;
|
||||
if (!sm.ParseFromString(subkeys[i].key_msg())) {
|
||||
return LICENSE_REQUEST_INVALID_SUBLICENSE;
|
||||
}
|
||||
License_KeyContainer keyc;
|
||||
if (!keyc.ParseFromString(sm.msg())) {
|
||||
return LICENSE_REQUEST_INVALID_SUBLICENSE;
|
||||
}
|
||||
size_t length;
|
||||
std::vector<CryptoKey> keys;
|
||||
keys.resize(1);
|
||||
keys[0].set_key_id(keyc.id());
|
||||
|
||||
// Strip PKCS#5 padding from sublicense content keys.
|
||||
// TODO(jfore): Refactor this to use ExtractContentKeys.
|
||||
if (keyc.key().size() > KEY_SIZE) {
|
||||
length = keyc.key().size() - KEY_SIZE;
|
||||
} else {
|
||||
length = 0;
|
||||
}
|
||||
keys[0].set_key_data(keyc.key().substr(0, length));
|
||||
keys[0].set_key_data_iv(keyc.iv());
|
||||
keys[0].set_key_control(keyc.key_control().key_control_block());
|
||||
keys[0].set_key_control_iv(keyc.key_control().iv());
|
||||
keys[0].set_track_label(keyc.track_label());
|
||||
//TODO: passing empty cipher_mode and srm_req params - OK?
|
||||
CdmResponseType result = crypto_session_->LoadKeys(
|
||||
sm.msg(), sm.signature(), std::string(), std::string(), keys,
|
||||
std::string(), std::string(), kLicenseKeyTypeContent);
|
||||
if (result != KEY_ADDED) {
|
||||
LOGE("CdmLicense::HandleSubLicense: LoadKeys() call failed, result=%d",
|
||||
result);
|
||||
return result;
|
||||
}
|
||||
loaded_keys.insert(keyc.id());
|
||||
*license.add_key() = keyc;
|
||||
}
|
||||
loaded_keys_.swap(loaded_keys);
|
||||
policy_engine_->UpdateLicenseKeys(license);
|
||||
|
||||
return KEY_MESSAGE;
|
||||
return (license_key_type_ == kLicenseKeyTypeEntitlement
|
||||
? HandleNewEntitledKeys(init_data.ExtractWrappedKeys())
|
||||
: HandleSubLicense(init_data));
|
||||
}
|
||||
|
||||
bool CdmLicense::RestoreOfflineLicense(
|
||||
@@ -1143,61 +1103,112 @@ CdmResponseType CdmLicense::HandleEntitlementKeyResponse(
|
||||
return resp;
|
||||
}
|
||||
|
||||
std::vector<CryptoKey> entitled_key_array;
|
||||
entitled_key_array.reserve(key_array.size());
|
||||
// Save the entitlement keys for future use to handle key changes.
|
||||
entitlement_keys_.CopyFrom(license.key());
|
||||
policy_engine_->SetLicense(license);
|
||||
|
||||
for (std::vector<video_widevine::WrappedKey>::iterator wk =
|
||||
wrapped_keys_.begin();
|
||||
wk != wrapped_keys_.end(); wk++) {
|
||||
for (std::vector<CryptoKey>::const_iterator key = key_array.begin();
|
||||
key != key_array.end(); key++) {
|
||||
if (wk->wrapping_key_id() == key->key_id()) {
|
||||
return HandleNewEntitledKeys(wrapped_keys_);
|
||||
}
|
||||
|
||||
CdmResponseType CdmLicense::HandleNewEntitledKeys(
|
||||
const std::vector<WidevinePsshData_EntitledKey>& wrapped_keys) {
|
||||
std::vector<CryptoKey> entitled_key_array;
|
||||
entitled_key_array.reserve(entitlement_keys_.size());
|
||||
|
||||
for (RepeatedPtrField<License_KeyContainer>::const_iterator kc =
|
||||
entitlement_keys_.begin();
|
||||
kc != entitlement_keys_.end(); kc++) {
|
||||
if (kc->type() != video_widevine::License::KeyContainer::ENTITLEMENT) {
|
||||
continue;
|
||||
}
|
||||
for (std::vector<WidevinePsshData_EntitledKey>::const_iterator wk =
|
||||
wrapped_keys.begin();
|
||||
wk != wrapped_keys.end(); wk++) {
|
||||
if (wk->entitlement_key_id() == kc->id()) {
|
||||
// Add a new entry to the key array to load oemcrypto.
|
||||
entitled_key_array.resize(entitled_key_array.size() + 1);
|
||||
|
||||
// Strip PKCS#5 padding from entitled content keys.
|
||||
std::string content_key = wk->key();
|
||||
if (content_key.size() > KEY_SIZE) {
|
||||
content_key.resize(KEY_SIZE);
|
||||
}
|
||||
|
||||
CryptoKey& this_entry = entitled_key_array.back();
|
||||
this_entry.set_key_id(wk->key_id());
|
||||
this_entry.set_key_data(wk->wrapped_key());
|
||||
this_entry.set_key_data_iv(wk->wrapping_iv());
|
||||
this_entry.set_entitlement_key_id(wk->wrapping_key_id());
|
||||
this_entry.set_key_data_iv(wk->iv());
|
||||
this_entry.set_entitlement_key_id(wk->entitlement_key_id());
|
||||
this_entry.set_key_data(content_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resp = crypto_session_->LoadEntitledContentKeys(entitled_key_array);
|
||||
CdmResponseType resp =
|
||||
crypto_session_->LoadEntitledContentKeys(entitled_key_array);
|
||||
if (KEY_ADDED == resp) {
|
||||
loaded_keys_.clear();
|
||||
for (std::vector<video_widevine::WrappedKey>::const_iterator it =
|
||||
wrapped_keys_.begin();
|
||||
it != wrapped_keys_.end(); ++it) {
|
||||
for (std::vector<WidevinePsshData_EntitledKey>::const_iterator it =
|
||||
wrapped_keys.begin();
|
||||
it != wrapped_keys.end(); ++it) {
|
||||
loaded_keys_.insert(it->key_id());
|
||||
}
|
||||
|
||||
// TODO(jfore): Move the information to build this "license" to the
|
||||
// entitlement key session. It is used to update the policy engine and
|
||||
// key status when using entitlement licenses. It may become unnecessary
|
||||
// if policy manager ius changed to allow setting keys from the wrapped
|
||||
// keys from init_data.
|
||||
video_widevine::License entitled_license;
|
||||
entitled_license.mutable_policy()->CopyFrom(license.policy());
|
||||
entitled_license.mutable_id()->CopyFrom(license.id());
|
||||
entitled_license.mutable_key()->CopyFrom(license.key());
|
||||
entitled_license.set_license_start_time(license.license_start_time());
|
||||
for (size_t i = 0; i < wrapped_keys_.size(); ++i) {
|
||||
for (int x = 0; x < entitled_license.key().size(); ++x) {
|
||||
if (entitled_license.key(x).id() ==
|
||||
wrapped_keys_[i].wrapping_key_id()) {
|
||||
video_widevine::License::KeyContainer* kc =
|
||||
entitled_license.mutable_key(x);
|
||||
kc->set_type(video_widevine::License::KeyContainer::CONTENT);
|
||||
kc->set_key(wrapped_keys_[i].wrapped_key());
|
||||
kc->set_id(wrapped_keys_[i].key_id());
|
||||
}
|
||||
}
|
||||
}
|
||||
policy_engine_->SetLicense(entitled_license);
|
||||
policy_engine_->SetEntitledLicenseKeys(wrapped_keys);
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
CdmResponseType CdmLicense::HandleSubLicense(
|
||||
const InitializationData& init_data) {
|
||||
std::vector<video_widevine::SubLicense> subkeys =
|
||||
init_data.ExtractSublicenseKeys();
|
||||
std::set<KeyId> loaded_keys;
|
||||
// Build a license with the rotated keys.
|
||||
License license;
|
||||
for (size_t i = 0; i < subkeys.size(); ++i) {
|
||||
SignedMessage sm;
|
||||
if (!sm.ParseFromString(subkeys[i].key_msg())) {
|
||||
return LICENSE_REQUEST_INVALID_SUBLICENSE;
|
||||
}
|
||||
License_KeyContainer keyc;
|
||||
if (!keyc.ParseFromString(sm.msg())) {
|
||||
return LICENSE_REQUEST_INVALID_SUBLICENSE;
|
||||
}
|
||||
size_t length;
|
||||
std::vector<CryptoKey> keys;
|
||||
keys.resize(1);
|
||||
keys[0].set_key_id(keyc.id());
|
||||
|
||||
// Strip PKCS#5 padding from sublicense content keys.
|
||||
// TODO(jfore): Refactor this to use ExtractContentKeys.
|
||||
if (keyc.key().size() > KEY_SIZE) {
|
||||
length = keyc.key().size() - KEY_SIZE;
|
||||
} else {
|
||||
length = 0;
|
||||
}
|
||||
keys[0].set_key_data(keyc.key().substr(0, length));
|
||||
keys[0].set_key_data_iv(keyc.iv());
|
||||
keys[0].set_key_control(keyc.key_control().key_control_block());
|
||||
keys[0].set_key_control_iv(keyc.key_control().iv());
|
||||
keys[0].set_track_label(keyc.track_label());
|
||||
// TODO: passing empty cipher_mode and srm_req params - OK?
|
||||
CdmResponseType result = crypto_session_->LoadKeys(
|
||||
sm.msg(), sm.signature(), std::string(), std::string(), keys,
|
||||
std::string(), std::string(), kLicenseKeyTypeContent);
|
||||
if (result != KEY_ADDED) {
|
||||
LOGE("CdmLicense::HandleSubLicense: LoadKeys() call failed, result=%d",
|
||||
result);
|
||||
return result;
|
||||
}
|
||||
loaded_keys.insert(keyc.id());
|
||||
*license.add_key() = keyc;
|
||||
}
|
||||
loaded_keys_.swap(loaded_keys);
|
||||
policy_engine_->UpdateLicenseKeys(license);
|
||||
|
||||
return KEY_MESSAGE;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool CdmLicense::SetTypeAndId(CdmLicenseType license_type,
|
||||
const std::string& request_id, T* content_id) {
|
||||
|
||||
Reference in New Issue
Block a user