Merge "Finer-Grained OEMCrypto Locking"

This commit is contained in:
John Bruce
2019-02-26 22:57:20 +00:00
committed by Android (Google) Code Review
2 changed files with 181 additions and 118 deletions

View File

@@ -17,6 +17,7 @@
#include "key_session.h"
#include "metrics_collections.h"
#include "oemcrypto_adapter.h"
#include "rw_lock.h"
#include "timer_metric.h"
#include "wv_cdm_types.h"
@@ -256,7 +257,7 @@ class CryptoSession {
// OEMCrypto to use a test keybox.
// Ownership of the object is transfered to CryptoSession.
static void SetCryptoSessionFactory(CryptoSessionFactory* factory) {
std::unique_lock<std::mutex> auto_lock(factory_lock_);
std::unique_lock<std::mutex> auto_lock(factory_mutex_);
factory_.reset(factory);
}
@@ -311,25 +312,59 @@ class CryptoSession {
size_t max_chunk_size);
static void IncrementIV(uint64_t increase_by, std::vector<uint8_t>* iv_out);
// These methods should be used to take the various CryptoSession locks in
// preference to taking the locks directly.
// These methods should be used to take the various CryptoSession mutexes in
// preference to taking the mutexes directly.
//
// The Static Field Lock should be taken before accessing any of
// CryptoSession's non-atomic static fields. The OEMCrypto Lock should be
// taken before calling into OEMCrypto. Note that accessing |key_session_|
// often accesses OEMCrypto, so this lock should be held before calling into
// |key_session_| as well. If a function needs to take both locks
// simultaneously, it must *always* take the Static Field Lock first. In
// general, locks should only be held for the minimum time necessary.
// (e.g. |oem_crypto_lock_| should only be held for the duration of a single
// call into OEMCrypto, unless there is a compelling argument otherwise such
// as making two calls into OEMCrypto immediately after each other.)
// A lock should be taken on the Static Field Mutex before accessing any of
// CryptoSession's non-atomic static fields. It can be taken as a reader or as
// a writer, depending on how you will be accessing the static fields.
//
// Before calling into OEMCrypto, code must take locks on the OEMCrypto Mutex
// and/or the OEMCrypto Session Mutex. Which of them should be taken and how
// depends on the OEMCrypto function being called; consult the OEMCrypto
// specification's threading guarantees before making any calls. The OEMCrypto
// specification defines several classes of functions for the purposes of
// parallelism. The methods below lock the OEMCrypto Mutex and OEMCrypto
// Session Mutex in the correct order and manner to fulfill the guarantees in
// the specification.
//
// For this function class... | ...use this locking method
// ------------------------------+---------------------------
// Initialization & Termination | WithOecWriteLock()
// Property | WithOecReadLock()
// Session Initialization | WithOecWriteLock()
// Usage Table | WithOecWriteLock()
// Session | WithOecSessionLock()
//
// Note that accessing |key_session_| often accesses the OEMCrypto session, so
// WithOecSessionLock() should be used before accessing |key_session_| as
// well.
//
// If a function needs to take a lock on both the Static Field Mutex and some
// of the OEMCrypto mutexes simultaneously, it must *always* lock the Static
// Field Mutex before the OEMCrypto mutexes.
//
// In general, all locks should only be held for the minimum time necessary
// (e.g. a lock on the OEMCrypto mutexes should only be held for the duration
// of a single call into OEMCrypto) unless there is a compelling argument
// otherwise, such as making two calls into OEMCrypto immediately after each
// other.
template <class Func>
static auto WithStaticFieldLock(const char* tag, Func body)
static auto WithStaticFieldWriteLock(const char* tag, Func body)
-> decltype(body());
template <class Func>
static auto WithOecLock(const char* tag, Func body) -> decltype(body());
static auto WithStaticFieldReadLock(const char* tag, Func body)
-> decltype(body());
template <class Func>
static auto WithOecWriteLock(const char* tag, Func body) -> decltype(body());
template <class Func>
static auto WithOecReadLock(const char* tag, Func body) -> decltype(body());
template <class Func>
auto WithOecSessionLock(const char* tag, Func body) -> decltype(body());
static bool IsInitialized();
@@ -337,11 +372,12 @@ class CryptoSession {
static const size_t kAes128BlockSize = 16; // Block size for AES_CBC_128
static const size_t kSignatureSize = 32; // size for HMAC-SHA256 signature
// The |WithStaticFieldLock| and |WithOecLock| methods should be used in
// preference to taking these locks directly. When taken, the rules of
// ordering documented with those functions must still be upheld.
static std::mutex static_field_lock_;
static std::mutex oem_crypto_lock_;
// The locking methods above should be used in preference to taking these
// mutexes directly. If code takes these manually and needs to take more
// than one, it must *always* take them in the order they are defined here.
static shared_mutex static_field_mutex_;
static shared_mutex oem_crypto_mutex_;
std::mutex oem_crypto_session_mutex_;
static bool initialized_;
static int session_count_;
@@ -374,9 +410,9 @@ class CryptoSession {
uint32_t api_version_;
// In order to avoid creating a deadlock if instantiation needs to take any
// of the CryptoSession static locks, |factory_| is protected by its own lock
// that is only used in the two funtions that interact with it.
static std::mutex factory_lock_;
// of the CryptoSession static mutexes, |factory_| is protected by its own
// mutex that is only used in the two funtions that interact with it.
static std::mutex factory_mutex_;
static std::unique_ptr<CryptoSessionFactory> factory_;
CORE_DISALLOW_COPY_AND_ASSIGN(CryptoSession);

View File

@@ -75,8 +75,8 @@ void DeleteX509Stack(STACK_OF(X509)* stack) {
} // namespace
namespace wvcdm {
std::mutex CryptoSession::static_field_lock_;
std::mutex CryptoSession::oem_crypto_lock_;
shared_mutex CryptoSession::static_field_mutex_;
shared_mutex CryptoSession::oem_crypto_mutex_;
bool CryptoSession::initialized_ = false;
int CryptoSession::session_count_ = 0;
UsageTableHeader* CryptoSession::usage_table_header_l1_ = NULL;
@@ -214,7 +214,7 @@ CdmResponseType CryptoSession::GetProvisioningMethod(
SecurityLevel requested_security_level,
CdmClientTokenType* token_type) {
OEMCrypto_ProvisioningMethod method;
WithOecLock("GetProvisioningMethod", [&] {
WithOecReadLock("GetProvisioningMethod", [&] {
method = OEMCrypto_GetProvisioningMethod(requested_security_level);
});
metrics_->oemcrypto_provisioning_method_.Record(method);
@@ -241,12 +241,12 @@ CdmResponseType CryptoSession::GetProvisioningMethod(
void CryptoSession::Init() {
LOGV("CryptoSession::Init");
WithStaticFieldLock("Init", [&] {
WithStaticFieldWriteLock("Init", [&] {
session_count_ += 1;
if (!initialized_) {
std::string sandbox_id;
OEMCryptoResult sts;
WithOecLock("Init", [&] {
WithOecWriteLock("Init", [&] {
if (Properties::GetSandboxId(&sandbox_id) && !sandbox_id.empty()) {
sts = OEMCrypto_SetSandbox(
reinterpret_cast<const uint8_t*>(sandbox_id.c_str()),
@@ -268,7 +268,7 @@ void CryptoSession::Init() {
void CryptoSession::Terminate() {
LOGV("CryptoSession::Terminate");
WithStaticFieldLock("Terminate", [&] {
WithStaticFieldWriteLock("Terminate", [&] {
LOGV("initialized_=%d, session_count_=%d", initialized_, session_count_);
if (session_count_ > 0) {
session_count_ -= 1;
@@ -277,7 +277,7 @@ void CryptoSession::Terminate() {
}
if (session_count_ > 0 || !initialized_) return;
OEMCryptoResult sts;
WithOecLock("Terminate", [&] {
WithOecWriteLock("Terminate", [&] {
sts = OEMCrypto_Terminate();
});
if (OEMCrypto_SUCCESS != sts) {
@@ -307,7 +307,7 @@ CdmResponseType CryptoSession::GetTokenFromKeybox(std::string* token) {
uint8_t* buf = reinterpret_cast<uint8_t*>(&temp_buffer[0]);
OEMCryptoResult status;
WithOecLock("GetTokenFromKeybox", [&] {
WithOecReadLock("GetTokenFromKeybox", [&] {
M_TIME(
status =
OEMCrypto_GetKeyData(buf, &buf_size, requested_security_level_),
@@ -338,7 +338,7 @@ CdmResponseType CryptoSession::GetTokenFromOemCert(std::string* token) {
while (true) {
size_t buf_size = temp_buffer.size();
uint8_t* buf = reinterpret_cast<uint8_t*>(&temp_buffer[0]);
WithOecLock("GetTokenFromOemCert", [&] {
WithOecSessionLock("GetTokenFromOemCert", [&] {
status = OEMCrypto_GetOEMPublicCertificate(oec_session_id_, buf,
&buf_size);
});
@@ -402,7 +402,7 @@ CdmSecurityLevel CryptoSession::GetSecurityLevel(
}
std::string security_level;
WithOecLock("GetSecurityLevel", [&] {
WithOecReadLock("GetSecurityLevel", [&] {
security_level = OEMCrypto_SecurityLevel(requested_level);
});
@@ -448,14 +448,14 @@ CdmResponseType CryptoSession::GetInternalDeviceUniqueId(
id.resize(id_length);
OEMCryptoResult sts;
WithOecLock("GetInternalDeviceUniqueId Attempt 1", [&] {
WithOecReadLock("GetInternalDeviceUniqueId Attempt 1", [&] {
sts = OEMCrypto_GetDeviceID(&id[0], &id_length, requested_security_level_);
});
// Increment the count of times this method was called.
metrics_->oemcrypto_get_device_id_.Increment(sts);
if (sts == OEMCrypto_ERROR_SHORT_BUFFER) {
id.resize(id_length);
WithOecLock("GetInternalDeviceUniqueId Attempt 2", [&] {
WithOecReadLock("GetInternalDeviceUniqueId Attempt 2", [&] {
sts = OEMCrypto_GetDeviceID(&id[0], &id_length,
requested_security_level_);
});
@@ -494,7 +494,7 @@ CdmResponseType CryptoSession::GetExternalDeviceUniqueId(
size_t id_length = 0;
OEMCryptoResult sts;
WithOecLock("GetExternalDeviceUniqueId", [&] {
WithOecReadLock("GetExternalDeviceUniqueId", [&] {
sts = OEMCrypto_GetDeviceID(NULL, &id_length, requested_security_level_);
});
metrics_->oemcrypto_get_device_id_.Increment(sts);
@@ -538,7 +538,7 @@ bool CryptoSession::GetApiVersion(SecurityLevel security_level,
return false;
}
WithOecLock("GetApiVersion", [&] {
WithOecReadLock("GetApiVersion", [&] {
*version = OEMCrypto_APIVersion(security_level);
});
// Record the version into the metrics.
@@ -758,7 +758,7 @@ CdmResponseType CryptoSession::GetProvisioningId(std::string* provisioning_id) {
uint8_t CryptoSession::GetSecurityPatchLevel() {
uint8_t patch;
WithOecLock("GetSecurityPatchLevel", [&] {
WithOecReadLock("GetSecurityPatchLevel", [&] {
patch = OEMCrypto_Security_Patch_Level(requested_security_level_);
});
metrics_->oemcrypto_security_patch_level_.Record(patch);
@@ -781,15 +781,17 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
OEMCrypto_SESSION sid;
requested_security_level_ = requested_security_level;
OEMCryptoResult sts;
WithOecLock("Open() calling OEMCrypto_OpenSession", [&] {
WithOecWriteLock("Open() calling OEMCrypto_OpenSession", [&] {
sts = OEMCrypto_OpenSession(&sid, requested_security_level);
});
if (sts != OEMCrypto_SUCCESS) {
WithStaticFieldLock("Open() reporting OEMCrypto_OpenSession Failure", [&] {
LOGE("OEMCrypto_Open failed: %d, open sessions: %ld, initialized: %d",
sts, session_count_, (int)initialized_);
});
WithStaticFieldReadLock(
"Open() reporting OEMCrypto_OpenSession Failure",
[&] {
LOGE("OEMCrypto_Open failed: %d, open sessions: %ld, initialized: %d",
sts, session_count_, (int)initialized_);
});
return MapOEMCryptoResult(sts, OPEN_CRYPTO_SESSION_ERROR, "Open");
}
@@ -808,7 +810,7 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
uint64_t request_id_base;
OEMCryptoResult random_sts;
WithOecLock("Open() calling OEMCrypto_GetRandom", [&] {
WithOecReadLock("Open() calling OEMCrypto_GetRandom", [&] {
random_sts = OEMCrypto_GetRandom(
reinterpret_cast<uint8_t*>(&request_id_base), sizeof(request_id_base));
});
@@ -834,10 +836,10 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
if (security_level == kSecurityLevelL1 ||
security_level == kSecurityLevelL3) {
{
// This block cannot use |WithStaticFieldLock| because it needs to
// unlock the lock partway through.
LOGV("Static Field Lock - Open() Initializing Usage Table");
std::unique_lock<std::mutex> auto_lock(static_field_lock_);
// This block cannot use |WithStaticFieldWriteLock| because it needs
// to unlock the lock partway through.
LOGV("Static Field Write Lock - Open() Initializing Usage Table");
std::unique_lock<shared_mutex> auto_lock(static_field_mutex_);
UsageTableHeader** header = security_level == kSecurityLevelL1
? &usage_table_header_l1_
@@ -866,7 +868,7 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
metrics_->oemcrypto_usage_table_support_.SetError(result);
}
WithOecLock("Open() calling key_session_.reset()", [&] {
WithOecSessionLock("Open() calling key_session_.reset()", [&] {
key_session_.reset(new ContentKeySession(oec_session_id_, metrics_));
});
@@ -880,7 +882,7 @@ void CryptoSession::Close() {
OEMCryptoResult close_sts;
bool update_usage_table = false;
WithOecLock("Close", [&] {
WithOecWriteLock("Close", [&] {
close_sts = OEMCrypto_CloseSession(oec_session_id_);
});
metrics_->oemcrypto_close_session_.Increment(close_sts);
@@ -932,7 +934,7 @@ CdmResponseType CryptoSession::LoadKeys(
CdmResponseType result = KEY_ADDED;
OEMCryptoResult sts;
WithOecLock("LoadKeys", [&] {
WithOecSessionLock("LoadKeys", [&] {
if (key_type == kLicenseKeyTypeEntitlement &&
key_session_->Type() != KeySession::kEntitlement) {
key_session_.reset(new EntitlementKeySession(oec_session_id_, metrics_));
@@ -979,7 +981,7 @@ CdmResponseType CryptoSession::LoadKeys(
CdmResponseType CryptoSession::LoadEntitledContentKeys(
const std::vector<CryptoKey>& key_array) {
OEMCryptoResult sts;
WithOecLock("LoadEntitledContentKeys", [&] {
WithOecSessionLock("LoadEntitledContentKeys", [&] {
sts = key_session_->LoadEntitledContentKeys(key_array);
});
@@ -1009,7 +1011,7 @@ CdmResponseType CryptoSession::LoadCertificatePrivateKey(
size_t buf_size = temp_buffer.size();
uint8_t* buf = reinterpret_cast<uint8_t*>(&temp_buffer[0]);
OEMCryptoResult sts;
WithOecLock(
WithOecSessionLock(
"LoadCertificatePrivateKey() calling OEMCrypto_GetOEMPublicCertificate",
[&] {
sts =
@@ -1018,7 +1020,7 @@ CdmResponseType CryptoSession::LoadCertificatePrivateKey(
metrics_->oemcrypto_get_oem_public_certificate_.Increment(sts);
LOGV("LoadDeviceRSAKey: id=%lu", oec_session_id_);
WithOecLock(
WithOecSessionLock(
"LoadCertificatePrivateKey() calling OEMCrypto_LoadDeviceRSAKey()",
[&] {
M_TIME(sts = OEMCrypto_LoadDeviceRSAKey(
@@ -1050,7 +1052,7 @@ CdmResponseType CryptoSession::RefreshKeys(const std::string& message,
}
LOGV("RefreshKeys: id=%lu", oec_session_id_);
OEMCryptoResult refresh_sts;
WithOecLock("RefreshKeys", [&] {
WithOecSessionLock("RefreshKeys", [&] {
M_TIME(refresh_sts = OEMCrypto_RefreshKeys(
oec_session_id_, msg, message.size(),
reinterpret_cast<const uint8_t*>(signature.data()),
@@ -1067,7 +1069,7 @@ CdmResponseType CryptoSession::RefreshKeys(const std::string& message,
CdmResponseType CryptoSession::SelectKey(const std::string& key_id,
CdmCipherMode cipher_mode) {
OEMCryptoResult sts;
WithOecLock("SelectKey", [&] {
WithOecSessionLock("SelectKey", [&] {
sts = key_session_->SelectKey(key_id, cipher_mode);
});
@@ -1105,7 +1107,7 @@ CdmResponseType CryptoSession::SelectKey(const std::string& key_id,
CdmResponseType CryptoSession::GenerateDerivedKeys(const std::string& message) {
OEMCryptoResult sts;
WithOecLock("GenerateDerivedKeys without session_key", [&] {
WithOecSessionLock("GenerateDerivedKeys without session_key", [&] {
sts = key_session_->GenerateDerivedKeys(message);
});
@@ -1116,7 +1118,7 @@ CdmResponseType CryptoSession::GenerateDerivedKeys(const std::string& message) {
CdmResponseType CryptoSession::GenerateDerivedKeys(
const std::string& message, const std::string& session_key) {
OEMCryptoResult sts;
WithOecLock("GenerateDerivedKeys with session_key", [&] {
WithOecSessionLock("GenerateDerivedKeys with session_key", [&] {
sts = key_session_->GenerateDerivedKeys(message, session_key);
});
@@ -1138,7 +1140,7 @@ CdmResponseType CryptoSession::GenerateSignature(const std::string& message,
// At most two attempts.
// The first attempt may fail due to buffer too short
for (int i = 0; i < 2; ++i) {
WithOecLock("GenerateSignature", [&] {
WithOecSessionLock("GenerateSignature", [&] {
M_TIME(sts = OEMCrypto_GenerateSignature(
oec_session_id_,
reinterpret_cast<const uint8_t*>(message.data()),
@@ -1181,7 +1183,7 @@ CdmResponseType CryptoSession::GenerateRsaSignature(const std::string& message,
// At most two attempts.
// The first attempt may fail due to buffer too short
for (int i = 0; i < 2; ++i) {
WithOecLock("GenerateRsaSignature", [&] {
WithOecSessionLock("GenerateRsaSignature", [&] {
M_TIME(sts = OEMCrypto_GenerateRSASignature(
oec_session_id_,
reinterpret_cast<const uint8_t*>(message.data()),
@@ -1247,7 +1249,7 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) {
if (!params.is_encrypted &&
params.subsample_flags ==
(OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)) {
WithOecLock("Decrypt() calling CopyBuffer", [&] {
WithOecSessionLock("Decrypt() calling CopyBuffer", [&] {
M_TIME(sts = OEMCrypto_CopyBuffer(oec_session_id_, params.encrypt_buffer,
params.encrypt_length,
&buffer_descriptor,
@@ -1279,7 +1281,7 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) {
if (result != NO_ERROR) return result;
}
WithOecLock("Decrypt() calling key_session_->Decrypt()", [&] {
WithOecSessionLock("Decrypt() calling key_session_->Decrypt()", [&] {
sts = key_session_->Decrypt(params, buffer_descriptor,
pattern_descriptor);
});
@@ -1348,7 +1350,7 @@ bool CryptoSession::UsageInformationSupport(SecurityLevel security_level,
return false;
}
WithOecLock("UsageInformationSupport", [&] {
WithOecReadLock("UsageInformationSupport", [&] {
*has_support = OEMCrypto_SupportsUsageTable(security_level);
});
return true;
@@ -1365,7 +1367,7 @@ CdmResponseType CryptoSession::UpdateUsageInformation() {
}
OEMCryptoResult status;
WithOecLock("UpdateUsageInformation", [&] {
WithOecWriteLock("UpdateUsageInformation", [&] {
status = OEMCrypto_UpdateUsageTable();
});
metrics_->oemcrypto_update_usage_table_.Increment(status);
@@ -1385,7 +1387,7 @@ CdmResponseType CryptoSession::DeactivateUsageInformation(
// TODO(fredgc or rfrias): make sure oec_session_id_ is valid.
OEMCryptoResult status;
WithOecLock("DeactivateUsageInformation", [&] {
WithOecWriteLock("DeactivateUsageInformation", [&] {
status = OEMCrypto_DeactivateUsageEntry(
oec_session_id_, pst, provider_session_token.length());
});
@@ -1425,7 +1427,7 @@ CdmResponseType CryptoSession::GenerateUsageReport(
size_t usage_length = 0;
OEMCryptoResult status;
WithOecLock("GenerateUsageReport Attempt 1", [&] {
WithOecWriteLock("GenerateUsageReport Attempt 1", [&] {
status = OEMCrypto_ReportUsage(
oec_session_id_, pst, provider_session_token.length(), NULL,
&usage_length);
@@ -1439,7 +1441,7 @@ CdmResponseType CryptoSession::GenerateUsageReport(
std::vector<uint8_t> buffer(usage_length);
WithOecLock("GenerateUsageReport Attempt 2", [&] {
WithOecWriteLock("GenerateUsageReport Attempt 2", [&] {
status = OEMCrypto_ReportUsage(oec_session_id_, pst,
provider_session_token.length(), &buffer[0],
&usage_length);
@@ -1516,7 +1518,7 @@ CdmResponseType CryptoSession::ReleaseUsageInformation(
const uint8_t* pst = msg + GetOffset(message, provider_session_token);
OEMCryptoResult status;
WithOecLock("ReleaseUsageInformation", [&] {
WithOecWriteLock("ReleaseUsageInformation", [&] {
status = OEMCrypto_DeleteUsageEntry(
oec_session_id_, pst, provider_session_token.length(), msg,
message.length(), sig, signature.length());
@@ -1538,7 +1540,7 @@ CdmResponseType CryptoSession::DeleteUsageInformation(
CdmResponseType response = NO_ERROR;
LOGV("CryptoSession::DeleteUsageInformation");
OEMCryptoResult status;
WithOecLock("DeleteUsageInformation", [&] {
WithOecWriteLock("DeleteUsageInformation", [&] {
status = OEMCrypto_ForceDeleteUsageEntry(
reinterpret_cast<const uint8_t*>(provider_session_token.c_str()),
provider_session_token.length());
@@ -1559,7 +1561,7 @@ CdmResponseType CryptoSession::DeleteMultipleUsageInformation(
const std::vector<std::string>& provider_session_tokens) {
LOGV("CryptoSession::DeleteMultipleUsageInformation");
CdmResponseType response = NO_ERROR;
WithOecLock("DeleteMultipleUsageInformation", [&] {
WithOecWriteLock("DeleteMultipleUsageInformation", [&] {
for (size_t i = 0; i < provider_session_tokens.size(); ++i) {
OEMCryptoResult status = OEMCrypto_ForceDeleteUsageEntry(
reinterpret_cast<const uint8_t*>(provider_session_tokens[i].c_str()),
@@ -1581,7 +1583,7 @@ CdmResponseType CryptoSession::DeleteMultipleUsageInformation(
CdmResponseType CryptoSession::DeleteAllUsageReports() {
LOGV("DeleteAllUsageReports");
OEMCryptoResult status;
WithOecLock("DeleteAllUsageReports", [&] {
WithOecWriteLock("DeleteAllUsageReports", [&] {
status = OEMCrypto_DeleteOldUsageTable();
});
metrics_->oemcrypto_delete_usage_table_.Increment(status);
@@ -1598,7 +1600,7 @@ CdmResponseType CryptoSession::DeleteAllUsageReports() {
bool CryptoSession::IsAntiRollbackHwPresent() {
bool is_present;
WithOecLock("IsAntiRollbackHwPresent", [&] {
WithOecReadLock("IsAntiRollbackHwPresent", [&] {
is_present = OEMCrypto_IsAntiRollbackHwPresent(requested_security_level_);
});
metrics_->oemcrypto_is_anti_rollback_hw_present_.Record(is_present);
@@ -1612,7 +1614,7 @@ CdmResponseType CryptoSession::GenerateNonce(uint32_t* nonce) {
}
OEMCryptoResult result;
WithOecLock("GenerateNonce", [&] {
WithOecSessionLock("GenerateNonce", [&] {
result = OEMCrypto_GenerateNonce(oec_session_id_, nonce);
});
metrics_->oemcrypto_generate_nonce_.Increment(result);
@@ -1690,7 +1692,7 @@ CdmResponseType CryptoSession::RewrapDeviceRSAKey(
// and 0 as wrapped_rsa_key_length.
size_t wrapped_rsa_key_length = 0;
OEMCryptoResult status;
WithOecLock("RewrapDeviceRSAKey Attempt 1", [&] {
WithOecSessionLock("RewrapDeviceRSAKey Attempt 1", [&] {
M_TIME(status = OEMCrypto_RewrapDeviceRSAKey(
oec_session_id_, signed_msg, message.size(),
reinterpret_cast<const uint8_t*>(signature.data()),
@@ -1705,7 +1707,7 @@ CdmResponseType CryptoSession::RewrapDeviceRSAKey(
}
wrapped_rsa_key->resize(wrapped_rsa_key_length);
WithOecLock("RewrapDeviceRSAKey Attempt 2", [&] {
WithOecSessionLock("RewrapDeviceRSAKey Attempt 2", [&] {
M_TIME(status = OEMCrypto_RewrapDeviceRSAKey(
oec_session_id_, signed_msg, message.size(),
reinterpret_cast<const uint8_t*>(signature.data()),
@@ -1749,7 +1751,7 @@ CdmResponseType CryptoSession::RewrapDeviceRSAKey30(
// and 0 as wrapped_rsa_key_length.
size_t wrapped_private_key_length = 0;
OEMCryptoResult status;
WithOecLock("RewrapDeviceRSAKey30 Attempt 1", [&] {
WithOecSessionLock("RewrapDeviceRSAKey30 Attempt 1", [&] {
M_TIME(
status = OEMCrypto_RewrapDeviceRSAKey30(
oec_session_id_, msg_nonce, msg_wrapping_key, wrapping_key.size(),
@@ -1766,7 +1768,7 @@ CdmResponseType CryptoSession::RewrapDeviceRSAKey30(
}
wrapped_private_key->resize(wrapped_private_key_length);
WithOecLock("RewrapDeviceRSAKey30 Attempt 2", [&] {
WithOecSessionLock("RewrapDeviceRSAKey30 Attempt 2", [&] {
M_TIME(
status = OEMCrypto_RewrapDeviceRSAKey30(
oec_session_id_, msg_nonce, msg_wrapping_key, wrapping_key.size(),
@@ -1809,7 +1811,7 @@ CdmResponseType CryptoSession::GetHdcpCapabilities(SecurityLevel security_level,
return PARAMETER_NULL;
}
OEMCryptoResult status;
WithOecLock("GetHdcpCapabilities", [&] {
WithOecReadLock("GetHdcpCapabilities", [&] {
status = OEMCrypto_GetHDCPCapability(security_level, current, max);
});
@@ -1837,7 +1839,7 @@ bool CryptoSession::GetSupportedCertificateTypes(
}
uint32_t oec_support;
WithOecLock("GetSupportedCertificateTypes", [&] {
WithOecReadLock("GetSupportedCertificateTypes", [&] {
oec_support = OEMCrypto_SupportedCertificates(requested_security_level_);
});
support->rsa_2048_bit = oec_support & OEMCrypto_Supports_RSA_2048bit;
@@ -1853,7 +1855,7 @@ CdmResponseType CryptoSession::GetRandom(size_t data_length,
return PARAMETER_NULL;
}
OEMCryptoResult sts;
WithOecLock("GetRandom", [&] {
WithOecReadLock("GetRandom", [&] {
sts = OEMCrypto_GetRandom(random_data, data_length);
});
metrics_->oemcrypto_get_random_.Increment(sts);
@@ -1876,7 +1878,7 @@ CdmResponseType CryptoSession::GetNumberOfOpenSessions(
size_t sessions_count;
OEMCryptoResult status;
WithOecLock("GetNumberOfOpenSessions", [&] {
WithOecReadLock("GetNumberOfOpenSessions", [&] {
status = OEMCrypto_GetNumberOfOpenSessions(security_level, &sessions_count);
});
@@ -1907,7 +1909,7 @@ CdmResponseType CryptoSession::GetMaxNumberOfSessions(
size_t max_sessions = 0;
OEMCryptoResult status;
WithOecLock("GetMaxNumberOfSessions", [&] {
WithOecReadLock("GetMaxNumberOfSessions", [&] {
status = OEMCrypto_GetMaxNumberOfSessions(security_level, &max_sessions);
});
@@ -1931,7 +1933,7 @@ CdmResponseType CryptoSession::GetSrmVersion(uint16_t* srm_version) {
}
OEMCryptoResult status;
WithOecLock("GetSrmVersion", [&] {
WithOecReadLock("GetSrmVersion", [&] {
status = OEMCrypto_GetCurrentSRMVersion(srm_version);
});
@@ -1942,7 +1944,7 @@ CdmResponseType CryptoSession::GetSrmVersion(uint16_t* srm_version) {
bool CryptoSession::IsSrmUpdateSupported() {
LOGV("IsSrmUpdateSupported");
if (!IsInitialized()) return false;
return WithOecLock("IsSrmUpdateSupported", [&] {
return WithOecReadLock("IsSrmUpdateSupported", [&] {
return OEMCrypto_IsSRMUpdateSupported();
});
}
@@ -1956,7 +1958,7 @@ CdmResponseType CryptoSession::LoadSrm(const std::string& srm) {
}
OEMCryptoResult status;
WithOecLock("LoadSrm", [&] {
WithOecWriteLock("LoadSrm", [&] {
status = OEMCrypto_LoadSRM(
reinterpret_cast<const uint8_t*>(srm.data()), srm.size());
});
@@ -1984,7 +1986,7 @@ bool CryptoSession::GetResourceRatingTier(SecurityLevel security_level,
LOGE("tier destination not provided");
return false;
}
WithOecLock("GetResourceRatingTier", [&] {
WithOecReadLock("GetResourceRatingTier", [&] {
*tier = OEMCrypto_ResourceRatingTier(security_level);
});
if (*tier < RESOURCE_RATING_TIER_LOW || *tier > RESOURCE_RATING_TIER_HIGH) {
@@ -2010,7 +2012,7 @@ bool CryptoSession::GetBuildInformation(SecurityLevel security_level,
return false;
}
const char* build_information;
WithOecLock("GetBuildInformation", [&] {
WithOecReadLock("GetBuildInformation", [&] {
build_information = OEMCrypto_BuildInformation(security_level);
});
if (build_information == nullptr) {
@@ -2030,7 +2032,7 @@ uint32_t CryptoSession::IsDecryptHashSupported(SecurityLevel security_level) {
}
uint32_t secure_decrypt_support;
WithOecLock("IsDecryptHashSupported", [&] {
WithOecReadLock("IsDecryptHashSupported", [&] {
secure_decrypt_support = OEMCrypto_SupportsDecryptHash(security_level);
});
switch (secure_decrypt_support) {
@@ -2052,7 +2054,7 @@ CdmResponseType CryptoSession::SetDecryptHash(
const std::string& hash) {
LOGV("SetDecryptHash");
OEMCryptoResult sts;
WithOecLock("SetDecryptHash", [&] {
WithOecSessionLock("SetDecryptHash", [&] {
sts = OEMCrypto_SetDecryptHash(
oec_session_id_, frame_number,
reinterpret_cast<const uint8_t*>(hash.data()), hash.size());
@@ -2071,7 +2073,7 @@ CdmResponseType CryptoSession::GetDecryptHashError(std::string* error_string) {
uint32_t failed_frame_number;
OEMCryptoResult sts;
WithOecLock("GetDecryptHashError", [&] {
WithOecSessionLock("GetDecryptHashError", [&] {
sts = OEMCrypto_GetHashErrorCode(oec_session_id_, &failed_frame_number);
});
error_string->assign(std::to_string(sts));
@@ -2127,7 +2129,7 @@ CdmResponseType CryptoSession::GenericEncrypt(const std::string& in_buffer,
OEMCryptoResult sts;
WithOecLock("GenericEncrypt", [&] {
WithOecSessionLock("GenericEncrypt", [&] {
M_TIME(
sts = OEMCrypto_Generic_Encrypt(
oec_session_id_, reinterpret_cast<const uint8_t*>(in_buffer.data()),
@@ -2190,7 +2192,7 @@ CdmResponseType CryptoSession::GenericDecrypt(const std::string& in_buffer,
OEMCryptoResult sts;
WithOecLock("GenericDecrypt", [&] {
WithOecSessionLock("GenericDecrypt", [&] {
M_TIME(
sts = OEMCrypto_Generic_Decrypt(
oec_session_id_, reinterpret_cast<const uint8_t*>(in_buffer.data()),
@@ -2251,7 +2253,7 @@ CdmResponseType CryptoSession::GenericSign(const std::string& message,
// At most two attempts.
// The first attempt may fail due to buffer too short
for (int i = 0; i < 2; ++i) {
WithOecLock("GenericSign", [&] {
WithOecSessionLock("GenericSign", [&] {
M_TIME(
sts = OEMCrypto_Generic_Sign(
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
@@ -2312,7 +2314,7 @@ CdmResponseType CryptoSession::GenericVerify(const std::string& message,
if (result != NO_ERROR) return result;
OEMCryptoResult sts;
WithOecLock("GenericVerify", [&] {
WithOecSessionLock("GenericVerify", [&] {
M_TIME(
sts = OEMCrypto_Generic_Verify(
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
@@ -2391,7 +2393,7 @@ CdmResponseType CryptoSession::CreateUsageTableHeader(
size_t usage_table_header_size = usage_table_header->size();
OEMCryptoResult result;
WithOecLock("CreateUsageTableHeader Attempt 1", [&] {
WithOecWriteLock("CreateUsageTableHeader Attempt 1", [&] {
result = OEMCrypto_CreateUsageTableHeader(
requested_security_level_,
reinterpret_cast<uint8_t*>(
@@ -2401,7 +2403,7 @@ CdmResponseType CryptoSession::CreateUsageTableHeader(
if (result == OEMCrypto_ERROR_SHORT_BUFFER) {
usage_table_header->resize(usage_table_header_size);
WithOecLock("CreateUsageTableHeader Attempt 2", [&] {
WithOecWriteLock("CreateUsageTableHeader Attempt 2", [&] {
result = OEMCrypto_CreateUsageTableHeader(
requested_security_level_,
reinterpret_cast<uint8_t*>(
@@ -2423,7 +2425,7 @@ CdmResponseType CryptoSession::LoadUsageTableHeader(
LOGV("LoadUsageTableHeader: id=%lu", oec_session_id_);
OEMCryptoResult result;
WithOecLock("LoadUsageTableHeader", [&] {
WithOecWriteLock("LoadUsageTableHeader", [&] {
result = OEMCrypto_LoadUsageTableHeader(
requested_security_level_,
reinterpret_cast<const uint8_t*>(usage_table_header.data()),
@@ -2468,7 +2470,7 @@ CdmResponseType CryptoSession::CreateUsageEntry(uint32_t* entry_number) {
}
OEMCryptoResult result;
WithOecLock("CreateUsageEntry", [&] {
WithOecWriteLock("CreateUsageEntry", [&] {
result = OEMCrypto_CreateNewUsageEntry(oec_session_id_, entry_number);
});
@@ -2495,7 +2497,7 @@ CdmResponseType CryptoSession::LoadUsageEntry(
LOGV("LoadUsageEntry: id=%lu", oec_session_id_);
OEMCryptoResult result;
WithOecLock("LoadUsageEntry", [&] {
WithOecWriteLock("LoadUsageEntry", [&] {
result = OEMCrypto_LoadUsageEntry(
oec_session_id_, entry_number,
reinterpret_cast<const uint8_t*>(usage_entry.data()),
@@ -2546,7 +2548,7 @@ CdmResponseType CryptoSession::UpdateUsageEntry(
size_t usage_table_header_len = 0;
size_t usage_entry_len = 0;
OEMCryptoResult result;
WithOecLock("UpdateUsageEntry Attempt 1", [&] {
WithOecWriteLock("UpdateUsageEntry Attempt 1", [&] {
result = OEMCrypto_UpdateUsageEntry(
oec_session_id_, NULL, &usage_table_header_len, NULL, &usage_entry_len);
});
@@ -2556,7 +2558,7 @@ CdmResponseType CryptoSession::UpdateUsageEntry(
usage_table_header->resize(usage_table_header_len);
usage_entry->resize(usage_entry_len);
WithOecLock("UpdateUsageEntry Attempt 2", [&] {
WithOecWriteLock("UpdateUsageEntry Attempt 2", [&] {
result = OEMCrypto_UpdateUsageEntry(
oec_session_id_,
reinterpret_cast<uint8_t*>(
@@ -2588,7 +2590,7 @@ CdmResponseType CryptoSession::ShrinkUsageTableHeader(
size_t usage_table_header_len = 0;
OEMCryptoResult result;
WithOecLock("ShrinkUsageTableHeader Attempt 1", [&] {
WithOecWriteLock("ShrinkUsageTableHeader Attempt 1", [&] {
result = OEMCrypto_ShrinkUsageTableHeader(
requested_security_level_, new_entry_count, NULL,
&usage_table_header_len);
@@ -2597,7 +2599,7 @@ CdmResponseType CryptoSession::ShrinkUsageTableHeader(
if (result == OEMCrypto_ERROR_SHORT_BUFFER) {
usage_table_header->resize(usage_table_header_len);
WithOecLock("ShrinkUsageTableHeader Attempt 2", [&] {
WithOecWriteLock("ShrinkUsageTableHeader Attempt 2", [&] {
result = OEMCrypto_ShrinkUsageTableHeader(
requested_security_level_, new_entry_count,
reinterpret_cast<uint8_t*>(
@@ -2618,7 +2620,7 @@ CdmResponseType CryptoSession::MoveUsageEntry(uint32_t new_entry_number) {
LOGV("MoveUsageEntry: id=%lu", oec_session_id_);
OEMCryptoResult result;
WithOecLock("MoveUsageEntry", [&] {
WithOecWriteLock("MoveUsageEntry", [&] {
result = OEMCrypto_MoveEntry(oec_session_id_, new_entry_number);
});
@@ -2660,7 +2662,7 @@ bool CryptoSession::CreateOldUsageEntry(
}
OEMCryptoResult result;
WithOecLock("CreateOldUsageEntry", [&] {
WithOecWriteLock("CreateOldUsageEntry", [&] {
result = OEMCrypto_CreateOldUsageEntry(
requested_security_level_, time_since_license_received,
time_since_first_decrypt, time_since_last_decrypt, status,
@@ -2683,7 +2685,7 @@ CdmResponseType CryptoSession::CopyOldUsageEntry(
LOGV("CopyOldUsageEntry: id=%lu", oec_session_id_);
OEMCryptoResult result;
WithOecLock("CopyOldUsageEntry", [&] {
WithOecWriteLock("CopyOldUsageEntry", [&] {
result = OEMCrypto_CopyOldUsageEntry(
oec_session_id_,
reinterpret_cast<const uint8_t*>(provider_session_token.data()),
@@ -2699,7 +2701,7 @@ bool CryptoSession::GetAnalogOutputCapabilities(bool* can_support_output,
bool* can_support_cgms_a) {
LOGV("GetAnalogOutputCapabilities: id=%lu", oec_session_id_);
uint32_t flags;
WithOecLock("GetAnalogOutputCapabilities", [&] {
WithOecReadLock("GetAnalogOutputCapabilities", [&] {
flags = OEMCrypto_GetAnalogOutputFlags(requested_security_level_);
});
@@ -2779,7 +2781,7 @@ OEMCryptoResult CryptoSession::CopyBufferInChunks(
}
OEMCryptoResult sts;
WithOecLock("CopyBufferInChunks", [&] {
WithOecSessionLock("CopyBufferInChunks", [&] {
M_TIME(sts = OEMCrypto_CopyBuffer(
oec_session_id_, params.encrypt_buffer + additional_offset,
chunk_size, &buffer_descriptor, subsample_flags),
@@ -2853,7 +2855,7 @@ OEMCryptoResult CryptoSession::DecryptInChunks(
// pattern length long, which is also guaranteed to be an exact number
// of AES blocks long.
OEMCryptoResult sts;
WithOecLock("DecryptInChunks", [&] {
WithOecSessionLock("DecryptInChunks", [&] {
M_TIME(
sts = OEMCrypto_DecryptCENC(
oec_session_id_, params.encrypt_buffer + additional_offset,
@@ -2927,27 +2929,52 @@ void CryptoSession::IncrementIV(uint64_t increase_by,
}
template <class Func>
auto CryptoSession::WithStaticFieldLock(const char* tag, Func body)
auto CryptoSession::WithStaticFieldWriteLock(const char* tag, Func body)
-> decltype(body()) {
LOGV("Static Field Lock - %s", tag);
std::unique_lock<std::mutex> auto_lock(static_field_lock_);
LOGV("Static Field Write Lock - %s", tag);
std::unique_lock<shared_mutex> auto_lock(static_field_mutex_);
return body();
}
template <class Func>
auto CryptoSession::WithOecLock(const char* tag, Func body)
auto CryptoSession::WithStaticFieldReadLock(const char* tag, Func body)
-> decltype(body()) {
LOGV("OEMCrypto Lock - %s", tag);
std::unique_lock<std::mutex> auto_lock(oem_crypto_lock_);
LOGV("Static Field Read Lock - %s", tag);
shared_lock<shared_mutex> auto_lock(static_field_mutex_);
return body();
}
template <class Func>
auto CryptoSession::WithOecWriteLock(const char* tag, Func body)
-> decltype(body()) {
LOGV("OEMCrypto Write Lock - %s", tag);
std::unique_lock<shared_mutex> auto_lock(oem_crypto_mutex_);
return body();
}
template <class Func>
auto CryptoSession::WithOecReadLock(const char* tag, Func body)
-> decltype(body()) {
LOGV("OEMCrypto Read Lock - %s", tag);
shared_lock<shared_mutex> auto_lock(oem_crypto_mutex_);
return body();
}
template <class Func>
auto CryptoSession::WithOecSessionLock(const char* tag, Func body)
-> decltype(body()) {
LOGV("OEMCrypto Session Lock - %s", tag);
shared_lock<shared_mutex> oec_auto_lock(oem_crypto_mutex_);
std::unique_lock<std::mutex> session_auto_lock(oem_crypto_session_mutex_);
return body();
}
bool CryptoSession::IsInitialized() {
return WithStaticFieldLock("IsInitialized", [] { return initialized_; });
return WithStaticFieldReadLock("IsInitialized", [] { return initialized_; });
}
// CryptoSesssionFactory support
std::mutex CryptoSession::factory_lock_;
std::mutex CryptoSession::factory_mutex_;
// The factory will either be set by WvCdmTestBase, or a default factory is
// created on the first call to MakeCryptoSession.
std::unique_ptr<CryptoSessionFactory> CryptoSession::factory_ =
@@ -2955,7 +2982,7 @@ std::unique_ptr<CryptoSessionFactory> CryptoSession::factory_ =
CryptoSession* CryptoSession::MakeCryptoSession(
metrics::CryptoMetrics* crypto_metrics) {
std::unique_lock<std::mutex> auto_lock(factory_lock_);
std::unique_lock<std::mutex> auto_lock(factory_mutex_);
// If the factory_ has not been set, then use a default factory.
if (factory_.get() == NULL) factory_.reset(new CryptoSessionFactory());
return factory_->MakeCryptoSession(crypto_metrics);