Refactor key sessions to move them out of crypto session.

Merge from Widevine repo of http://go/wvgerrit/41833

Bug: 64003606
Test: in child CL

Change-Id: I3e1d36d0b0944dce0fb1515257bc15243d76f397
This commit is contained in:
Fred Gylys-Colwell
2018-01-25 15:27:00 -08:00
committed by Rahul Frias
parent 8de7caf788
commit 8251aab9f6
8 changed files with 751 additions and 631 deletions

View File

@@ -32,6 +32,7 @@ LOCAL_SRC_FILES := \
$(CORE_SRC_DIR)/cdm_session_map.cpp \
$(CORE_SRC_DIR)/certificate_provisioning.cpp \
$(CORE_SRC_DIR)/client_identification.cpp \
$(CORE_SRC_DIR)/content_key_session.cpp \
$(CORE_SRC_DIR)/crypto_session.cpp \
$(CORE_SRC_DIR)/device_files.cpp \
$(CORE_SRC_DIR)/initialization_data.cpp \
@@ -41,6 +42,7 @@ LOCAL_SRC_FILES := \
$(CORE_SRC_DIR)/policy_engine.cpp \
$(CORE_SRC_DIR)/privacy_crypto_boringssl.cpp \
$(CORE_SRC_DIR)/service_certificate.cpp \
$(CORE_SRC_DIR)/sublicense_key_session.cpp \
$(CORE_SRC_DIR)/usage_table_header.cpp \
$(SRC_DIR)/wv_content_decryption_module.cpp \
$(METRICS_SRC_DIR)/counter_metric.cpp \

View File

@@ -0,0 +1,51 @@
#ifndef WVCDM_CORE_CONTENT_KEY_SESSSION_H_
#define WVCDM_CORE_CONTENT_KEY_SESSSION_H_
#include "key_session.h"
#include "timer_metric.h"
namespace wvcdm {
class DefaultKeySession : public KeySession {
public:
DefaultKeySession(CryptoSessionId oec_session_id,
metrics::CryptoMetrics* metrics)
: KeySession(metrics), oec_session_id_(oec_session_id) {}
virtual ~DefaultKeySession() {}
KeySessionType Type() { return kDefault; }
// Generate Derived Keys for DefaultKeySession
bool GenerateDerivedKeys(const std::string& message);
// Generate Derived Keys (from session key) for DefaultKeySession
bool GenerateDerivedKeys(const std::string& message,
const std::string& session_key);
// Load Keys for DefaultKeySession
OEMCryptoResult LoadKeys(const std::string& message,
const std::string& signature,
const std::string& mac_key_iv,
const std::string& mac_key,
const std::vector<CryptoKey>& keys,
const std::string& provider_session_token,
CdmCipherMode* cipher_mode,
const std::string& srm_requirement);
// Select Key for DefaultKeySession
OEMCryptoResult SelectKey(const std::string& key_id,
CdmCipherMode cipher_mode);
// Decrypt for DefaultKeySession
OEMCryptoResult Decrypt(const CdmDecryptionParameters& params,
OEMCrypto_DestBufferDesc& buffer_descriptor,
OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor);
private:
CryptoSessionId oec_session_id_;
KeyId cached_key_id_;
};
} // namespace wvcdm
#endif // WVCDM_CORE_CONTENT_KEY_SESSSION_H_

View File

