Remove Sub-Licenses and Sub-Sessions

(This is a merge of http://go/wvgerrit/66643)

The sub-license feature has been removed from the server and packager.
So that we do not have to continue maintaining the code that supports
this feature that never shipped, I am removing it from the CDM as well.

Bug: 113165466
Test: CE CDM Unit Tests
Test: Android Unit Tests
Change-Id: I5d25844b161e74aa19adf19a29c56e4881aa7304
This commit is contained in:
John W. Bruce
2018-12-06 09:00:51 -08:00
parent cb8631776a
commit 5629a646d8
22 changed files with 5 additions and 720 deletions

View File

@@ -44,7 +44,6 @@ LOCAL_SRC_FILES := \
$(CORE_SRC_DIR)/policy_engine.cpp \
$(CORE_SRC_DIR)/privacy_crypto_boringssl.cpp \
$(CORE_SRC_DIR)/service_certificate.cpp \
$(CORE_SRC_DIR)/sublicense_key_session.cpp \
$(CORE_SRC_DIR)/usage_table_header.cpp \
$(SRC_DIR)/wv_content_decryption_module.cpp \
$(METRICS_SRC_DIR)/attribute_handler.cpp \

View File

@@ -19,8 +19,6 @@ class CryptoKey {
const std::string& key_data_iv() const { return key_data_iv_; }
const std::string& key_control() const { return key_control_; }
const std::string& key_control_iv() const { return key_control_iv_; }
const std::string& sub_session_key_id() const {return sub_session_key_id_;}
const std::string& sub_session_key() const {return sub_session_key_;}
const std::string& entitlement_key_id() const {return entitlement_key_id_;}
const std::string& track_label() const { return track_label_; }
CdmCipherMode cipher_mode() const { return cipher_mode_; }
@@ -34,12 +32,6 @@ class CryptoKey {
void set_cipher_mode(CdmCipherMode cipher_mode) {
cipher_mode_ = cipher_mode;
}
void set_sub_session_key_id(const std::string& sub_session_key_id) {
sub_session_key_id_ = sub_session_key_id;
}
void set_sub_session_key(const std::string& sub_session_key) {
sub_session_key_ = sub_session_key;
}
void set_track_label(const std::string& track_label) {
track_label_ = track_label;
}
@@ -55,9 +47,7 @@ class CryptoKey {
std::string key_data_;
std::string key_control_;
std::string key_control_iv_;
std::string sub_session_key_id_;
std::string track_label_;
std::string sub_session_key_;
std::string entitlement_key_id_;
CdmCipherMode cipher_mode_;
};

View File

@@ -199,13 +199,6 @@ class CryptoSession {
bool* can_support_cgms_a);
virtual metrics::CryptoMetrics* GetCryptoMetrics() { return metrics_; }
virtual CdmResponseType AddSubSession(const std::string& sub_session_key_id,
const std::string& group_master_key_id);
// TODO(jfore): exists is set based on whether a sub session exists. For now,
// that is not assumed to be an error.
virtual bool GenerateSubSessionNonce(const std::string& sub_session_key_id,
bool* exists, uint32_t* nonce);
virtual CdmResponseType GetProvisioningMethod(
SecurityLevel requested_security_level,
CdmClientTokenType* token_type);
@@ -295,9 +288,6 @@ class CryptoSession {
std::string oem_token_; // Cached OEMCrypto Public Key
bool update_usage_table_after_close_session_;
CryptoSessionId oec_session_id_;
SubLicenseSessionMap sub_license_oec_sessions_;
// Used for sub license sessions.
std::string wrapped_key_;
std::unique_ptr<KeySession> key_session_;
OEMCryptoBufferType destination_buffer_type_;

View File

@@ -31,9 +31,6 @@ class InitializationData {
const CdmInitData& data() const { return data_; }
std::vector<uint8_t> hls_iv() const { return hls_iv_; }
CdmHlsMethod hls_method() const { return hls_method_; }
// TODO(jfore): Perhaps this should be a generic structure with the ids for
// any type of licensing?
std::vector<video_widevine::SubLicense> ExtractSublicenseKeys() const;
std::vector<video_widevine::WidevinePsshData_EntitledKey> ExtractWrappedKeys()
const;

View File

@@ -16,7 +16,7 @@ class KeySession {
KeySession(metrics::CryptoMetrics* metrics) : metrics_(metrics) {}
public:
typedef enum { kDefault, kSubLicense, kEntitlement } KeySessionType;
typedef enum { kDefault, kEntitlement } KeySessionType;
virtual ~KeySession() {}
virtual KeySessionType Type() = 0;
virtual bool GenerateDerivedKeys(const std::string& message) = 0;
@@ -43,8 +43,6 @@ class KeySession {
metrics::CryptoMetrics* metrics_;
};
typedef std::map<std::string, CryptoSessionId> SubLicenseSessionMap;
} // namespace wvcdm
#endif // WVCDM_CORE_KEY_SESSION_H_

View File

@@ -108,7 +108,6 @@ class CdmLicense {
CdmResponseType HandleNewEntitledKeys(
const std::vector<WidevinePsshData_EntitledKey>& wrapped_keys);
CdmResponseType HandleSubLicense(const InitializationData& init_data);
template <typename T>
bool SetTypeAndId(CdmLicenseType license_type, const std::string& request_id,
@@ -147,11 +146,6 @@ class CdmLicense {
// entitelement keys. It is also used in updating the key status info.
std::vector<WidevinePsshData_EntitledKey> wrapped_keys_;
// For sublicense key embedding. This key array will be initialized with any
// sub session keys we may have received in a license response. These keys
// may be used to support key rotation.
std::vector<CryptoKey> entitlement_key_array_;
CdmLicenseKeyType license_key_type_;
RepeatedPtrField<License_KeyContainer> entitlement_keys_;
#if defined(UNIT_TEST)

View File

@@ -59,11 +59,6 @@ class PolicyEngine {
// permits playback.
virtual void SetLicense(const video_widevine::License& license);
// TODO(jfore): Sublicense uses this to update the keys when they are
// changed during key rotation. Drop this method and use SetLicenseKeys
// instead.
virtual void UpdateLicenseKeys(const video_widevine::License& license);
// Used to update the currently loaded entitled content keys.
virtual void SetEntitledLicenseKeys(
const std::vector<WidevinePsshData_EntitledKey>& entitled_keys);

View File

@@ -106,7 +106,6 @@ class Properties {
FRIEND_TEST(CdmSessionTest, InitFailCryptoError);
FRIEND_TEST(CdmSessionTest, InitNeedsProvisioning);
FRIEND_TEST(CdmLicenseTest, PrepareKeyRequestValidation);
FRIEND_TEST(SubLicenseTest, VerifySubSessionData);
#endif
private:

View File

@@ -1,95 +0,0 @@
#ifndef WVCDM_CORE_SUBLICENSE_KEY_SESSION_H_
#define WVCDM_CORE_SUBLICENSE_KEY_SESSION_H_
#include "crypto_key.h"
#include "key_session.h"
namespace wvcdm {
class SubLicenseKeySession : public KeySession {
typedef enum {
kInitializing,
kInitialLicenseLoaded,
kInitialLicenseFailed,
} SubLicenseState;
public:
SubLicenseKeySession(SubLicenseSessionMap& sub_license_oec_sessions,
metrics::CryptoMetrics* metrics,
const std::string& wrapped_private_device_key,
SecurityLevel requested_security_level,
const std::string& group_id);
virtual ~SubLicenseKeySession();
KeySessionType Type() { return kSubLicense; }
// This version of GenerateDerivedKeys is for devices using keyboxes. It is
// not supported using sub licenses.
bool GenerateDerivedKeys(const std::string&) { return false; }
// GenerateDerivedKeys is called for each open oemcrypto session and is only
// called once.
bool GenerateDerivedKeys(const std::string& message,
const std::string& session_key);
// Load the keys in |keys|. The initial keys are saved for key rotation.
OEMCryptoResult LoadKeys(const std::string& message,
const std::string& signature,
const std::string& mac_key_iv,
const std::string& mac_key,
const std::vector<CryptoKey>& keys,
const std::string& provider_session_token,
CdmCipherMode* cipher_mode,
const std::string& srm_requirement);
OEMCryptoResult LoadEntitledContentKeys(const std::vector<CryptoKey>& /*keys*/) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Each oemcrypto session contains a single key. Find the right sub session
// and save it's id as the selected oemcrypto session.
OEMCryptoResult SelectKey(const std::string& key_id,
CdmCipherMode cipher_mode);
// Decrypt performs the decryption using the selected oemcrypto session.
// TODO(jfore): Support DecryptInChunks.
OEMCryptoResult Decrypt(const CdmDecryptionParameters& params,
OEMCrypto_DestBufferDesc& buffer_descriptor,
OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor);
private:
// Destroy each open oemcrypto session and relace them with new ones.
OEMCryptoResult ResetCryptoSessions();
// DoLoadKeys loads a single key into each oemcrypto session.
OEMCryptoResult DoLoadKeys(const std::string& message,
const std::string& signature,
const std::string& mac_key_iv,
const std::string& mac_key,
const std::vector<CryptoKey>& keys,
const std::string& provider_session_token,
CdmCipherMode* cipher_mode,
const std::string& srm_requirement);
// DoLoadKeys loads a single key into each oemcrypto session.
OEMCryptoResult DoSubLicenseLoadKeys(
const std::string& message, const std::string& signature,
const std::string& mac_key_iv, const std::string& mac_key,
const CryptoKey& key, const std::string& provider_session_token,
CdmCipherMode*, const std::string& srm_requirement);
SubLicenseState state_;
std::string cached_sub_session_key_id_;
std::string wrapped_private_device_key_;
std::string message_;
std::string session_key_;
std::vector<CryptoKey> keys_;
SubLicenseSessionMap& sub_license_oec_sessions_;
SecurityLevel requested_security_level_;
KeyId group_id_;
};
} // namespace wvcdm
#endif // WVCDM_CORE_SUBLICENSE_KEY_SESSION_H_

View File

@@ -318,7 +318,7 @@ enum CdmResponseType {
USAGE_STORE_ENTRY_RETRIEVE_INVALID_STORAGE_TYPE = 274,
REMOVE_ALL_USAGE_INFO_ERROR_6 = 275,
REMOVE_ALL_USAGE_INFO_ERROR_7 = 276,
LICENSE_REQUEST_INVALID_SUBLICENSE = 277,
/* previously LICENSE_REQUEST_INVALID_SUBLICENSE = 277, */
CERT_PROVISIONING_EMPTY_SERVICE_CERTIFICATE = 278,
LOAD_SYSTEM_ID_ERROR = 279,
INSUFFICIENT_CRYPTO_RESOURCES_4 = 280,

View File

@@ -418,18 +418,6 @@ CdmResponseType CdmSession::GenerateKeyRequestInternal(
return KEY_REQUEST_ERROR_1;
}
std::vector<video_widevine::SubLicense> embedded_key_data =
init_data.ExtractSublicenseKeys();
for (size_t i = 0; i < embedded_key_data.size(); ++i) {
CdmResponseType sts = crypto_session_->AddSubSession(
embedded_key_data[i].sub_session_key_id(),
embedded_key_data[i].group_id());
if (NO_ERROR != sts) {
LOGE("CdmSession::GenerateKeyRequest: Unable to generate sub session");
return sts;
}
}
app_parameters_ = app_parameters;
CdmResponseType status = license_parser_->PrepareKeyRequest(
init_data, license_type, app_parameters, &key_request->message,

View File

@@ -23,7 +23,6 @@
#include "properties.h"
#include "pst_report.h"
#include "string_conversions.h"
#include "sublicense_key_session.h"
#include "usage_table_header.h"
#include "wv_cdm_constants.h"
@@ -772,7 +771,6 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
metrics_->oemcrypto_usage_table_support_.SetError(result);
}
// TODO(gmorgan, jfore): resolve handling of usage records in sublicenses
key_session_.reset(new ContentKeySession(oec_session_id_, metrics_));
return NO_ERROR;
@@ -944,7 +942,6 @@ bool CryptoSession::LoadCertificatePrivateKey(std::string& wrapped_key) {
LOGE("LoadCertificatePrivateKey: OEMCrypto_LoadDeviceRSAKey error=%d", sts);
return false;
}
wrapped_key_ = wrapped_key;
return true;
}
@@ -2316,73 +2313,6 @@ bool CryptoSession::GetAnalogOutputCapabilities(bool* can_support_output,
return true;
}
CdmResponseType CryptoSession::AddSubSession(
const std::string& sub_session_key_id,
const std::string& group_master_key_id) {
size_t exists = sub_license_oec_sessions_.count(sub_session_key_id);
if (exists > 0) {
// TODO(jfore): Should this be an error if the key exists? If so add a new
// error. If not, perhaps this should just print info message.
LOGE("AddSubSession: SubSession already exists for id: %s",
sub_session_key_id.c_str());
return UNKNOWN_ERROR;
}
CryptoSessionId sid;
OEMCryptoResult sts = OEMCrypto_OpenSession(&sid, requested_security_level_);
if (OEMCrypto_ERROR_TOO_MANY_SESSIONS == sts) {
LOGE("OEMCrypto_Open failed: %d, open sessions: %ld, initialized: %d", sts,
session_count_, (int)initialized_);
return INSUFFICIENT_CRYPTO_RESOURCES;
} else if (OEMCrypto_SUCCESS != sts) {
LOGE("OEMCrypto_Open failed: %d, open sessions: %ld, initialized: %d", sts,
session_count_, (int)initialized_);
return UNKNOWN_ERROR;
}
M_TIME(sts = OEMCrypto_LoadDeviceRSAKey(
sid, reinterpret_cast<const uint8_t*>(wrapped_key_.data()),
wrapped_key_.size()),
metrics_, oemcrypto_load_device_rsa_key_, sts);
if (OEMCrypto_SUCCESS != sts) {
LOGE("LoadDeviceRSAKey failed: %d", sts);
return NEED_PROVISIONING;
}
sub_license_oec_sessions_[sub_session_key_id] = sid;
if (key_session_->Type() != KeySession::kSubLicense) {
key_session_.reset(new SubLicenseKeySession(
sub_license_oec_sessions_, metrics_, wrapped_key_,
requested_security_level_, group_master_key_id));
}
return NO_ERROR;
}
bool CryptoSession::GenerateSubSessionNonce(
const std::string& sub_session_key_id, bool* exists, uint32_t* nonce) {
if (!exists || !nonce) {
LOGE("input parameter is null");
return false;
}
LOGV("CryptoSession::GenerateSubSessionNonce: Lock");
AutoLock auto_lock(crypto_lock_);
SubLicenseSessionMap::iterator it =
sub_license_oec_sessions_.find(sub_session_key_id);
if (it == sub_license_oec_sessions_.end()) {
// A subsession does not exist. Indicate that and return success.
*exists = false;
return false;
}
*exists = true;
OEMCryptoResult result;
result = OEMCrypto_GenerateNonce(it->second, nonce);
return OEMCrypto_SUCCESS == result;
}
OEMCrypto_Algorithm CryptoSession::GenericSigningAlgorithm(
CdmSigningAlgorithm algorithm) {
if (kSigningAlgorithmHmacSha256 == algorithm) {

View File

@@ -85,15 +85,6 @@ InitializationData::InitializationData(const std::string& type,
}
}
// Parse the pssh data and return the embedded key data if it exists.
std::vector<video_widevine::SubLicense>
InitializationData::ExtractSublicenseKeys() const {
std::vector<video_widevine::SubLicense> keys;
// TODO(jfore): The pssh has changed in ways that are not compatible with
//sublicenses. Restructure or remove sublicense support including this method.
return keys;
}
std::vector<video_widevine::WidevinePsshData_EntitledKey>
InitializationData::ExtractWrappedKeys() const {
std::vector<video_widevine::WidevinePsshData_EntitledKey> keys;

View File

@@ -53,7 +53,6 @@ using video_widevine::SignedMessage;
static std::vector<CryptoKey> ExtractEntitlementKeys(const License& license) {
std::vector<CryptoKey> key_array;
// Extract sub session key(s)
for (int i = 0; i < license.key_size(); ++i) {
CryptoKey key;
size_t length = 0;
@@ -326,29 +325,6 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
license_request.set_key_control_nonce(nonce);
LOGD("PrepareKeyRequest: nonce=%u", nonce);
// Prepare the request for any embedded keys that may exist in the
// initialization data.
std::vector<video_widevine::SubLicense> embedded_key_data =
init_data.ExtractSublicenseKeys();
for (size_t i = 0; i < embedded_key_data.size(); ++i) {
bool exists = false;
if (!crypto_session_->GenerateSubSessionNonce(
embedded_key_data[i].sub_session_key_id(), &exists, &nonce)) {
if (exists) {
return LICENSE_REQUEST_NONCE_GENERATION_ERROR;
}
}
SignedMessage signed_sub_license;
License_KeyContainer keyc;
// Parse the sub license for this track to extract the label.
if (!signed_sub_license.ParseFromString(embedded_key_data[i].key_msg()) ||
!keyc.ParseFromString(signed_sub_license.msg()) ||
keyc.track_label().empty()) {
return LICENSE_REQUEST_INVALID_SUBLICENSE;
}
}
license_request.set_protocol_version(video_widevine::VERSION_2_1);
// License request is complete. Serialize it.
@@ -626,7 +602,6 @@ 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_keys, key_array, license);
@@ -722,9 +697,7 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
CdmResponseType CdmLicense::HandleEmbeddedKeyData(
const InitializationData& init_data) {
return (license_key_type_ == kLicenseKeyTypeEntitlement
? HandleNewEntitledKeys(init_data.ExtractWrappedKeys())
: HandleSubLicense(init_data));
return HandleNewEntitledKeys(init_data.ExtractWrappedKeys());
}
bool CdmLicense::RestoreOfflineLicense(
@@ -1127,57 +1100,6 @@ CdmResponseType CdmLicense::HandleNewEntitledKeys(
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() > CONTENT_KEY_SIZE) {
length = keyc.key().size() - CONTENT_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) {

View File

@@ -170,14 +170,6 @@ void PolicyEngine::SetLicense(const License& license) {
UpdateLicense(license);
}
void PolicyEngine::UpdateLicenseKeys(const video_widevine::License& license) {
// Use the current policy and set the new keys.
video_widevine::License loadable = license;
loadable.mutable_policy()->CopyFrom(policy_);
license_keys_->SetFromLicense(loadable);
NotifyKeysChange(kKeyStatusUsable);
}
void PolicyEngine::SetEntitledLicenseKeys(
const std::vector<WidevinePsshData_EntitledKey>& entitled_keys) {
license_keys_->SetEntitledKeys(entitled_keys);

View File

@@ -1,328 +0,0 @@
#include "sublicense_key_session.h"
#include "crypto_session.h"
#include "log.h"
#include "wv_cdm_constants.h"
namespace wvcdm {
SubLicenseKeySession::SubLicenseKeySession(
SubLicenseSessionMap& sub_license_oec_sessions,
metrics::CryptoMetrics* metrics,
const std::string& wrapped_private_device_key,
SecurityLevel requested_security_level,
const std::string& group_id)
: KeySession(metrics),
state_(kInitializing),
wrapped_private_device_key_(wrapped_private_device_key),
sub_license_oec_sessions_(sub_license_oec_sessions),
requested_security_level_(requested_security_level),
group_id_(group_id) {}
SubLicenseKeySession::~SubLicenseKeySession() {
for (SubLicenseSessionMap::iterator oec_session =
sub_license_oec_sessions_.begin();
oec_session != sub_license_oec_sessions_.end(); oec_session++) {
metrics_->oemcrypto_close_session_.Increment(
OEMCrypto_CloseSession(oec_session->second));
}
sub_license_oec_sessions_.clear();
}
// GenerateDerivedKeys is called for each open oemcrypto session and is only
// called once.
bool SubLicenseKeySession::GenerateDerivedKeys(const std::string& message,
const std::string& session_key) {
std::string mac_deriv_message;
std::string enc_deriv_message;
GenerateMacContext(message, &mac_deriv_message);
GenerateEncryptContext(message, &enc_deriv_message);
for (SubLicenseSessionMap::iterator it = sub_license_oec_sessions_.begin();
it != sub_license_oec_sessions_.end(); it++) {
LOGV("GenerateDerivedKeys: id=%ld", (uint32_t)it->second);
OEMCryptoResult sts;
M_TIME(sts = OEMCrypto_DeriveKeysFromSessionKey(
it->second, reinterpret_cast<const uint8_t*>(session_key.data()),
session_key.size(),
reinterpret_cast<const uint8_t*>(mac_deriv_message.data()),
mac_deriv_message.size(),
reinterpret_cast<const uint8_t*>(enc_deriv_message.data()),
enc_deriv_message.size()),
metrics_, oemcrypto_derive_keys_from_session_key_, sts);
if (OEMCrypto_SUCCESS != sts) {
LOGE("GenerateDerivedKeys: OEMCrypto_DeriveKeysFromSessionKey err=%d",
sts);
return false;
}
}
return true;
}
OEMCryptoResult SubLicenseKeySession::LoadKeys(
const std::string& message, const std::string& signature,
const std::string& mac_key_iv, const std::string& mac_key,
const std::vector<CryptoKey>& keys,
const std::string& provider_session_token, CdmCipherMode* cipher_mode,
const std::string& srm_requirement) {
if (state_ == kInitializing) {
state_ = kInitialLicenseLoaded;
keys_ = keys;
OEMCryptoResult sts =
DoLoadKeys(message, signature, mac_key_iv, mac_key, keys,
provider_session_token, cipher_mode, srm_requirement);
if (OEMCrypto_SUCCESS != sts) {
state_ = kInitialLicenseFailed;
}
return sts;
}
return DoSubLicenseLoadKeys(message, signature, mac_key_iv, mac_key, keys[0],
provider_session_token, cipher_mode,
srm_requirement);
}
OEMCryptoResult SubLicenseKeySession::SelectKey(const std::string& key_id,
CdmCipherMode cipher_mode) {
for (size_t i = 0; i < keys_.size(); ++i) {
if (keys_[i].key_id() == key_id) {
cached_sub_session_key_id_ = keys_[i].sub_session_key_id();
if (keys_[i].cipher_mode() != cipher_mode) {
SubLicenseSessionMap::iterator it =
sub_license_oec_sessions_.find(cached_sub_session_key_id_);
if (it == sub_license_oec_sessions_.end()) {
return OEMCrypto_ERROR_INVALID_SESSION;
}
OEMCryptoResult status = OEMCrypto_SUCCESS;
M_TIME(status = OEMCrypto_SelectKey(
it->second,
reinterpret_cast<const uint8_t*>(keys_[i].key_id().data()),
keys_[i].key_id().size(),
ToOEMCryptoCipherMode(cipher_mode)),
metrics_, oemcrypto_select_key_, status);
if (OEMCrypto_SUCCESS != status) {
return status;
}
keys_[i].set_cipher_mode(cipher_mode);
}
}
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult SubLicenseKeySession::Decrypt(
const CdmDecryptionParameters& params,
OEMCrypto_DestBufferDesc& buffer_descriptor,
OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor) {
SubLicenseSessionMap::iterator it =
sub_license_oec_sessions_.find(cached_sub_session_key_id_);
if (it == sub_license_oec_sessions_.end()) {
return OEMCrypto_ERROR_INVALID_SESSION;
}
OEMCryptoResult sts;
M_TIME(sts = OEMCrypto_DecryptCENC(
it->second, params.encrypt_buffer, params.encrypt_length,
params.is_encrypted, &(*params.iv).front(), params.block_offset,
&buffer_descriptor, &pattern_descriptor, params.subsample_flags),
metrics_, oemcrypto_decrypt_cenc_, sts,
metrics::Pow2Bucket(params.encrypt_length));
return sts;
}
OEMCryptoResult SubLicenseKeySession::ResetCryptoSessions() {
for (SubLicenseSessionMap::iterator it = sub_license_oec_sessions_.begin();
it != sub_license_oec_sessions_.end(); it++) {
OEMCryptoResult sts = OEMCrypto_CloseSession(it->second);
metrics_->oemcrypto_close_session_.Increment(sts);
if (OEMCrypto_SUCCESS != sts) {
return sts;
}
sts = OEMCrypto_OpenSession(&it->second, requested_security_level_);
if (OEMCrypto_SUCCESS != sts) {
return sts;
}
M_TIME(sts = OEMCrypto_LoadDeviceRSAKey(
it->second,
reinterpret_cast<const uint8_t*>(
wrapped_private_device_key_.data()),
wrapped_private_device_key_.size()),
metrics_, oemcrypto_load_device_rsa_key_, sts);
if (OEMCrypto_SUCCESS != sts) {
return sts;
}
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult SubLicenseKeySession::DoLoadKeys(
const std::string& message, const std::string& signature,
const std::string& mac_key_iv, const std::string& mac_key,
const std::vector<CryptoKey>& keys,
const std::string& provider_session_token, CdmCipherMode* cipher_mode,
const std::string& srm_requirement) {
const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data());
bool valid_mac_keys =
mac_key.length() >= MAC_KEY_SIZE && mac_key_iv.length() >= KEY_IV_SIZE;
OEMCrypto_Substring enc_mac_key =
GetSubstring(message, mac_key, !valid_mac_keys);
OEMCrypto_Substring enc_mac_key_iv =
GetSubstring(message, mac_key_iv, !valid_mac_keys);
if (!valid_mac_keys) LOGV("CryptoSession::LoadKeys: enc_mac_key not set");
OEMCrypto_Substring pst = GetSubstring(message, provider_session_token);
OEMCrypto_Substring srm_req = GetSubstring(message, srm_requirement);
for (size_t i = 0; i < keys.size(); i++) {
OEMCrypto_KeyObject key_object;
const CryptoKey& key_data = keys[i];
key_object.key_id = GetSubstring(message, key_data.key_id());
key_object.key_data_iv = GetSubstring(message, key_data.key_data_iv());
key_object.key_data = GetSubstring(message, key_data.key_data());
bool has_key_control = key_data.HasKeyControl();
key_object.key_control_iv =
GetSubstring(message, key_data.key_control_iv(), !has_key_control);
key_object.key_control =
GetSubstring(message, key_data.key_control(), !has_key_control);
if (!has_key_control) {
LOGE("For key %s: XXX key has no control block. size=%d",
key_data.key_id().c_str(), key_data.key_control().size());
}
OEMCryptoCipherMode oem_cipher_mode =
ToOEMCryptoCipherMode(key_data.cipher_mode());
// TODO(jfore): Does returning the cipher mode serve any purpose?
// If not drop.
*cipher_mode = key_data.cipher_mode();
SubLicenseSessionMap::iterator oec_session_id =
sub_license_oec_sessions_.find(key_data.sub_session_key_id());
if (oec_session_id == sub_license_oec_sessions_.end()) {
LOGE("CryptoSession::LoadKeys: Unrecognized sub session %s",
key_data.sub_session_key_id().c_str());
return OEMCrypto_ERROR_INVALID_SESSION;
}
OEMCryptoResult sts;
M_TIME(sts = OEMCrypto_LoadKeys_Back_Compat(
oec_session_id->second, msg, message.size(),
reinterpret_cast<const uint8_t*>(signature.data()),
signature.size(), enc_mac_key_iv, enc_mac_key, 1, &key_object,
pst, srm_req, OEMCrypto_ContentLicense, &oem_cipher_mode),
metrics_, oemcrypto_load_keys_, sts);
if (sts != OEMCrypto_SUCCESS) {
return sts;
}
M_TIME(sts = OEMCrypto_SelectKey(
oec_session_id->second,
reinterpret_cast<const uint8_t*>(key_data.key_id().data()),
key_data.key_id().size(),
ToOEMCryptoCipherMode(key_data.cipher_mode())),
metrics_, oemcrypto_select_key_, sts);
if (sts != OEMCrypto_SUCCESS) {
return sts;
}
}
keys_ = keys;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult SubLicenseKeySession::DoSubLicenseLoadKeys(
const std::string& message, const std::string& signature,
const std::string& mac_key_iv, const std::string& mac_key,
const CryptoKey& key, const std::string& provider_session_token,
CdmCipherMode*, const std::string& srm_requirement) {
SubLicenseSessionMap::iterator it = sub_license_oec_sessions_.end();
size_t key_index = 0;
for (; key_index < keys_.size(); key_index++) {
if (keys_[key_index].track_label() == key.track_label()) {
it =
sub_license_oec_sessions_.find(keys_[key_index].sub_session_key_id());
CryptoKey tmp = key;
tmp.set_sub_session_key_id(keys_[key_index].sub_session_key_id());
tmp.set_sub_session_key(keys_[key_index].sub_session_key());
keys_[key_index] = tmp;
break;
}
}
if (it == sub_license_oec_sessions_.end()) {
return OEMCrypto_SUCCESS;
}
LOGV("GenerateDerivedKeys: id=%ld", (uint32_t)it->second);
std::string mac_deriv_message;
std::string enc_deriv_message;
GenerateMacContext(group_id_ + message.c_str(), &mac_deriv_message);
GenerateEncryptContext(group_id_ + message.c_str(), &enc_deriv_message);
const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data());
bool valid_mac_keys =
mac_key.length() >= MAC_KEY_SIZE && mac_key_iv.length() >= KEY_IV_SIZE;
OEMCrypto_Substring enc_mac_key =
GetSubstring(message, mac_key, !valid_mac_keys);
OEMCrypto_Substring enc_mac_key_iv =
GetSubstring(message, mac_key_iv, !valid_mac_keys);
if (!valid_mac_keys) LOGV("CryptoSession::LoadKeys: enc_mac_key not set");
OEMCrypto_Substring pst = GetSubstring(message, provider_session_token);
OEMCrypto_Substring srm_req = GetSubstring(message, srm_requirement);
OEMCryptoResult sts;
const std::string& sub_session_key = keys_[key_index].sub_session_key();
LOGV("ssksize = %d", sub_session_key.size());
M_TIME(
sts = OEMCrypto_DeriveKeysFromSessionKey(
it->second, reinterpret_cast<const uint8_t*>(sub_session_key.data()),
sub_session_key.size(),
reinterpret_cast<const uint8_t*>(mac_deriv_message.data()),
mac_deriv_message.size(),
reinterpret_cast<const uint8_t*>(enc_deriv_message.data()),
enc_deriv_message.size()),
metrics_, oemcrypto_derive_keys_from_session_key_, sts);
if (OEMCrypto_SUCCESS != sts) {
LOGE("GenerateDerivedKeys: OEMCrypto_DeriveKeysFromSessionKey err=%d", sts);
return sts;
}
OEMCrypto_KeyObject key_object;
key_object.key_id = GetSubstring(message, keys_[key_index].key_id());
key_object.key_data_iv =
GetSubstring(message, keys_[key_index].key_data_iv());
key_object.key_data = GetSubstring(message, keys_[key_index].key_data());
bool has_key_control = key.HasKeyControl();
key_object.key_control_iv = GetSubstring(
message, keys_[key_index].key_control_iv(), !has_key_control);
key_object.key_control =
GetSubstring(message, keys_[key_index].key_control(), !has_key_control);
OEMCryptoCipherMode oem_cipher_mode =
ToOEMCryptoCipherMode(keys_[key_index].cipher_mode());
M_TIME(sts = OEMCrypto_LoadKeys_Back_Compat(
it->second, msg, message.size(),
reinterpret_cast<const uint8_t*>(signature.data()),
signature.size(), enc_mac_key_iv, enc_mac_key, 1, &key_object, pst,
srm_req, OEMCrypto_ContentLicense, &oem_cipher_mode),
metrics_, oemcrypto_load_keys_, sts);
if (sts != OEMCrypto_SUCCESS) {
return sts;
}
M_TIME(sts = OEMCrypto_SelectKey(
it->second,
reinterpret_cast<const uint8_t*>(keys_[key_index].key_id().data()),
keys_[key_index].key_id().size(),
ToOEMCryptoCipherMode(keys_[key_index].cipher_mode())),
metrics_, oemcrypto_select_key_, sts);
return sts;
}
} // namespace wvcdm

View File

@@ -170,19 +170,6 @@ const std::string kZeroSizedPsshBox = a2bs_hex(
// data:
"08011a0d7769646576696e655f74657374220f73747265616d696e675f636c697031");
const std::string kSubLicensePsshBox = a2bs_hex(
// Widevine PSSH box
"0000009f" // atom size
"70737368" // atom type="pssh"
"00000000" // v0, flags=0
"edef8ba979d64acea3c827dcd51d21ed" // system id (Widevine)
"0000007f" // data size
// data:
"0801120d746573745f6b65795f69645f30120d746573745f6b65795f69645f31220f"
"746573745f636f6e74656e745f69645a250a147375625f73657373696f6e5f6b6579"
"5f69645f30120d7375625f6c6963656e73655f305a250a147375625f73657373696f"
"6e5f6b65795f69645f31120d7375625f6c6963656e73655f31");
const std::string kMultipleWidevinePsshBox = a2bs_hex(
// first PSSH box, Widevine with single keys
"00000042" // atom size
@@ -515,7 +502,7 @@ class HlsTest : public ::testing::Test {};
} // namespace
TEST_F(InitializationDataTest, BadType) {
InitializationData init_data("bad", kSubLicensePsshBox);
InitializationData init_data("bad", kWidevinePssh);
EXPECT_TRUE(init_data.IsEmpty());
}
@@ -529,8 +516,7 @@ INSTANTIATE_TEST_CASE_P(
::testing::Values(kWidevinePssh, kWidevinePsshFirst,
kWidevinePsshAfterV0Pssh, kWidevinePsshAfterNonZeroFlags,
kWidevinePsshAfterV1Pssh, kWidevineV1Pssh, kOtherBoxFirst,
kZeroSizedPsshBox, kSubLicensePsshBox,
kMultipleWidevinePsshBox));
kZeroSizedPsshBox, kMultipleWidevinePsshBox));
TEST_F(InitializationDataTest, HandlesMultipleWidevinePsshs) {
InitializationData single_init_data(ISO_BMFF_VIDEO_MIME_TYPE,
@@ -546,28 +532,6 @@ TEST_F(InitializationDataTest, HandlesMultipleWidevinePsshs) {
EXPECT_EQ(kEntitledKeysWidevinePsshBoxData, entitled_init_data.data());
}
// TODO(jfore): The pssh has changed in ways that are not compatible with
//sublicenses. Restructure or remove sublicense support including this test.
TEST_F(InitializationDataTest, DISABLED_ExtractSubLicense) {
InitializationData init_data(ISO_BMFF_VIDEO_MIME_TYPE, kSubLicensePsshBox);
ASSERT_FALSE(init_data.IsEmpty());
std::vector<video_widevine::SubLicense> keys =
init_data.ExtractSublicenseKeys();
ASSERT_EQ(keys.size(), 2UL);
EXPECT_EQ(keys[0].sub_session_key_id(), "sub_session_key_id_0");
EXPECT_EQ(keys[1].sub_session_key_id(), "sub_session_key_id_1");
EXPECT_EQ(keys[0].key_msg(), "sub_license_0");
EXPECT_EQ(keys[1].key_msg(), "sub_license_1");
}
TEST_F(InitializationDataTest, ExtractEmptySubLicense) {
InitializationData init_data(ISO_BMFF_VIDEO_MIME_TYPE, kWidevinePssh);
ASSERT_FALSE(init_data.IsEmpty());
std::vector<video_widevine::SubLicense> keys =
init_data.ExtractSublicenseKeys();
ASSERT_TRUE(keys.empty());
}
TEST_P(HlsKeyFormatVersionsExtractionTest, ExtractKeyFormatVersions) {
std::vector<std::string> versions = GetParam();
std::string key_format_versions;

View File

@@ -113,32 +113,6 @@ const std::string kLicenseRequestSignature = a2bs_hex(
"9AE18B91516E0CDD0B581590DDDEA2A2527E2C9ABA273629B586A9D22D451A827E332CFC3E"
"9BEDB6CF3D8713F9E11675DF1F5DB9038DBBECAB9D1683F8722CAF6E18EC8C04AEE5");
const std::string kSubLicensePssh = a2bs_hex(
"000002317073736800000000edef8ba979d64acea3c827dcd51d21ed000002010801120d54"
"6573744b6579415544494f30120a546573744b6579534430120a546573744b65794844301a"
"0048e3dc959b0650025a9b010a101f10e4700b1a5b731c545fe2405cea1b12860112620a0d"
"546573744b6579415544494f3012102f4b661d1064b5ea82efcd3ef850f45b1a10a02c5cea"
"5182383c064c06abbc79bfa8200242240a1023acc9a0ef2bca66af2a1307cc9edeb21210e1"
"f1d352b4c6b1aad1fd78423db256946205415544494f1a20aaf4537f09332c502a88f43a18"
"a3e21ec28bbde675c5d87054fbca06f98e98015a95010a10c034cf6ae181b8d07f2e79142d"
"792bb3128001125c0a0a546573744b657953443012106d37a0a201afdef8a494f89a4b0772"
"4a1a10457db86b73bf87177a5cc61c0d04b690200242240a1001fe432d2a8afb7054ae76a3"
"9c2727e612108761b7e0ba354ee4132117a9de12abd3620253441a20e3f37529cb795b35a0"
"d186e4ce7187f08dda5f1df136ddb92eb0a65a899635005a95010a1021cdec9b2105c6b643"
"e71f68e5302c85128001125c0a0a546573744b6579484430121012a3e3afe1e23be2c3fc55"
"fddad877451a108f31ff0865f4d4fb41d96414297f7728200242240a1061e3cbca755b36c8"
"e7d6dda03af20e4f1210a2fa2fc5d10c9c84ddc5511446ce77e9620248441a20a945699aef"
"49355b0214b636edb7670bbe350c58b69cd52f207953b380a52df2");
const std::string kSubSessionKeyID1 =
a2bs_hex("1f10e4700b1a5b731c545fe2405cea1b");
const std::string kSubSessionKeyID2 =
a2bs_hex("c034cf6ae181b8d07f2e79142d792bb3");
const std::string kSubSessionKeyID3 =
a2bs_hex("21cdec9b2105c6b643e71f68e5302c85");
const CryptoSession::SupportedCertificateTypes kDefaultSupportedCertTypes = {
true,
true,
@@ -171,9 +145,6 @@ class MockCryptoSession : public TestCryptoSession {
MOCK_METHOD1(GetApiVersion, bool(uint32_t*));
MOCK_METHOD1(GenerateNonce, bool(uint32_t*));
MOCK_METHOD3(PrepareRequest, bool(const std::string&, bool, std::string*));
MOCK_METHOD3(GenerateSubSessionNonce,
bool(const std::string& sub_session_key_id, bool* exists,
uint32_t* nonce));
MOCK_METHOD1(LoadEntitledContentKeys,
CdmResponseType(const std::vector<CryptoKey>& key_array));
};
@@ -270,11 +241,6 @@ class CdmLicenseTest : public WvCdmTestBase {
std::string pssh_;
};
class SubLicenseTest : public CdmLicenseTest {
protected:
SubLicenseTest() : CdmLicenseTest(kSubLicensePssh) {}
};
TEST_F(CdmLicenseTest, InitSuccess) {
EXPECT_CALL(*crypto_session_, IsOpen()).WillOnce(Return(true));

View File

@@ -566,9 +566,6 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
case USAGE_STORE_ENTRY_RETRIEVE_INVALID_STORAGE_TYPE:
*os << "USAGE_STORE_ENTRY_RETRIEVE_INVALID_STORAGE_TYPE";
break;
case LICENSE_REQUEST_INVALID_SUBLICENSE:
*os << "LICENSE_REQUEST_INVALID_SUBLICENSE";
break;
case CERT_PROVISIONING_EMPTY_SERVICE_CERTIFICATE:
*os << "CERT_PROVISIONING_EMPTY_SERVICE_CERTIFICATE";
break;

View File

@@ -257,7 +257,6 @@ enum {
kUsageStoreEntryRetrieveInvalidStorageType = ERROR_DRM_VENDOR_MIN + 266,
kRemoveAllUsageInfoError6 = ERROR_DRM_VENDOR_MIN + 267,
kRemoveAllUsageInfoError7 = ERROR_DRM_VENDOR_MIN + 268,
kLicenseRequestInvalidSublicense = ERROR_DRM_VENDOR_MIN + 269,
kCertProvisioningEmptyServiceCertificate = ERROR_DRM_VENDOR_MIN + 270,
kLoadSystemIdError = ERROR_DRM_VENDOR_MIN + 271,
kInsufficientCryptoResources4 = ERROR_DRM_VENDOR_MIN + 272,

View File

@@ -500,8 +500,6 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) {
return kRemoveAllUsageInfoError6;
case wvcdm::REMOVE_ALL_USAGE_INFO_ERROR_7:
return kRemoveAllUsageInfoError7;
case wvcdm::LICENSE_REQUEST_INVALID_SUBLICENSE:
return kLicenseRequestInvalidSublicense;
case wvcdm::CERT_PROVISIONING_EMPTY_SERVICE_CERTIFICATE:
return kCertProvisioningEmptyServiceCertificate;
case wvcdm::LOAD_SYSTEM_ID_ERROR:

View File

@@ -195,7 +195,6 @@ static Status mapCdmResponseType(wvcdm::CdmResponseType res) {
case wvcdm::WEBM_INIT_DATA_UNAVAILABLE:
case wvcdm::PREPARE_WEBM_CONTENT_ID_FAILED:
case wvcdm::UNSUPPORTED_INIT_DATA_FORMAT:
case wvcdm::LICENSE_REQUEST_INVALID_SUBLICENSE:
case wvcdm::LICENSE_REQUEST_NONCE_GENERATION_ERROR:
case wvcdm::LICENSE_REQUEST_SERVICE_CERTIFICATE_GENERATION_ERROR:
case wvcdm::LICENSE_REQUEST_SIGNING_ERROR: