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:
committed by
Rahul Frias
parent
8de7caf788
commit
8251aab9f6
@@ -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 \
|
||||
|
||||
51
libwvdrmengine/cdm/core/include/content_key_session.h
Normal file
51
libwvdrmengine/cdm/core/include/content_key_session.h
Normal 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_
|
||||
@@ -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:
|
||||
|
||||
44
libwvdrmengine/cdm/core/include/key_session.h
Normal file
44
libwvdrmengine/cdm/core/include/key_session.h
Normal 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_
|
||||
91
libwvdrmengine/cdm/core/include/sublicense_key_session.h
Normal file
91
libwvdrmengine/cdm/core/include/sublicense_key_session.h
Normal 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_
|
||||
163
libwvdrmengine/cdm/core/src/content_key_session.cpp
Normal file
163
libwvdrmengine/cdm/core/src/content_key_session.cpp
Normal 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
|
||||
@@ -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),
|
||||
|
||||
351
libwvdrmengine/cdm/core/src/sublicense_key_session.cpp
Normal file
351
libwvdrmengine/cdm/core/src/sublicense_key_session.cpp
Normal 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
|
||||
Reference in New Issue
Block a user