@@ -8,6 +8,7 @@
#include <vector>
#include "OEMCryptoCENC.h"
#include "key_session.h"
#include "lock.h"
#include "metrics_collections.h"
#include "oemcrypto_adapter.h"
@@ -22,37 +23,13 @@ class CryptoKey;
class UsageTableHeader;
typedef std::map<std::string, CryptoKey*> CryptoKeyMap;
typedef std::map<std::string, CryptoSessionId> SubLicenseSessionMap;
class KeySession {
protected:
KeySession(metrics::CryptoMetrics* metrics) : metrics_(metrics) {}
public:
typedef enum { kDefault, kSubLicense } KeySessionType;
virtual ~KeySession() {}
virtual KeySessionType Type() = 0;
virtual bool GenerateDerivedKeys(const std::string& message) = 0;
virtual bool GenerateDerivedKeys(const std::string& message,
const std::string& session_key) = 0;
virtual OEMCryptoResult LoadKeys(const std::string& message,
const std::string& signature,
const std::string& mac_key_iv,
const std::string& mac_key,
const std::vector<CryptoKey>& keys,
const std::string& provider_session_token,
CdmCipherMode* cipher_mode,
const std::string& srm_requirement) = 0;
virtual OEMCryptoResult SelectKey(const std::string& key_id,
CdmCipherMode cipher_mode) = 0;
virtual OEMCryptoResult Decrypt(
const CdmDecryptionParameters& params,
OEMCrypto_DestBufferDesc& buffer_descriptor,
OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor) = 0;
protected:
metrics::CryptoMetrics* metrics_;
};
// Crypto session utility functions used by KeySession implementations.
void GenerateMacContext(const std::string& input_context,
std::string* deriv_context);
void GenerateEncryptContext(const std::string& input_context,
std::string* deriv_context);
size_t GetOffset(std::string message, std::string field);
class CryptoSession {
public:

View File

@@ -0,0 +1,44 @@
#ifndef WVCDM_CORE_KEY_SESSSION_H_
#define WVCDM_CORE_KEY_SESSSION_H_
#include "metrics_collections.h"
namespace wvcdm {
class CryptoKey;
class KeySession {
protected:
KeySession(metrics::CryptoMetrics* metrics) : metrics_(metrics) {}
public:
typedef enum { kDefault, kSubLicense } KeySessionType;
virtual ~KeySession() {}
virtual KeySessionType Type() = 0;
virtual bool GenerateDerivedKeys(const std::string& message) = 0;
virtual bool GenerateDerivedKeys(const std::string& message,
const std::string& session_key) = 0;
virtual OEMCryptoResult LoadKeys(const std::string& message,
const std::string& signature,
const std::string& mac_key_iv,
const std::string& mac_key,
const std::vector<CryptoKey>& keys,
const std::string& provider_session_token,
CdmCipherMode* cipher_mode,
const std::string& srm_requirement) = 0;
virtual OEMCryptoResult SelectKey(const std::string& key_id,
CdmCipherMode cipher_mode) = 0;
virtual OEMCryptoResult Decrypt(
const CdmDecryptionParameters& params,
OEMCrypto_DestBufferDesc& buffer_descriptor,
OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor) = 0;
protected:
metrics::CryptoMetrics* metrics_;
};
typedef std::map<std::string, CryptoSessionId> SubLicenseSessionMap;
} // namespace wvcdm
#endif // WVCDM_CORE_KEY_SESSSION_H_

View File

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

View File

@@ -0,0 +1,163 @@
#include "content_key_session.h"
#include "crypto_key.h"
#include "crypto_session.h"
#include "log.h"
#include "wv_cdm_constants.h"
namespace wvcdm {
// Generate Derived Keys for DefaultKeySession
bool DefaultKeySession::GenerateDerivedKeys(const std::string& message) {
std::string mac_deriv_message;
std::string enc_deriv_message;
GenerateMacContext(message, &mac_deriv_message);
GenerateEncryptContext(message, &enc_deriv_message);
LOGV("GenerateDerivedKeys: id=%ld", (uint32_t)oec_session_id_);
OEMCryptoResult sts;
M_TIME(sts = OEMCrypto_GenerateDerivedKeys(
oec_session_id_,
reinterpret_cast<const uint8_t*>(mac_deriv_message.data()),
mac_deriv_message.size(),
reinterpret_cast<const uint8_t*>(enc_deriv_message.data()),
enc_deriv_message.size()),
metrics_, oemcrypto_generate_derived_keys_, sts);
if (OEMCrypto_SUCCESS != sts) {
LOGE("GenerateDerivedKeys: OEMCrypto_GenerateDerivedKeys error=%d", sts);
return false;
}
return true;
}
// Generate Derived Keys (from session key) for DefaultKeySession
bool DefaultKeySession::GenerateDerivedKeys(const std::string& message,
const std::string& session_key) {
std::string mac_deriv_message;
std::string enc_deriv_message;
GenerateMacContext(message, &mac_deriv_message);
GenerateEncryptContext(message, &enc_deriv_message);
LOGV("GenerateDerivedKeys: id=%ld", (uint32_t)oec_session_id_);
OEMCryptoResult sts;
M_TIME(
sts = OEMCrypto_DeriveKeysFromSessionKey(
oec_session_id_, reinterpret_cast<const uint8_t*>(session_key.data()),
session_key.size(),
reinterpret_cast<const uint8_t*>(mac_deriv_message.data()),
mac_deriv_message.size(),
reinterpret_cast<const uint8_t*>(enc_deriv_message.data()),
enc_deriv_message.size()),
metrics_, oemcrypto_derive_keys_from_session_key_, sts);
if (OEMCrypto_SUCCESS != sts) {
LOGE("GenerateDerivedKeys: OEMCrypto_DeriveKeysFromSessionKey err=%d", sts);
return false;
}
return true;
}
// Load Keys for DefaultKeySession
OEMCryptoResult DefaultKeySession::LoadKeys(
const std::string& message, const std::string& signature,
const std::string& mac_key_iv, const std::string& mac_key,
const std::vector<CryptoKey>& keys,
const std::string& provider_session_token, CdmCipherMode* cipher_mode,
const std::string& srm_requirement) {
const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data());
const uint8_t* enc_mac_key = NULL;
const uint8_t* enc_mac_key_iv = NULL;
if (mac_key.size() >= MAC_KEY_SIZE && mac_key_iv.size() >= KEY_IV_SIZE) {
enc_mac_key = msg + GetOffset(message, mac_key);
enc_mac_key_iv = msg + GetOffset(message, mac_key_iv);
} else {
LOGV("DefaultKeySession::LoadKeys: enc_mac_key not set");
}
std::vector<OEMCrypto_KeyObject> load_keys(keys.size());
for (size_t i = 0; i < keys.size(); ++i) {
const CryptoKey* ki = &keys[i];
OEMCrypto_KeyObject* ko = &load_keys[i];
ko->key_id = msg + GetOffset(message, ki->key_id());
ko->key_id_length = ki->key_id().length();
ko->key_data_iv = msg + GetOffset(message, ki->key_data_iv());
ko->key_data = msg + GetOffset(message, ki->key_data());
ko->key_data_length = ki->key_data().length();
if (ki->HasKeyControl()) {
ko->key_control_iv = msg + GetOffset(message, ki->key_control_iv());
ko->key_control = msg + GetOffset(message, ki->key_control());
} else {
LOGE("For key %d: XXX key has no control block. size=%d", i,
ki->key_control().size());
ko->key_control_iv = NULL;
ko->key_control = NULL;
}
// TODO(jfore): Is returning the cipher needed. If not drop this.
*cipher_mode = ki->cipher_mode();
}
uint8_t* pst = NULL;
if (!provider_session_token.empty()) {
pst =
const_cast<uint8_t*>(msg) + GetOffset(message, provider_session_token);
}
uint8_t* srm_req = NULL;
if (!srm_requirement.empty()) {
srm_req = const_cast<uint8_t*>(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<const uint8_t*>(signature.data()), signature.size(),
enc_mac_key_iv, enc_mac_key, keys.size(), &load_keys[0], pst,
provider_session_token.length(), srm_req, OEMCrypto_ContentLicense),
metrics_, oemcrypto_load_keys_, sts);
return sts;
}
// Select Key for DefaultKeySession
OEMCryptoResult DefaultKeySession::SelectKey(const std::string& key_id,
CdmCipherMode cipher_mode) {
// Crypto session lock already locked.
if (!cached_key_id_.empty() && cached_key_id_ == key_id) {
// Already using the desired key.
return OEMCrypto_SUCCESS;
}
cached_key_id_ = key_id;
const uint8_t* key_id_string =
reinterpret_cast<const uint8_t*>(cached_key_id_.data());
OEMCryptoResult sts;
M_TIME(sts = OEMCrypto_SelectKey(
oec_session_id_, key_id_string, cached_key_id_.size(),
static_cast<OEMCryptoCipherMode>(cipher_mode)),
metrics_, oemcrypto_select_key_, sts);
if (OEMCrypto_SUCCESS != sts) {
cached_key_id_.clear();
}
return sts;
}
// Decrypt for DefaultKeySession
OEMCryptoResult DefaultKeySession::Decrypt(
const CdmDecryptionParameters& params,
OEMCrypto_DestBufferDesc& buffer_descriptor,
OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor) {
OEMCryptoResult sts;
M_TIME(sts = OEMCrypto_DecryptCENC(
oec_session_id_, params.encrypt_buffer, params.encrypt_length,
params.is_encrypted, &(*params.iv).front(), params.block_offset,
&buffer_descriptor, &pattern_descriptor, params.subsample_flags),
metrics_, oemcrypto_decrypt_cenc_, sts,
metrics::Pow2Bucket(params.encrypt_length));
return sts;
}
} // namespace wvcdm

