From 979ed70c7ba52618863670b4e945927ec9dd3172 Mon Sep 17 00:00:00 2001 From: Fred Gylys-Colwell Date: Tue, 23 Jan 2018 15:55:43 -0800 Subject: [PATCH] Add Entitlement License to OEMCrypto This CL adds entitlement license features and moves cipher mode from LoadKeys to SelectKeys. Merge from Widevine repo of http://go/wvgerrit/41660 bug: 70334840 Entitlement License - cdm layer bug: 70334345 Entitlement License - reference code and unit tests test: Entitlement license unit tests pass. Change-Id: Ic7d7f42c15e6d83ef7fcfd8a866c778adc4c8095 --- .../cdm/core/include/crypto_session.h | 6 +- .../cdm/core/src/crypto_session.cpp | 824 ++++++++---------- .../oemcrypto/mock/src/oemcrypto_key_mock.h | 30 +- .../oemcrypto/mock/src/oemcrypto_mock.cpp | 42 +- .../oemcrypto/mock/src/oemcrypto_session.cpp | 271 +++++- .../oemcrypto/mock/src/oemcrypto_session.h | 57 +- .../mock/src/oemcrypto_session_key_table.cpp | 71 ++ .../mock/src/oemcrypto_session_key_table.h | 25 +- .../oemcrypto/test/oec_session_util.cpp | 189 +++- .../oemcrypto/test/oec_session_util.h | 37 + .../oemcrypto/test/oemcrypto_test.cpp | 179 ++-- 11 files changed, 1136 insertions(+), 595 deletions(-) diff --git a/libwvdrmengine/cdm/core/include/crypto_session.h b/libwvdrmengine/cdm/core/include/crypto_session.h index 7720b55e..0bfc8a6f 100644 --- a/libwvdrmengine/cdm/core/include/crypto_session.h +++ b/libwvdrmengine/cdm/core/include/crypto_session.h @@ -43,7 +43,8 @@ class KeySession { const std::string& provider_session_token, CdmCipherMode* cipher_mode, const std::string& srm_requirement) = 0; - virtual OEMCryptoResult SelectKey(const std::string& key_id) = 0; + virtual OEMCryptoResult SelectKey(const std::string& key_id, + CdmCipherMode cipher_mode) = 0; virtual OEMCryptoResult Decrypt( const CdmDecryptionParameters& params, OEMCrypto_DestBufferDesc& buffer_descriptor, @@ -241,7 +242,8 @@ class CryptoSession { const std::string& private_key, const std::string& iv, const std::string& wrapping_key, std::string* wrapped_private_key); - CdmResponseType SelectKey(const std::string& key_id); + CdmResponseType SelectKey(const std::string& key_id, + CdmCipherMode cipher_mode); static const OEMCrypto_Algorithm kInvalidAlgorithm = static_cast(-1); diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index e1f0f89c..e1a84cc2 100644 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -73,6 +73,12 @@ void GenerateEncryptContext(const std::string& input_context, deriv_context->append(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; @@ -120,8 +126,7 @@ class DefaultKeySession : public KeySession { public: DefaultKeySession(CryptoSessionId oec_session_id, metrics::CryptoMetrics* metrics) - : KeySession(metrics), - oec_session_id_(oec_session_id) {} + : KeySession(metrics), oec_session_id_(oec_session_id) {} virtual ~DefaultKeySession() {} KeySessionType Type() { return kDefault; } @@ -135,16 +140,13 @@ class DefaultKeySession : public KeySession { 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); + 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; @@ -163,18 +165,15 @@ class DefaultKeySession : public KeySession { 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); + 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", @@ -221,9 +220,6 @@ class DefaultKeySession : public KeySession { ko->key_control_iv = NULL; ko->key_control = NULL; } - ko->cipher_mode = ki->cipher_mode() == kCipherModeCbc - ? OEMCrypto_CipherMode_CBC - : OEMCrypto_CipherMode_CTR; *cipher_mode = ki->cipher_mode(); } @@ -235,27 +231,24 @@ class DefaultKeySession : public KeySession { uint8_t* srm_req = NULL; if (!srm_requirement.empty()) { - srm_req = const_cast(msg) + - GetOffset(message, srm_requirement); + 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), - metrics_, - oemcrypto_load_keys_, - 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) { + 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. @@ -268,14 +261,10 @@ class DefaultKeySession : public KeySession { reinterpret_cast(cached_key_id_.data()); OEMCryptoResult sts; - M_TIME( - sts = OEMCrypto_SelectKey( - oec_session_id_, - key_id_string, - cached_key_id_.size()), - metrics_, - oemcrypto_select_key_, - 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(); @@ -289,21 +278,12 @@ class DefaultKeySession : public KeySession { 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)); + 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; } @@ -336,8 +316,8 @@ class SubLicenseKeySession : public KeySession { virtual ~SubLicenseKeySession() { for (SubLicenseSessionMap::iterator oec_session = - sub_license_oec_sessions_.begin(); - oec_session != sub_license_oec_sessions_.end(); 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)); } @@ -348,9 +328,7 @@ class SubLicenseKeySession : public KeySession { // This version of GenerateDerivedKeys is for devices using keyboxes. It is // not supported using sub licenses. - bool GenerateDerivedKeys(const std::string&) { - return false; - } + bool GenerateDerivedKeys(const std::string&) { return false; } // GenerateDerivedKeys is called for each open oemcrypto session and is only // called once. @@ -367,16 +345,13 @@ class SubLicenseKeySession : public KeySession { OEMCryptoResult sts; M_TIME( sts = OEMCrypto_DeriveKeysFromSessionKey( - it->second, - reinterpret_cast(session_key.data()), + 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); + metrics_, oemcrypto_derive_keys_from_session_key_, sts); if (OEMCrypto_SUCCESS != sts) { LOGE("GenerateDerivedKeys: OEMCrypto_DeriveKeysFromSessionKey err=%d", @@ -400,30 +375,45 @@ class SubLicenseKeySession : public KeySession { 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); + 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); + 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) { + 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; @@ -441,21 +431,12 @@ class SubLicenseKeySession : public KeySession { 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)); + 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; } @@ -473,13 +454,12 @@ class SubLicenseKeySession : public KeySession { 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); + 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; } @@ -509,18 +489,16 @@ class SubLicenseKeySession : public KeySession { uint8_t* pst = NULL; if (!provider_session_token.empty()) { pst = const_cast(msg) + - GetOffset(message, provider_session_token); + GetOffset(message, provider_session_token); } uint8_t* srm_req = NULL; if (!srm_requirement.empty()) { - srm_req = const_cast(msg) + - GetOffset(message, srm_requirement); + srm_req = const_cast(msg) + GetOffset(message, srm_requirement); } - // TODO(jfore): Use C++ 11 range loop? for (size_t i = 0; i < keys.size(); i++) { - OEMCrypto_KeyObject key_object; + 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(); @@ -538,9 +516,6 @@ class SubLicenseKeySession : public KeySession { key_object.key_control_iv = NULL; key_object.key_control = NULL; } - key_object.cipher_mode = key_data.cipher_mode() == kCipherModeCbc - ? OEMCrypto_CipherMode_CBC - : OEMCrypto_CipherMode_CTR; *cipher_mode = key_data.cipher_mode(); SubLicenseSessionMap::iterator oec_session_id = @@ -552,28 +527,24 @@ class SubLicenseKeySession : public KeySession { } 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), - metrics_, - oemcrypto_load_keys_, - 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()), - metrics_, - oemcrypto_select_key_, - 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; @@ -589,7 +560,6 @@ class SubLicenseKeySession : public KeySession { 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++) { @@ -611,10 +581,10 @@ class SubLicenseKeySession : public KeySession { 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); + 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; @@ -634,26 +604,22 @@ class SubLicenseKeySession : public KeySession { uint8_t* srm_req = NULL; if (!srm_requirement.empty()) { - srm_req = const_cast(msg) + - GetOffset(message, srm_requirement); + 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); + 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", @@ -661,32 +627,27 @@ class SubLicenseKeySession : public KeySession { return sts; } - OEMCrypto_KeyObject key_object; + 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_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()); + key_object.key_control = + msg + GetOffset(message, keys_[key_index].key_control()); } - key_object.cipher_mode = - (keys_[key_index].cipher_mode() == kCipherModeCbc) ? - OEMCrypto_CipherMode_CBC : OEMCrypto_CipherMode_CTR; M_TIME( - sts = OEMCrypto_LoadKeys( + 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), - metrics_, - oemcrypto_load_keys_, - sts); + 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; @@ -696,10 +657,9 @@ class SubLicenseKeySession : public KeySession { sts = OEMCrypto_SelectKey( it->second, reinterpret_cast(keys_[key_index].key_id().data()), - keys_[key_index].key_id().size()), - metrics_, - oemcrypto_select_key_, - sts); + keys_[key_index].key_id().size(), + static_cast(keys_[key_index].cipher_mode())), + metrics_, oemcrypto_select_key_, sts); return sts; } @@ -767,11 +727,7 @@ void CryptoSession::Init() { session_count_ += 1; if (!initialized_) { OEMCryptoResult sts; - M_TIME( - sts = OEMCrypto_Initialize(), - metrics_, - oemcrypto_initialize_, - sts); + M_TIME(sts = OEMCrypto_Initialize(), metrics_, oemcrypto_initialize_, sts); if (OEMCrypto_SUCCESS != sts) { LOGE("OEMCrypto_Initialize failed: %d", sts); return; @@ -822,14 +778,8 @@ bool CryptoSession::GetTokenFromKeybox(std::string* token) { OEMCryptoResult status; M_TIME( - status = OEMCrypto_GetKeyData( - buf, - &buf_size, - requested_security_level_), - metrics_, - oemcrypto_get_key_data_, - status, - metrics::Pow2Bucket(buf_size)); + status = OEMCrypto_GetKeyData(buf, &buf_size, requested_security_level_), + metrics_, oemcrypto_get_key_data_, status, metrics::Pow2Bucket(buf_size)); if (OEMCrypto_SUCCESS == status) { token->swap(temp_buffer); return true; @@ -943,8 +893,9 @@ CdmSecurityLevel CryptoSession::GetSecurityLevel() { bool CryptoSession::GetInternalDeviceUniqueId(std::string* device_id) { if (!device_id) { - LOGE("CryptoSession::GetInternalDeviceUniqueId : No buffer passed to " - "method."); + LOGE( + "CryptoSession::GetInternalDeviceUniqueId : No buffer passed to " + "method."); return false; } @@ -963,8 +914,8 @@ bool CryptoSession::GetInternalDeviceUniqueId(std::string* device_id) { size_t id_length = 32; id.resize(id_length); - OEMCryptoResult sts = OEMCrypto_GetDeviceID(&id[0], &id_length, - requested_security_level_); + OEMCryptoResult sts = + OEMCrypto_GetDeviceID(&id[0], &id_length, requested_security_level_); // Increment the count of times this method was called. metrics_->oemcrypto_get_device_id_.Increment(sts); @@ -1036,14 +987,8 @@ bool CryptoSession::GetSystemId(uint32_t* system_id) { OEMCryptoResult sts; M_TIME( - sts = OEMCrypto_GetKeyData( - buf, - &buf_size, - requested_security_level_), - metrics_, - oemcrypto_get_key_data_, - sts, - metrics::Pow2Bucket(buf_size)); + sts = OEMCrypto_GetKeyData(buf, &buf_size, requested_security_level_), + metrics_, oemcrypto_get_key_data_, sts, metrics::Pow2Bucket(buf_size)); if (OEMCrypto_SUCCESS != sts) { LOGE("CryptoSession::GetSystemId: OEMCrypto_GetKeyData failed with %d", @@ -1116,8 +1061,10 @@ bool CryptoSession::ExtractSystemIdFromOemCert(const std::string& oem_cert, ASN1_OBJECT* const extension_object = X509_EXTENSION_get_object(extension); if (!extension_object) { - LOGE("CryptoSession::GetSystemId: Unable to get object of cert " - "extension %d", i); + LOGE( + "CryptoSession::GetSystemId: Unable to get object of cert " + "extension %d", + i); continue; } @@ -1131,31 +1078,35 @@ bool CryptoSession::ExtractSystemIdFromOemCert(const std::string& oem_cert, ASN1_OCTET_STRING* const octet_str = X509_EXTENSION_get_data(extension); if (!octet_str) { - LOGE("CryptoSession::GetSystemId: Unable to get data of Widevine System " - "ID extension."); + LOGE( + "CryptoSession::GetSystemId: Unable to get data of Widevine System " + "ID extension."); return false; } const unsigned char* data = octet_str->data; if (!data) { - LOGE("CryptoSession::GetSystemId: Null data in Widevine System ID " - "extension."); + LOGE( + "CryptoSession::GetSystemId: Null data in Widevine System ID " + "extension."); return false; } ASN1_INTEGER* const asn1_integer = d2i_ASN1_INTEGER(NULL, &data, octet_str->length); if (!asn1_integer) { - LOGE("CryptoSession::GetSystemId: Unable to decode data in Widevine " - "System ID extension."); + LOGE( + "CryptoSession::GetSystemId: Unable to decode data in Widevine " + "System ID extension."); return false; } const long system_id_long = ASN1_INTEGER_get(asn1_integer); ASN1_INTEGER_free(asn1_integer); if (system_id_long == -1) { - LOGE("CryptoSession::GetSystemId: Unable to decode ASN integer in " - "Widevine System ID extension."); + LOGE( + "CryptoSession::GetSystemId: Unable to decode ASN integer in " + "Widevine System ID extension."); return false; } @@ -1197,14 +1148,8 @@ bool CryptoSession::GetProvisioningId(std::string* provisioning_id) { } else { OEMCryptoResult sts; M_TIME( - sts = OEMCrypto_GetKeyData( - buf, - &buf_size, - requested_security_level_), - metrics_, - oemcrypto_get_key_data_, - sts, - metrics::Pow2Bucket(buf_size)); + sts = OEMCrypto_GetKeyData(buf, &buf_size, requested_security_level_), + metrics_, oemcrypto_get_key_data_, sts, metrics::Pow2Bucket(buf_size)); if (OEMCrypto_SUCCESS != sts) { return false; } @@ -1223,8 +1168,8 @@ uint8_t CryptoSession::GetSecurityPatchLevel() { CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) { LOGD("CryptoSession::Open: Lock: requested_security_level: %s", requested_security_level == kLevel3 - ? QUERY_VALUE_SECURITY_LEVEL_L3.c_str() - : QUERY_VALUE_SECURITY_LEVEL_DEFAULT.c_str()); + ? QUERY_VALUE_SECURITY_LEVEL_L3.c_str() + : QUERY_VALUE_SECURITY_LEVEL_DEFAULT.c_str()); AutoLock auto_lock(crypto_lock_); if (!initialized_) return UNKNOWN_ERROR; if (open_) return NO_ERROR; @@ -1237,18 +1182,17 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) { LOGV("OpenSession: id= %ld", (uint32_t)oec_session_id_); open_ = true; } else if (OEMCrypto_ERROR_TOO_MANY_SESSIONS == sts) { - LOGE("OEMCrypto_Open failed: %d, open sessions: %ld, initialized: %d", - sts, session_count_, (int)initialized_); + LOGE("OEMCrypto_Open failed: %d, open sessions: %ld, initialized: %d", sts, + session_count_, (int)initialized_); return INSUFFICIENT_CRYPTO_RESOURCES; } if (!open_) { - LOGE("OEMCrypto_Open failed: %d, open sessions: %ld, initialized: %d", - sts, session_count_, (int)initialized_); + LOGE("OEMCrypto_Open failed: %d, open sessions: %ld, initialized: %d", sts, + session_count_, (int)initialized_); return UNKNOWN_ERROR; } OEMCryptoResult random_sts = OEMCrypto_GetRandom( - reinterpret_cast(&request_id_base_), - sizeof(request_id_base_)); + reinterpret_cast(&request_id_base_), sizeof(request_id_base_)); metrics_->oemcrypto_get_random_.Increment(random_sts); ++request_id_index_; @@ -1258,8 +1202,9 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) { CdmSecurityLevel security_level = GetSecurityLevel(); if (security_level == kSecurityLevelL1 || security_level == kSecurityLevelL3) { - UsageTableHeader** header = security_level == kSecurityLevelL1 ? - &usage_table_header_l1_ : &usage_table_header_l3_; + UsageTableHeader** header = security_level == kSecurityLevelL1 + ? &usage_table_header_l1_ + : &usage_table_header_l3_; if (*header == NULL) { *header = new UsageTableHeader(); // Ignore errors since we do not know when a session is opened, @@ -1299,8 +1244,7 @@ void CryptoSession::Close() { close_sts = OEMCrypto_CloseSession(oec_session_id_); metrics_->oemcrypto_close_session_.Increment(close_sts); - if (OEMCrypto_SUCCESS == close_sts) - open_ = false; + if (OEMCrypto_SUCCESS == close_sts) open_ = false; update_usage_table = update_usage_table_after_close_session_; } if (close_sts == OEMCrypto_SUCCESS && update_usage_table && @@ -1416,17 +1360,14 @@ bool CryptoSession::LoadCertificatePrivateKey(std::string& wrapped_key) { size_t buf_size = temp_buffer.size(); uint8_t* buf = reinterpret_cast(&temp_buffer[0]); OEMCryptoResult sts = - OEMCrypto_GetOEMPublicCertificate(oec_session_id_, buf, &buf_size); + OEMCrypto_GetOEMPublicCertificate(oec_session_id_, buf, &buf_size); LOGV("LoadDeviceRSAKey: id=%ld", (uint32_t)oec_session_id_); M_TIME( sts = OEMCrypto_LoadDeviceRSAKey( - oec_session_id_, - reinterpret_cast(wrapped_key.data()), + oec_session_id_, reinterpret_cast(wrapped_key.data()), wrapped_key.size()), - metrics_, - oemcrypto_load_device_rsa_key_, - sts); + metrics_, oemcrypto_load_device_rsa_key_, sts); if (OEMCrypto_SUCCESS != sts) { LOGE("LoadCertificatePrivateKey: OEMCrypto_LoadDeviceRSAKey error=%d", sts); @@ -1467,25 +1408,19 @@ bool CryptoSession::RefreshKeys(const std::string& message, } LOGV("RefreshKeys: id=%ld", static_cast(oec_session_id_)); OEMCryptoResult refresh_sts; - M_TIME( - refresh_sts = OEMCrypto_RefreshKeys( - oec_session_id_, - msg, - message.size(), - reinterpret_cast(signature.data()), - signature.size(), - num_keys, - &load_key_array[0]), - metrics_, - oemcrypto_refresh_keys_, - refresh_sts); + M_TIME(refresh_sts = OEMCrypto_RefreshKeys( + oec_session_id_, msg, message.size(), + reinterpret_cast(signature.data()), + signature.size(), num_keys, &load_key_array[0]), + metrics_, oemcrypto_refresh_keys_, refresh_sts); return OEMCrypto_SUCCESS == refresh_sts; } -CdmResponseType CryptoSession::SelectKey(const std::string& key_id) { +CdmResponseType CryptoSession::SelectKey(const std::string& key_id, + CdmCipherMode cipher_mode) { // Crypto session lock already locked. - OEMCryptoResult sts = key_session_->SelectKey(key_id); + OEMCryptoResult sts = key_session_->SelectKey(key_id, cipher_mode); switch (sts) { case OEMCrypto_SUCCESS: @@ -1536,17 +1471,13 @@ bool CryptoSession::GenerateSignature(const std::string& message, // At most two attempts. // The first attempt may fail due to buffer too short for (int i = 0; i < 2; ++i) { - M_TIME( - sts = OEMCrypto_GenerateSignature( - oec_session_id_, - reinterpret_cast(message.data()), - message.size(), - reinterpret_cast(const_cast(signature->data())), - &length), - metrics_, - oemcrypto_generate_signature_, - sts, - metrics::Pow2Bucket(length)); + M_TIME(sts = OEMCrypto_GenerateSignature( + oec_session_id_, + reinterpret_cast(message.data()), message.size(), + reinterpret_cast(const_cast(signature->data())), + &length), + metrics_, oemcrypto_generate_signature_, sts, + metrics::Pow2Bucket(length)); if (OEMCrypto_SUCCESS == sts) { // Trim signature buffer and done signature->resize(length); @@ -1579,18 +1510,13 @@ bool CryptoSession::GenerateRsaSignature(const std::string& message, // At most two attempts. // The first attempt may fail due to buffer too short for (int i = 0; i < 2; ++i) { - M_TIME( - sts = OEMCrypto_GenerateRSASignature( - oec_session_id_, - reinterpret_cast(message.data()), - message.size(), - reinterpret_cast(const_cast(signature->data())), - &length, - kSign_RSASSA_PSS), - metrics_, - oemcrypto_generate_rsa_signature_, - sts, - metrics::Pow2Bucket(length)); + M_TIME(sts = OEMCrypto_GenerateRSASignature( + oec_session_id_, + reinterpret_cast(message.data()), message.size(), + reinterpret_cast(const_cast(signature->data())), + &length, kSign_RSASSA_PSS), + metrics_, oemcrypto_generate_rsa_signature_, sts, + metrics::Pow2Bucket(length)); if (OEMCrypto_SUCCESS == sts) { // Trim signature buffer and done @@ -1643,20 +1569,14 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) { } OEMCryptoResult sts = OEMCrypto_ERROR_NOT_IMPLEMENTED; - if (!params.is_encrypted && + if (!params.is_encrypted && params.subsample_flags == (OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)) { - M_TIME( - sts = OEMCrypto_CopyBuffer( - requested_security_level_, - params.encrypt_buffer, - params.encrypt_length, - &buffer_descriptor, - params.subsample_flags), - metrics_, - oemcrypto_copy_buffer_, - sts, + sts = OEMCrypto_CopyBuffer(requested_security_level_, + params.encrypt_buffer, params.encrypt_length, + &buffer_descriptor, params.subsample_flags), + metrics_, oemcrypto_copy_buffer_, sts, metrics::Pow2Bucket(params.encrypt_length)); if (sts == OEMCrypto_ERROR_BUFFER_TOO_LARGE && @@ -1677,7 +1597,7 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) { AutoLock auto_lock(crypto_lock_); // Check if key needs to be selected if (params.is_encrypted) { - CdmResponseType result = SelectKey(*params.key_id); + CdmResponseType result = SelectKey(*params.key_id, params.cipher_mode); if (result != NO_ERROR) return result; } @@ -1692,9 +1612,9 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) { (pattern_descriptor.encrypt + pattern_descriptor.skip) * kAes128BlockSize; const size_t chunk_size = - pattern_length > 0 ? - kMaximumChunkSize - (kMaximumChunkSize % pattern_length) : - kMaximumChunkSize; + pattern_length > 0 + ? kMaximumChunkSize - (kMaximumChunkSize % pattern_length) + : kMaximumChunkSize; if (params.encrypt_length > chunk_size) { sts = DecryptInChunks(params, buffer_descriptor, pattern_descriptor, @@ -1733,7 +1653,8 @@ bool CryptoSession::UsageInformationSupport(bool* has_support) { } CdmResponseType CryptoSession::UpdateUsageInformation() { - LOGV("CryptoSession::UpdateUsageInformation: id=%ld", (uint32_t)oec_session_id_); + LOGV("CryptoSession::UpdateUsageInformation: id=%ld", + (uint32_t)oec_session_id_); AutoLock auto_lock(crypto_lock_); if (!initialized_) return UNKNOWN_ERROR; @@ -1793,8 +1714,8 @@ CdmResponseType CryptoSession::GenerateUsageReport( size_t usage_length = 0; OEMCryptoResult status = OEMCrypto_ReportUsage( - oec_session_id_, pst, provider_session_token.length(), - NULL, &usage_length); + oec_session_id_, pst, provider_session_token.length(), NULL, + &usage_length); metrics_->oemcrypto_report_usage_.Increment(status); if (OEMCrypto_SUCCESS != status) { @@ -1807,12 +1728,9 @@ CdmResponseType CryptoSession::GenerateUsageReport( std::vector buffer(usage_length); - status = OEMCrypto_ReportUsage( - oec_session_id_, - pst, - provider_session_token.length(), - &buffer[0], - &usage_length); + status = OEMCrypto_ReportUsage(oec_session_id_, pst, + provider_session_token.length(), &buffer[0], + &usage_length); metrics_->oemcrypto_report_usage_.Increment(status); if (OEMCrypto_SUCCESS != status) { @@ -1823,8 +1741,8 @@ CdmResponseType CryptoSession::GenerateUsageReport( if (usage_length != buffer.size()) { buffer.resize(usage_length); } - (*usage_report) = std::string(reinterpret_cast(&buffer[0]), - buffer.size()); + (*usage_report) = + std::string(reinterpret_cast(&buffer[0]), buffer.size()); Unpacked_PST_Report pst_report(&buffer[0]); *usage_duration_status = kUsageDurationsInvalid; @@ -1841,8 +1759,7 @@ CdmResponseType CryptoSession::GenerateUsageReport( LOGV("OEMCrypto_PST_Report.status: %d\n", pst_report.status()); LOGV("OEMCrypto_PST_Report.clock_security_level: %d\n", pst_report.clock_security_level()); - LOGV("OEMCrypto_PST_Report.pst_length: %d\n", - pst_report.pst_length()); + LOGV("OEMCrypto_PST_Report.pst_length: %d\n", pst_report.pst_length()); LOGV("OEMCrypto_PST_Report.padding: %d\n", pst_report.padding()); LOGV("OEMCrypto_PST_Report.seconds_since_license_received: %lld\n", pst_report.seconds_since_license_received()); @@ -1861,7 +1778,7 @@ CdmResponseType CryptoSession::GenerateUsageReport( if (kInactive == pst_report.status() && (0 > pst_report.seconds_since_first_decrypt() || pst_report.seconds_since_license_received() < - pst_report.seconds_since_first_decrypt())) { + pst_report.seconds_since_first_decrypt())) { *usage_duration_status = kUsageDurationPlaybackNotBegun; return NO_ERROR; } @@ -1888,8 +1805,8 @@ CdmResponseType CryptoSession::ReleaseUsageInformation( const uint8_t* pst = msg + GetOffset(message, provider_session_token); OEMCryptoResult status = OEMCrypto_DeleteUsageEntry( - oec_session_id_, pst, provider_session_token.length(), - msg, message.length(), sig, signature.length()); + oec_session_id_, pst, provider_session_token.length(), msg, + message.length(), sig, signature.length()); metrics_->oemcrypto_delete_usage_entry_.Increment(status); if (OEMCrypto_SUCCESS != status) { @@ -1899,13 +1816,12 @@ CdmResponseType CryptoSession::ReleaseUsageInformation( } } - if (usage_support_type_ == kUsageTableSupport) - UpdateUsageInformation(); + if (usage_support_type_ == kUsageTableSupport) UpdateUsageInformation(); return NO_ERROR; } CdmResponseType CryptoSession::DeleteUsageInformation( - const std::string& provider_session_token) { + const std::string& provider_session_token) { CdmResponseType response = NO_ERROR; LOGV("CryptoSession::DeleteUsageInformation"); OEMCryptoResult status; @@ -1916,13 +1832,14 @@ CdmResponseType CryptoSession::DeleteUsageInformation( provider_session_token.length()); metrics_->oemcrypto_force_delete_usage_entry_.Increment(status); if (OEMCrypto_SUCCESS != status) { - LOGE("CryptoSession::DeleteUsageInformation: Delete Usage Table error " - "= %ld", status); + LOGE( + "CryptoSession::DeleteUsageInformation: Delete Usage Table error " + "= %ld", + status); response = UNKNOWN_ERROR; } } - if (usage_support_type_ == kUsageTableSupport) - UpdateUsageInformation(); + if (usage_support_type_ == kUsageTableSupport) UpdateUsageInformation(); return response; } @@ -1932,20 +1849,21 @@ CdmResponseType CryptoSession::DeleteMultipleUsageInformation( CdmResponseType response = NO_ERROR; { AutoLock auto_lock(crypto_lock_); - for (size_t i=0; i < provider_session_tokens.size(); ++i) { + for (size_t i = 0; i < provider_session_tokens.size(); ++i) { OEMCryptoResult status = OEMCrypto_ForceDeleteUsageEntry( reinterpret_cast(provider_session_tokens[i].c_str()), provider_session_tokens[i].length()); metrics_->oemcrypto_force_delete_usage_entry_.Increment(status); if (OEMCrypto_SUCCESS != status) { - LOGW("CryptoSession::DeleteMultipleUsageInformation: " - "Delete Usage Table error =%ld", status); + LOGW( + "CryptoSession::DeleteMultipleUsageInformation: " + "Delete Usage Table error =%ld", + status); response = UNKNOWN_ERROR; } } } - if (usage_support_type_ == kUsageTableSupport) - UpdateUsageInformation(); + if (usage_support_type_ == kUsageTableSupport) UpdateUsageInformation(); return response; } @@ -1957,13 +1875,14 @@ CdmResponseType CryptoSession::DeleteAllUsageReports() { status = OEMCrypto_DeleteOldUsageTable(); metrics_->oemcrypto_delete_usage_table_.Increment(status); if (OEMCrypto_SUCCESS != status) { - LOGE("CryptoSession::DeleteAllUsageReports: Delete Usage Table error " - "=%ld", status); + LOGE( + "CryptoSession::DeleteAllUsageReports: Delete Usage Table error " + "=%ld", + status); } } - if (usage_support_type_ == kUsageTableSupport) - UpdateUsageInformation(); + if (usage_support_type_ == kUsageTableSupport) UpdateUsageInformation(); return NO_ERROR; } @@ -2018,19 +1937,18 @@ bool CryptoSession::RewrapCertificate(const std::string& signed_message, static_cast(oec_session_id_)); if (pre_provision_token_type_ == kClientTokenKeybox) { - - return RewrapDeviceRSAKey(signed_message, signature, nonce, private_key, - iv, wrapped_private_key); + return RewrapDeviceRSAKey(signed_message, signature, nonce, private_key, iv, + wrapped_private_key); } else if (pre_provision_token_type_ == kClientTokenOemCert) { - return RewrapDeviceRSAKey30(signed_message, nonce, private_key, iv, wrapping_key, wrapped_private_key); } else { - LOGE("CryptoSession::RewrapCertificate, Bad pre-provision type=%d: " - "session id=%ld", pre_provision_token_type_, - static_cast(oec_session_id_)); + LOGE( + "CryptoSession::RewrapCertificate, Bad pre-provision type=%d: " + "session id=%ld", + pre_provision_token_type_, static_cast(oec_session_id_)); return false; } } @@ -2059,44 +1977,25 @@ bool CryptoSession::RewrapDeviceRSAKey(const std::string& message, // and 0 as wrapped_rsa_key_length. size_t wrapped_rsa_key_length = 0; OEMCryptoResult status; - M_TIME( - status = OEMCrypto_RewrapDeviceRSAKey( - oec_session_id_, - signed_msg, - message.size(), - reinterpret_cast(signature.data()), - signature.size(), - msg_nonce, - msg_rsa_key, - enc_rsa_key.size(), - msg_rsa_key_iv, - NULL, - &wrapped_rsa_key_length), - metrics_, - oemcrypto_rewrap_device_rsa_key_, - status); + M_TIME(status = OEMCrypto_RewrapDeviceRSAKey( + oec_session_id_, signed_msg, message.size(), + reinterpret_cast(signature.data()), + signature.size(), msg_nonce, msg_rsa_key, enc_rsa_key.size(), + msg_rsa_key_iv, NULL, &wrapped_rsa_key_length), + metrics_, oemcrypto_rewrap_device_rsa_key_, status); if (status != OEMCrypto_ERROR_SHORT_BUFFER) { LOGE("OEMCrypto_RewrapDeviceRSAKey fails to get wrapped_rsa_key_length"); return false; } wrapped_rsa_key->resize(wrapped_rsa_key_length); - M_TIME( - status = OEMCrypto_RewrapDeviceRSAKey( - oec_session_id_, - signed_msg, - message.size(), - reinterpret_cast(signature.data()), - signature.size(), - msg_nonce, - msg_rsa_key, - enc_rsa_key.size(), - msg_rsa_key_iv, - reinterpret_cast(&(*wrapped_rsa_key)[0]), - &wrapped_rsa_key_length), - metrics_, - oemcrypto_rewrap_device_rsa_key_, - status); + M_TIME(status = OEMCrypto_RewrapDeviceRSAKey( + oec_session_id_, signed_msg, message.size(), + reinterpret_cast(signature.data()), + signature.size(), msg_nonce, msg_rsa_key, enc_rsa_key.size(), + msg_rsa_key_iv, reinterpret_cast(&(*wrapped_rsa_key)[0]), + &wrapped_rsa_key_length), + metrics_, oemcrypto_rewrap_device_rsa_key_, status); wrapped_rsa_key->resize(wrapped_rsa_key_length); @@ -2169,8 +2068,8 @@ bool CryptoSession::GetHdcpCapabilities(HdcpCapability* current, "NULL"); return false; } - OEMCryptoResult status = OEMCrypto_GetHDCPCapability( - requested_security_level_, current, max); + OEMCryptoResult status = + OEMCrypto_GetHDCPCapability(requested_security_level_, current, max); if (OEMCrypto_SUCCESS != status) { metrics_->oemcrypto_current_hdcp_capability_.SetError(status); @@ -2188,8 +2087,9 @@ bool CryptoSession::GetSupportedCertificateTypes( LOGV("GetSupportedCertificateTypes: id=%ld", (uint32_t)oec_session_id_); if (!initialized_) return false; if (support == NULL) { - LOGE("CryptoSession::GetSupportedCertificateTypes: |support| cannot be " - "NULL"); + LOGE( + "CryptoSession::GetSupportedCertificateTypes: |support| cannot be " + "NULL"); return false; } @@ -2197,7 +2097,7 @@ bool CryptoSession::GetSupportedCertificateTypes( OEMCrypto_SupportedCertificates(requested_security_level_); support->rsa_2048_bit = oec_support & OEMCrypto_Supports_RSA_2048bit; support->rsa_3072_bit = oec_support & OEMCrypto_Supports_RSA_3072bit; - support->rsa_cast = oec_support & OEMCrypto_Supports_RSA_CAST; + support->rsa_cast = oec_support & OEMCrypto_Supports_RSA_CAST; return true; } @@ -2327,22 +2227,21 @@ CdmResponseType CryptoSession::GenericEncrypt(const std::string& in_buffer, } AutoLock auto_lock(crypto_lock_); - CdmResponseType result = SelectKey(key_id); + // TODO(jfore): We need to select a key with a cipher mode and algorithm + // doesn't seem to fit. Is it ok to just use a default value here? + // Or do we need to pass it in? + CdmResponseType result = SelectKey(key_id, kCipherModeCbc); if (result != NO_ERROR) return result; OEMCryptoResult sts; M_TIME( sts = OEMCrypto_Generic_Encrypt( - oec_session_id_, - reinterpret_cast(in_buffer.data()), - in_buffer.size(), - reinterpret_cast(iv.data()), + oec_session_id_, reinterpret_cast(in_buffer.data()), + in_buffer.size(), reinterpret_cast(iv.data()), oec_algorithm, reinterpret_cast(const_cast(out_buffer->data()))), - metrics_, - oemcrypto_generic_encrypt_, - sts, + metrics_, oemcrypto_generic_encrypt_, sts, metrics::Pow2Bucket(in_buffer.size())); if (OEMCrypto_SUCCESS != sts) { @@ -2380,22 +2279,21 @@ CdmResponseType CryptoSession::GenericDecrypt(const std::string& in_buffer, } AutoLock auto_lock(crypto_lock_); - CdmResponseType result = SelectKey(key_id); + // TODO(jfore): We need to select a key with a cipher mode and algorithm + // doesn't seem to fit. Is it ok to just use a default value here? + // Or do we need to pass it in? + CdmResponseType result = SelectKey(key_id, kCipherModeCbc); if (result != NO_ERROR) return result; OEMCryptoResult sts; M_TIME( sts = OEMCrypto_Generic_Decrypt( - oec_session_id_, - reinterpret_cast(in_buffer.data()), - in_buffer.size(), - reinterpret_cast(iv.data()), + oec_session_id_, reinterpret_cast(in_buffer.data()), + in_buffer.size(), reinterpret_cast(iv.data()), oec_algorithm, reinterpret_cast(const_cast(out_buffer->data()))), - metrics_, - oemcrypto_generic_decrypt_, - sts, + metrics_, oemcrypto_generic_decrypt_, sts, metrics::Pow2Bucket(in_buffer.size())); if (OEMCrypto_SUCCESS != sts) { @@ -2430,7 +2328,10 @@ CdmResponseType CryptoSession::GenericSign(const std::string& message, size_t length = signature->size(); AutoLock auto_lock(crypto_lock_); - CdmResponseType result = SelectKey(key_id); + // TODO(jfore): We need to select a key with a cipher mode and algorithm + // doesn't seem to fit. Is it ok to just use a default value here? + // Or do we need to pass it in? + CdmResponseType result = SelectKey(key_id, kCipherModeCbc); if (result != NO_ERROR) return result; // At most two attempts. @@ -2438,15 +2339,11 @@ CdmResponseType CryptoSession::GenericSign(const std::string& message, for (int i = 0; i < 2; ++i) { M_TIME( sts = OEMCrypto_Generic_Sign( - oec_session_id_, - reinterpret_cast(message.data()), - message.size(), - oec_algorithm, + oec_session_id_, reinterpret_cast(message.data()), + message.size(), oec_algorithm, reinterpret_cast(const_cast(signature->data())), &length), - metrics_, - oemcrypto_generic_sign_, - sts, + metrics_, oemcrypto_generic_sign_, sts, metrics::Pow2Bucket(message.size())); if (OEMCrypto_SUCCESS == sts) { @@ -2484,21 +2381,19 @@ CdmResponseType CryptoSession::GenericVerify(const std::string& message, } AutoLock auto_lock(crypto_lock_); - CdmResponseType result = SelectKey(key_id); + // TODO(jfore): We need to select a key with a cipher mode and algorithm + // doesn't seem to fit. Is it ok to just use a default value here? + // Or do we need to pass it in? + CdmResponseType result = SelectKey(key_id, kCipherModeCbc); if (result != NO_ERROR) return result; OEMCryptoResult sts; M_TIME( sts = OEMCrypto_Generic_Verify( - oec_session_id_, - reinterpret_cast(message.data()), - message.size(), - oec_algorithm, - reinterpret_cast(signature.data()), - signature.size()), - metrics_, - oemcrypto_generic_verify_, - sts, + oec_session_id_, reinterpret_cast(message.data()), + message.size(), oec_algorithm, + reinterpret_cast(signature.data()), signature.size()), + metrics_, oemcrypto_generic_verify_, sts, metrics::Pow2Bucket(signature.size())); if (OEMCrypto_SUCCESS != sts) { @@ -2546,8 +2441,9 @@ CdmResponseType CryptoSession::GetUsageSupportType( } *usage_support_type = usage_support_type_ = - (api_version >= kOemCryptoApiVersionSupportsBigUsageTables) ? - kUsageEntrySupport : kUsageTableSupport; + (api_version >= kOemCryptoApiVersionSupportsBigUsageTables) + ? kUsageEntrySupport + : kUsageTableSupport; return NO_ERROR; } @@ -2649,8 +2545,7 @@ CdmResponseType CryptoSession::CreateUsageEntry(uint32_t* entry_number) { } CdmResponseType CryptoSession::LoadUsageEntry( - uint32_t entry_number, - const CdmUsageEntry& usage_entry) { + uint32_t entry_number, const CdmUsageEntry& usage_entry) { LOGV("LoadUsageEntry: id=%ld", (uint32_t)oec_session_id_); OEMCryptoResult result = OEMCrypto_LoadUsageEntry( @@ -2679,8 +2574,7 @@ CdmResponseType CryptoSession::LoadUsageEntry( } CdmResponseType CryptoSession::UpdateUsageEntry( - CdmUsageTableHeader* usage_table_header, - CdmUsageEntry* usage_entry) { + CdmUsageTableHeader* usage_table_header, CdmUsageEntry* usage_entry) { LOGV("UpdateUsageEntry: id=%ld", (uint32_t)oec_session_id_); if (usage_table_header == NULL) { @@ -2726,8 +2620,7 @@ CdmResponseType CryptoSession::ShrinkUsageTableHeader( LOGV("ShrinkUsageTableHeader: id=%ld", (uint32_t)oec_session_id_); if (usage_table_header == NULL) { - LOGE( - "ShrinkUsageTableHeader: usage_table_header param not provided"); + LOGE("ShrinkUsageTableHeader: usage_table_header param not provided"); return INVALID_PARAMETERS_ENG_21; } @@ -2747,9 +2640,8 @@ CdmResponseType CryptoSession::ShrinkUsageTableHeader( } if (result != OEMCrypto_SUCCESS) { - LOGE( - "ShrinkUsageTableHeader: OEMCrypto_ShrinkUsageTableHeader error: %d", - result); + LOGE("ShrinkUsageTableHeader: OEMCrypto_ShrinkUsageTableHeader error: %d", + result); return SHRINK_USAGE_TABLER_HEADER_UNKNOWN_ERROR; } @@ -2772,45 +2664,46 @@ CdmResponseType CryptoSession::MoveUsageEntry(uint32_t new_entry_number) { } bool CryptoSession::CreateOldUsageEntry( - uint64_t time_since_license_received, - uint64_t time_since_first_decrypt, - uint64_t time_since_last_decrypt, - UsageDurationStatus usage_duration_status, - const std::string& server_mac_key, - const std::string& client_mac_key, + uint64_t time_since_license_received, uint64_t time_since_first_decrypt, + uint64_t time_since_last_decrypt, UsageDurationStatus usage_duration_status, + const std::string& server_mac_key, const std::string& client_mac_key, const std::string& provider_session_token) { LOGV("CreateOldUsageEntry: Lock"); AutoLock auto_lock(crypto_lock_); if (server_mac_key.size() < MAC_KEY_SIZE || client_mac_key.size() < MAC_KEY_SIZE) { - LOGE("CreateOldUsageEntry: Invalid mac key size: server mac key size %d, " - "client mac key size: %d", server_mac_key.size(), - client_mac_key.size()); + LOGE( + "CreateOldUsageEntry: Invalid mac key size: server mac key size %d, " + "client mac key size: %d", + server_mac_key.size(), client_mac_key.size()); return false; } OEMCrypto_Usage_Entry_Status status = kUnused; switch (usage_duration_status) { - case kUsageDurationsInvalid: status = kUnused; break; - case kUsageDurationPlaybackNotBegun: status = kInactiveUnused; break; - case kUsageDurationsValid: status = kActive; break; + case kUsageDurationsInvalid: + status = kUnused; + break; + case kUsageDurationPlaybackNotBegun: + status = kInactiveUnused; + break; + case kUsageDurationsValid: + status = kActive; + break; default: LOGE("CreateOldUsageEntry: Unrecognized usage duration status: %d", usage_duration_status); return false; } - OEMCryptoResult result = - OEMCrypto_CreateOldUsageEntry( - requested_security_level_, time_since_license_received, - time_since_first_decrypt, time_since_last_decrypt, status, - reinterpret_cast( - const_cast(server_mac_key.data())), - reinterpret_cast( - const_cast(client_mac_key.data())), - reinterpret_cast(provider_session_token.data()), - provider_session_token.size()); + OEMCryptoResult result = OEMCrypto_CreateOldUsageEntry( + requested_security_level_, time_since_license_received, + time_since_first_decrypt, time_since_last_decrypt, status, + reinterpret_cast(const_cast(server_mac_key.data())), + reinterpret_cast(const_cast(client_mac_key.data())), + reinterpret_cast(provider_session_token.data()), + provider_session_token.size()); if (result != OEMCrypto_SUCCESS) { LOGE("CreateOldUsageEntry: OEMCrypto_CreateOldUsageEntry error: %d", @@ -2852,23 +2745,19 @@ CdmResponseType CryptoSession::AddSubSession( 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_); + 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; + 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(wrapped_key_.data()), - wrapped_key_.size()), - metrics_, - oemcrypto_load_device_rsa_key_, - sts); + M_TIME(sts = OEMCrypto_LoadDeviceRSAKey( + sid, reinterpret_cast(wrapped_key_.data()), + wrapped_key_.size()), + metrics_, oemcrypto_load_device_rsa_key_, sts); if (OEMCrypto_SUCCESS != sts) { LOGE("LoadDeviceRSAKey failed: %d", sts); @@ -2877,10 +2766,9 @@ CdmResponseType CryptoSession::AddSubSession( 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)); + key_session_.reset(new SubLicenseKeySession( + sub_license_oec_sessions_, metrics_, wrapped_key_, + requested_security_level_, group_master_key_id)); } return NO_ERROR; } @@ -2945,8 +2833,8 @@ OEMCryptoResult CryptoSession::CopyBufferInChunks( while (remaining_encrypt_length > 0) { // Calculate the size of the next chunk and its offset into the original // buffer. - const size_t chunk_size = std::min(remaining_encrypt_length, - kMaximumChunkSize); + const size_t chunk_size = + std::min(remaining_encrypt_length, kMaximumChunkSize); const size_t additional_offset = params.encrypt_length - remaining_encrypt_length; @@ -2979,20 +2867,15 @@ OEMCryptoResult CryptoSession::CopyBufferInChunks( } OEMCryptoResult sts; - M_TIME( - sts = OEMCrypto_CopyBuffer( - requested_security_level_, - params.encrypt_buffer + additional_offset, - chunk_size, - &buffer_descriptor, - subsample_flags), - metrics_, - oemcrypto_copy_buffer_, - sts, - metrics::Pow2Bucket(chunk_size)); + M_TIME(sts = OEMCrypto_CopyBuffer(requested_security_level_, + params.encrypt_buffer + additional_offset, + chunk_size, &buffer_descriptor, + subsample_flags), + metrics_, oemcrypto_copy_buffer_, sts, + metrics::Pow2Bucket(chunk_size)); if (sts != OEMCrypto_SUCCESS) { - return sts; + return sts; } // Clear any subsample flags before the next loop iteration. @@ -3008,20 +2891,19 @@ OEMCryptoResult CryptoSession::DecryptInChunks( const OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor, size_t max_chunk_size) { size_t remaining_encrypt_length = params.encrypt_length; - uint8_t subsample_flags = - (params.subsample_flags & OEMCrypto_FirstSubsample) ? - OEMCrypto_FirstSubsample : 0; + uint8_t subsample_flags = (params.subsample_flags & OEMCrypto_FirstSubsample) + ? OEMCrypto_FirstSubsample + : 0; std::vector iv = *params.iv; const size_t pattern_length_in_bytes = - (pattern_descriptor.encrypt + pattern_descriptor.skip) * - kAes128BlockSize; + (pattern_descriptor.encrypt + pattern_descriptor.skip) * kAes128BlockSize; while (remaining_encrypt_length > 0) { // Calculate the size of the next chunk and its offset into the // original buffer. - const size_t chunk_size = std::min(remaining_encrypt_length, - max_chunk_size); + const size_t chunk_size = + std::min(remaining_encrypt_length, max_chunk_size); const size_t additional_offset = params.encrypt_length - remaining_encrypt_length; @@ -3060,22 +2942,14 @@ OEMCryptoResult CryptoSession::DecryptInChunks( OEMCryptoResult sts; M_TIME( sts = OEMCrypto_DecryptCENC( - oec_session_id_, - params.encrypt_buffer + additional_offset, - chunk_size, - params.is_encrypted, - &iv.front(), - params.block_offset, - &buffer_descriptor, - &pattern_descriptor, - subsample_flags), - metrics_, - oemcrypto_decrypt_cenc_, - sts, + oec_session_id_, params.encrypt_buffer + additional_offset, + chunk_size, params.is_encrypted, &iv.front(), params.block_offset, + &buffer_descriptor, &pattern_descriptor, subsample_flags), + metrics_, oemcrypto_decrypt_cenc_, sts, metrics::Pow2Bucket(chunk_size)); if (sts != OEMCrypto_SUCCESS) { - return sts; + return sts; } // If we are not yet done, update the IV so that it is valid for the next diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_key_mock.h b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_key_mock.h index 1e76543c..2860ac02 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_key_mock.h +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_key_mock.h @@ -69,15 +69,15 @@ class Key { public: Key(const Key& key) : value_(key.value_), control_(key.control_), ctr_mode_(key.ctr_mode_) {} - Key(const std::vector& key_string, const KeyControlBlock& control, - bool ctr_mode) - : value_(key_string), control_(control), ctr_mode_(ctr_mode){}; + Key(const std::vector& key_string, const KeyControlBlock& control) + : value_(key_string), control_(control), ctr_mode_(true){}; virtual ~Key(){}; void UpdateDuration(const KeyControlBlock& control); - const std::vector& value() const { return value_; } + virtual const std::vector& value() const { return value_; } const KeyControlBlock& control() const { return control_; } bool ctr_mode() const { return ctr_mode_; } + void set_ctr_mode(bool ctr_mode) { ctr_mode_ = ctr_mode; } private: std::vector value_; @@ -85,6 +85,28 @@ class Key { bool ctr_mode_; }; +// AES-256 entitlement key. |Key| holds the entitlement key. |EntitlementKey| +// holds the content key. +class EntitlementKey : public Key { + public: + EntitlementKey(const Key& key) : Key(key) {} + virtual ~EntitlementKey() {} + virtual const std::vector& value() const { return content_key_; } + const std::vector& content_key() { return content_key_; } + const std::vector& content_key_id() { return content_key_id_; } + const std::vector& entitlement_key() { return Key::value(); } + bool SetContentKey(const std::vector& content_key, + const std::vector& content_key_id) { + content_key_.assign(content_key.begin(), content_key.end()); + content_key_id_.assign(content_key_id.begin(), content_key_id.end()); + return true; + } + + private: + std::vector content_key_; + std::vector content_key_id_; +}; + } // namespace wvoec_mock #endif // OEMCRYPTO_KEY_MOCK_H_ diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_mock.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_mock.cpp index 5c1ca9fa..6c5ee661 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_mock.cpp +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_mock.cpp @@ -31,7 +31,7 @@ const uint8_t kBakedInCertificateMagicBytes[] = {0xDE, 0xAD, 0xBE, 0xEF}; // Return uint32 referenced through a potentially unaligned pointer. // If the pointer is NULL, return 0. -uint32_t unaligned_dereference_uint32(const uint32_t* unaligned_ptr) { +uint32_t unaligned_dereference_uint32(const void* unaligned_ptr) { if (unaligned_ptr == NULL) return 0; uint32_t value; const uint8_t* src = reinterpret_cast(unaligned_ptr); @@ -299,7 +299,7 @@ extern "C" OEMCryptoResult OEMCrypto_LoadKeys( const uint8_t* signature, size_t signature_length, const uint8_t* enc_mac_key_iv, const uint8_t* enc_mac_keys, size_t num_keys, const OEMCrypto_KeyObject* key_array, const uint8_t* pst, size_t pst_length, - const uint8_t* srm_requirement) { + const uint8_t* srm_requirement, OEMCrypto_LicenseType license_type) { if (!crypto_engine) { LOGE("OEMCrypto_LoadKeys: OEMCrypto Not Initialized."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -326,9 +326,6 @@ extern "C" OEMCryptoResult OEMCrypto_LoadKeys( key_array[i].key_control_iv, wvcdm::KEY_IV_SIZE); dump_array_part("key_array", i, "key_control", key_array[i].key_control, wvcdm::KEY_IV_SIZE); - LOGV("key_array[%zu].cipher_mode=%s;\n", i, - key_array[i].cipher_mode == OEMCrypto_CipherMode_CTR ? "CTR" - : "CBC"); } } } @@ -389,7 +386,32 @@ extern "C" OEMCryptoResult OEMCrypto_LoadKeys( return session_ctx->LoadKeys(message, message_length, signature, signature_length, enc_mac_key_iv, enc_mac_keys, num_keys, key_array, pst, pst_length, - srm_requirement); + srm_requirement, license_type); +} + +extern "C" OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( + OEMCrypto_SESSION session, + size_t num_keys, + const OEMCrypto_EntitledContentKeyObject* key_array) { + if (num_keys == 0) { + LOGE("[OEMCrypto_LoadEntitledContentKeys(): key_array is empty."); + return OEMCrypto_SUCCESS; + } + if (!key_array) { + LOGE("[OEMCrypto_LoadEntitledContentKeys(): missing key_array."); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (!crypto_engine) { + LOGE("OEMCrypto_LoadEntitledContentKeys: OEMCrypto Not Initialized."); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + SessionContext* session_ctx = crypto_engine->FindSession(session); + if (!session_ctx || !session_ctx->isValid()) { + LOGE("[OEMCrypto_LoadEntitledContentKeys(): ERROR_INVALID_SESSION]"); + return OEMCrypto_ERROR_INVALID_SESSION; + } + + return session_ctx->LoadEntitledContentKeys(num_keys, key_array); } extern "C" OEMCryptoResult OEMCrypto_RefreshKeys( @@ -521,9 +543,9 @@ extern "C" OEMCryptoResult OEMCrypto_QueryKeyControl( return OEMCrypto_SUCCESS; } -extern "C" OEMCryptoResult OEMCrypto_SelectKey(const OEMCrypto_SESSION session, - const uint8_t* key_id, - size_t key_id_length) { +extern "C" OEMCryptoResult OEMCrypto_SelectKey( + const OEMCrypto_SESSION session, const uint8_t* key_id, + size_t key_id_length, OEMCryptoCipherMode cipher_mode) { if (LogCategoryEnabled(kLoggingTraceDecryptCalls)) { LOGI("-- OEMCryptoResult OEMCrypto_SelectKey(%d, id=%s)", session, wvcdm::HexEncode(key_id, key_id_length).c_str()); @@ -543,7 +565,7 @@ extern "C" OEMCryptoResult OEMCrypto_SelectKey(const OEMCrypto_SESSION session, const std::vector key_id_str = std::vector(key_id, key_id + key_id_length); - return session_ctx->SelectContentKey(key_id_str); + return session_ctx->SelectContentKey(key_id_str, cipher_mode); } extern "C" OEMCryptoResult OEMCrypto_DecryptCENC( diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_session.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_session.cpp index fc3db54d..1e63af81 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_session.cpp +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_session.cpp @@ -56,11 +56,124 @@ void dump_boringssl_error() { namespace wvoec_mock { +/***************************************/ + +class ContentKeysContext : public SessionContextKeys { + public: + explicit ContentKeysContext() {} + virtual ~ContentKeysContext() {} + virtual size_t size() { return session_keys_.size(); } + bool Insert(const KeyId& key_id, const Key& key_data); + virtual Key* Find(const KeyId& key_id); + virtual void Remove(const KeyId& key_id); + virtual void UpdateDuration(const KeyControlBlock& control); + + virtual OEMCrypto_LicenseType type() { return OEMCrypto_ContentLicense; } + + virtual bool SetContentKey(const KeyId& entitlement_id, + const KeyId& content_key_id, + const std::vector& content_key); + virtual bool GetEntitlementKey( + const KeyId& entitlement_id, + const std::vector** entitlement_key); + + private: + SessionKeyTable session_keys_; + CORE_DISALLOW_COPY_AND_ASSIGN(ContentKeysContext); +}; + +bool ContentKeysContext::Insert(const KeyId& key_id, const Key& key_data) { + return session_keys_.Insert(key_id, key_data); +} + +Key* ContentKeysContext::Find(const KeyId& key_id) { + return session_keys_.Find(key_id); +} + +void ContentKeysContext::Remove(const KeyId& key_id) { + session_keys_.Remove(key_id); +} + +void ContentKeysContext::UpdateDuration(const KeyControlBlock& control) { + session_keys_.UpdateDuration(control); +} + +bool ContentKeysContext::SetContentKey( + const KeyId& entitlement_id, const KeyId& content_key_id, + const std::vector& content_key) { + // Unsupported action for this type. + return false; +} + +bool ContentKeysContext::GetEntitlementKey( + const KeyId& entitlement_id, const std::vector** key) { + // Unsupported action for this type. + return false; +}; + +/***************************************/ + +class EntitlementKeysContext : public SessionContextKeys { + public: + EntitlementKeysContext() {} + virtual ~EntitlementKeysContext() {} + virtual size_t size() { return session_keys_.size(); } + bool Insert(const KeyId& key_id, const Key& key_data); + virtual Key* Find(const KeyId& key_id); + virtual void Remove(const KeyId& key_id); + virtual void UpdateDuration(const KeyControlBlock& control); + virtual bool SetContentKey(const KeyId& entitlement_id, + const KeyId& content_key_id, + const std::vector& content_key); + virtual bool GetEntitlementKey(const KeyId& entitlement_id, + const std::vector** key); + + virtual OEMCrypto_LicenseType type() { return OEMCrypto_EntitlementLicense; } + + private: + EntitlementKeyTable session_keys_; + CORE_DISALLOW_COPY_AND_ASSIGN(EntitlementKeysContext); +}; + +bool EntitlementKeysContext::Insert(const KeyId& key_id, const Key& key_data) { + return session_keys_.Insert(key_id, key_data); +} + +Key* EntitlementKeysContext::Find(const KeyId& key_id) { + return session_keys_.Find(key_id); +} + +void EntitlementKeysContext::Remove(const KeyId& key_id) { + session_keys_.Remove(key_id); +} + +void EntitlementKeysContext::UpdateDuration(const KeyControlBlock& control) { + session_keys_.UpdateDuration(control); +} + +bool EntitlementKeysContext::SetContentKey( + const KeyId& entitlement_id, const KeyId& content_key_id, + const std::vector& content_key) { + return session_keys_.SetContentKey(entitlement_id, content_key_id, + content_key); +} + +bool EntitlementKeysContext::GetEntitlementKey( + const KeyId& entitlement_id, const std::vector** out_key) { + return session_keys_.GetEntitlementKey(entitlement_id, out_key); +} + +/***************************************/ + SessionContext::~SessionContext() { if (usage_entry_) { delete usage_entry_; usage_entry_ = NULL; } + if (session_keys_) { + delete session_keys_; + session_keys_ = NULL; + } } // Internal utility function to derive key using CMAC-128 @@ -398,7 +511,7 @@ OEMCryptoResult SessionContext::CheckNonceOrEntry( return CheckStatusOnline(key_control_block.nonce(), key_control_block.control_bits()); break; - case kControlNonceOrEntry: // Offline license. Nonce required on first use. + case kControlNonceOrEntry: // Offline license. Nonce required on first use. return CheckStatusOffline(key_control_block.nonce(), key_control_block.control_bits()); break; @@ -423,13 +536,32 @@ OEMCryptoResult SessionContext::LoadKeys( const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length, const uint8_t* enc_mac_key_iv, const uint8_t* enc_mac_keys, size_t num_keys, - const OEMCrypto_KeyObject* key_array, const uint8_t* pst, - size_t pst_length, const uint8_t* srm_requirement) { + const OEMCrypto_KeyObject* key_array, const uint8_t* pst, size_t pst_length, + const uint8_t* srm_requirement, OEMCrypto_LicenseType license_type) { // Validate message signature if (!ValidateMessage(message, message_length, signature, signature_length)) { return OEMCrypto_ERROR_SIGNATURE_FAILURE; } + if (!session_keys_) { + switch (license_type) { + case OEMCrypto_ContentLicense: + session_keys_ = new ContentKeysContext(); + break; + + case OEMCrypto_EntitlementLicense: + session_keys_ = new EntitlementKeysContext(); + break; + + default: + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + } else { + if (session_keys_->type() != license_type) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + } + StartTimer(); if (srm_requirement) { @@ -454,15 +586,15 @@ OEMCryptoResult SessionContext::LoadKeys( LOGW("[LoadKeys: SRM blacklisted device attached]"); srm_requirements_status_ = InvalidSRMVersion; } else { - LOGI("[LoadKeys: SRM Versions is %d, required: %d]", - current_version, minimum_version); + LOGI("[LoadKeys: SRM Versions is %d, required: %d]", current_version, + minimum_version); srm_requirements_status_ = ValidSRMVersion; } } // If there are already keys installed in this session, then we can load // a shared license. - bool second_license = (session_keys_.size() > 0); + bool second_license = (session_keys_->size() > 0); // Decrypt and install keys in key object // Each key will have a key control block. They will all have the same nonce. @@ -490,7 +622,7 @@ OEMCryptoResult SessionContext::LoadKeys( OEMCryptoResult result = InstallKey( key_id, enc_key_data, key_data_iv, key_control, key_control_iv, - key_array[i].cipher_mode == OEMCrypto_CipherMode_CTR, second_license); + second_license); if (result != OEMCrypto_SUCCESS) { status = result; break; @@ -550,11 +682,57 @@ OEMCryptoResult SessionContext::LoadKeys( return OEMCrypto_SUCCESS; } +OEMCryptoResult SessionContext::LoadEntitledContentKeys( + size_t num_keys, + const OEMCrypto_EntitledContentKeyObject* key_array) { + if (!key_array) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (!session_keys_ || session_keys_->type() != OEMCrypto_EntitlementLicense) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + for (size_t i = 0; i < num_keys; ++i) { + const OEMCrypto_EntitledContentKeyObject* key_data = &key_array[i]; + std::vector entitlement_key_id; + entitlement_key_id.assign(key_data->entitlement_key_id, + key_data->entitlement_key_id + + key_data->entitlement_key_id_length); + + const std::vector* entitlement_key = NULL; + if (!session_keys_->GetEntitlementKey(entitlement_key_id, + &entitlement_key)) { + return OEMCrypto_KEY_NOT_ENTITLED; + } + std::vector content_key; + std::vector iv; + std::vector encrypted_content_key; + std::vector content_key_id; + + iv.assign(key_data->content_key_data_iv, + key_data->content_key_data_iv + 16); + encrypted_content_key.assign( + key_data->content_key_data, + key_data->content_key_data + key_data->content_key_data_length); + content_key_id.assign( + key_data->content_key_id, + key_data->content_key_id + key_data->content_key_id_length); + if (!DecryptEntitlement(*entitlement_key, iv, + encrypted_content_key, &content_key)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (!session_keys_->SetContentKey( + entitlement_key_id, content_key_id, content_key)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + } + return OEMCrypto_SUCCESS; +} + OEMCryptoResult SessionContext::InstallKey( const KeyId& key_id, const std::vector& key_data, const std::vector& key_data_iv, const std::vector& key_control, - const std::vector& key_control_iv, bool ctr_mode, + const std::vector& key_control_iv, bool second_license) { // Decrypt encrypted key_data using derived encryption key and offered iv std::vector content_key; @@ -566,12 +744,11 @@ OEMCryptoResult SessionContext::InstallKey( } if (LogCategoryEnabled(kLoggingDumpContentKeys)) { - LOGI((" InstallKey: key_id = " + - wvcdm::b2a_hex(key_id)).c_str()); - LOGI((" InstallKey: content_key = " + - wvcdm::b2a_hex(content_key)).c_str()); - LOGI((" InstallKey: key_control = " + - wvcdm::b2a_hex(key_control_str)).c_str()); + LOGI((" InstallKey: key_id = " + wvcdm::b2a_hex(key_id)).c_str()); + LOGI( + (" InstallKey: content_key = " + wvcdm::b2a_hex(content_key)).c_str()); + LOGI((" InstallKey: key_control = " + wvcdm::b2a_hex(key_control_str)) + .c_str()); } // Key control must be supplied by license server @@ -633,8 +810,11 @@ OEMCryptoResult SessionContext::InstallKey( } } - Key key(content_key, key_control_block, ctr_mode); - session_keys_.Insert(key_id, key); + Key key(content_key, key_control_block); + if (!session_keys_) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + session_keys_->Insert(key_id, key); return OEMCrypto_SUCCESS; } @@ -663,6 +843,9 @@ bool SessionContext::InstallRSAEncryptedKey( OEMCryptoResult SessionContext::RefreshKey( const KeyId& key_id, const std::vector& key_control, const std::vector& key_control_iv) { + if (!session_keys_) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } if (key_id.empty()) { // Key control is not encrypted if key id is NULL KeyControlBlock key_control_block(key_control); @@ -676,11 +859,11 @@ OEMCryptoResult SessionContext::RefreshKey( return OEMCrypto_ERROR_INVALID_NONCE; } // Apply duration to all keys in this session - session_keys_.UpdateDuration(key_control_block); + session_keys_->UpdateDuration(key_control_block); return OEMCrypto_SUCCESS; } - Key* content_key = session_keys_.Find(key_id); + Key* content_key = session_keys_->Find(key_id); if (NULL == content_key) { if (LogCategoryEnabled(kLoggingDumpKeyControlBlocks)) { @@ -1014,7 +1197,10 @@ bool SessionContext::UpdateMacKeys(const std::vector& enc_mac_keys, } bool SessionContext::QueryKeyControlBlock(const KeyId& key_id, uint32_t* data) { - const Key* content_key = session_keys_.Find(key_id); + if (!session_keys_) { + return false; + } + const Key* content_key = session_keys_->Find(key_id); if (LogCategoryEnabled(kLoggingTraceDecryption)) { LOGI(("Select Key: key_id = " + wvcdm::b2a_hex(key_id)).c_str()); if (content_key) { @@ -1035,25 +1221,34 @@ bool SessionContext::QueryKeyControlBlock(const KeyId& key_id, uint32_t* data) { return true; } -OEMCryptoResult SessionContext::SelectContentKey(const KeyId& key_id) { - const Key* content_key = session_keys_.Find(key_id); - +OEMCryptoResult SessionContext::SelectContentKey( + const KeyId& key_id, OEMCryptoCipherMode cipher_mode) { if (LogCategoryEnabled(kLoggingTraceDecryption)) { - LOGI((" Select Key: key_id = " + wvcdm::b2a_hex(key_id)).c_str()); - LOGI((" Select Key: key = " + wvcdm::b2a_hex(content_key->value())) - .c_str()); + LOGI(" Select Key: key_id = %s", wvcdm::b2a_hex(key_id).c_str()); + LOGI(" Select Key: cipher_mode = %s", + (cipher_mode == OEMCrypto_CipherMode_CTR) ? "CTR" : "CBC"); } - + if (!session_keys_) { + LOGE("Select Key: no session keys."); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + Key* content_key = session_keys_->Find(key_id); if (NULL == content_key) { LOGE("[SelectContentKey(): No key matches key id]"); return OEMCrypto_ERROR_NO_CONTENT_KEY; } + if (LogCategoryEnabled(kLoggingTraceDecryption)) { + LOGI((" Select Key: key = " + wvcdm::b2a_hex(content_key->value())) + .c_str()); + } + content_key->set_ctr_mode(cipher_mode == OEMCrypto_CipherMode_CTR); current_content_key_ = content_key; const KeyControlBlock& control = current_content_key()->control(); + if (control.duration() > 0) { if (control.duration() < CurrentTimer()) { - LOGE("[SelectContentKey(): KEY_EXPIRED %d versus %d]", - control.duration(), CurrentTimer()); + LOGE("[SelectContentKey(): KEY_EXPIRED %d versus %d]", control.duration(), + CurrentTimer()); return OEMCrypto_ERROR_KEY_EXPIRED; } } @@ -1131,7 +1326,6 @@ OEMCryptoResult SessionContext::CopyOldUsageEntry( return usage_entry_->CopyOldUsageEntry(pst); } - // Internal utility function to decrypt the message bool SessionContext::DecryptMessage(const std::vector& key, const std::vector& iv, @@ -1151,6 +1345,25 @@ bool SessionContext::DecryptMessage(const std::vector& key, return true; } +bool SessionContext::DecryptEntitlement( + const std::vector& key, + const std::vector& iv, + const std::vector& message, + std::vector* decrypted) { + if (key.empty() || iv.empty() || message.empty() || !decrypted) { + LOGE("[DecryptMessage(): OEMCrypto_ERROR_INVALID_CONTEXT]"); + return false; + } + decrypted->resize(message.size()); + uint8_t iv_buffer[16]; + memcpy(iv_buffer, &iv[0], 16); + AES_KEY aes_key; + AES_set_decrypt_key(&key[0], 256, &aes_key); + AES_cbc_encrypt(&message[0], &(decrypted->front()), message.size(), &aes_key, + iv_buffer, AES_DECRYPT); + return true; +} + OEMCryptoResult SessionContext::DecryptCENC( const uint8_t* iv, size_t block_offset, const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data, diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_session.h b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_session.h index e5cc6b7d..edba1dfa 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_session.h +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_session.h @@ -30,6 +30,34 @@ typedef uint32_t SessionId; enum SRMVersionStatus { NoSRMVersion, ValidSRMVersion, InvalidSRMVersion }; +// TODO(jfore): Is there a better name? +class SessionContextKeys { + public: + virtual OEMCrypto_LicenseType type() = 0; + virtual size_t size() = 0; + virtual bool Insert(const KeyId& key_id, const Key& key_data) = 0; + virtual Key* Find(const KeyId& key_id) = 0; + virtual void Remove(const KeyId& key_id) = 0; + virtual void UpdateDuration(const KeyControlBlock& control) = 0; + + // Methods supported exclusively for entitlement keys. Returns false if + // entitlement keys are not found or not supported by the current key table. + // It is the caller's responsibility to check the context. + virtual bool SetContentKey(const KeyId& entitlement_id, + const KeyId& content_key_id, + const std::vector& content_key) = 0; + virtual bool GetEntitlementKey(const KeyId& entitlement_id, + const std::vector** key) = 0; + + virtual ~SessionContextKeys() {} + + protected: + SessionContextKeys() {} + + private: + CORE_DISALLOW_COPY_AND_ASSIGN(SessionContextKeys); +}; + class SessionContext { private: SessionContext() {} @@ -40,6 +68,7 @@ class SessionContext { ce_(ce), id_(sid), current_content_key_(NULL), + session_keys_(NULL), rsa_key_(rsa_key), allowed_schemes_(kSign_RSASSA_PSS), usage_entry_(NULL), @@ -89,19 +118,22 @@ class SessionContext { size_t signature_length); void StartTimer(); uint32_t CurrentTimer(); // (seconds). - OEMCryptoResult LoadKeys(const uint8_t* message, size_t message_length, - const uint8_t* signature, size_t signature_length, - const uint8_t* enc_mac_key_iv, - const uint8_t* enc_mac_keys, size_t num_keys, - const OEMCrypto_KeyObject* key_array, - const uint8_t* pst, size_t pst_length, - const uint8_t* srm_requirement); + OEMCryptoResult LoadKeys( + const uint8_t* message, size_t message_length, const uint8_t* signature, + size_t signature_length, const uint8_t* enc_mac_key_iv, + const uint8_t* enc_mac_keys, size_t num_keys, + const OEMCrypto_KeyObject* key_array, const uint8_t* pst, + size_t pst_length, const uint8_t* srm_requirement, + OEMCrypto_LicenseType license_type); + OEMCryptoResult LoadEntitledContentKeys( + size_t num_keys, + const OEMCrypto_EntitledContentKeyObject* key_array); OEMCryptoResult InstallKey(const KeyId& key_id, const std::vector& key_data, const std::vector& key_data_iv, const std::vector& key_control, const std::vector& key_control_iv, - bool ctr_mode, bool second_license); + bool second_license); bool InstallRSAEncryptedKey(const uint8_t* encrypted_message_key, size_t encrypted_message_key_length); bool DecryptRSAKey(const uint8_t* enc_rsa_key, size_t enc_rsa_key_length, @@ -115,7 +147,8 @@ class SessionContext { bool UpdateMacKeys(const std::vector& mac_keys, const std::vector& iv); bool QueryKeyControlBlock(const KeyId& key_id, uint32_t* data); - OEMCryptoResult SelectContentKey(const KeyId& key_id); + OEMCryptoResult SelectContentKey(const KeyId& key_id, + OEMCryptoCipherMode cipher_mode); const Key* current_content_key(void) { return current_content_key_; } void set_mac_key_server(const std::vector& mac_key_server) { mac_key_server_ = mac_key_server; @@ -157,6 +190,10 @@ class SessionContext { const std::vector& iv, const std::vector& message, std::vector* decrypted); + bool DecryptEntitlement(const std::vector& key, + const std::vector& iv, + const std::vector& message, + std::vector* decrypted); // Either verify the nonce or usage entry, as required by the key control // block. OEMCryptoResult CheckNonceOrEntry(const KeyControlBlock& key_control_block); @@ -193,7 +230,7 @@ class SessionContext { std::vector encryption_key_; std::vector session_key_; const Key* current_content_key_; - SessionKeyTable session_keys_; + SessionContextKeys* session_keys_; NonceTable nonce_table_; RSA_shared_ptr rsa_key_; uint32_t allowed_schemes_; // for RSA signatures. diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_session_key_table.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_session_key_table.cpp index 35cee58c..5eec8d67 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_session_key_table.cpp +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_session_key_table.cpp @@ -43,4 +43,75 @@ void SessionKeyTable::UpdateDuration(const KeyControlBlock& control) { } } +bool EntitlementKeyTable::Insert(const KeyId key_id, const Key& key_data) { + // |key_id| and |key_data| are for an entitlement key. Insert a new + // entitlement key entry. + if (keys_.find(key_id) != keys_.end()) return false; + keys_[key_id] = new EntitlementKey(key_data); + // If this is a new insertion, we don't have a content key assigned yet. + return true; +} + +Key* EntitlementKeyTable::Find(const KeyId key_id) { + // |key_id| refers to a content key. + ContentIdToEntitlementIdMap::iterator it = + contentid_to_entitlementid_.find(key_id); + if (it == contentid_to_entitlementid_.end()) { + return NULL; + } + + if (keys_.find(it->second) == keys_.end()) { + return NULL; + } + return keys_[it->second]; +} + +void EntitlementKeyTable::Remove(const KeyId key_id) { + // |key_id| refers to a content key. No one currently calls Remove so this + // method is free to change if needed. + ContentIdToEntitlementIdMap::iterator it = + contentid_to_entitlementid_.find(key_id); + if (it == contentid_to_entitlementid_.end()) { + return; + } + keys_.erase(it->second); + contentid_to_entitlementid_.erase(key_id); +} + +void EntitlementKeyTable::UpdateDuration(const KeyControlBlock& control) { + for (EntitlementKeyMap::iterator it = keys_.begin(); it != keys_.end(); + ++it) { + it->second->UpdateDuration(control); + } +} + +bool EntitlementKeyTable::SetContentKey( + const KeyId& entitlement_id, const KeyId& content_key_id, + const std::vector content_key) { + EntitlementKeyMap::iterator it = keys_.find(entitlement_id); + if (it == keys_.end()) { + return false; + } + contentid_to_entitlementid_.erase(it->second->content_key_id()); + if (!it->second->SetContentKey(content_key_id, content_key)) { + return false; + } + contentid_to_entitlementid_[content_key_id] = entitlement_id; + return true; +} + +bool EntitlementKeyTable::GetEntitlementKey( + const KeyId& entitlement_id, + const std::vector** entitlement_key) { + if (!entitlement_key) { + return false; + } + EntitlementKeyMap::iterator it = keys_.find(entitlement_id); + if (it == keys_.end()) { + return false; + } + *entitlement_key = &it->second->entitlement_key(); + return true; +} + } // namespace wvoec_mock diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_session_key_table.h b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_session_key_table.h index 5fb6b371..221db3b6 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_session_key_table.h +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_session_key_table.h @@ -19,8 +19,9 @@ class CryptoEngine; class UsageTable; class UsageTableEntry; -typedef std::vector KeyId; +typedef std::vector KeyId; typedef std::map KeyMap; +typedef std::map EntitlementKeyMap; // SessionKeyTable holds the keys for the current session class SessionKeyTable { @@ -40,6 +41,28 @@ class SessionKeyTable { CORE_DISALLOW_COPY_AND_ASSIGN(SessionKeyTable); }; +class EntitlementKeyTable { + typedef std::map ContentIdToEntitlementIdMap; + + public: + EntitlementKeyTable() {} + ~EntitlementKeyTable() {} + bool Insert(const KeyId key_id, const Key& key_data); + Key* Find(const KeyId key_id); + void Remove(const KeyId key_id); + void UpdateDuration(const KeyControlBlock& control); + size_t size() const { return contentid_to_entitlementid_.size(); } + bool SetContentKey(const KeyId& entitlement_id, const KeyId& content_key_id, + const std::vector content_key); + bool GetEntitlementKey(const KeyId& entitlement_id, + const std::vector** entitlement_key); + + private: + EntitlementKeyMap keys_; + ContentIdToEntitlementIdMap contentid_to_entitlementid_; + CORE_DISALLOW_COPY_AND_ASSIGN(EntitlementKeyTable); +}; + } // namespace wvoec_mock #endif // MOCK_OEMCRYPTO_SESSION_KEY_TABLE_H_ diff --git a/libwvdrmengine/oemcrypto/test/oec_session_util.cpp b/libwvdrmengine/oemcrypto/test/oec_session_util.cpp index aee800c8..9dd26732 100644 --- a/libwvdrmengine/oemcrypto/test/oec_session_util.cpp +++ b/libwvdrmengine/oemcrypto/test/oec_session_util.cpp @@ -227,7 +227,8 @@ void Session::LoadTestKeys(const std::string& pst, bool new_mac_keys) { &signature_[0], signature_.size(), encrypted_license().mac_key_iv, encrypted_license().mac_keys, num_keys_, - key_array_, pst_ptr, pst.length(), NULL)); + key_array_, pst_ptr, pst.length(), NULL, + OEMCrypto_ContentLicense)); // Update new generated keys. memcpy(&mac_key_server_[0], license_.mac_keys, wvcdm::MAC_KEY_SIZE); memcpy(&mac_key_client_[0], license_.mac_keys + wvcdm::MAC_KEY_SIZE, @@ -237,11 +238,113 @@ void Session::LoadTestKeys(const std::string& pst, bool new_mac_keys) { OEMCrypto_SUCCESS, OEMCrypto_LoadKeys(session_id(), message_ptr(), message_size_, &signature_[0], signature_.size(), NULL, NULL, - num_keys_, key_array_, pst_ptr, pst.length(), NULL)); + num_keys_, key_array_, pst_ptr, pst.length(), NULL, + OEMCrypto_ContentLicense)); } VerifyTestKeys(); } +void Session::LoadEnitlementTestKeys(const std::string& pst, + bool new_mac_keys, + OEMCryptoResult expected_sts) { + uint8_t* pst_ptr = NULL; + if (pst.length() > 0) { + pst_ptr = encrypted_license().pst; + } + if (new_mac_keys) { + ASSERT_EQ(expected_sts, + OEMCrypto_LoadKeys(session_id(), message_ptr(), message_size_, + &signature_[0], signature_.size(), + encrypted_license().mac_key_iv, + encrypted_license().mac_keys, num_keys_, + key_array_, pst_ptr, pst.length(), NULL, + OEMCrypto_EntitlementLicense)); + // Update new generated keys. + memcpy(&mac_key_server_[0], license_.mac_keys, wvcdm::MAC_KEY_SIZE); + memcpy(&mac_key_client_[0], license_.mac_keys + wvcdm::MAC_KEY_SIZE, + wvcdm::MAC_KEY_SIZE); + } else { + ASSERT_EQ( + expected_sts, + OEMCrypto_LoadKeys(session_id(), message_ptr(), message_size_, + &signature_[0], signature_.size(), NULL, NULL, + num_keys_, key_array_, pst_ptr, pst.length(), NULL, + OEMCrypto_EntitlementLicense)); + } +} + +void Session::FillEntitledKeyArray() { + for (size_t i = 0; i < num_keys_; ++i) { + EntitledContentKeyData* key_data = &entitled_key_data_[i]; + + entitled_key_array_[i].entitlement_key_id = key_array_[i].key_id; + entitled_key_array_[i].entitlement_key_id_length = + key_array_[i].key_id_length; + + EXPECT_EQ( + 1, GetRandBytes(key_data->content_key_id, + sizeof(key_data->content_key_id))); + entitled_key_array_[i].content_key_id = key_data->content_key_id; + entitled_key_array_[i].content_key_id_length = + sizeof(key_data->content_key_id); + + EXPECT_EQ( + 1, GetRandBytes(key_data->content_key_data, + sizeof(key_data->content_key_data))); + entitled_key_array_[i].content_key_data = key_data->content_key_data; + entitled_key_array_[i].content_key_data_length = + sizeof(key_data->content_key_data); + + EXPECT_EQ( + 1, GetRandBytes(entitled_key_data_[i].content_key_data_iv, + sizeof(entitled_key_data_[i].content_key_data_iv))); + entitled_key_array_[i].content_key_data_iv = key_data->content_key_data_iv; + } +} + +void Session::LoadEntitledContentKeys(OEMCryptoResult expected_sts) { + // Create a copy of the stored |entitled_key_array_|. + std::vector encrypted_entitled_key_array; + encrypted_entitled_key_array.resize(num_keys_); + memcpy(&encrypted_entitled_key_array[0], &entitled_key_array_[0], + sizeof(OEMCrypto_EntitledContentKeyObject) * num_keys_); + + // Create a encrypted version of all of the content keys stored in + // |entitled_key_array_|. + std::vector > encrypted_content_keys; + encrypted_content_keys.resize(num_keys_); + + for (size_t i = 0; i < num_keys_; ++i) { + // Load the entitlement key from |key_array_|. + AES_KEY aes_key; + AES_set_encrypt_key(&key_array_[i].key_data[0], 256, &aes_key); + encrypted_content_keys[i].resize( + encrypted_entitled_key_array[i].content_key_data_length); + + // Encrypt the content key with the entitlement key. + uint8_t iv[16]; + memcpy(&iv[0], &encrypted_entitled_key_array[i].content_key_data[0], 16); + AES_cbc_encrypt( + &entitled_key_array_[i].content_key_data[0], + const_cast( + &encrypted_entitled_key_array[i].content_key_data[0]), + encrypted_entitled_key_array[i].content_key_data_length, + &aes_key, iv, AES_ENCRYPT); + + // Set the |encrypted_entitled_key_array| to point to the encrypted copy + // of the content key. + encrypted_entitled_key_array[i].content_key_data = + encrypted_content_keys[i].data(); + } + ASSERT_EQ(expected_sts, + OEMCrypto_LoadEntitledContentKeys( + session_id(), num_keys_, &encrypted_entitled_key_array[0])); + if (expected_sts != OEMCrypto_SUCCESS) { + return; + } + VerifyEntitlementTestKeys(); +} + void Session::VerifyTestKeys() { for (unsigned int i = 0; i < num_keys_; i++) { KeyControlBlock block; @@ -264,6 +367,29 @@ void Session::VerifyTestKeys() { } } +void Session::VerifyEntitlementTestKeys() { + for (unsigned int i = 0; i < num_keys_; i++) { + KeyControlBlock block; + size_t size = sizeof(block); + OEMCryptoResult sts = OEMCrypto_QueryKeyControl( + session_id(), entitled_key_array_[i].content_key_id, + entitled_key_array_[i].content_key_id_length, + reinterpret_cast(&block), &size); + if (sts != OEMCrypto_ERROR_NOT_IMPLEMENTED) { + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + ASSERT_EQ(sizeof(block), size); + // control duration and bits stored in network byte order. For printing + // we change to host byte order. + ASSERT_EQ((htonl_fnc(license_.keys[i].control.duration)), + (htonl_fnc(block.duration))) + << "For key " << i; + ASSERT_EQ(htonl_fnc(license_.keys[i].control.control_bits), + htonl_fnc(block.control_bits)) + << "For key " << i; + } + } +} + void Session::RefreshTestKeys(const size_t key_count, uint32_t control_bits, uint32_t nonce, OEMCryptoResult expected_result) { // Note: we store the message in encrypted_license_, but the refresh key @@ -319,7 +445,57 @@ void Session::FillSimpleMessage(uint32_t duration, uint32_t control, sizeof(license_.keys[i].key_iv))); EXPECT_EQ(1, GetRandBytes(license_.keys[i].control_iv, sizeof(license_.keys[i].control_iv))); - if (global_features.api_version == 13) { + if (global_features.api_version == 14) { + // For version 14, we require OEMCrypto to handle kc14 for all licenses. + memcpy(license_.keys[i].control.verification, "kc14", 4); + } else if (global_features.api_version == 13) { + // For version 13, we require OEMCrypto to handle kc13 for all licenses. + memcpy(license_.keys[i].control.verification, "kc13", 4); + } else if (global_features.api_version == 12) { + // For version 12, we require OEMCrypto to handle kc12 for all licenses. + memcpy(license_.keys[i].control.verification, "kc12", 4); + } else if (control & wvoec_mock::kControlSecurityPatchLevelMask) { + // For versions before 12, we require the special key control block only + // when there are newer features present. + memcpy(license_.keys[i].control.verification, "kc11", 4); + } else if (control & wvoec_mock::kControlRequireAntiRollbackHardware) { + memcpy(license_.keys[i].control.verification, "kc10", 4); + } else if (control & (wvoec_mock::kControlHDCPVersionMask | + wvoec_mock::kControlReplayMask)) { + memcpy(license_.keys[i].control.verification, "kc09", 4); + } else { + memcpy(license_.keys[i].control.verification, "kctl", 4); + } + license_.keys[i].control.duration = htonl(duration); + license_.keys[i].control.nonce = htonl(nonce); + license_.keys[i].control.control_bits = htonl(control); + license_.keys[i].cipher_mode = OEMCrypto_CipherMode_CTR; + } + memcpy(license_.pst, pst.c_str(), min(sizeof(license_.pst), pst.length())); + pst_ = pst; +} + +void Session::FillSimpleEntitlementMessage( + uint32_t duration, uint32_t control, uint32_t nonce, + const std::string& pst) { + EXPECT_EQ( + 1, GetRandBytes(license_.mac_key_iv, sizeof(license_.mac_key_iv))); + EXPECT_EQ(1, GetRandBytes(license_.mac_keys, sizeof(license_.mac_keys))); + for (unsigned int i = 0; i < num_keys_; i++) { + memset(license_.keys[i].key_id, 0, kTestKeyIdMaxLength); + license_.keys[i].key_id_length = kDefaultKeyIdLength; + memset(license_.keys[i].key_id, i, license_.keys[i].key_id_length); + EXPECT_EQ(1, GetRandBytes(license_.keys[i].key_data, + sizeof(license_.keys[i].key_data))); + license_.keys[i].key_data_length = wvcdm::KEY_SIZE * 2; // AES-256 keys + EXPECT_EQ(1, GetRandBytes(license_.keys[i].key_iv, + sizeof(license_.keys[i].key_iv))); + EXPECT_EQ(1, GetRandBytes(license_.keys[i].control_iv, + sizeof(license_.keys[i].control_iv))); + if (global_features.api_version == 14) { + // For version 13, we require OEMCrypto to handle kc14 for all licenses. + memcpy(license_.keys[i].control.verification, "kc14", 4); + } else if (global_features.api_version == 13) { // For version 13, we require OEMCrypto to handle kc13 for all licenses. memcpy(license_.keys[i].control.verification, "kc13", 4); } else if (global_features.api_version == 12) { @@ -464,7 +640,6 @@ void Session::FillKeyArray(const MessageData& data, key_array[i].key_control_iv = data.keys[i].control_iv; key_array[i].key_control = reinterpret_cast(&data.keys[i].control); - key_array[i].cipher_mode = data.keys[i].cipher_mode; } } @@ -514,7 +689,8 @@ void Session::TestDecryptCTR(bool select_key_first, if (select_key_first) { // Select the key (from FillSimpleMessage) sts = OEMCrypto_SelectKey(session_id(), license_.keys[key_index].key_id, - license_.keys[key_index].key_id_length); + license_.keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR); ASSERT_EQ(OEMCrypto_SUCCESS, sts); } @@ -578,7 +754,8 @@ void Session::TestSelectExpired(unsigned int key_index) { if (global_features.api_version >= 13) { OEMCryptoResult status = OEMCrypto_SelectKey(session_id(), license().keys[key_index].key_id, - license().keys[key_index].key_id_length); + license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR); // It is OK for SelectKey to succeed with an expired key, but if there is // an error, it must be OEMCrypto_ERROR_KEY_EXIRED. if (status != OEMCrypto_SUCCESS) { diff --git a/libwvdrmengine/oemcrypto/test/oec_session_util.h b/libwvdrmengine/oemcrypto/test/oec_session_util.h index 985b8bba..eb732b83 100644 --- a/libwvdrmengine/oemcrypto/test/oec_session_util.h +++ b/libwvdrmengine/oemcrypto/test/oec_session_util.h @@ -103,6 +103,13 @@ struct Test_PST_Report { std::string pst; }; +struct EntitledContentKeyData { + uint8_t entitlement_key_id[wvcdm::KEY_SIZE]; + uint8_t content_key_id[wvcdm::KEY_SIZE]; + uint8_t content_key_data_iv[wvcdm::KEY_SIZE]; + uint8_t content_key_data[wvcdm::KEY_SIZE]; +}; + // Increment counter for AES-CTR. The CENC spec specifies we increment only // the low 64 bits of the IV counter, and leave the high 64 bits alone. This // is different from the OpenSSL implementation, so we implement the CTR loop @@ -151,9 +158,27 @@ class Session { // by FillSimpleMessage, modified if needed, and then encrypted and signed by // the server's mac key in EncryptAndSign. void LoadTestKeys(const std::string& pst = "", bool new_mac_keys = true); + // Loads the entitlement keys in the message pointed to by message_ptr() + // using OEMCrypto_LoadKeys. This message should have already been created + // by FillSimpleEntitlementMessage, modified if needed, and then encrypted + // and signed by the server's mac key in EncryptAndSign. + void LoadEnitlementTestKeys(const std::string& pst = "", + bool new_mac_keys = true, + OEMCryptoResult expected_sts = OEMCrypto_SUCCESS); + // Fills an OEMCrypto_EntitledContentKeyObject using the information from + // the license_ and randomly generated content keys. This method should be + // called after LoadEnitlementTestKeys. + void FillEntitledKeyArray(); + // Encrypts and loads the entitled content keys via + // OEMCrypto_LoadEntitledContentKeys. + void LoadEntitledContentKeys( + OEMCryptoResult expected_sts = OEMCrypto_SUCCESS); // This uses OEMCrypto_QueryKeyControl to check that the keys in OEMCrypto // have the correct key control data. void VerifyTestKeys(); + // This uses OEMCrypto_QueryKeyControl to check that the keys in OEMCrypto + // have the correct key control data. + void VerifyEntitlementTestKeys(); // This creates a refresh key or license renewal message, signs it with the // server's mac key, and calls OEMCrypto_RefreshKeys. void RefreshTestKeys(const size_t key_count, uint32_t control_bits, @@ -166,6 +191,12 @@ class Session { // before being loaded in LoadTestKeys. void FillSimpleMessage(uint32_t duration, uint32_t control, uint32_t nonce, const std::string& pst = ""); + // This fills the data structure license_ with entitlement key information. + // This data can be modified, and then should be encrypted and signed in + // EncryptAndSign before being loaded in LoadEnitlementTestKeys. + void FillSimpleEntitlementMessage( + uint32_t duration, uint32_t control, + uint32_t nonce, const std::string& pst = ""); // Like FillSimpleMessage, this fills encrypted_license_ with data. The name // is a little misleading: the license renewal message is not encrypted, it // is just signed. The signature is computed in RefreshTestKeys, above. @@ -360,6 +391,12 @@ class Session { vector encrypted_usage_entry_; uint32_t usage_entry_number_; string pst_; + + // Clear Entitlement key data. This is the backing data for + // |entitled_key_array_|. + EntitledContentKeyData entitled_key_data_[kMaxNumKeys]; + // Entitled key object. Pointers are backed by |entitled_key_data_|. + OEMCrypto_EntitledContentKeyObject entitled_key_array_[kMaxNumKeys]; }; } // namespace wvoec diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp index c83344f6..6e40c2ed 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp @@ -835,6 +835,29 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithNoMAC) { ASSERT_EQ(expected_signature, signature); } +TEST_F(OEMCryptoSessionTests, LoadEntitlementKeys) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); + ASSERT_NO_FATAL_FAILURE(s.FillSimpleEntitlementMessage(0, 0, 0)); + ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); + ASSERT_NO_FATAL_FAILURE(s.LoadEnitlementTestKeys()); + s.FillEntitledKeyArray(); + ASSERT_NO_FATAL_FAILURE(s.LoadEntitledContentKeys()); + s.FillEntitledKeyArray(); + ASSERT_NO_FATAL_FAILURE(s.LoadEntitledContentKeys()); +} + +TEST_F(OEMCryptoSessionTests, LoadEntitlementKeysNoEntitlementKeys) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); + ASSERT_NO_FATAL_FAILURE(s.FillSimpleEntitlementMessage(0, 0, 0)); + ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); + s.FillEntitledKeyArray(); + s.LoadEntitledContentKeys(OEMCrypto_ERROR_INVALID_CONTEXT); +} + // This tests GenerateSignature with an 8k licnese request. TEST_F(OEMCryptoSessionTests, ClientSignatureLargeBuffer) { Session s; @@ -894,7 +917,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange1) { s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, &mac_keys[0], // Not pointing into buffer. - s.num_keys(), s.key_array(), NULL, 0, NULL); + s.num_keys(), s.key_array(), NULL, 0, NULL, OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -913,7 +936,8 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange2) { &s.signature()[0], s.signature().size(), &mac_key_iv[0], // bad. s.encrypted_license().mac_keys, s.num_keys(), - s.key_array(), NULL, 0, NULL); + s.key_array(), NULL, 0, NULL, + OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -932,7 +956,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange3) { s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL); + NULL, OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -952,7 +976,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange4) { s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL); + NULL, OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -970,7 +994,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange5) { s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL); + NULL, OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -990,7 +1014,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange6) { s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL); + NULL, OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -1010,7 +1034,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange7) { s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL); + NULL, OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -1026,7 +1050,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadNonce) { s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL); + NULL, OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -1052,7 +1076,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithRepeatNonce) { s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL); + NULL, OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -1068,7 +1092,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadVerification) { s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL); + NULL, OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -1104,7 +1128,7 @@ TEST_P(SessionTestAlternateVerification, LoadKeys) { s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL); + NULL, OEMCrypto_ContentLicense); // If this is a future API, then LoadKeys should fail. if (global_features.api_version < target_api_) { ASSERT_NE(OEMCrypto_SUCCESS, sts); @@ -1132,7 +1156,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeysBadSignature) { s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL); + NULL, OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -1146,7 +1170,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeysWithNoDerivedKeys) { s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL); + NULL, OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -1163,7 +1187,8 @@ TEST_F(OEMCryptoSessionTests, LoadKeyNoKeys) { OEMCrypto_SUCCESS, OEMCrypto_LoadKeys(s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), NULL, NULL, - kNoKeys, s.key_array(), NULL, 0, NULL)); + kNoKeys, s.key_array(), NULL, 0, NULL, + OEMCrypto_ContentLicense)); } TEST_F(OEMCryptoSessionTests, LoadKeyNoKeyWithNonce) { @@ -1178,7 +1203,8 @@ TEST_F(OEMCryptoSessionTests, LoadKeyNoKeyWithNonce) { OEMCrypto_SUCCESS, OEMCrypto_LoadKeys(s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), NULL, NULL, - kNoKeys, s.key_array(), NULL, 0, NULL)); + kNoKeys, s.key_array(), NULL, 0, NULL, + OEMCrypto_ContentLicense)); } TEST_F(OEMCryptoSessionTests, QueryKeyControl) { @@ -1219,7 +1245,7 @@ TEST_F(OEMCryptoSessionTests, AntiRollbackHardwareRequired) { s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL); + NULL, OEMCrypto_ContentLicense); if (OEMCrypto_IsAntiRollbackHwPresent()) { ASSERT_EQ(OEMCrypto_SUCCESS, sts); } else { @@ -1243,7 +1269,8 @@ TEST_F(OEMCryptoSessionTests, CheckMinimumPatchLevel) { &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), - s.key_array(), NULL, 0, NULL)); + s.key_array(), NULL, 0, NULL, + OEMCrypto_ContentLicense)); } if (patch_level < 0x3F) { Session s; @@ -1259,7 +1286,8 @@ TEST_F(OEMCryptoSessionTests, CheckMinimumPatchLevel) { &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), - s.key_array(), NULL, 0, NULL)); + s.key_array(), NULL, 0, NULL, + OEMCrypto_ContentLicense)); } if (patch_level > 0) { Session s; @@ -1275,7 +1303,8 @@ TEST_F(OEMCryptoSessionTests, CheckMinimumPatchLevel) { &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), - s.key_array(), NULL, 0, NULL)); + s.key_array(), NULL, 0, NULL, + OEMCrypto_ContentLicense)); } } @@ -1687,7 +1716,8 @@ class OEMCryptoSessionTestsDecryptTests ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys()); sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[0].key_id, - s.license().keys[0].key_id_length); + s.license().keys[0].key_id_length, + cipher_mode_); ASSERT_EQ(OEMCrypto_SUCCESS, sts); // We decrypt each subsample. @@ -2016,7 +2046,7 @@ INSTANTIATE_TEST_CASE_P(CTRTests, OEMCryptoSessionTestsPartialBlockTests, // Decrypt in place for CBC tests was only required in v13. INSTANTIATE_TEST_CASE_P( - CBCTestsAPI13, OEMCryptoSessionTestsPartialBlockTests, + CBCTestsAPI14, OEMCryptoSessionTestsPartialBlockTests, Combine( Values(MakePattern(0, 0), MakePattern(3, 7), @@ -2039,7 +2069,7 @@ INSTANTIATE_TEST_CASE_P( // Decrypt in place for CBC tests was only required in v13. INSTANTIATE_TEST_CASE_P( - CBCTestsAPI13, OEMCryptoSessionTestsDecryptTests, + CBCTestsAPI14, OEMCryptoSessionTestsDecryptTests, Combine( Values(MakePattern(0, 0), MakePattern(3, 7), @@ -3783,7 +3813,8 @@ class GenericCryptoTest : public OEMCryptoSessionTests { EncryptBuffer(key_index, clear_buffer_, &expected_encrypted); sts = OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector encrypted(buffer_length); sts = @@ -3801,7 +3832,8 @@ class GenericCryptoTest : public OEMCryptoSessionTests { EncryptBuffer(key_index, clear_buffer_, &encrypted); sts = OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector resultant(encrypted.size()); sts = @@ -3818,7 +3850,8 @@ class GenericCryptoTest : public OEMCryptoSessionTests { sts = OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR); ASSERT_EQ(OEMCrypto_SUCCESS, sts); size_t signature_length = (size_t)SHA256_DIGEST_LENGTH; vector signature(SHA256_DIGEST_LENGTH); @@ -3840,7 +3873,8 @@ class GenericCryptoTest : public OEMCryptoSessionTests { sts = OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR); ASSERT_EQ(OEMCrypto_SUCCESS, sts); sts = OEMCrypto_Generic_Verify(session_.session_id(), &clear_buffer_[0], clear_buffer_.size(), algorithm, @@ -3867,7 +3901,8 @@ TEST_F(GenericCryptoTest, GenericKeyEncrypt) { OEMCrypto_SUCCESS, OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length)); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); vector encrypted(clear_buffer_.size()); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Generic_Encrypt( @@ -3895,7 +3930,8 @@ TEST_F(GenericCryptoTest, GenericKeyEncryptSameBufferAPI12) { OEMCrypto_SUCCESS, OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length)); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); // Input and output are same buffer: vector buffer = clear_buffer_; ASSERT_EQ(OEMCrypto_SUCCESS, @@ -3914,7 +3950,8 @@ TEST_F(GenericCryptoTest, GenericKeyDecrypt) { OEMCrypto_SUCCESS, OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length)); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); vector resultant(encrypted.size()); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Generic_Decrypt( @@ -3932,7 +3969,8 @@ TEST_F(GenericCryptoTest, GenericKeyDecryptSameBufferAPI12) { OEMCrypto_SUCCESS, OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length)); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); vector buffer = encrypted; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Generic_Decrypt( @@ -3952,7 +3990,8 @@ TEST_F(GenericCryptoTest, GenericSecureToClear) { OEMCrypto_SUCCESS, OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length)); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); vector resultant(encrypted.size()); ASSERT_NE(OEMCrypto_SUCCESS, OEMCrypto_Generic_Decrypt( @@ -3981,7 +4020,8 @@ TEST_F(GenericCryptoTest, GenericKeySign) { OEMCrypto_SUCCESS, OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length)); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); size_t gen_signature_length = 0; ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, OEMCrypto_Generic_Sign(session_.session_id(), &clear_buffer_[0], @@ -4014,7 +4054,8 @@ TEST_F(GenericCryptoTest, GenericKeyVerify) { OEMCrypto_SUCCESS, OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length)); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Generic_Verify( session_.session_id(), &clear_buffer_[0], clear_buffer_.size(), @@ -4042,7 +4083,8 @@ TEST_F(GenericCryptoTest, GenericKeyEncryptLargeBuffer) { OEMCrypto_SUCCESS, OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length)); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); vector encrypted(clear_buffer_.size()); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Generic_Encrypt( @@ -4062,7 +4104,8 @@ TEST_F(GenericCryptoTest, GenericKeyDecryptLargeBuffer) { OEMCrypto_SUCCESS, OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length)); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); vector resultant(encrypted.size()); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Generic_Decrypt( @@ -4082,7 +4125,8 @@ TEST_F(GenericCryptoTest, GenericKeySignLargeBuffer) { OEMCrypto_SUCCESS, OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length)); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); size_t gen_signature_length = 0; ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, OEMCrypto_Generic_Sign(session_.session_id(), &clear_buffer_[0], @@ -4108,7 +4152,8 @@ TEST_F(GenericCryptoTest, GenericKeyVerifyLargeBuffer) { OEMCrypto_SUCCESS, OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length)); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Generic_Verify( session_.session_id(), &clear_buffer_[0], clear_buffer_.size(), @@ -4128,7 +4173,8 @@ TEST_F(GenericCryptoTest, KeyDurationEncrypt) { OEMCrypto_SUCCESS, OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length)); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Generic_Encrypt( session_.session_id(), &clear_buffer_[0], clear_buffer_.size(), @@ -4157,7 +4203,8 @@ TEST_F(GenericCryptoTest, KeyDurationDecrypt) { OEMCrypto_SUCCESS, OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length)); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); sleep(kShortSleep); // Should still be valid key. @@ -4193,7 +4240,8 @@ TEST_F(GenericCryptoTest, KeyDurationSign) { OEMCrypto_SUCCESS, OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length)); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); sleep(kShortSleep); // Should still be valid key. @@ -4226,7 +4274,8 @@ TEST_F(GenericCryptoTest, KeyDurationVerify) { OEMCrypto_SUCCESS, OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length)); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); sleep(kShortSleep); // Should still be valid key. @@ -4292,7 +4341,8 @@ class GenericCryptoKeyIdLengthTest : public GenericCryptoTest { ASSERT_EQ( OEMCrypto_SUCCESS, OEMCrypto_SelectKey(session_.session_id(), key_id_buffer.data(), - session_.license().keys[key_index].key_id_length)); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); vector resultant(encrypted.size()); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Generic_Decrypt( @@ -4500,7 +4550,8 @@ TEST_F(UsageTableTest, RepeatOnlineLicense) { &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), - s.key_array(), pst_ptr, pst.length(), NULL)); + s.key_array(), pst_ptr, pst.length(), NULL, + OEMCrypto_ContentLicense)); ASSERT_NO_FATAL_FAILURE(s2.close()); } @@ -4518,7 +4569,7 @@ TEST_F(UsageTableTest, OnlineEmptyPST) { s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL); + NULL, OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); ASSERT_NO_FATAL_FAILURE(s.close()); } @@ -4538,7 +4589,7 @@ TEST_F(UsageTableTest, OnlineMissingEntry) { s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), - s.encrypted_license().pst, pst.length(), NULL); + s.encrypted_license().pst, pst.length(), NULL, OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); ASSERT_NO_FATAL_FAILURE(s.close()); } @@ -4617,7 +4668,8 @@ TEST_P(UsageTableTestWithMAC, GenericCryptoEncrypt) { EncryptBuffer(key_index, clear_buffer_, &expected_encrypted); sts = OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector encrypted(clear_buffer_.size()); sts = OEMCrypto_Generic_Encrypt( @@ -4653,7 +4705,8 @@ TEST_P(UsageTableTestWithMAC, GenericCryptoDecrypt) { EncryptBuffer(key_index, clear_buffer_, &encrypted); sts = OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector resultant(encrypted.size()); sts = OEMCrypto_Generic_Decrypt( @@ -4692,7 +4745,8 @@ TEST_P(UsageTableTestWithMAC, GenericCryptoSign) { sts = OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR); ASSERT_EQ(OEMCrypto_SUCCESS, sts); size_t gen_signature_length = 0; sts = OEMCrypto_Generic_Sign(session_.session_id(), &clear_buffer_[0], @@ -4738,7 +4792,8 @@ TEST_P(UsageTableTestWithMAC, GenericCryptoVerify) { sts = OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length); + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR); ASSERT_EQ(OEMCrypto_SUCCESS, sts); sts = OEMCrypto_Generic_Verify(session_.session_id(), &clear_buffer_[0], clear_buffer_.size(), OEMCrypto_HMAC_SHA256, @@ -4885,7 +4940,8 @@ TEST_P(UsageTableTestWithMAC, BadReloadOfflineLicense) { &s2.signature()[0], s2.signature().size(), s2.encrypted_license().mac_key_iv, s2.encrypted_license().mac_keys, s.num_keys(), - s2.key_array(), pst_ptr, pst.length(), NULL)); + s2.key_array(), pst_ptr, pst.length(), NULL, + OEMCrypto_ContentLicense)); ASSERT_NO_FATAL_FAILURE(s2.close()); // Offline license with same mac keys should still be OK. @@ -4912,7 +4968,7 @@ TEST_P(UsageTableTestWithMAC, OfflineBadNonce) { s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), pst_ptr, - pst.length(), NULL); + pst.length(), NULL, OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); ASSERT_NO_FATAL_FAILURE(s.close()); } @@ -4930,7 +4986,7 @@ TEST_P(UsageTableTestWithMAC, OfflineEmptyPST) { s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0, - NULL); + NULL, OEMCrypto_ContentLicense); ASSERT_NE(OEMCrypto_SUCCESS, sts); ASSERT_NO_FATAL_FAILURE(s.close()); } @@ -4952,7 +5008,8 @@ TEST_P(UsageTableTestWithMAC, ReloadOfflineWrongPST) { OEMCrypto_LoadKeys(s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], s.signature().size(), NULL, NULL, s.num_keys(), s.key_array(), - pst_ptr, bad_pst.length(), NULL)); + pst_ptr, bad_pst.length(), NULL, + OEMCrypto_ContentLicense)); } TEST_P(UsageTableTestWithMAC, DeactivateOfflineLicense) { @@ -4986,7 +5043,8 @@ TEST_P(UsageTableTestWithMAC, DeactivateOfflineLicense) { &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), - s.key_array(), pst_ptr, pst.length(), NULL)); + s.key_array(), pst_ptr, pst.length(), NULL, + OEMCrypto_ContentLicense)); s2.close(); // But we can still generate a report. Session s3; @@ -5013,7 +5071,8 @@ TEST_P(UsageTableTestWithMAC, BadRange) { &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), - s.key_array(), pst_ptr, pst.length(), NULL)); + s.key_array(), pst_ptr, pst.length(), NULL, + OEMCrypto_ContentLicense)); } TEST_F(UsageTableTest, UpdateFailsWithNullPtr) { @@ -5090,7 +5149,8 @@ class UsageTableDefragTest : public UsageTableTest { &s->signature()[0], s->signature().size(), s->encrypted_license().mac_key_iv, s->encrypted_license().mac_keys, s->num_keys(), - s->key_array(), pst_ptr, s->pst().length(), NULL)); + s->key_array(), pst_ptr, s->pst().length(), NULL, + OEMCrypto_ContentLicense)); ASSERT_NO_FATAL_FAILURE(s->close()); } @@ -5212,6 +5272,7 @@ TEST_F(UsageTableDefragTest, ReloadUsageEntryBadData) { ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); vector data = s.encrypted_usage_entry(); + ASSERT_LT(0, data.size()); data[0] ^= 42; // Error could be signature or verification error. ASSERT_NE(OEMCrypto_SUCCESS, @@ -5607,7 +5668,8 @@ TEST_F(UsageTableTest, LoadSharedLicenseWithNoMaster) { &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, - s.num_keys(), s.key_array(), pst_ptr, pst.length(), NULL)); + s.num_keys(), s.key_array(), pst_ptr, pst.length(), NULL, + OEMCrypto_ContentLicense)); ASSERT_NO_FATAL_FAILURE(s.close()); } @@ -5642,7 +5704,8 @@ TEST_F(UsageTableTest, PSTLargeBuffer) { &s.signature()[0], s.signature().size(), s.encrypted_license().mac_key_iv, s.encrypted_license().mac_keys, s.num_keys(), - s.key_array(), pst_ptr, pst.length(), NULL)); + s.key_array(), pst_ptr, pst.length(), NULL, + OEMCrypto_ContentLicense)); s2.close(); // But we can still generate a report. Session s3;