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);