View File

@@ -11,6 +11,7 @@
#include <iostream>
#include <memory>
#include "content_key_session.h"
#include "crypto_key.h"
#include "log.h"
#include "openssl/asn1.h"
@@ -19,6 +20,7 @@
#include "properties.h"
#include "pst_report.h"
#include "string_conversions.h"
#include "sublicense_key_session.h"
#include "usage_table_header.h"
#include "wv_cdm_constants.h"
@@ -34,6 +36,46 @@ std::string EncodeUint32(unsigned int u) {
return s;
}
const uint32_t kRsaSignatureLength = 256;
const size_t kMaximumChunkSize = 100 * 1024; // 100 KiB
const size_t kEstimatedInitialUsageTableHeader = 40;
const size_t kOemCryptoApiVersionSupportsBigUsageTables = 13;
// Constants and utility objects relating to OEM Certificates
const int kExtensionOidSize = 64;
const char* const kWidevineSystemIdExtensionOid = "1.3.6.1.4.1.11129.4.1.1";
// Helpers for working with BoringSSL
template <typename T, void (*func)(T*)>
class boringssl_ptr {
public:
explicit boringssl_ptr(T* p = NULL) : ptr_(p) {}
~boringssl_ptr() {
if (ptr_) func(ptr_);
}
T& operator*() const { return *ptr_; }
T* operator->() const { return ptr_; }
T* get() const { return ptr_; }
private:
T* ptr_;
CORE_DISALLOW_COPY_AND_ASSIGN(boringssl_ptr);
};
void DeleteX509Stack(STACK_OF(X509)* stack) {
sk_X509_pop_free(stack, X509_free);
}
}
namespace wvcdm {
Lock CryptoSession::crypto_lock_;
bool CryptoSession::initialized_ = false;
int CryptoSession::session_count_ = 0;
uint64_t CryptoSession::request_id_index_ = 0;
UsageTableHeader* CryptoSession::usage_table_header_l1_ = NULL;
UsageTableHeader* CryptoSession::usage_table_header_l3_ = NULL;
size_t GetOffset(std::string message, std::string field) {
size_t pos = message.find(field);
if (pos == std::string::npos) {
@@ -77,607 +119,6 @@ void GenerateEncryptContext(const std::string& input_context,
deriv_context->append(EncodeUint32(kEncryptionKeySizeBits));
}
OEMCryptoCipherMode ToOEMCryptoCipherMode(wvcdm::CdmCipherMode cipher_mode) {
return (cipher_mode == wvcdm::kCipherModeCtr) ? OEMCrypto_CipherMode_CTR
: OEMCrypto_CipherMode_CBC;
}
const uint32_t kRsaSignatureLength = 256;
const size_t kMaximumChunkSize = 100 * 1024; // 100 KiB
const size_t kEstimatedInitialUsageTableHeader = 40;
const size_t kOemCryptoApiVersionSupportsBigUsageTables = 13;
// Constants and utility objects relating to OEM Certificates
const int kExtensionOidSize = 64;
const char* const kWidevineSystemIdExtensionOid = "1.3.6.1.4.1.11129.4.1.1";
// Helpers for working with BoringSSL
template <typename T, void (*func)(T*)>
class boringssl_ptr {
public:
explicit boringssl_ptr(T* p = NULL) : ptr_(p) {}
~boringssl_ptr() {
if (ptr_) func(ptr_);
}
T& operator*() const { return *ptr_; }
T* operator->() const { return ptr_; }
T* get() const { return ptr_; }
private:
T* ptr_;
CORE_DISALLOW_COPY_AND_ASSIGN(boringssl_ptr);
};
void DeleteX509Stack(STACK_OF(X509)* stack) {
sk_X509_pop_free(stack, X509_free);
}
}
namespace wvcdm {
Lock CryptoSession::crypto_lock_;
bool CryptoSession::initialized_ = false;
int CryptoSession::session_count_ = 0;
uint64_t CryptoSession::request_id_index_ = 0;
UsageTableHeader* CryptoSession::usage_table_header_l1_ = NULL;
UsageTableHeader* CryptoSession::usage_table_header_l3_ = NULL;
// TODO(jfore, rfrias, gmorgan): This object should be split off into it's own
// module or refactored out.
class DefaultKeySession : public KeySession {
public:
DefaultKeySession(CryptoSessionId oec_session_id,
metrics::CryptoMetrics* metrics)
: KeySession(metrics), oec_session_id_(oec_session_id) {}
virtual ~DefaultKeySession() {}
KeySessionType Type() { return kDefault; }
// Generate Derived Keys for DefaultKeySession
bool GenerateDerivedKeys(const std::string& message) {
std::string mac_deriv_message;
std::string enc_deriv_message;
GenerateMacContext(message, &mac_deriv_message);
GenerateEncryptContext(message, &enc_deriv_message);
LOGV("GenerateDerivedKeys: id=%ld", (uint32_t)oec_session_id_);
OEMCryptoResult sts;
M_TIME(sts = OEMCrypto_GenerateDerivedKeys(
oec_session_id_,
reinterpret_cast<const uint8_t*>(mac_deriv_message.data()),
mac_deriv_message.size(),
reinterpret_cast<const uint8_t*>(enc_deriv_message.data()),
enc_deriv_message.size()),
metrics_, oemcrypto_generate_derived_keys_, sts);
if (OEMCrypto_SUCCESS != sts) {
LOGE("GenerateDerivedKeys: OEMCrypto_GenerateDerivedKeys error=%d", sts);
return false;
}
return true;
}
// Generate Derived Keys (from session key) for DefaultKeySession
bool GenerateDerivedKeys(const std::string& message,
const std::string& session_key) {
std::string mac_deriv_message;
std::string enc_deriv_message;
GenerateMacContext(message, &mac_deriv_message);
GenerateEncryptContext(message, &enc_deriv_message);
LOGV("GenerateDerivedKeys: id=%ld", (uint32_t)oec_session_id_);
OEMCryptoResult sts;
M_TIME(sts = OEMCrypto_DeriveKeysFromSessionKey(
oec_session_id_,
reinterpret_cast<const uint8_t*>(session_key.data()),
session_key.size(),
reinterpret_cast<const uint8_t*>(mac_deriv_message.data()),
mac_deriv_message.size(),
reinterpret_cast<const uint8_t*>(enc_deriv_message.data()),
enc_deriv_message.size()),
metrics_, oemcrypto_derive_keys_from_session_key_, sts);
if (OEMCrypto_SUCCESS != sts) {
LOGE("GenerateDerivedKeys: OEMCrypto_DeriveKeysFromSessionKey err=%d",
sts);
return false;
}
return true;
}
// Load Keys for DefaultKeySession
OEMCryptoResult LoadKeys(const std::string& message,
const std::string& signature,
const std::string& mac_key_iv,
const std::string& mac_key,
const std::vector<CryptoKey>& keys,
const std::string& provider_session_token,
CdmCipherMode* cipher_mode,
const std::string& srm_requirement) {
const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data());
const uint8_t* enc_mac_key = NULL;
const uint8_t* enc_mac_key_iv = NULL;
if (mac_key.size() >= MAC_KEY_SIZE && mac_key_iv.size() >= KEY_IV_SIZE) {
enc_mac_key = msg + GetOffset(message, mac_key);
enc_mac_key_iv = msg + GetOffset(message, mac_key_iv);
} else {
LOGV("DefaultKeySession::LoadKeys: enc_mac_key not set");
}
std::vector<OEMCrypto_KeyObject_V13> load_keys(keys.size());
for (size_t i = 0; i < keys.size(); ++i) {
const CryptoKey* ki = &keys[i];
OEMCrypto_KeyObject_V13* ko = &load_keys[i];
ko->key_id = msg + GetOffset(message, ki->key_id());
ko->key_id_length = ki->key_id().length();
ko->key_data_iv = msg + GetOffset(message, ki->key_data_iv());
ko->key_data = msg + GetOffset(message, ki->key_data());
ko->key_data_length = ki->key_data().length();
if (ki->HasKeyControl()) {
ko->key_control_iv = msg + GetOffset(message, ki->key_control_iv());
ko->key_control = msg + GetOffset(message, ki->key_control());
} else {
LOGE("For key %d: XXX key has no control block. size=%d", i,
ki->key_control().size());
ko->key_control_iv = NULL;
ko->key_control = NULL;
}
*cipher_mode = ki->cipher_mode();
}
uint8_t* pst = NULL;
if (!provider_session_token.empty()) {
pst = const_cast<uint8_t*>(msg) +
GetOffset(message, provider_session_token);
}
uint8_t* srm_req = NULL;
if (!srm_requirement.empty()) {
srm_req = const_cast<uint8_t*>(msg) + GetOffset(message, srm_requirement);
}
LOGV("LoadKeys: id=%ld", (uint32_t)oec_session_id_);
OEMCryptoResult sts;
M_TIME(sts = OEMCrypto_LoadKeys_Back_Compat(
oec_session_id_, msg, message.size(),
reinterpret_cast<const uint8_t*>(signature.data()),
signature.size(), enc_mac_key_iv, enc_mac_key, keys.size(),
&load_keys[0], pst, provider_session_token.length(), srm_req,
OEMCrypto_ContentLicense),
metrics_, oemcrypto_load_keys_, sts);
return sts;
}
// Select Key for DefaultKeySession
OEMCryptoResult SelectKey(const std::string& key_id,
CdmCipherMode cipher_mode) {
// Crypto session lock already locked.
if (!cached_key_id_.empty() && cached_key_id_ == key_id) {
// Already using the desired key.
return OEMCrypto_SUCCESS;
}
cached_key_id_ = key_id;
const uint8_t* key_id_string =
reinterpret_cast<const uint8_t*>(cached_key_id_.data());
OEMCryptoResult sts;
M_TIME(sts = OEMCrypto_SelectKey(oec_session_id_, key_id_string,
cached_key_id_.size(),
ToOEMCryptoCipherMode(cipher_mode)),
metrics_, oemcrypto_select_key_, sts);
if (OEMCrypto_SUCCESS != sts) {
cached_key_id_.clear();
}
return sts;
}
// Decrypt for DefaultKeySession
OEMCryptoResult Decrypt(
const CdmDecryptionParameters& params,
OEMCrypto_DestBufferDesc& buffer_descriptor,
OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor) {
OEMCryptoResult sts;
M_TIME(sts = OEMCrypto_DecryptCENC(
oec_session_id_, params.encrypt_buffer, params.encrypt_length,
params.is_encrypted, &(*params.iv).front(), params.block_offset,
&buffer_descriptor, &pattern_descriptor, params.subsample_flags),
metrics_, oemcrypto_decrypt_cenc_, sts,
metrics::Pow2Bucket(params.encrypt_length));
return sts;
}
private:
CryptoSessionId oec_session_id_;
KeyId cached_key_id_;
};
// TODO(jfore, rfrias, gmorgan): This object should be split off into it's own
// module or refactored out.
class SubLicenseKeySession : public KeySession {
typedef enum {
kInitializing,
kInitialLicenseLoaded,
kInitialLicenseFailed,
} SubLicenseState;
public:
SubLicenseKeySession(SubLicenseSessionMap& sub_license_oec_sessions,
metrics::CryptoMetrics* metrics,
const std::string& wrapped_private_device_key,
SecurityLevel requested_security_level,
const std::string& group_master_key_id)
: KeySession(metrics),
state_(kInitializing),
wrapped_private_device_key_(wrapped_private_device_key),
sub_license_oec_sessions_(sub_license_oec_sessions),
requested_security_level_(requested_security_level),
group_master_key_id_(group_master_key_id) {}
virtual ~SubLicenseKeySession() {
for (SubLicenseSessionMap::iterator oec_session =
sub_license_oec_sessions_.begin();
oec_session != sub_license_oec_sessions_.end(); oec_session++) {
metrics_->oemcrypto_close_session_.Increment(
OEMCrypto_CloseSession(oec_session->second));
}
sub_license_oec_sessions_.clear();
}
KeySessionType Type() { return kSubLicense; }
// This version of GenerateDerivedKeys is for devices using keyboxes. It is
// not supported using sub licenses.
bool GenerateDerivedKeys(const std::string&) { return false; }
// GenerateDerivedKeys is called for each open oemcrypto session and is only
// called once.
bool GenerateDerivedKeys(const std::string& message,
const std::string& session_key) {
std::string mac_deriv_message;
std::string enc_deriv_message;
GenerateMacContext(message, &mac_deriv_message);
GenerateEncryptContext(message, &enc_deriv_message);
for (SubLicenseSessionMap::iterator it = sub_license_oec_sessions_.begin();
it != sub_license_oec_sessions_.end(); it++) {
LOGV("GenerateDerivedKeys: id=%ld", (uint32_t)it->second);
OEMCryptoResult sts;
M_TIME(
sts = OEMCrypto_DeriveKeysFromSessionKey(
it->second, reinterpret_cast<const uint8_t*>(session_key.data()),
session_key.size(),
reinterpret_cast<const uint8_t*>(mac_deriv_message.data()),
mac_deriv_message.size(),
reinterpret_cast<const uint8_t*>(enc_deriv_message.data()),
enc_deriv_message.size()),
metrics_, oemcrypto_derive_keys_from_session_key_, sts);
if (OEMCrypto_SUCCESS != sts) {
LOGE("GenerateDerivedKeys: OEMCrypto_DeriveKeysFromSessionKey err=%d",
sts);
return false;
}
}
return true;
}
// Load the keys in |keys|. The initial keys are saved for key rotation.
OEMCryptoResult LoadKeys(const std::string& message,
const std::string& signature,
const std::string& mac_key_iv,
const std::string& mac_key,
const std::vector<CryptoKey>& keys,
const std::string& provider_session_token,
CdmCipherMode* cipher_mode,
const std::string& srm_requirement) {
if (state_ == kInitializing) {
state_ = kInitialLicenseLoaded;
keys_ = keys;
OEMCryptoResult sts =
DoLoadKeys(message, signature, mac_key_iv, mac_key, keys,
provider_session_token, cipher_mode, srm_requirement);
if (OEMCrypto_SUCCESS != sts) {
state_ = kInitialLicenseFailed;
}
return sts;
}
return DoSubLicenseLoadKeys(message, signature, mac_key_iv, mac_key,
keys[0], provider_session_token, cipher_mode,
srm_requirement);
}
// Each oemcrypto session contains a single key. Find the right sub session
// and save it's id as the selected oemcrypto session.
OEMCryptoResult SelectKey(const std::string& key_id,
CdmCipherMode cipher_mode) {
for (size_t i = 0; i < keys_.size(); ++i) {
if (keys_[i].key_id() == key_id) {
cached_sub_session_key_id_ = keys_[i].sub_session_key_id();
if (keys_[i].cipher_mode() != cipher_mode) {
SubLicenseSessionMap::iterator it =
sub_license_oec_sessions_.find(cached_sub_session_key_id_);
if (it == sub_license_oec_sessions_.end()) {
return OEMCrypto_ERROR_INVALID_SESSION;
}
OEMCryptoResult status = OEMCrypto_SUCCESS;
M_TIME(status = OEMCrypto_SelectKey(
it->second,
reinterpret_cast<const uint8_t*>(keys_[i].key_id().data()),
keys_[i].key_id().size(),
static_cast<OEMCryptoCipherMode>(cipher_mode)),
metrics_, oemcrypto_select_key_, status);
if (OEMCrypto_SUCCESS != status) {
return status;
}
keys_[i].set_cipher_mode(cipher_mode);
}
}
}
return OEMCrypto_SUCCESS;
}
// Decrypt performs the decryption using the selected oemcrypto session.
// TODO(jfore): Support DecryptInChunks.
OEMCryptoResult Decrypt(
const CdmDecryptionParameters& params,
OEMCrypto_DestBufferDesc& buffer_descriptor,
OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor) {
SubLicenseSessionMap::iterator it =
sub_license_oec_sessions_.find(cached_sub_session_key_id_);
if (it == sub_license_oec_sessions_.end()) {
return OEMCrypto_ERROR_INVALID_SESSION;
}
OEMCryptoResult sts;
M_TIME(sts = OEMCrypto_DecryptCENC(
it->second, params.encrypt_buffer, params.encrypt_length,
params.is_encrypted, &(*params.iv).front(), params.block_offset,
&buffer_descriptor, &pattern_descriptor, params.subsample_flags),
metrics_, oemcrypto_decrypt_cenc_, sts,
metrics::Pow2Bucket(params.encrypt_length));
return sts;
}
private:
// Destroy each open oemcrypto session and relace them with new ones.
OEMCryptoResult ResetCryptoSessions() {
for (SubLicenseSessionMap::iterator it = sub_license_oec_sessions_.begin();
it != sub_license_oec_sessions_.end(); it++) {
OEMCryptoResult sts = OEMCrypto_CloseSession(it->second);
metrics_->oemcrypto_close_session_.Increment(sts);
if (OEMCrypto_SUCCESS != sts) {
return sts;
}
sts = OEMCrypto_OpenSession(&it->second, requested_security_level_);
if (OEMCrypto_SUCCESS != sts) {
return sts;
}
M_TIME(sts = OEMCrypto_LoadDeviceRSAKey(
it->second,
reinterpret_cast<const uint8_t*>(
wrapped_private_device_key_.data()),
wrapped_private_device_key_.size()),
metrics_, oemcrypto_load_device_rsa_key_, sts);
if (OEMCrypto_SUCCESS != sts) {
return sts;
}
}
return OEMCrypto_SUCCESS;
}
// DoLoadKeys loads a single key into each oemcrypto session.
OEMCryptoResult DoLoadKeys(const std::string& message,
const std::string& signature,
const std::string& mac_key_iv,
const std::string& mac_key,
const std::vector<CryptoKey>& keys,
const std::string& provider_session_token,
CdmCipherMode* cipher_mode,
const std::string& srm_requirement) {
const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data());
const uint8_t* enc_mac_key = NULL;
const uint8_t* enc_mac_key_iv = NULL;
if (mac_key.size() >= MAC_KEY_SIZE && mac_key_iv.size() >= KEY_IV_SIZE) {
enc_mac_key = msg + GetOffset(message, mac_key);
enc_mac_key_iv = msg + GetOffset(message, mac_key_iv);
} else {
LOGV("CryptoSession::LoadKeys: enc_mac_key not set");
}
uint8_t* pst = NULL;
if (!provider_session_token.empty()) {
pst = const_cast<uint8_t*>(msg) +
GetOffset(message, provider_session_token);
}
uint8_t* srm_req = NULL;
if (!srm_requirement.empty()) {
srm_req = const_cast<uint8_t*>(msg) + GetOffset(message, srm_requirement);
}
for (size_t i = 0; i < keys.size(); i++) {
OEMCrypto_KeyObject_V13 key_object;
const CryptoKey& key_data = keys[i];
key_object.key_id = msg + GetOffset(message, key_data.key_id());
key_object.key_id_length = key_data.key_id().length();
key_object.key_data_iv = msg + GetOffset(message, key_data.key_data_iv());
key_object.key_data = msg + GetOffset(message, key_data.key_data());
key_object.key_data_length = key_data.key_data().length();
if (key_data.HasKeyControl()) {
key_object.key_control_iv =
msg + GetOffset(message, key_data.key_control_iv());
key_object.key_control =
msg + GetOffset(message, key_data.key_control());
} else {
LOGE("For key %s: XXX key has no control block. size=%d",
key_data.key_id().c_str(), key_data.key_control().size());
key_object.key_control_iv = NULL;
key_object.key_control = NULL;
}
*cipher_mode = key_data.cipher_mode();
SubLicenseSessionMap::iterator oec_session_id =
sub_license_oec_sessions_.find(key_data.sub_session_key_id());
if (oec_session_id == sub_license_oec_sessions_.end()) {
LOGE("CryptoSession::LoadKeys: Unrecognized sub session %s",
key_data.sub_session_key_id().c_str());
return OEMCrypto_ERROR_INVALID_SESSION;
}
OEMCryptoResult sts;
M_TIME(sts = OEMCrypto_LoadKeys_Back_Compat(
oec_session_id->second, msg, message.size(),
reinterpret_cast<const uint8_t*>(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<const uint8_t*>(key_data.key_id().data()),
key_data.key_id().size(),
static_cast<OEMCryptoCipherMode>(key_data.cipher_mode())),
metrics_, oemcrypto_select_key_, sts);
if (sts != OEMCrypto_SUCCESS) {
return sts;
}
}
keys_ = keys;
return OEMCrypto_SUCCESS;
}
// DoLoadKeys loads a single key into each oemcrypto session.
OEMCryptoResult DoSubLicenseLoadKeys(
const std::string& message, const std::string& signature,
const std::string& mac_key_iv, const std::string& mac_key,
const CryptoKey& key, const std::string& provider_session_token,
CdmCipherMode*, const std::string& srm_requirement) {
SubLicenseSessionMap::iterator it = sub_license_oec_sessions_.end();
size_t key_index = 0;
for (; key_index < keys_.size(); key_index++) {
if (keys_[key_index].track_label() == key.track_label()) {
it = sub_license_oec_sessions_.find(
keys_[key_index].sub_session_key_id());
CryptoKey tmp = key;
tmp.set_sub_session_key_id(keys_[key_index].sub_session_key_id());
tmp.set_sub_session_key(keys_[key_index].sub_session_key());
keys_[key_index] = tmp;
break;
}
}
if (it == sub_license_oec_sessions_.end()) {
return OEMCrypto_SUCCESS;
}
LOGV("GenerateDerivedKeys: id=%ld", (uint32_t)it->second);
std::string mac_deriv_message;
std::string enc_deriv_message;
GenerateMacContext(group_master_key_id_ + key.track_label(),
&mac_deriv_message);
GenerateEncryptContext(group_master_key_id_ + key.track_label(),
&enc_deriv_message);
const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data());
const uint8_t* enc_mac_key = NULL;
const uint8_t* enc_mac_key_iv = NULL;
if (mac_key.size() >= MAC_KEY_SIZE && mac_key_iv.size() >= KEY_IV_SIZE) {
enc_mac_key = msg + GetOffset(message, mac_key);
enc_mac_key_iv = msg + GetOffset(message, mac_key_iv);
} else {
LOGV("CryptoSession::LoadKeys: enc_mac_key not set");
}
uint8_t* pst = NULL;
if (!provider_session_token.empty()) {
pst = const_cast<uint8_t*>(msg) +
GetOffset(message, provider_session_token);
}
uint8_t* srm_req = NULL;
if (!srm_requirement.empty()) {
srm_req = const_cast<uint8_t*>(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<const uint8_t*>(sub_session_key.data()),
sub_session_key.size(),
reinterpret_cast<const uint8_t*>(mac_deriv_message.data()),
mac_deriv_message.size(),
reinterpret_cast<const uint8_t*>(enc_deriv_message.data()),
enc_deriv_message.size()),
metrics_, oemcrypto_derive_keys_from_session_key_, sts);
if (OEMCrypto_SUCCESS != sts) {
LOGE("GenerateDerivedKeys: OEMCrypto_DeriveKeysFromSessionKey err=%d",
sts);
return sts;
}
OEMCrypto_KeyObject_V13 key_object;
key_object.key_id = msg + GetOffset(message, keys_[key_index].key_id());
key_object.key_id_length = keys_[key_index].key_id().length();
key_object.key_data_iv =
msg + GetOffset(message, keys_[key_index].key_data_iv());
key_object.key_data = msg + GetOffset(message, keys_[key_index].key_data());
key_object.key_data_length = keys_[key_index].key_data().length();
if (key.HasKeyControl()) {
key_object.key_control_iv =
msg + GetOffset(message, keys_[key_index].key_control_iv());
key_object.key_control =
msg + GetOffset(message, keys_[key_index].key_control());
}
M_TIME(
sts = OEMCrypto_LoadKeys_Back_Compat(
it->second, msg, message.size(),
reinterpret_cast<const uint8_t*>(signature.data()),
signature.size(), enc_mac_key_iv, enc_mac_key, 1, &key_object, pst,
provider_session_token.length(), srm_req, OEMCrypto_ContentLicense),
metrics_, oemcrypto_load_keys_, sts);
if (sts != OEMCrypto_SUCCESS) {
return sts;
}
M_TIME(
sts = OEMCrypto_SelectKey(
it->second,
reinterpret_cast<const uint8_t*>(keys_[key_index].key_id().data()),
keys_[key_index].key_id().size(),
static_cast<OEMCryptoCipherMode>(keys_[key_index].cipher_mode())),
metrics_, oemcrypto_select_key_, sts);
return sts;
}
SubLicenseState state_;
std::string cached_sub_session_key_id_;
std::string wrapped_private_device_key_;
std::string message_;
std::string session_key_;
std::vector<CryptoKey> keys_;
SubLicenseSessionMap& sub_license_oec_sessions_;
SecurityLevel requested_security_level_;
KeyId group_master_key_id_;
};
CryptoSession::CryptoSession(metrics::CryptoMetrics* metrics)
: metrics_(metrics),
system_id_(-1),

View File

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