From 8251aab9f6064384fb266a2211e46ae99615e379 Mon Sep 17 00:00:00 2001 From: Fred Gylys-Colwell Date: Thu, 25 Jan 2018 15:27:00 -0800 Subject: [PATCH] Refactor key sessions to move them out of crypto session. Merge from Widevine repo of http://go/wvgerrit/41833 Bug: 64003606 Test: in child CL Change-Id: I3e1d36d0b0944dce0fb1515257bc15243d76f397 --- libwvdrmengine/cdm/Android.mk | 2 + .../cdm/core/include/content_key_session.h | 51 ++ .../cdm/core/include/crypto_session.h | 37 +- libwvdrmengine/cdm/core/include/key_session.h | 44 ++ .../cdm/core/include/sublicense_key_session.h | 91 +++ .../cdm/core/src/content_key_session.cpp | 163 +++++ .../cdm/core/src/crypto_session.cpp | 643 ++---------------- .../cdm/core/src/sublicense_key_session.cpp | 351 ++++++++++ 8 files changed, 751 insertions(+), 631 deletions(-) create mode 100644 libwvdrmengine/cdm/core/include/content_key_session.h create mode 100644 libwvdrmengine/cdm/core/include/key_session.h create mode 100644 libwvdrmengine/cdm/core/include/sublicense_key_session.h create mode 100644 libwvdrmengine/cdm/core/src/content_key_session.cpp create mode 100644 libwvdrmengine/cdm/core/src/sublicense_key_session.cpp diff --git a/libwvdrmengine/cdm/Android.mk b/libwvdrmengine/cdm/Android.mk index 73dbfc1c..d9eaed57 100644 --- a/libwvdrmengine/cdm/Android.mk +++ b/libwvdrmengine/cdm/Android.mk @@ -32,6 +32,7 @@ LOCAL_SRC_FILES := \ $(CORE_SRC_DIR)/cdm_session_map.cpp \ $(CORE_SRC_DIR)/certificate_provisioning.cpp \ $(CORE_SRC_DIR)/client_identification.cpp \ + $(CORE_SRC_DIR)/content_key_session.cpp \ $(CORE_SRC_DIR)/crypto_session.cpp \ $(CORE_SRC_DIR)/device_files.cpp \ $(CORE_SRC_DIR)/initialization_data.cpp \ @@ -41,6 +42,7 @@ 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)/counter_metric.cpp \ diff --git a/libwvdrmengine/cdm/core/include/content_key_session.h b/libwvdrmengine/cdm/core/include/content_key_session.h new file mode 100644 index 00000000..c9368b9a --- /dev/null +++ b/libwvdrmengine/cdm/core/include/content_key_session.h @@ -0,0 +1,51 @@ +#ifndef WVCDM_CORE_CONTENT_KEY_SESSSION_H_ +#define WVCDM_CORE_CONTENT_KEY_SESSSION_H_ + +#include "key_session.h" +#include "timer_metric.h" + +namespace wvcdm { + +class DefaultKeySession : public KeySession { + public: + DefaultKeySession(CryptoSessionId oec_session_id, + metrics::CryptoMetrics* metrics) + : KeySession(metrics), oec_session_id_(oec_session_id) {} + virtual ~DefaultKeySession() {} + + KeySessionType Type() { return kDefault; } + + // Generate Derived Keys for DefaultKeySession + bool GenerateDerivedKeys(const std::string& message); + + // Generate Derived Keys (from session key) for DefaultKeySession + bool GenerateDerivedKeys(const std::string& message, + const std::string& session_key); + + // Load Keys for DefaultKeySession + OEMCryptoResult LoadKeys(const std::string& message, + const std::string& signature, + const std::string& mac_key_iv, + const std::string& mac_key, + const std::vector& keys, + const std::string& provider_session_token, + CdmCipherMode* cipher_mode, + const std::string& srm_requirement); + + // Select Key for DefaultKeySession + OEMCryptoResult SelectKey(const std::string& key_id, + CdmCipherMode cipher_mode); + + // Decrypt for DefaultKeySession + OEMCryptoResult Decrypt(const CdmDecryptionParameters& params, + OEMCrypto_DestBufferDesc& buffer_descriptor, + OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor); + + private: + CryptoSessionId oec_session_id_; + KeyId cached_key_id_; +}; + +} // namespace wvcdm + +#endif // WVCDM_CORE_CONTENT_KEY_SESSSION_H_ \ No newline at end of file diff --git a/libwvdrmengine/cdm/core/include/crypto_session.h b/libwvdrmengine/cdm/core/include/crypto_session.h index 2e93135c..cabd78b5 100644 --- a/libwvdrmengine/cdm/core/include/crypto_session.h +++ b/libwvdrmengine/cdm/core/include/crypto_session.h @@ -8,6 +8,7 @@ #include #include "OEMCryptoCENC.h" +#include "key_session.h" #include "lock.h" #include "metrics_collections.h" #include "oemcrypto_adapter.h" @@ -22,37 +23,13 @@ class CryptoKey; class UsageTableHeader; typedef std::map CryptoKeyMap; -typedef std::map SubLicenseSessionMap; -class KeySession { - protected: - KeySession(metrics::CryptoMetrics* metrics) : metrics_(metrics) {} - - public: - typedef enum { kDefault, kSubLicense } KeySessionType; - virtual ~KeySession() {} - virtual KeySessionType Type() = 0; - virtual bool GenerateDerivedKeys(const std::string& message) = 0; - virtual bool GenerateDerivedKeys(const std::string& message, - const std::string& session_key) = 0; - virtual OEMCryptoResult LoadKeys(const std::string& message, - const std::string& signature, - const std::string& mac_key_iv, - const std::string& mac_key, - const std::vector& keys, - const std::string& provider_session_token, - CdmCipherMode* cipher_mode, - const std::string& srm_requirement) = 0; - virtual OEMCryptoResult SelectKey(const std::string& key_id, - CdmCipherMode cipher_mode) = 0; - virtual OEMCryptoResult Decrypt( - const CdmDecryptionParameters& params, - OEMCrypto_DestBufferDesc& buffer_descriptor, - OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor) = 0; - - protected: - metrics::CryptoMetrics* metrics_; -}; +// Crypto session utility functions used by KeySession implementations. +void GenerateMacContext(const std::string& input_context, + std::string* deriv_context); +void GenerateEncryptContext(const std::string& input_context, + std::string* deriv_context); +size_t GetOffset(std::string message, std::string field); class CryptoSession { public: diff --git a/libwvdrmengine/cdm/core/include/key_session.h b/libwvdrmengine/cdm/core/include/key_session.h new file mode 100644 index 00000000..9de19537 --- /dev/null +++ b/libwvdrmengine/cdm/core/include/key_session.h @@ -0,0 +1,44 @@ +#ifndef WVCDM_CORE_KEY_SESSSION_H_ +#define WVCDM_CORE_KEY_SESSSION_H_ + +#include "metrics_collections.h" + +namespace wvcdm { + +class CryptoKey; + +class KeySession { + protected: + KeySession(metrics::CryptoMetrics* metrics) : metrics_(metrics) {} + + public: + typedef enum { kDefault, kSubLicense } KeySessionType; + virtual ~KeySession() {} + virtual KeySessionType Type() = 0; + virtual bool GenerateDerivedKeys(const std::string& message) = 0; + virtual bool GenerateDerivedKeys(const std::string& message, + const std::string& session_key) = 0; + virtual OEMCryptoResult LoadKeys(const std::string& message, + const std::string& signature, + const std::string& mac_key_iv, + const std::string& mac_key, + const std::vector& keys, + const std::string& provider_session_token, + CdmCipherMode* cipher_mode, + const std::string& srm_requirement) = 0; + virtual OEMCryptoResult SelectKey(const std::string& key_id, + CdmCipherMode cipher_mode) = 0; + virtual OEMCryptoResult Decrypt( + const CdmDecryptionParameters& params, + OEMCrypto_DestBufferDesc& buffer_descriptor, + OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor) = 0; + + protected: + metrics::CryptoMetrics* metrics_; +}; + +typedef std::map SubLicenseSessionMap; + +} // namespace wvcdm + +#endif // WVCDM_CORE_KEY_SESSSION_H_ \ No newline at end of file diff --git a/libwvdrmengine/cdm/core/include/sublicense_key_session.h b/libwvdrmengine/cdm/core/include/sublicense_key_session.h new file mode 100644 index 00000000..ea6bb380 --- /dev/null +++ b/libwvdrmengine/cdm/core/include/sublicense_key_session.h @@ -0,0 +1,91 @@ +#ifndef WVCDM_CORE_SUBLICENSE_KEY_SESSSION_H_ +#define WVCDM_CORE_SUBLICENSE_KEY_SESSSION_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_master_key_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& keys, + const std::string& provider_session_token, + CdmCipherMode* cipher_mode, + const std::string& srm_requirement); + + // 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& 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 keys_; + SubLicenseSessionMap& sub_license_oec_sessions_; + SecurityLevel requested_security_level_; + KeyId group_master_key_id_; +}; + +} // namespace wvcdm + +#endif // WVCDM_CORE_SUBLICENSE_KEY_SESSSION_H_ \ No newline at end of file diff --git a/libwvdrmengine/cdm/core/src/content_key_session.cpp b/libwvdrmengine/cdm/core/src/content_key_session.cpp new file mode 100644 index 00000000..42591d1e --- /dev/null +++ b/libwvdrmengine/cdm/core/src/content_key_session.cpp @@ -0,0 +1,163 @@ +#include "content_key_session.h" +#include "crypto_key.h" +#include "crypto_session.h" +#include "log.h" +#include "wv_cdm_constants.h" + +namespace wvcdm { + +// Generate Derived Keys for DefaultKeySession +bool DefaultKeySession::GenerateDerivedKeys(const std::string& message) { + std::string mac_deriv_message; + std::string enc_deriv_message; + GenerateMacContext(message, &mac_deriv_message); + GenerateEncryptContext(message, &enc_deriv_message); + + LOGV("GenerateDerivedKeys: id=%ld", (uint32_t)oec_session_id_); + OEMCryptoResult sts; + M_TIME(sts = OEMCrypto_GenerateDerivedKeys( + oec_session_id_, + reinterpret_cast(mac_deriv_message.data()), + mac_deriv_message.size(), + reinterpret_cast(enc_deriv_message.data()), + enc_deriv_message.size()), + metrics_, oemcrypto_generate_derived_keys_, sts); + if (OEMCrypto_SUCCESS != sts) { + LOGE("GenerateDerivedKeys: OEMCrypto_GenerateDerivedKeys error=%d", sts); + return false; + } + + return true; +} + +// Generate Derived Keys (from session key) for DefaultKeySession +bool DefaultKeySession::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); + + LOGV("GenerateDerivedKeys: id=%ld", (uint32_t)oec_session_id_); + OEMCryptoResult sts; + M_TIME( + sts = OEMCrypto_DeriveKeysFromSessionKey( + oec_session_id_, reinterpret_cast(session_key.data()), + session_key.size(), + reinterpret_cast(mac_deriv_message.data()), + mac_deriv_message.size(), + reinterpret_cast(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; +} + +// Load Keys for DefaultKeySession +OEMCryptoResult DefaultKeySession::LoadKeys( + const std::string& message, const std::string& signature, + const std::string& mac_key_iv, const std::string& mac_key, + const std::vector& keys, + const std::string& provider_session_token, CdmCipherMode* cipher_mode, + const std::string& srm_requirement) { + const uint8_t* msg = reinterpret_cast(message.data()); + const uint8_t* enc_mac_key = NULL; + const uint8_t* enc_mac_key_iv = NULL; + if (mac_key.size() >= MAC_KEY_SIZE && mac_key_iv.size() >= KEY_IV_SIZE) { + enc_mac_key = msg + GetOffset(message, mac_key); + enc_mac_key_iv = msg + GetOffset(message, mac_key_iv); + } else { + LOGV("DefaultKeySession::LoadKeys: enc_mac_key not set"); + } + std::vector load_keys(keys.size()); + for (size_t i = 0; i < keys.size(); ++i) { + const CryptoKey* ki = &keys[i]; + OEMCrypto_KeyObject* ko = &load_keys[i]; + ko->key_id = msg + GetOffset(message, ki->key_id()); + ko->key_id_length = ki->key_id().length(); + ko->key_data_iv = msg + GetOffset(message, ki->key_data_iv()); + ko->key_data = msg + GetOffset(message, ki->key_data()); + ko->key_data_length = ki->key_data().length(); + if (ki->HasKeyControl()) { + ko->key_control_iv = msg + GetOffset(message, ki->key_control_iv()); + ko->key_control = msg + GetOffset(message, ki->key_control()); + } else { + LOGE("For key %d: XXX key has no control block. size=%d", i, + ki->key_control().size()); + ko->key_control_iv = NULL; + ko->key_control = NULL; + } + // TODO(jfore): Is returning the cipher needed. If not drop this. + *cipher_mode = ki->cipher_mode(); + } + + uint8_t* pst = NULL; + if (!provider_session_token.empty()) { + pst = + const_cast(msg) + GetOffset(message, provider_session_token); + } + + uint8_t* srm_req = NULL; + if (!srm_requirement.empty()) { + srm_req = const_cast(msg) + GetOffset(message, srm_requirement); + } + + LOGV("LoadKeys: id=%ld", (uint32_t)oec_session_id_); + OEMCryptoResult sts; + M_TIME( + sts = OEMCrypto_LoadKeys( + oec_session_id_, msg, message.size(), + reinterpret_cast(signature.data()), signature.size(), + enc_mac_key_iv, enc_mac_key, keys.size(), &load_keys[0], pst, + provider_session_token.length(), srm_req, OEMCrypto_ContentLicense), + metrics_, oemcrypto_load_keys_, sts); + return sts; +} + +// Select Key for DefaultKeySession +OEMCryptoResult DefaultKeySession::SelectKey(const std::string& key_id, + CdmCipherMode cipher_mode) { + // Crypto session lock already locked. + if (!cached_key_id_.empty() && cached_key_id_ == key_id) { + // Already using the desired key. + return OEMCrypto_SUCCESS; + } + + cached_key_id_ = key_id; + + const uint8_t* key_id_string = + reinterpret_cast(cached_key_id_.data()); + + OEMCryptoResult sts; + M_TIME(sts = OEMCrypto_SelectKey( + oec_session_id_, key_id_string, cached_key_id_.size(), + static_cast(cipher_mode)), + metrics_, oemcrypto_select_key_, sts); + + if (OEMCrypto_SUCCESS != sts) { + cached_key_id_.clear(); + } + return sts; +} + +// Decrypt for DefaultKeySession +OEMCryptoResult DefaultKeySession::Decrypt( + const CdmDecryptionParameters& params, + OEMCrypto_DestBufferDesc& buffer_descriptor, + OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor) { + OEMCryptoResult sts; + M_TIME(sts = OEMCrypto_DecryptCENC( + oec_session_id_, 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; +} + +} // namespace wvcdm \ No newline at end of file diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index 295adba1..41044407 100644 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -11,6 +11,7 @@ #include #include +#include "content_key_session.h" #include "crypto_key.h" #include "log.h" #include "openssl/asn1.h" @@ -19,6 +20,7 @@ #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" @@ -34,6 +36,46 @@ std::string EncodeUint32(unsigned int u) { return s; } +const uint32_t kRsaSignatureLength = 256; +const size_t kMaximumChunkSize = 100 * 1024; // 100 KiB +const size_t kEstimatedInitialUsageTableHeader = 40; +const size_t kOemCryptoApiVersionSupportsBigUsageTables = 13; + +// Constants and utility objects relating to OEM Certificates +const int kExtensionOidSize = 64; +const char* const kWidevineSystemIdExtensionOid = "1.3.6.1.4.1.11129.4.1.1"; + +// Helpers for working with BoringSSL +template +class boringssl_ptr { + public: + explicit boringssl_ptr(T* p = NULL) : ptr_(p) {} + ~boringssl_ptr() { + if (ptr_) func(ptr_); + } + T& operator*() const { return *ptr_; } + T* operator->() const { return ptr_; } + T* get() const { return ptr_; } + + private: + T* ptr_; + CORE_DISALLOW_COPY_AND_ASSIGN(boringssl_ptr); +}; + +void DeleteX509Stack(STACK_OF(X509)* stack) { + sk_X509_pop_free(stack, X509_free); +} + +} + +namespace wvcdm { +Lock CryptoSession::crypto_lock_; +bool CryptoSession::initialized_ = false; +int CryptoSession::session_count_ = 0; +uint64_t CryptoSession::request_id_index_ = 0; +UsageTableHeader* CryptoSession::usage_table_header_l1_ = NULL; +UsageTableHeader* CryptoSession::usage_table_header_l3_ = NULL; + size_t GetOffset(std::string message, std::string field) { size_t pos = message.find(field); if (pos == std::string::npos) { @@ -77,607 +119,6 @@ void GenerateEncryptContext(const std::string& input_context, deriv_context->append(EncodeUint32(kEncryptionKeySizeBits)); } -OEMCryptoCipherMode ToOEMCryptoCipherMode(wvcdm::CdmCipherMode cipher_mode) { - return (cipher_mode == wvcdm::kCipherModeCtr) ? OEMCrypto_CipherMode_CTR - : OEMCrypto_CipherMode_CBC; -} - -const uint32_t kRsaSignatureLength = 256; -const size_t kMaximumChunkSize = 100 * 1024; // 100 KiB -const size_t kEstimatedInitialUsageTableHeader = 40; -const size_t kOemCryptoApiVersionSupportsBigUsageTables = 13; - -// Constants and utility objects relating to OEM Certificates -const int kExtensionOidSize = 64; -const char* const kWidevineSystemIdExtensionOid = "1.3.6.1.4.1.11129.4.1.1"; - -// Helpers for working with BoringSSL -template -class boringssl_ptr { - public: - explicit boringssl_ptr(T* p = NULL) : ptr_(p) {} - ~boringssl_ptr() { - if (ptr_) func(ptr_); - } - T& operator*() const { return *ptr_; } - T* operator->() const { return ptr_; } - T* get() const { return ptr_; } - - private: - T* ptr_; - CORE_DISALLOW_COPY_AND_ASSIGN(boringssl_ptr); -}; - -void DeleteX509Stack(STACK_OF(X509)* stack) { - sk_X509_pop_free(stack, X509_free); -} - -} - -namespace wvcdm { - -Lock CryptoSession::crypto_lock_; -bool CryptoSession::initialized_ = false; -int CryptoSession::session_count_ = 0; -uint64_t CryptoSession::request_id_index_ = 0; -UsageTableHeader* CryptoSession::usage_table_header_l1_ = NULL; -UsageTableHeader* CryptoSession::usage_table_header_l3_ = NULL; - -// TODO(jfore, rfrias, gmorgan): This object should be split off into it's own -// module or refactored out. -class DefaultKeySession : public KeySession { - public: - DefaultKeySession(CryptoSessionId oec_session_id, - metrics::CryptoMetrics* metrics) - : KeySession(metrics), oec_session_id_(oec_session_id) {} - virtual ~DefaultKeySession() {} - - KeySessionType Type() { return kDefault; } - - // Generate Derived Keys for DefaultKeySession - bool GenerateDerivedKeys(const std::string& message) { - std::string mac_deriv_message; - std::string enc_deriv_message; - GenerateMacContext(message, &mac_deriv_message); - GenerateEncryptContext(message, &enc_deriv_message); - - LOGV("GenerateDerivedKeys: id=%ld", (uint32_t)oec_session_id_); - OEMCryptoResult sts; - M_TIME(sts = OEMCrypto_GenerateDerivedKeys( - oec_session_id_, - reinterpret_cast(mac_deriv_message.data()), - mac_deriv_message.size(), - reinterpret_cast(enc_deriv_message.data()), - enc_deriv_message.size()), - metrics_, oemcrypto_generate_derived_keys_, sts); - if (OEMCrypto_SUCCESS != sts) { - LOGE("GenerateDerivedKeys: OEMCrypto_GenerateDerivedKeys error=%d", sts); - return false; - } - - return true; - } - - // Generate Derived Keys (from session key) for DefaultKeySession - bool 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); - - LOGV("GenerateDerivedKeys: id=%ld", (uint32_t)oec_session_id_); - OEMCryptoResult sts; - M_TIME(sts = OEMCrypto_DeriveKeysFromSessionKey( - oec_session_id_, - reinterpret_cast(session_key.data()), - session_key.size(), - reinterpret_cast(mac_deriv_message.data()), - mac_deriv_message.size(), - reinterpret_cast(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; - } - - // Load Keys for DefaultKeySession - OEMCryptoResult LoadKeys(const std::string& message, - const std::string& signature, - const std::string& mac_key_iv, - const std::string& mac_key, - const std::vector& keys, - const std::string& provider_session_token, - CdmCipherMode* cipher_mode, - const std::string& srm_requirement) { - const uint8_t* msg = reinterpret_cast(message.data()); - const uint8_t* enc_mac_key = NULL; - const uint8_t* enc_mac_key_iv = NULL; - if (mac_key.size() >= MAC_KEY_SIZE && mac_key_iv.size() >= KEY_IV_SIZE) { - enc_mac_key = msg + GetOffset(message, mac_key); - enc_mac_key_iv = msg + GetOffset(message, mac_key_iv); - } else { - LOGV("DefaultKeySession::LoadKeys: enc_mac_key not set"); - } - std::vector load_keys(keys.size()); - for (size_t i = 0; i < keys.size(); ++i) { - const CryptoKey* ki = &keys[i]; - OEMCrypto_KeyObject_V13* ko = &load_keys[i]; - ko->key_id = msg + GetOffset(message, ki->key_id()); - ko->key_id_length = ki->key_id().length(); - ko->key_data_iv = msg + GetOffset(message, ki->key_data_iv()); - ko->key_data = msg + GetOffset(message, ki->key_data()); - ko->key_data_length = ki->key_data().length(); - if (ki->HasKeyControl()) { - ko->key_control_iv = msg + GetOffset(message, ki->key_control_iv()); - ko->key_control = msg + GetOffset(message, ki->key_control()); - } else { - LOGE("For key %d: XXX key has no control block. size=%d", i, - ki->key_control().size()); - ko->key_control_iv = NULL; - ko->key_control = NULL; - } - *cipher_mode = ki->cipher_mode(); - } - - uint8_t* pst = NULL; - if (!provider_session_token.empty()) { - pst = const_cast(msg) + - GetOffset(message, provider_session_token); - } - - uint8_t* srm_req = NULL; - if (!srm_requirement.empty()) { - srm_req = const_cast(msg) + GetOffset(message, srm_requirement); - } - - LOGV("LoadKeys: id=%ld", (uint32_t)oec_session_id_); - OEMCryptoResult sts; - M_TIME(sts = OEMCrypto_LoadKeys_Back_Compat( - oec_session_id_, msg, message.size(), - reinterpret_cast(signature.data()), - signature.size(), enc_mac_key_iv, enc_mac_key, keys.size(), - &load_keys[0], pst, provider_session_token.length(), srm_req, - OEMCrypto_ContentLicense), - metrics_, oemcrypto_load_keys_, sts); - return sts; - } - - // Select Key for DefaultKeySession - OEMCryptoResult SelectKey(const std::string& key_id, - CdmCipherMode cipher_mode) { - // Crypto session lock already locked. - if (!cached_key_id_.empty() && cached_key_id_ == key_id) { - // Already using the desired key. - return OEMCrypto_SUCCESS; - } - - cached_key_id_ = key_id; - - const uint8_t* key_id_string = - reinterpret_cast(cached_key_id_.data()); - - OEMCryptoResult sts; - M_TIME(sts = OEMCrypto_SelectKey(oec_session_id_, key_id_string, - cached_key_id_.size(), - ToOEMCryptoCipherMode(cipher_mode)), - metrics_, oemcrypto_select_key_, sts); - - if (OEMCrypto_SUCCESS != sts) { - cached_key_id_.clear(); - } - return sts; - } - - // Decrypt for DefaultKeySession - OEMCryptoResult Decrypt( - const CdmDecryptionParameters& params, - OEMCrypto_DestBufferDesc& buffer_descriptor, - OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor) { - OEMCryptoResult sts; - M_TIME(sts = OEMCrypto_DecryptCENC( - oec_session_id_, 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; - } - - private: - CryptoSessionId oec_session_id_; - KeyId cached_key_id_; -}; - -// TODO(jfore, rfrias, gmorgan): This object should be split off into it's own -// module or refactored out. -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_master_key_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_master_key_id_(group_master_key_id) {} - - virtual ~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(); - } - - 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) { - 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(session_key.data()), - session_key.size(), - reinterpret_cast(mac_deriv_message.data()), - mac_deriv_message.size(), - reinterpret_cast(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; - } - - // 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& 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); - } - - // 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) { - 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(keys_[i].key_id().data()), - keys_[i].key_id().size(), - static_cast(cipher_mode)), - metrics_, oemcrypto_select_key_, status); - if (OEMCrypto_SUCCESS != status) { - return status; - } - keys_[i].set_cipher_mode(cipher_mode); - } - } - } - return OEMCrypto_SUCCESS; - } - - // 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) { - 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; - } - - private: - // Destroy each open oemcrypto session and relace them with new ones. - OEMCryptoResult 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( - 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; - } - - // 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& keys, - const std::string& provider_session_token, - CdmCipherMode* cipher_mode, - const std::string& srm_requirement) { - const uint8_t* msg = reinterpret_cast(message.data()); - const uint8_t* enc_mac_key = NULL; - const uint8_t* enc_mac_key_iv = NULL; - if (mac_key.size() >= MAC_KEY_SIZE && mac_key_iv.size() >= KEY_IV_SIZE) { - enc_mac_key = msg + GetOffset(message, mac_key); - enc_mac_key_iv = msg + GetOffset(message, mac_key_iv); - } else { - LOGV("CryptoSession::LoadKeys: enc_mac_key not set"); - } - - uint8_t* pst = NULL; - if (!provider_session_token.empty()) { - pst = const_cast(msg) + - GetOffset(message, provider_session_token); - } - - uint8_t* srm_req = NULL; - if (!srm_requirement.empty()) { - srm_req = const_cast(msg) + GetOffset(message, srm_requirement); - } - - for (size_t i = 0; i < keys.size(); i++) { - OEMCrypto_KeyObject_V13 key_object; - const CryptoKey& key_data = keys[i]; - key_object.key_id = msg + GetOffset(message, key_data.key_id()); - key_object.key_id_length = key_data.key_id().length(); - key_object.key_data_iv = msg + GetOffset(message, key_data.key_data_iv()); - key_object.key_data = msg + GetOffset(message, key_data.key_data()); - key_object.key_data_length = key_data.key_data().length(); - if (key_data.HasKeyControl()) { - key_object.key_control_iv = - msg + GetOffset(message, key_data.key_control_iv()); - key_object.key_control = - msg + GetOffset(message, key_data.key_control()); - } else { - LOGE("For key %s: XXX key has no control block. size=%d", - key_data.key_id().c_str(), key_data.key_control().size()); - key_object.key_control_iv = NULL; - key_object.key_control = NULL; - } - *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(signature.data()), - signature.size(), enc_mac_key_iv, enc_mac_key, 1, &key_object, - pst, provider_session_token.length(), srm_req, - OEMCrypto_ContentLicense), - metrics_, oemcrypto_load_keys_, sts); - - if (sts != OEMCrypto_SUCCESS) { - return sts; - } - - M_TIME(sts = OEMCrypto_SelectKey( - oec_session_id->second, - reinterpret_cast(key_data.key_id().data()), - key_data.key_id().size(), - static_cast(key_data.cipher_mode())), - metrics_, oemcrypto_select_key_, sts); - - if (sts != OEMCrypto_SUCCESS) { - return sts; - } - } - keys_ = keys; - return OEMCrypto_SUCCESS; - } - - // 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) { - 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_master_key_id_ + key.track_label(), - &mac_deriv_message); - GenerateEncryptContext(group_master_key_id_ + key.track_label(), - &enc_deriv_message); - - const uint8_t* msg = reinterpret_cast(message.data()); - const uint8_t* enc_mac_key = NULL; - const uint8_t* enc_mac_key_iv = NULL; - if (mac_key.size() >= MAC_KEY_SIZE && mac_key_iv.size() >= KEY_IV_SIZE) { - enc_mac_key = msg + GetOffset(message, mac_key); - enc_mac_key_iv = msg + GetOffset(message, mac_key_iv); - } else { - LOGV("CryptoSession::LoadKeys: enc_mac_key not set"); - } - - uint8_t* pst = NULL; - if (!provider_session_token.empty()) { - pst = const_cast(msg) + - GetOffset(message, provider_session_token); - } - - uint8_t* srm_req = NULL; - if (!srm_requirement.empty()) { - srm_req = const_cast(msg) + GetOffset(message, srm_requirement); - } - - OEMCryptoResult sts; - const std::string& sub_session_key = keys_[key_index].sub_session_key(); - LOGE("ssksize = %d", sub_session_key.size()); - - M_TIME(sts = OEMCrypto_DeriveKeysFromSessionKey( - it->second, - reinterpret_cast(sub_session_key.data()), - sub_session_key.size(), - reinterpret_cast(mac_deriv_message.data()), - mac_deriv_message.size(), - reinterpret_cast(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_V13 key_object; - key_object.key_id = msg + GetOffset(message, keys_[key_index].key_id()); - key_object.key_id_length = keys_[key_index].key_id().length(); - key_object.key_data_iv = - msg + GetOffset(message, keys_[key_index].key_data_iv()); - key_object.key_data = msg + GetOffset(message, keys_[key_index].key_data()); - key_object.key_data_length = keys_[key_index].key_data().length(); - if (key.HasKeyControl()) { - key_object.key_control_iv = - msg + GetOffset(message, keys_[key_index].key_control_iv()); - key_object.key_control = - msg + GetOffset(message, keys_[key_index].key_control()); - } - - M_TIME( - sts = OEMCrypto_LoadKeys_Back_Compat( - it->second, msg, message.size(), - reinterpret_cast(signature.data()), - signature.size(), enc_mac_key_iv, enc_mac_key, 1, &key_object, pst, - provider_session_token.length(), srm_req, OEMCrypto_ContentLicense), - metrics_, oemcrypto_load_keys_, sts); - - if (sts != OEMCrypto_SUCCESS) { - return sts; - } - - M_TIME( - sts = OEMCrypto_SelectKey( - it->second, - reinterpret_cast(keys_[key_index].key_id().data()), - keys_[key_index].key_id().size(), - static_cast(keys_[key_index].cipher_mode())), - metrics_, oemcrypto_select_key_, sts); - - return sts; - } - - SubLicenseState state_; - std::string cached_sub_session_key_id_; - std::string wrapped_private_device_key_; - std::string message_; - std::string session_key_; - std::vector keys_; - SubLicenseSessionMap& sub_license_oec_sessions_; - SecurityLevel requested_security_level_; - KeyId group_master_key_id_; -}; - CryptoSession::CryptoSession(metrics::CryptoMetrics* metrics) : metrics_(metrics), system_id_(-1), diff --git a/libwvdrmengine/cdm/core/src/sublicense_key_session.cpp b/libwvdrmengine/cdm/core/src/sublicense_key_session.cpp new file mode 100644 index 00000000..29a57534 --- /dev/null +++ b/libwvdrmengine/cdm/core/src/sublicense_key_session.cpp @@ -0,0 +1,351 @@ +#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_master_key_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_master_key_id_(group_master_key_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(session_key.data()), + session_key.size(), + reinterpret_cast(mac_deriv_message.data()), + mac_deriv_message.size(), + reinterpret_cast(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& 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(keys_[i].key_id().data()), + keys_[i].key_id().size(), + static_cast(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( + 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& keys, + const std::string& provider_session_token, CdmCipherMode* cipher_mode, + const std::string& srm_requirement) { + const uint8_t* msg = reinterpret_cast(message.data()); + const uint8_t* enc_mac_key = NULL; + const uint8_t* enc_mac_key_iv = NULL; + if (mac_key.size() >= MAC_KEY_SIZE && mac_key_iv.size() >= KEY_IV_SIZE) { + enc_mac_key = msg + GetOffset(message, mac_key); + enc_mac_key_iv = msg + GetOffset(message, mac_key_iv); + } else { + LOGV("CryptoSession::LoadKeys: enc_mac_key not set"); + } + + uint8_t* pst = NULL; + if (!provider_session_token.empty()) { + pst = + const_cast(msg) + GetOffset(message, provider_session_token); + } + + uint8_t* srm_req = NULL; + if (!srm_requirement.empty()) { + srm_req = const_cast(msg) + GetOffset(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 = msg + GetOffset(message, key_data.key_id()); + key_object.key_id_length = key_data.key_id().length(); + key_object.key_data_iv = msg + GetOffset(message, key_data.key_data_iv()); + key_object.key_data = msg + GetOffset(message, key_data.key_data()); + key_object.key_data_length = key_data.key_data().length(); + if (key_data.HasKeyControl()) { + key_object.key_control_iv = + msg + GetOffset(message, key_data.key_control_iv()); + key_object.key_control = msg + GetOffset(message, key_data.key_control()); + } else { + LOGE("For key %s: XXX key has no control block. size=%d", + key_data.key_id().c_str(), key_data.key_control().size()); + key_object.key_control_iv = NULL; + key_object.key_control = NULL; + } + // 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( + oec_session_id->second, msg, message.size(), + reinterpret_cast(signature.data()), + signature.size(), enc_mac_key_iv, enc_mac_key, 1, &key_object, pst, + provider_session_token.length(), srm_req, OEMCrypto_ContentLicense), + metrics_, oemcrypto_load_keys_, sts); + + if (sts != OEMCrypto_SUCCESS) { + return sts; + } + + M_TIME(sts = OEMCrypto_SelectKey( + oec_session_id->second, + reinterpret_cast(key_data.key_id().data()), + key_data.key_id().size(), + static_cast(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_master_key_id_ + key.track_label(), + &mac_deriv_message); + GenerateEncryptContext(group_master_key_id_ + key.track_label(), + &enc_deriv_message); + + const uint8_t* msg = reinterpret_cast(message.data()); + const uint8_t* enc_mac_key = NULL; + const uint8_t* enc_mac_key_iv = NULL; + if (mac_key.size() >= MAC_KEY_SIZE && mac_key_iv.size() >= KEY_IV_SIZE) { + enc_mac_key = msg + GetOffset(message, mac_key); + enc_mac_key_iv = msg + GetOffset(message, mac_key_iv); + } else { + LOGV("CryptoSession::LoadKeys: enc_mac_key not set"); + } + + uint8_t* pst = NULL; + if (!provider_session_token.empty()) { + pst = + const_cast(msg) + GetOffset(message, provider_session_token); + } + + uint8_t* srm_req = NULL; + if (!srm_requirement.empty()) { + srm_req = const_cast(msg) + GetOffset(message, srm_requirement); + } + + OEMCryptoResult sts; + const std::string& sub_session_key = keys_[key_index].sub_session_key(); + LOGE("ssksize = %d", sub_session_key.size()); + + M_TIME( + sts = OEMCrypto_DeriveKeysFromSessionKey( + it->second, reinterpret_cast(sub_session_key.data()), + sub_session_key.size(), + reinterpret_cast(mac_deriv_message.data()), + mac_deriv_message.size(), + reinterpret_cast(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 = msg + GetOffset(message, keys_[key_index].key_id()); + key_object.key_id_length = keys_[key_index].key_id().length(); + key_object.key_data_iv = + msg + GetOffset(message, keys_[key_index].key_data_iv()); + key_object.key_data = msg + GetOffset(message, keys_[key_index].key_data()); + key_object.key_data_length = keys_[key_index].key_data().length(); + if (key.HasKeyControl()) { + key_object.key_control_iv = + msg + GetOffset(message, keys_[key_index].key_control_iv()); + key_object.key_control = + msg + GetOffset(message, keys_[key_index].key_control()); + } + + M_TIME( + sts = OEMCrypto_LoadKeys( + it->second, msg, message.size(), + reinterpret_cast(signature.data()), signature.size(), + enc_mac_key_iv, enc_mac_key, 1, &key_object, pst, + provider_session_token.length(), srm_req, OEMCrypto_ContentLicense), + metrics_, oemcrypto_load_keys_, sts); + + if (sts != OEMCrypto_SUCCESS) { + return sts; + } + + M_TIME(sts = OEMCrypto_SelectKey( + it->second, + reinterpret_cast(keys_[key_index].key_id().data()), + keys_[key_index].key_id().size(), + static_cast(keys_[key_index].cipher_mode())), + metrics_, oemcrypto_select_key_, sts); + + return sts; +} + +} // namespace wvcdm \ No newline at end of file