diff --git a/libwvdrmengine/cdm/core/include/entitlement_key_session.h b/libwvdrmengine/cdm/core/include/entitlement_key_session.h index 1877d305..da4fee41 100644 --- a/libwvdrmengine/cdm/core/include/entitlement_key_session.h +++ b/libwvdrmengine/cdm/core/include/entitlement_key_session.h @@ -5,7 +5,12 @@ #ifndef WVCDM_CORE_ENTITLEMENT_KEY_SESSSION_H_ #define WVCDM_CORE_ENTITLEMENT_KEY_SESSSION_H_ +#include +#include + +#include "OEMCryptoCENC.h" #include "content_key_session.h" +#include "crypto_key.h" #include "metrics_collections.h" #include "override.h" @@ -30,6 +35,17 @@ class EntitlementKeySession : public ContentKeySession { const std::string& srm_requirement) OVERRIDE; virtual OEMCryptoResult LoadEntitledContentKeys( const std::vector& keys) OVERRIDE; + virtual OEMCryptoResult SelectKey(const std::string& key_id, + CdmCipherMode cipher_mode) OVERRIDE; + + private: + // The object returned by this function contains raw pointers to the passed-in + // CryptoKey object. Care should be taken that it does not outlive the + // CryptoKey. + OEMCrypto_EntitledContentKeyObject MakeOecEntitledKey( + const CryptoKey& input_key); + + std::map entitled_keys_; }; } // namespace wvcdm diff --git a/libwvdrmengine/cdm/core/src/entitlement_key_session.cpp b/libwvdrmengine/cdm/core/src/entitlement_key_session.cpp index 393f920f..06041886 100644 --- a/libwvdrmengine/cdm/core/src/entitlement_key_session.cpp +++ b/libwvdrmengine/cdm/core/src/entitlement_key_session.cpp @@ -9,7 +9,7 @@ namespace wvcdm { EntitlementKeySession::EntitlementKeySession(CryptoSessionId oec_session_id, metrics::CryptoMetrics* metrics) - : ContentKeySession(oec_session_id, metrics) {} + : ContentKeySession(oec_session_id, metrics), entitled_keys_() {} OEMCryptoResult EntitlementKeySession::LoadKeys( const std::string& message, const std::string& signature, @@ -28,32 +28,67 @@ OEMCryptoResult EntitlementKeySession::LoadEntitledContentKeys( const std::vector& keys) { // The array |keys| contains new content keys, plus entitlement key ids for // those content keys. - std::vector entitlements; - entitlements.resize(keys.size()); - for (size_t i = 0; i < keys.size(); ++i) { - entitlements[i].entitlement_key_id = - reinterpret_cast(keys[i].entitlement_key_id().data()); - entitlements[i].entitlement_key_id_length = - keys[i].entitlement_key_id().size(); - - entitlements[i].content_key_id = - reinterpret_cast(keys[i].key_id().data()); - entitlements[i].content_key_id_length = keys[i].key_id().size(); - - entitlements[i].content_key_data_iv = - reinterpret_cast(keys[i].key_data_iv().data()); - - entitlements[i].content_key_data = - reinterpret_cast(keys[i].key_data().data()); - entitlements[i].content_key_data_length = keys[i].key_data().size(); + // Since OEMCrypto only supports loading one entitled key per entitlement + // key at a time, (b/110266851) we defer loading until SelectKey() tells us + // which entitled key we actually need. For fast lookup later, we index the + // entitled keys by their ID. + const CryptoKey& input_key = keys[i]; + entitled_keys_[input_key.key_id()] = input_key; } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult EntitlementKeySession::SelectKey(const std::string& key_id, + CdmCipherMode cipher_mode) { + // Before the key can be selected, it must be loaded under its associated + // entitlement key. This could, in theory, be done ahead of time during + // LoadEntitledContentKeys(), but OEMCrypto v14 only supports one content key + // per entitlement key at a time, (b/110266851) so we must swap out for the + // correct key every time SelectKey() is called. + if (entitled_keys_.find(key_id) == entitled_keys_.end()) { + LOGE("Unknown entitled key ID selected."); + return OEMCrypto_KEY_NOT_LOADED; + } + + OEMCrypto_EntitledContentKeyObject entitled_key = + MakeOecEntitledKey(entitled_keys_[key_id]); + OEMCryptoResult result = OEMCrypto_SUCCESS; - M_TIME(result = OEMCrypto_LoadEntitledContentKeys( - oec_session_id_, entitlements.size(), &entitlements[0]), + M_TIME(result = OEMCrypto_LoadEntitledContentKeys(oec_session_id_, 1, + &entitled_key), metrics_, oemcrypto_load_entitled_keys_, result); - return result; + if (result != OEMCrypto_SUCCESS) { + return result; + } + + return ContentKeySession::SelectKey(key_id, cipher_mode); +} + +OEMCrypto_EntitledContentKeyObject EntitlementKeySession::MakeOecEntitledKey( + const CryptoKey& input_key) { + OEMCrypto_EntitledContentKeyObject output_key; + + const std::string& entitlement_key_id = input_key.entitlement_key_id(); + output_key.entitlement_key_id = + reinterpret_cast(entitlement_key_id.data()); + output_key.entitlement_key_id_length = entitlement_key_id.size(); + + const std::string& key_id = input_key.key_id(); + output_key.content_key_id = reinterpret_cast(key_id.data()); + output_key.content_key_id_length = key_id.size(); + + const std::string& key_data_iv = input_key.key_data_iv(); + output_key.content_key_data_iv = + reinterpret_cast(key_data_iv.data()); + + const std::string& key_data = input_key.key_data(); + output_key.content_key_data = + reinterpret_cast(key_data.data()); + output_key.content_key_data_length = key_data.size(); + + return output_key; } } // namespace wvcdm diff --git a/libwvdrmengine/cdm/core/src/license.cpp b/libwvdrmengine/cdm/core/src/license.cpp index be246f44..fc560e88 100644 --- a/libwvdrmengine/cdm/core/src/license.cpp +++ b/libwvdrmengine/cdm/core/src/license.cpp @@ -1154,7 +1154,6 @@ CdmResponseType CdmLicense::HandleNewEntitledKeys( CdmResponseType resp = crypto_session_->LoadEntitledContentKeys(entitled_key_array); if (KEY_ADDED == resp) { - loaded_keys_.clear(); for (std::vector::const_iterator it = wrapped_keys.begin(); it != wrapped_keys.end(); ++it) {