From 7e97ba438385c5e07ac588e4dc16ad4b5739e4c6 Mon Sep 17 00:00:00 2001 From: "John W. Bruce" Date: Tue, 19 Feb 2019 13:51:11 -0800 Subject: [PATCH] Split CryptoSession Lock into Three (This is a merge of http://go/wvgerrit/71324) This patch increases the granularity of the locking in CryptoSession without substantially changing its locking semantics. Where before there was a single |crypto_lock_| performing multiple duties, now there are three locks: 1) |static_field_lock_|, which is used when needing to access the non-atomic static member fields of CryptoSession. 2) |oem_crypto_lock_|, which is used when needing to call into OEMCrypto. 3) |factory_lock_|, used only by the functions that interact with the CryptoSession factory. All the code in CryptoSession has been updated to use these locks. It has also been updated to only hold them for the minimal amount of time necessary, as opposed to holding them for a whole function. This should help some with the ability of CryptoSession calls to happen concurrently. To assist in taking locks in a consistent manner, two helper functions, |WithStaticFieldLock()| and |WithOecLock()| have been added. Also, for the very common case of reading |initialized_|, the accessor |IsInitialized()| will read the value safely. While changing all the code to lock differently, I found that some places in CryptoSession were *not* locking before accessing static state or calling into OEMCrypto. I have made these callsites consistent with the rest of CryptoSession. As a result of taking locks for only the minimum time necessary, it is no longer necessary for functions to make assumptions about whether the lock will already be held before they are called. Locks should not be held while calling helper functions, and code should always take a lock for the brief time it is necessary to do so. In tests, including the concurrent unit tests coming in the following patch, this code did not perform substantially better or worse than the code that preceded it, but the hope is that it will experience less contention on devices that are more resource-constrained than my desktop, such as older game consoles. This patch appears to address some real threading issues. Hopefully, it will also make it easier to maintain soundness in the future and to reason about when code in CryptoSession needs to take a lock. This is the first step to implementing the "Finer-Grained Locking in CryptoSession" specification. A future patch will make some of these locks reader-writer locks, to allow even greater parallelism. Bug: 70889998 Bug: 118584039 Bug: 123319961 Test: CE CDM Unit Tests Test: Android Unit Tests Test: GTS Test: Play Movies Test: Netflix Change-Id: I346c04a5d9875723db54af33ee91772bf49ca12f --- .../cdm/core/include/crypto_session.h | 41 +- .../cdm/core/src/crypto_session.cpp | 1018 ++++++++++------- 2 files changed, 627 insertions(+), 432 deletions(-) diff --git a/libwvdrmengine/cdm/core/include/crypto_session.h b/libwvdrmengine/cdm/core/include/crypto_session.h index a3769473..1e3f85c6 100644 --- a/libwvdrmengine/cdm/core/include/crypto_session.h +++ b/libwvdrmengine/cdm/core/include/crypto_session.h @@ -158,7 +158,7 @@ class CryptoSession { HdcpCapability* max); virtual CdmResponseType GetHdcpCapabilities(SecurityLevel security_level, HdcpCapability* current, - HdcpCapability* max); + HdcpCapability* max); virtual bool GetResourceRatingTier(uint32_t* tier); virtual bool GetResourceRatingTier(SecurityLevel security_level, uint32_t* tier); @@ -180,11 +180,10 @@ class CryptoSession { virtual uint32_t IsDecryptHashSupported(SecurityLevel security_level); virtual CdmResponseType SetDecryptHash(uint32_t frame_number, - const std::string& hash); + const std::string& hash); virtual CdmResponseType GetDecryptHashError(std::string* error_string); - virtual CdmResponseType GenericEncrypt(const std::string& in_buffer, const std::string& key_id, const std::string& iv, @@ -257,6 +256,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 auto_lock(factory_lock_); factory_.reset(factory); } @@ -311,9 +311,38 @@ class CryptoSession { size_t max_chunk_size); static void IncrementIV(uint64_t increase_by, std::vector* iv_out); + // These methods should be used to take the various CryptoSession locks in + // preference to taking the locks 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.) + template + static auto WithStaticFieldLock(const char* tag, Func body) + -> decltype(body()); + + template + static auto WithOecLock(const char* tag, Func body) -> decltype(body()); + + static bool IsInitialized(); + + // Constants static const size_t kAes128BlockSize = 16; // Block size for AES_CBC_128 static const size_t kSignatureSize = 32; // size for HMAC-SHA256 signature - static std::mutex crypto_lock_; + + // 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_; + static bool initialized_; static int session_count_; @@ -344,6 +373,10 @@ class CryptoSession { CdmCipherMode cipher_mode_; 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_; static std::unique_ptr factory_; CORE_DISALLOW_COPY_AND_ASSIGN(CryptoSession); diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index 6b4a8c04..5e736b7b 100644 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -75,7 +75,8 @@ void DeleteX509Stack(STACK_OF(X509)* stack) { } // namespace namespace wvcdm { -std::mutex CryptoSession::crypto_lock_; +std::mutex CryptoSession::static_field_lock_; +std::mutex CryptoSession::oem_crypto_lock_; bool CryptoSession::initialized_ = false; int CryptoSession::session_count_ = 0; UsageTableHeader* CryptoSession::usage_table_header_l1_ = NULL; @@ -212,8 +213,10 @@ CryptoSession::~CryptoSession() { CdmResponseType CryptoSession::GetProvisioningMethod( SecurityLevel requested_security_level, CdmClientTokenType* token_type) { - OEMCrypto_ProvisioningMethod method = - OEMCrypto_GetProvisioningMethod(requested_security_level); + OEMCrypto_ProvisioningMethod method; + WithOecLock("GetProvisioningMethod", [&] { + method = OEMCrypto_GetProvisioningMethod(requested_security_level); + }); metrics_->oemcrypto_provisioning_method_.Record(method); CdmClientTokenType type; switch (method) { @@ -238,51 +241,60 @@ CdmResponseType CryptoSession::GetProvisioningMethod( void CryptoSession::Init() { LOGV("CryptoSession::Init"); - std::unique_lock auto_lock(crypto_lock_); - session_count_ += 1; - if (!initialized_) { - std::string sandbox_id; - OEMCryptoResult sts; - if (Properties::GetSandboxId(&sandbox_id) && !sandbox_id.empty()) { - sts = OEMCrypto_SetSandbox( - reinterpret_cast(sandbox_id.c_str()), - sandbox_id.length()); - // TODO(blueeyes): it might be worth saving the sandbox id in a metric. + WithStaticFieldLock("Init", [&] { + session_count_ += 1; + if (!initialized_) { + std::string sandbox_id; + OEMCryptoResult sts; + WithOecLock("Init", [&] { + if (Properties::GetSandboxId(&sandbox_id) && !sandbox_id.empty()) { + sts = OEMCrypto_SetSandbox( + reinterpret_cast(sandbox_id.c_str()), + sandbox_id.length()); + // TODO(blueeyes): it might be worth saving the sandbox id in a + // metric. + } + M_TIME(sts = OEMCrypto_Initialize(), metrics_, oemcrypto_initialize_, + sts); + }); + if (OEMCrypto_SUCCESS != sts) { + LOGE("OEMCrypto_Initialize failed: %d", sts); + return; + } + initialized_ = true; } - M_TIME(sts = OEMCrypto_Initialize(), metrics_, oemcrypto_initialize_, sts); - if (OEMCrypto_SUCCESS != sts) { - LOGE("OEMCrypto_Initialize failed: %d", sts); - return; - } - initialized_ = true; - } + }); } void CryptoSession::Terminate() { - LOGV("CryptoSession::Terminate: initialized_=%d, session_count_=%d", - initialized_, session_count_); - std::unique_lock auto_lock(crypto_lock_); - if (session_count_ > 0) { - session_count_ -= 1; - } else { - LOGE("CryptoSession::Terminate error, session count: %d", session_count_); - } - if (session_count_ > 0 || !initialized_) return; - OEMCryptoResult sts = OEMCrypto_Terminate(); - if (OEMCrypto_SUCCESS != sts) { - LOGE("OEMCrypto_Terminate failed: %d", sts); - } + LOGV("CryptoSession::Terminate"); + WithStaticFieldLock("Terminate", [&] { + LOGV("initialized_=%d, session_count_=%d", initialized_, session_count_); + if (session_count_ > 0) { + session_count_ -= 1; + } else { + LOGE("CryptoSession::Terminate error, session count: %d", session_count_); + } + if (session_count_ > 0 || !initialized_) return; + OEMCryptoResult sts; + WithOecLock("Terminate", [&] { + sts = OEMCrypto_Terminate(); + }); + if (OEMCrypto_SUCCESS != sts) { + LOGE("OEMCrypto_Terminate failed: %d", sts); + } - if (usage_table_header_l1_ != NULL) { - delete usage_table_header_l1_; - usage_table_header_l1_ = NULL; - } - if (usage_table_header_l3_ != NULL) { - delete usage_table_header_l3_; - usage_table_header_l3_ = NULL; - } + if (usage_table_header_l1_ != NULL) { + delete usage_table_header_l1_; + usage_table_header_l1_ = NULL; + } + if (usage_table_header_l3_ != NULL) { + delete usage_table_header_l3_; + usage_table_header_l3_ = NULL; + } - initialized_ = false; + initialized_ = false; + }); } CdmResponseType CryptoSession::GetTokenFromKeybox(std::string* token) { @@ -291,14 +303,17 @@ CdmResponseType CryptoSession::GetTokenFromKeybox(std::string* token) { return PARAMETER_NULL; } std::string temp_buffer(KEYBOX_KEY_DATA_SIZE, '\0'); - // lock is held by caller size_t buf_size = temp_buffer.size(); uint8_t* buf = reinterpret_cast(&temp_buffer[0]); OEMCryptoResult status; - M_TIME( - status = OEMCrypto_GetKeyData(buf, &buf_size, requested_security_level_), - metrics_, oemcrypto_get_key_data_, status, metrics::Pow2Bucket(buf_size)); + WithOecLock("GetTokenFromKeybox", [&] { + M_TIME( + status = + OEMCrypto_GetKeyData(buf, &buf_size, requested_security_level_), + metrics_, oemcrypto_get_key_data_, status, + metrics::Pow2Bucket(buf_size)); + }); if (OEMCrypto_SUCCESS == status) { token->swap(temp_buffer); @@ -319,12 +334,14 @@ CdmResponseType CryptoSession::GetTokenFromOemCert(std::string* token) { return NO_ERROR; } std::string temp_buffer(CERTIFICATE_DATA_SIZE, '\0'); - // lock is held by caller bool retrying = false; while (true) { size_t buf_size = temp_buffer.size(); uint8_t* buf = reinterpret_cast(&temp_buffer[0]); - status = OEMCrypto_GetOEMPublicCertificate(oec_session_id_, buf, &buf_size); + WithOecLock("GetTokenFromOemCert", [&] { + status = OEMCrypto_GetOEMPublicCertificate(oec_session_id_, buf, + &buf_size); + }); metrics_->oemcrypto_get_oem_public_certificate_.Increment(status); if (OEMCrypto_SUCCESS == status) { @@ -351,12 +368,9 @@ CdmResponseType CryptoSession::GetProvisioningToken(std::string* token) { metrics_->crypto_session_get_token_.Increment(PARAMETER_NULL); return PARAMETER_NULL; } - LOGV("CryptoSession::GetProvisioningToken: Lock"); - std::unique_lock auto_lock(crypto_lock_); - if (!initialized_) { - metrics_->crypto_session_get_token_.Increment( - CRYPTO_SESSION_NOT_INITIALIZED); + if (!IsInitialized()) { + metrics_->crypto_session_get_token_.Increment(CRYPTO_SESSION_NOT_INITIALIZED); return CRYPTO_SESSION_NOT_INITIALIZED; } @@ -382,12 +396,15 @@ CdmSecurityLevel CryptoSession::GetSecurityLevel() { CdmSecurityLevel CryptoSession::GetSecurityLevel( SecurityLevel requested_level) { LOGV("CryptoSession::GetSecurityLevel"); - if (!initialized_) { - LOGW("CryptoSession::GetSecurityLevel: not initialized"); + if (!IsInitialized()) { + LOGW("Not Initialized"); return kSecurityLevelUninitialized; } - std::string security_level = OEMCrypto_SecurityLevel(requested_level); + std::string security_level; + WithOecLock("GetSecurityLevel", [&] { + security_level = OEMCrypto_SecurityLevel(requested_level); + }); if ((security_level.size() != 2) || (security_level.at(0) != 'L')) { return kSecurityLevelUnknown; @@ -421,9 +438,7 @@ CdmResponseType CryptoSession::GetInternalDeviceUniqueId( return PARAMETER_NULL; } - LOGV("CryptoSession::GetInternalDeviceUniqueId: Lock"); - std::unique_lock auto_lock(crypto_lock_); - if (!initialized_) { + if (!IsInitialized()) { LOGE("CryptoSession::GetInternalDeviceUniqueId: not initialized"); return CRYPTO_SESSION_NOT_INITIALIZED; } @@ -432,13 +447,18 @@ CdmResponseType CryptoSession::GetInternalDeviceUniqueId( size_t id_length = 32; id.resize(id_length); - OEMCryptoResult sts = - OEMCrypto_GetDeviceID(&id[0], &id_length, requested_security_level_); + OEMCryptoResult sts; + WithOecLock("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); - sts = OEMCrypto_GetDeviceID(&id[0], &id_length, requested_security_level_); + WithOecLock("GetInternalDeviceUniqueId Attempt 2", [&] { + sts = OEMCrypto_GetDeviceID(&id[0], &id_length, + requested_security_level_); + }); metrics_->oemcrypto_get_device_id_.Increment(sts); } @@ -473,8 +493,10 @@ CdmResponseType CryptoSession::GetExternalDeviceUniqueId( if (status != NO_ERROR) return status; size_t id_length = 0; - OEMCryptoResult sts = - OEMCrypto_GetDeviceID(NULL, &id_length, requested_security_level_); + OEMCryptoResult sts; + WithOecLock("GetExternalDeviceUniqueId", [&] { + sts = OEMCrypto_GetDeviceID(NULL, &id_length, requested_security_level_); + }); metrics_->oemcrypto_get_device_id_.Increment(sts); if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED && @@ -511,12 +533,14 @@ bool CryptoSession::GetApiVersion(SecurityLevel security_level, return false; } - if (!initialized_) { + if (!IsInitialized()) { LOGW("CryptoSession::GetApiVersion: not initialized"); return false; } - *version = OEMCrypto_APIVersion(security_level); + WithOecLock("GetApiVersion", [&] { + *version = OEMCrypto_APIVersion(security_level); + }); // Record the version into the metrics. metrics_->oemcrypto_api_version_.Record(*version); @@ -529,9 +553,7 @@ bool CryptoSession::GetSystemId(uint32_t* system_id) { return false; } - LOGV("CryptoSession::GetSystemId: Lock"); - std::unique_lock auto_lock(crypto_lock_); - if (!initialized_ || !open_) { + if (!IsInitialized() || !open_) { return false; } *system_id = system_id_; @@ -539,8 +561,8 @@ bool CryptoSession::GetSystemId(uint32_t* system_id) { } // This method gets the system id from the keybox key data. -// This method assumes that OEMCrypto has been initialized and that -// the caller has acquired the crypto_lock_ before making this call. +// This method assumes that OEMCrypto has been initialized before making this +// call. CdmResponseType CryptoSession::GetSystemIdInternal(uint32_t* system_id) { if (system_id == nullptr) { LOGE("CryptoSession::GetSystemIdInternal: No system_id passed to method."); @@ -695,12 +717,8 @@ CdmResponseType CryptoSession::GetProvisioningId(std::string* provisioning_id) { return PARAMETER_NULL; } - { - LOGV("CryptoSession::GetProvisioningId: Lock"); - std::unique_lock auto_lock(crypto_lock_); - if (!initialized_) { - return CRYPTO_SESSION_NOT_INITIALIZED; - } + if (!IsInitialized()) { + return CRYPTO_SESSION_NOT_INITIALIZED; } if (pre_provision_token_type_ == kClientTokenOemCert) { @@ -718,8 +736,6 @@ CdmResponseType CryptoSession::GetProvisioningId(std::string* provisioning_id) { return NO_ERROR; } else if (pre_provision_token_type_ == kClientTokenKeybox) { - LOGV("CryptoSession::GetProvisioningId: Lock"); - std::unique_lock auto_lock(crypto_lock_); std::string token; CdmResponseType status = GetTokenFromKeybox(&token); @@ -735,42 +751,45 @@ CdmResponseType CryptoSession::GetProvisioningId(std::string* provisioning_id) { return NO_ERROR; } else { LOGE("CryptoSession::GetProvisioningId: unsupported token type: %d", - pre_provision_token_type_); + pre_provision_token_type_); return UNKNOWN_CLIENT_TOKEN_TYPE; } } uint8_t CryptoSession::GetSecurityPatchLevel() { - uint8_t patch = OEMCrypto_Security_Patch_Level(requested_security_level_); + uint8_t patch; + WithOecLock("GetSecurityPatchLevel", [&] { + patch = OEMCrypto_Security_Patch_Level(requested_security_level_); + }); metrics_->oemcrypto_security_patch_level_.Record(patch); return patch; } CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) { - { - LOGD("CryptoSession::Open: Lock: requested_security_level: %s", - requested_security_level == kLevel3 - ? QUERY_VALUE_SECURITY_LEVEL_L3.c_str() - : QUERY_VALUE_SECURITY_LEVEL_DEFAULT.c_str()); - std::unique_lock auto_lock(crypto_lock_); - if (!initialized_) return UNKNOWN_ERROR; - if (open_) return NO_ERROR; - } + LOGD("CryptoSession::Open: requested_security_level: %s", + requested_security_level == kLevel3 + ? QUERY_VALUE_SECURITY_LEVEL_L3.c_str() + : QUERY_VALUE_SECURITY_LEVEL_DEFAULT.c_str()); + if (!IsInitialized()) return UNKNOWN_ERROR; + if (open_) return NO_ERROR; CdmResponseType result = GetProvisioningMethod(requested_security_level, &pre_provision_token_type_); if (result != NO_ERROR) return result; - LOGV("CryptoSession::Open: Lock"); - std::unique_lock auto_lock(crypto_lock_); OEMCrypto_SESSION sid; requested_security_level_ = requested_security_level; - OEMCryptoResult sts = OEMCrypto_OpenSession(&sid, requested_security_level); + OEMCryptoResult sts; + WithOecLock("Open() calling OEMCrypto_OpenSession", [&] { + sts = OEMCrypto_OpenSession(&sid, requested_security_level); + }); if (sts != OEMCrypto_SUCCESS) { - LOGE("OEMCrypto_Open failed: %d, open sessions: %ld, initialized: %d", sts, - session_count_, (int)initialized_); + WithStaticFieldLock("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"); } @@ -788,8 +807,11 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) { } uint64_t request_id_base; - OEMCryptoResult random_sts = OEMCrypto_GetRandom( - reinterpret_cast(&request_id_base), sizeof(request_id_base)); + OEMCryptoResult random_sts; + WithOecLock("Open() calling OEMCrypto_GetRandom", [&] { + random_sts = OEMCrypto_GetRandom( + reinterpret_cast(&request_id_base), sizeof(request_id_base)); + }); metrics_->oemcrypto_get_random_.Increment(random_sts); uint64_t request_id_index = request_id_index_source_.fetch_add(1, std::memory_order_relaxed); @@ -811,33 +833,42 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) { CdmSecurityLevel security_level = GetSecurityLevel(); if (security_level == kSecurityLevelL1 || security_level == kSecurityLevelL3) { - UsageTableHeader** header = security_level == kSecurityLevelL1 - ? &usage_table_header_l1_ - : &usage_table_header_l3_; - if (*header == NULL) { - *header = new UsageTableHeader(); - // Ignore errors since we do not know when a session is opened, - // if it is intended to be used for offline/usage session related - // or otherwise. - auto_lock.unlock(); - bool is_usage_table_header_inited = - (*header)->Init(security_level, this); - auto_lock.lock(); - if (!is_usage_table_header_inited) { - delete *header; - *header = NULL; - usage_table_header_ = NULL; - return NO_ERROR; + { + // 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 auto_lock(static_field_lock_); + + UsageTableHeader** header = security_level == kSecurityLevelL1 + ? &usage_table_header_l1_ + : &usage_table_header_l3_; + if (*header == NULL) { + *header = new UsageTableHeader(); + // Ignore errors since we do not know when a session is opened, + // if it is intended to be used for offline/usage session related + // or otherwise. + auto_lock.unlock(); + bool is_usage_table_header_inited = + (*header)->Init(security_level, this); + auto_lock.lock(); + if (!is_usage_table_header_inited) { + delete *header; + *header = NULL; + usage_table_header_ = NULL; + return NO_ERROR; + } } + usage_table_header_ = *header; } - usage_table_header_ = *header; } } } else { metrics_->oemcrypto_usage_table_support_.SetError(result); } - key_session_.reset(new ContentKeySession(oec_session_id_, metrics_)); + WithOecLock("Open() calling key_session_.reset()", [&] { + key_session_.reset(new ContentKeySession(oec_session_id_, metrics_)); + }); return NO_ERROR; } @@ -845,18 +876,16 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) { void CryptoSession::Close() { LOGV("CloseSession: id=%lu open=%s", oec_session_id_, open_ ? "true" : "false"); + if (!open_) return; OEMCryptoResult close_sts; bool update_usage_table = false; - { - std::unique_lock auto_lock(crypto_lock_); - if (!open_) return; - + WithOecLock("Close", [&] { close_sts = OEMCrypto_CloseSession(oec_session_id_); - metrics_->oemcrypto_close_session_.Increment(close_sts); - if (OEMCrypto_SUCCESS == close_sts) open_ = false; - update_usage_table = update_usage_table_after_close_session_; - } + }); + metrics_->oemcrypto_close_session_.Increment(close_sts); + if (OEMCrypto_SUCCESS == close_sts) open_ = false; + update_usage_table = update_usage_table_after_close_session_; if (close_sts == OEMCrypto_SUCCESS && update_usage_table && usage_support_type_ == kUsageTableSupport) { UpdateUsageInformation(); @@ -864,11 +893,8 @@ void CryptoSession::Close() { } CdmResponseType CryptoSession::PrepareRequest(const std::string& message, - bool is_provisioning, - std::string* signature) { - LOGV("CryptoSession::PrepareRequest: Lock"); - std::unique_lock auto_lock(crypto_lock_); - + bool is_provisioning, + std::string* signature) { if (signature == nullptr) { LOGE("CryptoSession::PrepareRequest : No output destination provided."); return PARAMETER_NULL; @@ -887,9 +913,6 @@ CdmResponseType CryptoSession::PrepareRequest(const std::string& message, CdmResponseType CryptoSession::PrepareRenewalRequest(const std::string& message, std::string* signature) { - LOGV("CryptoSession::PrepareRenewalRequest: Lock"); - std::unique_lock auto_lock(crypto_lock_); - if (signature == nullptr) { LOGE( "CryptoSession::PrepareRenewalRequest : No output destination " @@ -907,45 +930,44 @@ CdmResponseType CryptoSession::LoadKeys( const std::string& provider_session_token, const std::string& srm_requirement, CdmLicenseKeyType key_type) { CdmResponseType result = KEY_ADDED; - { - LOGV("CryptoSession::LoadKeys: Lock"); - std::unique_lock auto_lock(crypto_lock_); + OEMCryptoResult sts; + WithOecLock("LoadKeys", [&] { if (key_type == kLicenseKeyTypeEntitlement && key_session_->Type() != KeySession::kEntitlement) { key_session_.reset(new EntitlementKeySession(oec_session_id_, metrics_)); } LOGV("LoadKeys: id=%lu", oec_session_id_); - OEMCryptoResult sts = key_session_->LoadKeys( + sts = key_session_->LoadKeys( message, signature, mac_key_iv, mac_key, keys, provider_session_token, &cipher_mode_, srm_requirement); + }); - if (sts != OEMCrypto_SUCCESS) { - LOGE("CryptoSession::LoadKeys: OEMCrypto_LoadKeys error=%d", sts); - } + if (sts != OEMCrypto_SUCCESS) { + LOGE("CryptoSession::LoadKeys: OEMCrypto_LoadKeys error=%d", sts); + } - switch (sts) { - case OEMCrypto_SUCCESS: - if (!provider_session_token.empty()) - update_usage_table_after_close_session_ = true; - result = KEY_ADDED; - break; - case OEMCrypto_ERROR_TOO_MANY_KEYS: - result = INSUFFICIENT_CRYPTO_RESOURCES_4; - break; - case OEMCrypto_ERROR_USAGE_TABLE_UNRECOVERABLE: - // Handle vendor specific error - return NEED_PROVISIONING; - case OEMCrypto_ERROR_SESSION_LOST_STATE: - return SESSION_LOST_STATE_ERROR; - case OEMCrypto_ERROR_SYSTEM_INVALIDATED: - return SYSTEM_INVALIDATED_ERROR; - default: - result = LOAD_KEY_ERROR; - break; - } - } // Release crypto_lock_ + switch (sts) { + case OEMCrypto_SUCCESS: + if (!provider_session_token.empty()) + update_usage_table_after_close_session_ = true; + result = KEY_ADDED; + break; + case OEMCrypto_ERROR_TOO_MANY_KEYS: + result = INSUFFICIENT_CRYPTO_RESOURCES_4; + break; + case OEMCrypto_ERROR_USAGE_TABLE_UNRECOVERABLE: + // Handle vendor specific error + return NEED_PROVISIONING; + case OEMCrypto_ERROR_SESSION_LOST_STATE: + return SESSION_LOST_STATE_ERROR; + case OEMCrypto_ERROR_SYSTEM_INVALIDATED: + return SYSTEM_INVALIDATED_ERROR; + default: + result = LOAD_KEY_ERROR; + break; + } if (!provider_session_token.empty() && usage_support_type_ == kUsageTableSupport) { @@ -956,10 +978,10 @@ CdmResponseType CryptoSession::LoadKeys( CdmResponseType CryptoSession::LoadEntitledContentKeys( const std::vector& key_array) { - LOGV("CryptoSession::LoadEntitledContentKeys: Lock"); - std::unique_lock auto_lock(crypto_lock_); - - OEMCryptoResult sts = key_session_->LoadEntitledContentKeys(key_array); + OEMCryptoResult sts; + WithOecLock("LoadEntitledContentKeys", [&] { + sts = key_session_->LoadEntitledContentKeys(key_array); + }); switch (sts) { case OEMCrypto_SUCCESS: @@ -981,24 +1003,30 @@ CdmResponseType CryptoSession::LoadEntitledContentKeys( CdmResponseType CryptoSession::LoadCertificatePrivateKey( std::string& wrapped_key) { - LOGV("CryptoSession::LoadCertificatePrivateKey: Lock"); - std::unique_lock auto_lock(crypto_lock_); - // Call OEMCrypto_GetOEMPublicCertificate before OEMCrypto_LoadDeviceRSAKey // so it caches the OEMCrypto Public Key and then throw away result std::string temp_buffer(CERTIFICATE_DATA_SIZE, '\0'); size_t buf_size = temp_buffer.size(); uint8_t* buf = reinterpret_cast(&temp_buffer[0]); - OEMCryptoResult sts = - OEMCrypto_GetOEMPublicCertificate(oec_session_id_, buf, &buf_size); + OEMCryptoResult sts; + WithOecLock( + "LoadCertificatePrivateKey() calling OEMCrypto_GetOEMPublicCertificate", + [&] { + sts = + OEMCrypto_GetOEMPublicCertificate(oec_session_id_, buf, &buf_size); + }); metrics_->oemcrypto_get_oem_public_certificate_.Increment(sts); LOGV("LoadDeviceRSAKey: id=%lu", oec_session_id_); - M_TIME( - sts = OEMCrypto_LoadDeviceRSAKey( - oec_session_id_, reinterpret_cast(wrapped_key.data()), - wrapped_key.size()), - metrics_, oemcrypto_load_device_rsa_key_, sts); + WithOecLock( + "LoadCertificatePrivateKey() calling OEMCrypto_LoadDeviceRSAKey()", + [&] { + M_TIME(sts = OEMCrypto_LoadDeviceRSAKey( + oec_session_id_, + reinterpret_cast(wrapped_key.data()), + wrapped_key.size()), + metrics_, oemcrypto_load_device_rsa_key_, sts); + }); return MapOEMCryptoResult( sts, LOAD_DEVICE_RSA_KEY_ERROR, "LoadCertificatePrivateKey"); @@ -1008,9 +1036,6 @@ CdmResponseType CryptoSession::RefreshKeys(const std::string& message, const std::string& signature, int num_keys, const CryptoKey* key_array) { - LOGV("CryptoSession::RefreshKeys: Lock"); - std::unique_lock auto_lock(crypto_lock_); - const uint8_t* msg = reinterpret_cast(message.data()); std::vector load_key_array(num_keys); for (int i = 0; i < num_keys; ++i) { @@ -1025,11 +1050,13 @@ CdmResponseType CryptoSession::RefreshKeys(const std::string& message, } LOGV("RefreshKeys: id=%lu", oec_session_id_); OEMCryptoResult refresh_sts; - M_TIME(refresh_sts = OEMCrypto_RefreshKeys( - oec_session_id_, msg, message.size(), - reinterpret_cast(signature.data()), - signature.size(), num_keys, &load_key_array[0]), - metrics_, oemcrypto_refresh_keys_, refresh_sts); + WithOecLock("RefreshKeys", [&] { + M_TIME(refresh_sts = OEMCrypto_RefreshKeys( + oec_session_id_, msg, message.size(), + reinterpret_cast(signature.data()), + signature.size(), num_keys, &load_key_array[0]), + metrics_, oemcrypto_refresh_keys_, refresh_sts); + }); if (refresh_sts == OEMCrypto_SUCCESS) return KEY_ADDED; @@ -1039,9 +1066,10 @@ CdmResponseType CryptoSession::RefreshKeys(const std::string& message, CdmResponseType CryptoSession::SelectKey(const std::string& key_id, CdmCipherMode cipher_mode) { - // Crypto session lock already locked. - - OEMCryptoResult sts = key_session_->SelectKey(key_id, cipher_mode); + OEMCryptoResult sts; + WithOecLock("SelectKey", [&] { + sts = key_session_->SelectKey(key_id, cipher_mode); + }); switch (sts) { case OEMCrypto_SUCCESS: @@ -1076,15 +1104,21 @@ CdmResponseType CryptoSession::SelectKey(const std::string& key_id, } CdmResponseType CryptoSession::GenerateDerivedKeys(const std::string& message) { - OEMCryptoResult sts = key_session_->GenerateDerivedKeys(message); + OEMCryptoResult sts; + WithOecLock("GenerateDerivedKeys without session_key", [&] { + sts = key_session_->GenerateDerivedKeys(message); + }); return MapOEMCryptoResult( sts, GENERATE_DERIVED_KEYS_ERROR_2, "GenerateDerivedKeys"); } -CdmResponseType CryptoSession::GenerateDerivedKeys(const std::string& message, - const std::string& session_key) { - OEMCryptoResult sts = key_session_->GenerateDerivedKeys(message, session_key); +CdmResponseType CryptoSession::GenerateDerivedKeys( + const std::string& message, const std::string& session_key) { + OEMCryptoResult sts; + WithOecLock("GenerateDerivedKeys with session_key", [&] { + sts = key_session_->GenerateDerivedKeys(message, session_key); + }); return MapOEMCryptoResult( sts, GENERATE_DERIVED_KEYS_ERROR, "GenerateDerivedKeys"); @@ -1104,13 +1138,17 @@ 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) { - M_TIME(sts = OEMCrypto_GenerateSignature( - oec_session_id_, - reinterpret_cast(message.data()), message.size(), - reinterpret_cast(const_cast(signature->data())), - &length), - metrics_, oemcrypto_generate_signature_, sts, - metrics::Pow2Bucket(length)); + WithOecLock("GenerateSignature", [&] { + M_TIME(sts = OEMCrypto_GenerateSignature( + oec_session_id_, + reinterpret_cast(message.data()), + message.size(), + reinterpret_cast( + const_cast(signature->data())), + &length), + metrics_, oemcrypto_generate_signature_, sts, + metrics::Pow2Bucket(length)); + }); if (OEMCrypto_SUCCESS == sts) { // Trim signature buffer and done signature->resize(length); @@ -1143,13 +1181,17 @@ 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) { - M_TIME(sts = OEMCrypto_GenerateRSASignature( - oec_session_id_, - reinterpret_cast(message.data()), message.size(), - reinterpret_cast(const_cast(signature->data())), - &length, kSign_RSASSA_PSS), - metrics_, oemcrypto_generate_rsa_signature_, sts, - metrics::Pow2Bucket(length)); + WithOecLock("GenerateRsaSignature", [&] { + M_TIME(sts = OEMCrypto_GenerateRSASignature( + oec_session_id_, + reinterpret_cast(message.data()), + message.size(), + reinterpret_cast( + const_cast(signature->data())), + &length, kSign_RSASSA_PSS), + metrics_, oemcrypto_generate_rsa_signature_, sts, + metrics::Pow2Bucket(length)); + }); if (OEMCrypto_SUCCESS == sts) { // Trim signature buffer and done @@ -1205,11 +1247,14 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) { if (!params.is_encrypted && params.subsample_flags == (OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)) { - M_TIME(sts = OEMCrypto_CopyBuffer(oec_session_id_, params.encrypt_buffer, - params.encrypt_length, &buffer_descriptor, - params.subsample_flags), - metrics_, oemcrypto_copy_buffer_, sts, - metrics::Pow2Bucket(params.encrypt_length)); + WithOecLock("Decrypt() calling CopyBuffer", [&] { + M_TIME(sts = OEMCrypto_CopyBuffer(oec_session_id_, params.encrypt_buffer, + params.encrypt_length, + &buffer_descriptor, + params.subsample_flags), + metrics_, oemcrypto_copy_buffer_, sts, + metrics::Pow2Bucket(params.encrypt_length)); + }); if (sts == OEMCrypto_ERROR_BUFFER_TOO_LARGE && params.encrypt_length > kMaximumChunkSize) { @@ -1228,14 +1273,16 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) { pattern_descriptor.encrypt = params.pattern_descriptor.encrypt_blocks; pattern_descriptor.skip = params.pattern_descriptor.skip_blocks; pattern_descriptor.offset = 0; // Deprecated field - std::unique_lock auto_lock(crypto_lock_); // Check if key needs to be selected if (params.is_encrypted) { CdmResponseType result = SelectKey(*params.key_id, params.cipher_mode); if (result != NO_ERROR) return result; } - sts = key_session_->Decrypt(params, buffer_descriptor, pattern_descriptor); + WithOecLock("Decrypt() calling key_session_->Decrypt()", [&] { + sts = key_session_->Decrypt(params, buffer_descriptor, + pattern_descriptor); + }); if (sts == OEMCrypto_ERROR_BUFFER_TOO_LARGE) { // OEMCrypto_DecryptCENC rejected the buffer as too large, so chunk it @@ -1296,27 +1343,31 @@ bool CryptoSession::UsageInformationSupport(bool* has_support) { bool CryptoSession::UsageInformationSupport(SecurityLevel security_level, bool* has_support) { LOGV("CryptoSession::UsageInformationSupport"); - if (!initialized_) { + if (!IsInitialized()) { LOGW("CryptoSession::UsageInformationSupport: not initialized"); return false; } - *has_support = OEMCrypto_SupportsUsageTable(security_level); + WithOecLock("UsageInformationSupport", [&] { + *has_support = OEMCrypto_SupportsUsageTable(security_level); + }); return true; } CdmResponseType CryptoSession::UpdateUsageInformation() { LOGV("CryptoSession::UpdateUsageInformation: id=%lu", oec_session_id_); - std::unique_lock auto_lock(crypto_lock_); - if (!initialized_) return UNKNOWN_ERROR; + if (!IsInitialized()) return UNKNOWN_ERROR; if (usage_table_header_ != NULL) { LOGV("UpdateUsageInformation: deprecated for OEMCrypto v13+"); return NO_ERROR; } - OEMCryptoResult status = OEMCrypto_UpdateUsageTable(); + OEMCryptoResult status; + WithOecLock("UpdateUsageInformation", [&] { + status = OEMCrypto_UpdateUsageTable(); + }); metrics_->oemcrypto_update_usage_table_.Increment(status); if (status != OEMCrypto_SUCCESS) { LOGE("CryptoSession::UpdateUsageInformation: error=%ld", status); @@ -1329,13 +1380,15 @@ CdmResponseType CryptoSession::DeactivateUsageInformation( const std::string& provider_session_token) { LOGV("DeactivateUsageInformation: id=%lu", oec_session_id_); - std::unique_lock auto_lock(crypto_lock_); uint8_t* pst = reinterpret_cast( const_cast(provider_session_token.data())); // TODO(fredgc or rfrias): make sure oec_session_id_ is valid. - OEMCryptoResult status = OEMCrypto_DeactivateUsageEntry( - oec_session_id_, pst, provider_session_token.length()); + OEMCryptoResult status; + WithOecLock("DeactivateUsageInformation", [&] { + status = OEMCrypto_DeactivateUsageEntry( + oec_session_id_, pst, provider_session_token.length()); + }); metrics_->oemcrypto_deactivate_usage_entry_.Increment(status); if (status != OEMCrypto_SUCCESS) { @@ -1367,14 +1420,16 @@ CdmResponseType CryptoSession::GenerateUsageReport( return PARAMETER_NULL; } - std::unique_lock auto_lock(crypto_lock_); uint8_t* pst = reinterpret_cast( const_cast(provider_session_token.data())); size_t usage_length = 0; - OEMCryptoResult status = OEMCrypto_ReportUsage( - oec_session_id_, pst, provider_session_token.length(), NULL, - &usage_length); + OEMCryptoResult status; + WithOecLock("GenerateUsageReport Attempt 1", [&] { + status = OEMCrypto_ReportUsage( + oec_session_id_, pst, provider_session_token.length(), NULL, + &usage_length); + }); metrics_->oemcrypto_report_usage_.Increment(status); if (status != OEMCrypto_SUCCESS && status != OEMCrypto_ERROR_SHORT_BUFFER) { @@ -1384,9 +1439,11 @@ CdmResponseType CryptoSession::GenerateUsageReport( std::vector buffer(usage_length); - status = OEMCrypto_ReportUsage(oec_session_id_, pst, - provider_session_token.length(), &buffer[0], - &usage_length); + WithOecLock("GenerateUsageReport Attempt 2", [&] { + status = OEMCrypto_ReportUsage(oec_session_id_, pst, + provider_session_token.length(), &buffer[0], + &usage_length); + }); metrics_->oemcrypto_report_usage_.Increment(status); if (status != OEMCrypto_SUCCESS) { @@ -1449,27 +1506,27 @@ CdmResponseType CryptoSession::ReleaseUsageInformation( const std::string& message, const std::string& signature, const std::string& provider_session_token) { LOGV("ReleaseUsageInformation: id=%lu", oec_session_id_); - { - std::unique_lock auto_lock(crypto_lock_); - if (usage_table_header_ != NULL) { - LOGW("ReleaseUsageInformation: deprecated for OEMCrypto v13+"); - return NO_ERROR; - } + if (usage_table_header_ != NULL) { + LOGW("ReleaseUsageInformation: deprecated for OEMCrypto v13+"); + return NO_ERROR; + } - const uint8_t* msg = reinterpret_cast(message.data()); - const uint8_t* sig = reinterpret_cast(signature.data()); - const uint8_t* pst = msg + GetOffset(message, provider_session_token); + const uint8_t* msg = reinterpret_cast(message.data()); + const uint8_t* sig = reinterpret_cast(signature.data()); + const uint8_t* pst = msg + GetOffset(message, provider_session_token); - OEMCryptoResult status = OEMCrypto_DeleteUsageEntry( + OEMCryptoResult status; + WithOecLock("ReleaseUsageInformation", [&] { + status = OEMCrypto_DeleteUsageEntry( oec_session_id_, pst, provider_session_token.length(), msg, message.length(), sig, signature.length()); - metrics_->oemcrypto_delete_usage_entry_.Increment(status); + }); + metrics_->oemcrypto_delete_usage_entry_.Increment(status); - if (OEMCrypto_SUCCESS != status) { - LOGE("CryptoSession::ReleaseUsageInformation: Report Usage error=%ld", - status); - return UNKNOWN_ERROR; - } + if (OEMCrypto_SUCCESS != status) { + LOGE("CryptoSession::ReleaseUsageInformation: Report Usage error=%ld", + status); + return UNKNOWN_ERROR; } if (usage_support_type_ == kUsageTableSupport) UpdateUsageInformation(); @@ -1481,19 +1538,18 @@ CdmResponseType CryptoSession::DeleteUsageInformation( CdmResponseType response = NO_ERROR; LOGV("CryptoSession::DeleteUsageInformation"); OEMCryptoResult status; - { - std::unique_lock auto_lock(crypto_lock_); + WithOecLock("DeleteUsageInformation", [&] { status = OEMCrypto_ForceDeleteUsageEntry( reinterpret_cast(provider_session_token.c_str()), provider_session_token.length()); - metrics_->oemcrypto_force_delete_usage_entry_.Increment(status); - if (OEMCrypto_SUCCESS != status) { - LOGE( - "CryptoSession::DeleteUsageInformation: Delete Usage Table error " - "= %ld", - status); - response = UNKNOWN_ERROR; - } + }); + metrics_->oemcrypto_force_delete_usage_entry_.Increment(status); + if (OEMCrypto_SUCCESS != status) { + LOGE( + "CryptoSession::DeleteUsageInformation: Delete Usage Table error " + "= %ld", + status); + response = UNKNOWN_ERROR; } if (usage_support_type_ == kUsageTableSupport) UpdateUsageInformation(); return response; @@ -1503,8 +1559,7 @@ CdmResponseType CryptoSession::DeleteMultipleUsageInformation( const std::vector& provider_session_tokens) { LOGV("CryptoSession::DeleteMultipleUsageInformation"); CdmResponseType response = NO_ERROR; - { - std::unique_lock auto_lock(crypto_lock_); + WithOecLock("DeleteMultipleUsageInformation", [&] { for (size_t i = 0; i < provider_session_tokens.size(); ++i) { OEMCryptoResult status = OEMCrypto_ForceDeleteUsageEntry( reinterpret_cast(provider_session_tokens[i].c_str()), @@ -1518,7 +1573,7 @@ CdmResponseType CryptoSession::DeleteMultipleUsageInformation( response = UNKNOWN_ERROR; } } - } + }); if (usage_support_type_ == kUsageTableSupport) UpdateUsageInformation(); return response; } @@ -1526,16 +1581,15 @@ CdmResponseType CryptoSession::DeleteMultipleUsageInformation( CdmResponseType CryptoSession::DeleteAllUsageReports() { LOGV("DeleteAllUsageReports"); OEMCryptoResult status; - { - std::unique_lock auto_lock(crypto_lock_); + WithOecLock("DeleteAllUsageReports", [&] { status = OEMCrypto_DeleteOldUsageTable(); - metrics_->oemcrypto_delete_usage_table_.Increment(status); - if (OEMCrypto_SUCCESS != status) { - LOGE( - "CryptoSession::DeleteAllUsageReports: Delete Usage Table error " - "=%ld", - status); - } + }); + metrics_->oemcrypto_delete_usage_table_.Increment(status); + if (OEMCrypto_SUCCESS != status) { + LOGE( + "CryptoSession::DeleteAllUsageReports: Delete Usage Table error " + "=%ld", + status); } if (usage_support_type_ == kUsageTableSupport) UpdateUsageInformation(); @@ -1543,8 +1597,10 @@ CdmResponseType CryptoSession::DeleteAllUsageReports() { } bool CryptoSession::IsAntiRollbackHwPresent() { - bool is_present = - OEMCrypto_IsAntiRollbackHwPresent(requested_security_level_); + bool is_present; + WithOecLock("IsAntiRollbackHwPresent", [&] { + is_present = OEMCrypto_IsAntiRollbackHwPresent(requested_security_level_); + }); metrics_->oemcrypto_is_anti_rollback_hw_present_.Record(is_present); return is_present; } @@ -1555,10 +1611,10 @@ CdmResponseType CryptoSession::GenerateNonce(uint32_t* nonce) { return PARAMETER_NULL; } - LOGV("CryptoSession::GenerateNonce: Lock"); - std::unique_lock auto_lock(crypto_lock_); - - OEMCryptoResult result = OEMCrypto_GenerateNonce(oec_session_id_, nonce); + OEMCryptoResult result; + WithOecLock("GenerateNonce", [&] { + result = OEMCrypto_GenerateNonce(oec_session_id_, nonce); + }); metrics_->oemcrypto_generate_nonce_.Increment(result); return MapOEMCryptoResult(result, NONCE_GENERATION_ERROR, "GenerateNonce"); @@ -1634,12 +1690,14 @@ CdmResponseType CryptoSession::RewrapDeviceRSAKey( // and 0 as wrapped_rsa_key_length. size_t wrapped_rsa_key_length = 0; OEMCryptoResult status; - M_TIME(status = OEMCrypto_RewrapDeviceRSAKey( - oec_session_id_, signed_msg, message.size(), - reinterpret_cast(signature.data()), - signature.size(), msg_nonce, msg_rsa_key, enc_rsa_key.size(), - msg_rsa_key_iv, NULL, &wrapped_rsa_key_length), - metrics_, oemcrypto_rewrap_device_rsa_key_, status); + WithOecLock("RewrapDeviceRSAKey Attempt 1", [&] { + M_TIME(status = OEMCrypto_RewrapDeviceRSAKey( + oec_session_id_, signed_msg, message.size(), + reinterpret_cast(signature.data()), + signature.size(), msg_nonce, msg_rsa_key, enc_rsa_key.size(), + msg_rsa_key_iv, NULL, &wrapped_rsa_key_length), + metrics_, oemcrypto_rewrap_device_rsa_key_, status); + }); if (status != OEMCrypto_ERROR_SHORT_BUFFER) { return MapOEMCryptoResult( @@ -1647,13 +1705,16 @@ CdmResponseType CryptoSession::RewrapDeviceRSAKey( } wrapped_rsa_key->resize(wrapped_rsa_key_length); - M_TIME(status = OEMCrypto_RewrapDeviceRSAKey( - oec_session_id_, signed_msg, message.size(), - reinterpret_cast(signature.data()), - signature.size(), msg_nonce, msg_rsa_key, enc_rsa_key.size(), - msg_rsa_key_iv, reinterpret_cast(&(*wrapped_rsa_key)[0]), - &wrapped_rsa_key_length), - metrics_, oemcrypto_rewrap_device_rsa_key_, status); + WithOecLock("RewrapDeviceRSAKey Attempt 2", [&] { + M_TIME(status = OEMCrypto_RewrapDeviceRSAKey( + oec_session_id_, signed_msg, message.size(), + reinterpret_cast(signature.data()), + signature.size(), msg_nonce, msg_rsa_key, enc_rsa_key.size(), + msg_rsa_key_iv, + reinterpret_cast(&(*wrapped_rsa_key)[0]), + &wrapped_rsa_key_length), + metrics_, oemcrypto_rewrap_device_rsa_key_, status); + }); wrapped_rsa_key->resize(wrapped_rsa_key_length); @@ -1688,14 +1749,16 @@ CdmResponseType CryptoSession::RewrapDeviceRSAKey30( // and 0 as wrapped_rsa_key_length. size_t wrapped_private_key_length = 0; OEMCryptoResult status; - M_TIME( - status = OEMCrypto_RewrapDeviceRSAKey30( - oec_session_id_, msg_nonce, msg_wrapping_key, wrapping_key.size(), - msg_private_key, private_key.size(), msg_iv, NULL, - &wrapped_private_key_length), - metrics_, - oemcrypto_rewrap_device_rsa_key_30_, - status); + WithOecLock("RewrapDeviceRSAKey30 Attempt 1", [&] { + M_TIME( + status = OEMCrypto_RewrapDeviceRSAKey30( + oec_session_id_, msg_nonce, msg_wrapping_key, wrapping_key.size(), + msg_private_key, private_key.size(), msg_iv, NULL, + &wrapped_private_key_length), + metrics_, + oemcrypto_rewrap_device_rsa_key_30_, + status); + }); if (status != OEMCrypto_ERROR_SHORT_BUFFER) { return MapOEMCryptoResult( @@ -1703,15 +1766,17 @@ CdmResponseType CryptoSession::RewrapDeviceRSAKey30( } wrapped_private_key->resize(wrapped_private_key_length); - M_TIME( - status = OEMCrypto_RewrapDeviceRSAKey30( - oec_session_id_, msg_nonce, msg_wrapping_key, wrapping_key.size(), - msg_private_key, private_key.size(), msg_iv, - reinterpret_cast(&(*wrapped_private_key)[0]), - &wrapped_private_key_length), - metrics_, - oemcrypto_rewrap_device_rsa_key_30_, - status); + WithOecLock("RewrapDeviceRSAKey30 Attempt 2", [&] { + M_TIME( + status = OEMCrypto_RewrapDeviceRSAKey30( + oec_session_id_, msg_nonce, msg_wrapping_key, wrapping_key.size(), + msg_private_key, private_key.size(), msg_iv, + reinterpret_cast(&(*wrapped_private_key)[0]), + &wrapped_private_key_length), + metrics_, + oemcrypto_rewrap_device_rsa_key_30_, + status); + }); wrapped_private_key->resize(wrapped_private_key_length); @@ -1733,7 +1798,7 @@ CdmResponseType CryptoSession::GetHdcpCapabilities(SecurityLevel security_level, HdcpCapability* current, HdcpCapability* max) { LOGV("CryptoSession::GetHdcpCapabilities"); - if (!initialized_) { + if (!IsInitialized()) { LOGW("CryptoSession::GetHdcpCapabilities: not initialized"); return CRYPTO_SESSION_NOT_INITIALIZED; } @@ -1743,8 +1808,10 @@ CdmResponseType CryptoSession::GetHdcpCapabilities(SecurityLevel security_level, "NULL"); return PARAMETER_NULL; } - OEMCryptoResult status = - OEMCrypto_GetHDCPCapability(security_level, current, max); + OEMCryptoResult status; + WithOecLock("GetHdcpCapabilities", [&] { + status = OEMCrypto_GetHDCPCapability(security_level, current, max); + }); if (OEMCrypto_SUCCESS == status) { metrics_->oemcrypto_current_hdcp_capability_.Record(*current); @@ -1761,7 +1828,7 @@ CdmResponseType CryptoSession::GetHdcpCapabilities(SecurityLevel security_level, bool CryptoSession::GetSupportedCertificateTypes( SupportedCertificateTypes* support) { LOGV("GetSupportedCertificateTypes: id=%lu", oec_session_id_); - if (!initialized_) return false; + if (!IsInitialized()) return false; if (support == NULL) { LOGE( "CryptoSession::GetSupportedCertificateTypes: |support| cannot be " @@ -1769,8 +1836,10 @@ bool CryptoSession::GetSupportedCertificateTypes( return false; } - uint32_t oec_support = - OEMCrypto_SupportedCertificates(requested_security_level_); + uint32_t oec_support; + WithOecLock("GetSupportedCertificateTypes", [&] { + oec_support = OEMCrypto_SupportedCertificates(requested_security_level_); + }); support->rsa_2048_bit = oec_support & OEMCrypto_Supports_RSA_2048bit; support->rsa_3072_bit = oec_support & OEMCrypto_Supports_RSA_3072bit; support->rsa_cast = oec_support & OEMCrypto_Supports_RSA_CAST; @@ -1783,7 +1852,10 @@ CdmResponseType CryptoSession::GetRandom(size_t data_length, LOGE("CryptoSession::GetRandom: random data destination not provided"); return PARAMETER_NULL; } - OEMCryptoResult sts = OEMCrypto_GetRandom(random_data, data_length); + OEMCryptoResult sts; + WithOecLock("GetRandom", [&] { + sts = OEMCrypto_GetRandom(random_data, data_length); + }); metrics_->oemcrypto_get_random_.Increment(sts); return MapOEMCryptoResult(sts, RANDOM_GENERATION_ERROR, "GetRandom"); @@ -1793,7 +1865,7 @@ CdmResponseType CryptoSession::GetNumberOfOpenSessions( SecurityLevel security_level, size_t* count) { LOGV("GetNumberOfOpenSessions"); - if (!initialized_) { + if (!IsInitialized()) { LOGW("CryptoSession::GetNumberOfOpenSessions: not initialized"); return CRYPTO_SESSION_NOT_INITIALIZED; } @@ -1803,8 +1875,10 @@ CdmResponseType CryptoSession::GetNumberOfOpenSessions( } size_t sessions_count; - OEMCryptoResult status = OEMCrypto_GetNumberOfOpenSessions( - security_level, &sessions_count); + OEMCryptoResult status; + WithOecLock("GetNumberOfOpenSessions", [&] { + status = OEMCrypto_GetNumberOfOpenSessions(security_level, &sessions_count); + }); if (OEMCrypto_SUCCESS == status) { metrics_->oemcrypto_number_of_open_sessions_.Record(sessions_count); @@ -1821,7 +1895,7 @@ CdmResponseType CryptoSession::GetMaxNumberOfSessions( SecurityLevel security_level, size_t* max) { LOGV("GetMaxNumberOfSessions"); - if (!initialized_) { + if (!IsInitialized()) { LOGW("CryptoSession::GetMaxNumberOfSessions: not initialized"); return CRYPTO_SESSION_NOT_INITIALIZED; } @@ -1832,8 +1906,10 @@ CdmResponseType CryptoSession::GetMaxNumberOfSessions( } size_t max_sessions = 0; - OEMCryptoResult status = OEMCrypto_GetMaxNumberOfSessions( - security_level, &max_sessions); + OEMCryptoResult status; + WithOecLock("GetMaxNumberOfSessions", [&] { + status = OEMCrypto_GetMaxNumberOfSessions(security_level, &max_sessions); + }); if (OEMCrypto_SUCCESS == status) { metrics_->oemcrypto_max_number_of_sessions_.Record(max_sessions); @@ -1848,13 +1924,16 @@ CdmResponseType CryptoSession::GetMaxNumberOfSessions( CdmResponseType CryptoSession::GetSrmVersion(uint16_t* srm_version) { LOGV("GetSrmVersion"); - if (!initialized_) return CRYPTO_SESSION_NOT_INITIALIZED; + if (!IsInitialized()) return CRYPTO_SESSION_NOT_INITIALIZED; if (srm_version == nullptr) { LOGE("CryptoSession::GetSrmVersion: |srm_version| cannot be NULL"); return PARAMETER_NULL; } - OEMCryptoResult status = OEMCrypto_GetCurrentSRMVersion(srm_version); + OEMCryptoResult status; + WithOecLock("GetSrmVersion", [&] { + status = OEMCrypto_GetCurrentSRMVersion(srm_version); + }); return MapOEMCryptoResult( status, GET_SRM_VERSION_ERROR, "GetCurrentSRMVersion"); @@ -1862,20 +1941,25 @@ CdmResponseType CryptoSession::GetSrmVersion(uint16_t* srm_version) { bool CryptoSession::IsSrmUpdateSupported() { LOGV("IsSrmUpdateSupported"); - if (!initialized_) return false; - return OEMCrypto_IsSRMUpdateSupported(); + if (!IsInitialized()) return false; + return WithOecLock("IsSrmUpdateSupported", [&] { + return OEMCrypto_IsSRMUpdateSupported(); + }); } CdmResponseType CryptoSession::LoadSrm(const std::string& srm) { LOGV("LoadSrm"); - if (!initialized_) return CRYPTO_SESSION_NOT_INITIALIZED; + if (!IsInitialized()) return CRYPTO_SESSION_NOT_INITIALIZED; if (srm.empty()) { LOGE("CryptoSession::LoadSrm: |srm| cannot be empty"); return INVALID_SRM_LIST; } - OEMCryptoResult status = OEMCrypto_LoadSRM( - reinterpret_cast(srm.data()), srm.size()); + OEMCryptoResult status; + WithOecLock("LoadSrm", [&] { + status = OEMCrypto_LoadSRM( + reinterpret_cast(srm.data()), srm.size()); + }); return MapOEMCryptoResult(status, LOAD_SRM_ERROR, "LoadSRM"); } @@ -1892,7 +1976,7 @@ bool CryptoSession::GetResourceRatingTier(uint32_t* tier) { bool CryptoSession::GetResourceRatingTier(SecurityLevel security_level, uint32_t* tier) { LOGV("GetResourceRatingTier"); - if (!initialized_) { + if (!IsInitialized()) { LOGW("CryptoSession::GetResourceRatingTier: not initialized"); return false; } @@ -1900,7 +1984,9 @@ bool CryptoSession::GetResourceRatingTier(SecurityLevel security_level, LOGE("tier destination not provided"); return false; } - *tier = OEMCrypto_ResourceRatingTier(security_level); + WithOecLock("GetResourceRatingTier", [&] { + *tier = OEMCrypto_ResourceRatingTier(security_level); + }); if (*tier < RESOURCE_RATING_TIER_LOW || *tier > RESOURCE_RATING_TIER_HIGH) { uint32_t api_version; if (GetApiVersion(security_level, &api_version)) { @@ -1915,7 +2001,7 @@ bool CryptoSession::GetResourceRatingTier(SecurityLevel security_level, bool CryptoSession::GetBuildInformation(SecurityLevel security_level, std::string* info) { LOGV("GetBuildInformation"); - if (!initialized_) { + if (!IsInitialized()) { LOGW("CryptoSession::GetBuildInformation: not initialized"); return false; } @@ -1923,8 +2009,10 @@ bool CryptoSession::GetBuildInformation(SecurityLevel security_level, LOGE("CryptoSession::GetBuildInformation: |info| cannot be empty"); return false; } - const char* build_information = - OEMCrypto_BuildInformation(security_level); + const char* build_information; + WithOecLock("GetBuildInformation", [&] { + build_information = OEMCrypto_BuildInformation(security_level); + }); if (build_information == nullptr) { LOGE("CryptoSession::GetBuildInformation: returned null"); return false; @@ -1936,13 +2024,15 @@ bool CryptoSession::GetBuildInformation(SecurityLevel security_level, uint32_t CryptoSession::IsDecryptHashSupported(SecurityLevel security_level) { LOGV("IsDecryptHashSupported"); - if (!initialized_) { + if (!IsInitialized()) { LOGW("CryptoSession::IsDecryptHashSupported: not initialized"); return false; } - uint32_t secure_decrypt_support = - OEMCrypto_SupportsDecryptHash(security_level); + uint32_t secure_decrypt_support; + WithOecLock("IsDecryptHashSupported", [&] { + secure_decrypt_support = OEMCrypto_SupportsDecryptHash(security_level); + }); switch (secure_decrypt_support) { case OEMCrypto_Hash_Not_Supported: case OEMCrypto_CRC_Clear_Buffer: @@ -1961,9 +2051,12 @@ CdmResponseType CryptoSession::SetDecryptHash( uint32_t frame_number, const std::string& hash) { LOGV("SetDecryptHash"); - OEMCryptoResult sts = OEMCrypto_SetDecryptHash( - oec_session_id_, frame_number, - reinterpret_cast(hash.data()), hash.size()); + OEMCryptoResult sts; + WithOecLock("SetDecryptHash", [&] { + sts = OEMCrypto_SetDecryptHash( + oec_session_id_, frame_number, + reinterpret_cast(hash.data()), hash.size()); + }); return MapOEMCryptoResult(sts, SET_DECRYPT_HASH_ERROR, "SetDecryptHash"); } @@ -1977,8 +2070,10 @@ CdmResponseType CryptoSession::GetDecryptHashError(std::string* error_string) { error_string->clear(); uint32_t failed_frame_number; - OEMCryptoResult sts = OEMCrypto_GetHashErrorCode( - oec_session_id_, &failed_frame_number); + OEMCryptoResult sts; + WithOecLock("GetDecryptHashError", [&] { + sts = OEMCrypto_GetHashErrorCode(oec_session_id_, &failed_frame_number); + }); error_string->assign(std::to_string(sts)); if (sts != OEMCrypto_SUCCESS) { @@ -2024,7 +2119,6 @@ CdmResponseType CryptoSession::GenericEncrypt(const std::string& in_buffer, out_buffer->resize(in_buffer.size()); } - std::unique_lock auto_lock(crypto_lock_); // TODO(jfore): We need to select a key with a cipher mode and algorithm // doesn't seem to fit. Is it ok to just use a default value here? // Or do we need to pass it in? @@ -2033,14 +2127,16 @@ CdmResponseType CryptoSession::GenericEncrypt(const std::string& in_buffer, OEMCryptoResult sts; - M_TIME( - sts = OEMCrypto_Generic_Encrypt( - oec_session_id_, reinterpret_cast(in_buffer.data()), - in_buffer.size(), reinterpret_cast(iv.data()), - oec_algorithm, - reinterpret_cast(const_cast(out_buffer->data()))), - metrics_, oemcrypto_generic_encrypt_, sts, - metrics::Pow2Bucket(in_buffer.size())); + WithOecLock("GenericEncrypt", [&] { + M_TIME( + sts = OEMCrypto_Generic_Encrypt( + oec_session_id_, reinterpret_cast(in_buffer.data()), + in_buffer.size(), reinterpret_cast(iv.data()), + oec_algorithm, + reinterpret_cast(const_cast(out_buffer->data()))), + metrics_, oemcrypto_generic_encrypt_, sts, + metrics::Pow2Bucket(in_buffer.size())); + }); if (OEMCrypto_SUCCESS != sts) { LOGE("GenericEncrypt: OEMCrypto_Generic_Encrypt err=%d", sts); @@ -2086,7 +2182,6 @@ CdmResponseType CryptoSession::GenericDecrypt(const std::string& in_buffer, out_buffer->resize(in_buffer.size()); } - std::unique_lock auto_lock(crypto_lock_); // TODO(jfore): We need to select a key with a cipher mode and algorithm // doesn't seem to fit. Is it ok to just use a default value here? // Or do we need to pass it in? @@ -2095,14 +2190,16 @@ CdmResponseType CryptoSession::GenericDecrypt(const std::string& in_buffer, OEMCryptoResult sts; - M_TIME( - sts = OEMCrypto_Generic_Decrypt( - oec_session_id_, reinterpret_cast(in_buffer.data()), - in_buffer.size(), reinterpret_cast(iv.data()), - oec_algorithm, - reinterpret_cast(const_cast(out_buffer->data()))), - metrics_, oemcrypto_generic_decrypt_, sts, - metrics::Pow2Bucket(in_buffer.size())); + WithOecLock("GenericDecrypt", [&] { + M_TIME( + sts = OEMCrypto_Generic_Decrypt( + oec_session_id_, reinterpret_cast(in_buffer.data()), + in_buffer.size(), reinterpret_cast(iv.data()), + oec_algorithm, + reinterpret_cast(const_cast(out_buffer->data()))), + metrics_, oemcrypto_generic_decrypt_, sts, + metrics::Pow2Bucket(in_buffer.size())); + }); if (OEMCrypto_SUCCESS != sts) { LOGE("GenericDecrypt: OEMCrypto_Generic_Decrypt err=%d", sts); @@ -2145,7 +2242,6 @@ CdmResponseType CryptoSession::GenericSign(const std::string& message, OEMCryptoResult sts; size_t length = signature->size(); - std::unique_lock auto_lock(crypto_lock_); // TODO(jfore): We need to select a key with a cipher mode and algorithm // doesn't seem to fit. Is it ok to just use a default value here? // Or do we need to pass it in? @@ -2155,14 +2251,16 @@ 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) { - M_TIME( - sts = OEMCrypto_Generic_Sign( - oec_session_id_, reinterpret_cast(message.data()), - message.size(), oec_algorithm, - reinterpret_cast(const_cast(signature->data())), - &length), - metrics_, oemcrypto_generic_sign_, sts, - metrics::Pow2Bucket(message.size())); + WithOecLock("GenericSign", [&] { + M_TIME( + sts = OEMCrypto_Generic_Sign( + oec_session_id_, reinterpret_cast(message.data()), + message.size(), oec_algorithm, + reinterpret_cast(const_cast(signature->data())), + &length), + metrics_, oemcrypto_generic_sign_, sts, + metrics::Pow2Bucket(message.size())); + }); if (OEMCrypto_SUCCESS == sts) { // Trim signature buffer and done @@ -2207,7 +2305,6 @@ CdmResponseType CryptoSession::GenericVerify(const std::string& message, return INVALID_PARAMETERS_ENG_16; } - std::unique_lock auto_lock(crypto_lock_); // TODO(jfore): We need to select a key with a cipher mode and algorithm // doesn't seem to fit. Is it ok to just use a default value here? // Or do we need to pass it in? @@ -2215,13 +2312,16 @@ CdmResponseType CryptoSession::GenericVerify(const std::string& message, if (result != NO_ERROR) return result; OEMCryptoResult sts; - M_TIME( - sts = OEMCrypto_Generic_Verify( - oec_session_id_, reinterpret_cast(message.data()), - message.size(), oec_algorithm, - reinterpret_cast(signature.data()), signature.size()), - metrics_, oemcrypto_generic_verify_, sts, - metrics::Pow2Bucket(signature.size())); + WithOecLock("GenericVerify", [&] { + M_TIME( + sts = OEMCrypto_Generic_Verify( + oec_session_id_, reinterpret_cast(message.data()), + message.size(), oec_algorithm, + reinterpret_cast(signature.data()), + signature.size()), + metrics_, oemcrypto_generic_verify_, sts, + metrics::Pow2Bucket(signature.size())); + }); if (OEMCrypto_SUCCESS != sts) { LOGE("GenericVerify: OEMCrypto_Generic_Verify err=%d", sts); @@ -2290,18 +2390,24 @@ CdmResponseType CryptoSession::CreateUsageTableHeader( usage_table_header->resize(kEstimatedInitialUsageTableHeader); size_t usage_table_header_size = usage_table_header->size(); - OEMCryptoResult result = OEMCrypto_CreateUsageTableHeader( - requested_security_level_, - reinterpret_cast(const_cast(usage_table_header->data())), - &usage_table_header_size); - - if (result == OEMCrypto_ERROR_SHORT_BUFFER) { - usage_table_header->resize(usage_table_header_size); + OEMCryptoResult result; + WithOecLock("CreateUsageTableHeader Attempt 1", [&] { result = OEMCrypto_CreateUsageTableHeader( requested_security_level_, reinterpret_cast( const_cast(usage_table_header->data())), &usage_table_header_size); + }); + + if (result == OEMCrypto_ERROR_SHORT_BUFFER) { + usage_table_header->resize(usage_table_header_size); + WithOecLock("CreateUsageTableHeader Attempt 2", [&] { + result = OEMCrypto_CreateUsageTableHeader( + requested_security_level_, + reinterpret_cast( + const_cast(usage_table_header->data())), + &usage_table_header_size); + }); } if (result == OEMCrypto_SUCCESS) { @@ -2316,10 +2422,13 @@ CdmResponseType CryptoSession::LoadUsageTableHeader( const CdmUsageTableHeader& usage_table_header) { LOGV("LoadUsageTableHeader: id=%lu", oec_session_id_); - OEMCryptoResult result = OEMCrypto_LoadUsageTableHeader( - requested_security_level_, - reinterpret_cast(usage_table_header.data()), - usage_table_header.size()); + OEMCryptoResult result; + WithOecLock("LoadUsageTableHeader", [&] { + result = OEMCrypto_LoadUsageTableHeader( + requested_security_level_, + reinterpret_cast(usage_table_header.data()), + usage_table_header.size()); + }); if (result != OEMCrypto_SUCCESS) { if (result == OEMCrypto_WARNING_GENERATION_SKEW) { @@ -2358,8 +2467,10 @@ CdmResponseType CryptoSession::CreateUsageEntry(uint32_t* entry_number) { return INVALID_PARAMETERS_ENG_18; } - OEMCryptoResult result = - OEMCrypto_CreateNewUsageEntry(oec_session_id_, entry_number); + OEMCryptoResult result; + WithOecLock("CreateUsageEntry", [&] { + result = OEMCrypto_CreateNewUsageEntry(oec_session_id_, entry_number); + }); if (result != OEMCrypto_SUCCESS) { LOGE("CreateUsageEntry: OEMCrypto_CreateNewUsageEntry error: %d", result); @@ -2383,9 +2494,13 @@ CdmResponseType CryptoSession::LoadUsageEntry( uint32_t entry_number, const CdmUsageEntry& usage_entry) { LOGV("LoadUsageEntry: id=%lu", oec_session_id_); - OEMCryptoResult result = OEMCrypto_LoadUsageEntry( - oec_session_id_, entry_number, - reinterpret_cast(usage_entry.data()), usage_entry.size()); + OEMCryptoResult result; + WithOecLock("LoadUsageEntry", [&] { + result = OEMCrypto_LoadUsageEntry( + oec_session_id_, entry_number, + reinterpret_cast(usage_entry.data()), + usage_entry.size()); + }); if (result != OEMCrypto_SUCCESS) { if (result == OEMCrypto_WARNING_GENERATION_SKEW) { @@ -2430,21 +2545,26 @@ CdmResponseType CryptoSession::UpdateUsageEntry( size_t usage_table_header_len = 0; size_t usage_entry_len = 0; - OEMCryptoResult result = OEMCrypto_UpdateUsageEntry( - oec_session_id_, NULL, &usage_table_header_len, NULL, &usage_entry_len); + OEMCryptoResult result; + WithOecLock("UpdateUsageEntry Attempt 1", [&] { + result = OEMCrypto_UpdateUsageEntry( + oec_session_id_, NULL, &usage_table_header_len, NULL, &usage_entry_len); + }); metrics_->oemcrypto_update_usage_entry_.Increment(result); if (result == OEMCrypto_ERROR_SHORT_BUFFER) { usage_table_header->resize(usage_table_header_len); usage_entry->resize(usage_entry_len); - result = OEMCrypto_UpdateUsageEntry( - oec_session_id_, - reinterpret_cast( - const_cast(usage_table_header->data())), - &usage_table_header_len, - reinterpret_cast(const_cast(usage_entry->data())), - &usage_entry_len); + WithOecLock("UpdateUsageEntry Attempt 2", [&] { + result = OEMCrypto_UpdateUsageEntry( + oec_session_id_, + reinterpret_cast( + const_cast(usage_table_header->data())), + &usage_table_header_len, + reinterpret_cast(const_cast(usage_entry->data())), + &usage_entry_len); + }); metrics_->oemcrypto_update_usage_entry_.Increment(result); } @@ -2467,18 +2587,23 @@ CdmResponseType CryptoSession::ShrinkUsageTableHeader( } size_t usage_table_header_len = 0; - OEMCryptoResult result = OEMCrypto_ShrinkUsageTableHeader( - requested_security_level_, new_entry_count, NULL, - &usage_table_header_len); + OEMCryptoResult result; + WithOecLock("ShrinkUsageTableHeader Attempt 1", [&] { + result = OEMCrypto_ShrinkUsageTableHeader( + requested_security_level_, new_entry_count, NULL, + &usage_table_header_len); + }); if (result == OEMCrypto_ERROR_SHORT_BUFFER) { usage_table_header->resize(usage_table_header_len); - result = OEMCrypto_ShrinkUsageTableHeader( - requested_security_level_, new_entry_count, - reinterpret_cast( - const_cast(usage_table_header->data())), - &usage_table_header_len); + WithOecLock("ShrinkUsageTableHeader Attempt 2", [&] { + result = OEMCrypto_ShrinkUsageTableHeader( + requested_security_level_, new_entry_count, + reinterpret_cast( + const_cast(usage_table_header->data())), + &usage_table_header_len); + }); } if (result == OEMCrypto_SUCCESS) { @@ -2492,8 +2617,10 @@ CdmResponseType CryptoSession::ShrinkUsageTableHeader( CdmResponseType CryptoSession::MoveUsageEntry(uint32_t new_entry_number) { LOGV("MoveUsageEntry: id=%lu", oec_session_id_); - OEMCryptoResult result = - OEMCrypto_MoveEntry(oec_session_id_, new_entry_number); + OEMCryptoResult result; + WithOecLock("MoveUsageEntry", [&] { + result = OEMCrypto_MoveEntry(oec_session_id_, new_entry_number); + }); return MapOEMCryptoResult( result, MOVE_USAGE_ENTRY_UNKNOWN_ERROR, "MoveUsageEntry"); @@ -2504,8 +2631,7 @@ bool CryptoSession::CreateOldUsageEntry( uint64_t time_since_last_decrypt, UsageDurationStatus usage_duration_status, const std::string& server_mac_key, const std::string& client_mac_key, const std::string& provider_session_token) { - LOGV("CreateOldUsageEntry: Lock"); - std::unique_lock auto_lock(crypto_lock_); + LOGV("CreateOldUsageEntry"); if (server_mac_key.size() < MAC_KEY_SIZE || client_mac_key.size() < MAC_KEY_SIZE) { @@ -2533,13 +2659,16 @@ bool CryptoSession::CreateOldUsageEntry( return false; } - OEMCryptoResult result = OEMCrypto_CreateOldUsageEntry( - requested_security_level_, time_since_license_received, - time_since_first_decrypt, time_since_last_decrypt, status, - reinterpret_cast(const_cast(server_mac_key.data())), - reinterpret_cast(const_cast(client_mac_key.data())), - reinterpret_cast(provider_session_token.data()), - provider_session_token.size()); + OEMCryptoResult result; + WithOecLock("CreateOldUsageEntry", [&] { + result = OEMCrypto_CreateOldUsageEntry( + requested_security_level_, time_since_license_received, + time_since_first_decrypt, time_since_last_decrypt, status, + reinterpret_cast(const_cast(server_mac_key.data())), + reinterpret_cast(const_cast(client_mac_key.data())), + reinterpret_cast(provider_session_token.data()), + provider_session_token.size()); + }); if (result != OEMCrypto_SUCCESS) { LOGE("CreateOldUsageEntry: OEMCrypto_CreateOldUsageEntry error: %d", @@ -2553,10 +2682,13 @@ CdmResponseType CryptoSession::CopyOldUsageEntry( const std::string& provider_session_token) { LOGV("CopyOldUsageEntry: id=%lu", oec_session_id_); - OEMCryptoResult result = OEMCrypto_CopyOldUsageEntry( - oec_session_id_, - reinterpret_cast(provider_session_token.data()), - provider_session_token.size()); + OEMCryptoResult result; + WithOecLock("CopyOldUsageEntry", [&] { + result = OEMCrypto_CopyOldUsageEntry( + oec_session_id_, + reinterpret_cast(provider_session_token.data()), + provider_session_token.size()); + }); return MapOEMCryptoResult( result, COPY_OLD_USAGE_ENTRY_UNKNOWN_ERROR, "CopyOldUsageEntry"); @@ -2566,7 +2698,10 @@ bool CryptoSession::GetAnalogOutputCapabilities(bool* can_support_output, bool* can_disable_output, bool* can_support_cgms_a) { LOGV("GetAnalogOutputCapabilities: id=%lu", oec_session_id_); - uint32_t flags = OEMCrypto_GetAnalogOutputFlags(requested_security_level_); + uint32_t flags; + WithOecLock("GetAnalogOutputCapabilities", [&] { + flags = OEMCrypto_GetAnalogOutputFlags(requested_security_level_); + }); if ((flags & OEMCrypto_Unknown_Analog_Output) != 0) return false; *can_support_cgms_a = flags & OEMCrypto_Supports_CGMS_A; @@ -2644,11 +2779,13 @@ OEMCryptoResult CryptoSession::CopyBufferInChunks( } OEMCryptoResult sts; - M_TIME(sts = OEMCrypto_CopyBuffer( - oec_session_id_, params.encrypt_buffer + additional_offset, - chunk_size, &buffer_descriptor, subsample_flags), - metrics_, oemcrypto_copy_buffer_, sts, - metrics::Pow2Bucket(chunk_size)); + WithOecLock("CopyBufferInChunks", [&] { + M_TIME(sts = OEMCrypto_CopyBuffer( + oec_session_id_, params.encrypt_buffer + additional_offset, + chunk_size, &buffer_descriptor, subsample_flags), + metrics_, oemcrypto_copy_buffer_, sts, + metrics::Pow2Bucket(chunk_size)); + }); if (sts != OEMCrypto_SUCCESS) { return sts; @@ -2716,13 +2853,15 @@ OEMCryptoResult CryptoSession::DecryptInChunks( // pattern length long, which is also guaranteed to be an exact number // of AES blocks long. OEMCryptoResult sts; - M_TIME( - sts = OEMCrypto_DecryptCENC( - oec_session_id_, params.encrypt_buffer + additional_offset, - chunk_size, params.is_encrypted, &iv.front(), params.block_offset, - &buffer_descriptor, &pattern_descriptor, subsample_flags), - metrics_, oemcrypto_decrypt_cenc_, sts, - metrics::Pow2Bucket(chunk_size)); + WithOecLock("DecryptInChunks", [&] { + M_TIME( + sts = OEMCrypto_DecryptCENC( + oec_session_id_, params.encrypt_buffer + additional_offset, + chunk_size, params.is_encrypted, &iv.front(), params.block_offset, + &buffer_descriptor, &pattern_descriptor, subsample_flags), + metrics_, oemcrypto_decrypt_cenc_, sts, + metrics::Pow2Bucket(chunk_size)); + }); if (sts != OEMCrypto_SUCCESS) { return sts; @@ -2787,6 +2926,28 @@ void CryptoSession::IncrementIV(uint64_t increase_by, (*counter_buffer) = htonll64(ntohll64(*counter_buffer) + increase_by); } +template +auto CryptoSession::WithStaticFieldLock(const char* tag, Func body) + -> decltype(body()) { + LOGV("Static Field Lock - %s", tag); + std::unique_lock auto_lock(static_field_lock_); + return body(); +} + +template +auto CryptoSession::WithOecLock(const char* tag, Func body) + -> decltype(body()) { + LOGV("OEMCrypto Lock - %s", tag); + std::unique_lock auto_lock(oem_crypto_lock_); + return body(); +} + +bool CryptoSession::IsInitialized() { + return WithStaticFieldLock("IsInitialized", [] { return initialized_; }); +} + +// CryptoSesssionFactory support +std::mutex CryptoSession::factory_lock_; // The factory will either be set by WvCdmTestBase, or a default factory is // created on the first call to MakeCryptoSession. std::unique_ptr CryptoSession::factory_ = @@ -2794,6 +2955,7 @@ std::unique_ptr CryptoSession::factory_ = CryptoSession* CryptoSession::MakeCryptoSession( metrics::CryptoMetrics* crypto_metrics) { + std::unique_lock auto_lock(factory_lock_); // 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);