Merge latest oemcrypto-v17 change

No-Typo-Check: Not related to this change.

Bug: 161477208
Change-Id: I99e4780f6855b7045aa0cd5a49c13d2d0d51ed64
This commit is contained in:
Kyle Zhang
2022-01-21 05:58:12 +00:00
committed by Fred Gylys-Colwell
parent c924960962
commit 642965c678
176 changed files with 301013 additions and 296749 deletions

View File

@@ -31,7 +31,7 @@
// Stringify turns macro arguments into static C strings.
// Example: STRINGIFY(this_argument) -> "this_argument"
#define STRINGIFY(PARAM...) #PARAM
#define STRINGIFY(PARAM) #PARAM
#define RETURN_IF_NULL(PARAM, ret_value) \
if ((PARAM) == nullptr) { \
@@ -51,6 +51,16 @@
return ret_value; \
}
#ifdef HAS_DUAL_KEY
/**
* Internal only OEMCrypto method. This is called before parsing the license
* response to indicate the response uses dual keys. If this isn't called,
* it is using single keys.
*/
extern "C" OEMCryptoResult OEMCrypto_UseSecondaryKey(OEMCrypto_SESSION session,
bool dual_key);
#endif
namespace wvcdm {
namespace {
using UsageTableLock = std::unique_lock<std::recursive_mutex>;
@@ -83,7 +93,7 @@ constexpr size_t kMaxSubsampleRegionSizes[] = {
};
// The +1 in this calculation is because the bounds RESOURCE_RATING_TIER_MAX and
// RESOURCE_RATING_TIER_MIN are inclusive.
static_assert(ArraySize(kMaxSubsampleRegionSizes) ==
static_assert(wvutil::ArraySize(kMaxSubsampleRegionSizes) ==
RESOURCE_RATING_TIER_MAX - RESOURCE_RATING_TIER_MIN + 1,
"The kMaxSubsampleRegionSizes table needs to be updated to "
"reflect the supported range of resource rating tiers");
@@ -128,8 +138,8 @@ CdmResponseType MapOEMCryptoResult(OEMCryptoResult result,
void AdvanceDestBuffer(OEMCrypto_DestBufferDesc* dest_buffer, size_t bytes) {
switch (dest_buffer->type) {
case OEMCrypto_BufferType_Clear:
dest_buffer->buffer.clear.address += bytes;
dest_buffer->buffer.clear.address_length -= bytes;
dest_buffer->buffer.clear.clear_buffer += bytes;
dest_buffer->buffer.clear.clear_buffer_length -= bytes;
return;
case OEMCrypto_BufferType_Secure:
@@ -176,8 +186,8 @@ size_t GenericEncryptionBlockSize(CdmEncryptionAlgorithm algorithm) {
} // namespace
// CryptoSession variables allocation.
shared_mutex CryptoSession::static_field_mutex_;
shared_mutex CryptoSession::oem_crypto_mutex_;
wvutil::shared_mutex CryptoSession::static_field_mutex_;
wvutil::shared_mutex CryptoSession::oem_crypto_mutex_;
bool CryptoSession::initialized_ = false;
bool CryptoSession::needs_keybox_provisioning_ = false;
int CryptoSession::session_count_ = 0;
@@ -233,7 +243,7 @@ void GenerateMacContext(const std::string& input_context,
deriv_context->assign(kSigningKeyLabel);
deriv_context->append(1, '\0');
deriv_context->append(input_context);
deriv_context->append(EncodeUint32(kSigningKeySizeBits * 2));
deriv_context->append(wvutil::EncodeUint32(kSigningKeySizeBits * 2));
}
void GenerateEncryptContext(const std::string& input_context,
@@ -249,12 +259,12 @@ void GenerateEncryptContext(const std::string& input_context,
deriv_context->assign(kEncryptionKeyLabel);
deriv_context->append(1, '\0');
deriv_context->append(input_context);
deriv_context->append(EncodeUint32(kEncryptionKeySizeBits));
deriv_context->append(wvutil::EncodeUint32(kEncryptionKeySizeBits));
}
OEMCryptoCipherMode ToOEMCryptoCipherMode(CdmCipherMode cipher_mode) {
return cipher_mode == kCipherModeCtr ? OEMCrypto_CipherMode_CTR
: OEMCrypto_CipherMode_CBC;
return cipher_mode == kCipherModeCtr ? OEMCrypto_CipherMode_CENC
: OEMCrypto_CipherMode_CBCS;
}
CryptoSession::CryptoSession(metrics::CryptoMetrics* metrics)
@@ -306,6 +316,9 @@ CdmResponseType CryptoSession::GetProvisioningMethod(
case OEMCrypto_DrmCertificate:
type = kClientTokenDrmCert;
break;
case OEMCrypto_BootCertificateChain:
type = kClientTokenBootCertChain;
break;
case OEMCrypto_ProvisioningError:
default:
if (static_cast<int>(method) == 0 && needs_keybox_provisioning_) {
@@ -361,10 +374,18 @@ void CryptoSession::Init() {
void CryptoSession::ReinitializeForTest() {
if (initialized_) {
initialized_ = false;
if (OEMCrypto_SUCCESS != OEMCrypto_Terminate()) return;
OEMCryptoResult status = OEMCrypto_Terminate();
if (OEMCrypto_SUCCESS != status) {
LOGE("OEMCrypto_Terminate failed: %d", status);
return;
}
}
// Give up if we cannot initialize at all.
if (OEMCrypto_SUCCESS != OEMCrypto_Initialize()) return;
OEMCryptoResult status = OEMCrypto_Initialize();
if (OEMCrypto_SUCCESS != status) {
LOGE("OEMCrypto_Initialize failed: %d", status);
return;
}
initialized_ = true;
// For integration and unit tests we will install a test keybox and do not
// need to do keybox provisioning.
@@ -562,10 +583,12 @@ CdmResponseType CryptoSession::GetTokenFromOemCert(std::string* token) {
}
}
CdmResponseType CryptoSession::GetProvisioningToken(std::string* token) {
if (token == nullptr) {
CdmResponseType CryptoSession::GetProvisioningToken(
std::string* token, std::string* additional_token) {
if (token == nullptr || additional_token == nullptr) {
metrics_->crypto_session_get_token_.Increment(PARAMETER_NULL);
RETURN_IF_NULL(token, PARAMETER_NULL);
RETURN_IF_NULL(additional_token, PARAMETER_NULL);
}
if (!IsInitialized()) {
@@ -579,6 +602,8 @@ CdmResponseType CryptoSession::GetProvisioningToken(std::string* token) {
status = GetTokenFromKeybox(token);
} else if (pre_provision_token_type_ == kClientTokenOemCert) {
status = GetTokenFromOemCert(token);
} else if (pre_provision_token_type_ == kClientTokenBootCertChain) {
status = GetBootCertificateChain(token, additional_token);
}
metrics_->crypto_session_get_token_.Increment(status);
return status;
@@ -595,41 +620,28 @@ CdmSecurityLevel CryptoSession::GetSecurityLevel(
LOGV("Getting security level: requested_security_level = %s",
SecurityLevelToString(requested_security_level));
RETURN_IF_UNINITIALIZED(kSecurityLevelUninitialized);
const char* const level = WithOecReadLock("GetSecurityLevel", [&] {
return OEMCrypto_SecurityLevel(requested_security_level);
});
if (level == nullptr) {
LOGE("Security level is null: requested_security_level = %d",
const OEMCrypto_Security_Level level = WithOecReadLock(
"GetSecurityLevel",
[&] { return OEMCrypto_SecurityLevel(requested_security_level); });
if (level == 0) {
LOGE("Security level is unknown: requested_security_level = %d",
static_cast<int>(requested_security_level));
return kSecurityLevelUnknown;
}
// Check length in the event of a bad pointer.
// |kMaxSecurityLevelLength| is a value larger than expected to
// be able to detect an overrun.
constexpr size_t kMaxSecurityLevelLength = 5;
const size_t length = strnlen(level, kMaxSecurityLevelLength);
constexpr size_t kExpectedSecurityLevelLength = 2;
if (length != kExpectedSecurityLevelLength) {
LOGE(
"Unexpected security level length: "
"length = %zu, requested_security_level = %s",
length, SecurityLevelToString(requested_security_level));
return kSecurityLevelUnknown;
}
const std::string security_level(level);
if (security_level == "L1") {
if (level == OEMCrypto_Level1) {
return kSecurityLevelL1;
}
if (security_level == "L2") {
if (level == OEMCrypto_Level2) {
return kSecurityLevelL2;
}
if (security_level == "L3") {
if (level == OEMCrypto_Level3) {
return kSecurityLevelL3;
}
LOGE(
"Ill-formed security level: "
"level = \"%s\", requested_security_level = %s",
security_level.c_str(), SecurityLevelToString(requested_security_level));
"level = \"L%u\", requested_security_level = %s",
static_cast<unsigned int>(level),
SecurityLevelToString(requested_security_level));
return kSecurityLevelUnknown;
}
@@ -815,6 +827,11 @@ CdmResponseType CryptoSession::GetSystemIdInternal(uint32_t* system_id) {
// Drm certificate.
return NO_ERROR;
}
if (pre_provision_token_type_ == kClientTokenBootCertChain) {
// A system id can not be inferred from BCC. If the provisioning process has
// come to the second stage, we may read system id from the stored OEM cert.
return NO_ERROR;
}
LOGE("Unsupported pre-provision token type: %d",
static_cast<int>(pre_provision_token_type_));
return UNKNOWN_CLIENT_TOKEN_TYPE;
@@ -938,10 +955,10 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
metrics_->oemcrypto_get_random_.Increment(random_sts);
uint64_t request_id_index =
request_id_index_source_.fetch_add(1, std::memory_order_relaxed);
request_id_ = HexEncode(reinterpret_cast<uint8_t*>(&request_id_base),
sizeof(request_id_base)) +
HexEncode(reinterpret_cast<uint8_t*>(&request_id_index),
sizeof(request_id_index));
request_id_ = wvutil::HexEncode(reinterpret_cast<uint8_t*>(&request_id_base),
sizeof(request_id_base)) +
wvutil::HexEncode(reinterpret_cast<uint8_t*>(&request_id_index),
sizeof(request_id_index));
// Initialize key session
WithOecSessionLock("Open() calling key_session_.reset()", [&] {
@@ -1058,6 +1075,19 @@ CdmResponseType CryptoSession::PrepareAndSignLicenseRequest(
"PrepareAndSignLicenseRequest");
}
CdmResponseType CryptoSession::UseSecondaryKey(bool dual_key) {
#ifdef HAS_DUAL_KEY
OEMCryptoResult sts;
WithOecSessionLock("UseSecondaryKey", [&] {
sts = OEMCrypto_UseSecondaryKey(oec_session_id_, dual_key);
});
return MapOEMCryptoResult(sts, LOAD_KEY_ERROR, "UseSecondaryKey");
#else
return NO_ERROR;
#endif
}
CdmResponseType CryptoSession::LoadKeys(
const std::string& message, const std::string& signature,
const std::string& mac_key_iv, const std::string& mac_key,
@@ -1388,6 +1418,122 @@ CdmResponseType CryptoSession::LoadCertificatePrivateKey(
"LoadCertificatePrivateKey");
}
CdmResponseType CryptoSession::GetBootCertificateChain(
std::string* bcc, std::string* additional_signature) {
RETURN_IF_NULL(bcc, PARAMETER_NULL);
RETURN_IF_NULL(additional_signature, PARAMETER_NULL);
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
LOGV("GetBootCertificateChain");
if (pre_provision_token_type_ != kClientTokenBootCertChain) {
return PROVISIONING_TYPE_IS_NOT_BOOT_CERTIFICATE_CHAIN_ERROR;
}
size_t bcc_length = 0;
size_t additional_signature_length = 0;
OEMCryptoResult sts;
WithOecReadLock("GetBootCertificateChain Attempt 1", [&] {
sts = OEMCrypto_GetBootCertificateChain(nullptr, &bcc_length, nullptr,
&additional_signature_length);
});
if (sts == OEMCrypto_ERROR_SHORT_BUFFER) {
bcc->resize(bcc_length);
additional_signature->resize(additional_signature_length);
WithOecReadLock("GetBootCertificateChain Attempt 2", [&] {
sts = OEMCrypto_GetBootCertificateChain(
reinterpret_cast<uint8_t*>(&bcc->front()), &bcc_length,
reinterpret_cast<uint8_t*>(&additional_signature->front()),
&additional_signature_length);
});
}
return MapOEMCryptoResult(sts, GET_BOOT_CERTIFICATE_CHAIN_ERROR,
"GetBootCertificateChain");
}
CdmResponseType CryptoSession::GenerateCertificateKeyPair(
std::string* public_key, std::string* public_key_signature,
std::string* wrapped_private_key, CryptoWrappedKey::Type* key_type) {
LOGV("Generating certificate key pair: id = %u", oec_session_id_);
RETURN_IF_NULL(public_key, PARAMETER_NULL);
RETURN_IF_NULL(public_key_signature, PARAMETER_NULL);
RETURN_IF_NULL(wrapped_private_key, PARAMETER_NULL);
RETURN_IF_NULL(key_type, PARAMETER_NULL);
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
// Round 1, get the size of all the fields.
size_t public_key_length = 0;
size_t public_key_signature_length = 0;
size_t wrapped_private_key_length = 0;
OEMCrypto_PrivateKeyType oemcrypto_key_type;
OEMCryptoResult status;
WithOecSessionLock("GenerateCertificateKeyPair Attempt 1", [&] {
M_TIME(status = OEMCrypto_GenerateCertificateKeyPair(
oec_session_id_, nullptr, &public_key_length, nullptr,
&public_key_signature_length, nullptr,
&wrapped_private_key_length, &oemcrypto_key_type),
metrics_, oemcrypto_generate_certificate_key_pair_, status);
});
if (status != OEMCrypto_ERROR_SHORT_BUFFER) {
return MapOEMCryptoResult(status, GENERATE_CERTIFICATE_KEY_PAIR_ERROR,
"GenerateCertificateKeyPair");
}
public_key->resize(public_key_length);
public_key_signature->resize(public_key_signature_length);
wrapped_private_key->resize(wrapped_private_key_length);
WithOecSessionLock("GenerateCertificateKeyPair Attempt 2", [&] {
M_TIME(
status = OEMCrypto_GenerateCertificateKeyPair(
oec_session_id_, reinterpret_cast<uint8_t*>(&public_key->front()),
&public_key_length,
reinterpret_cast<uint8_t*>(&public_key_signature->front()),
&public_key_signature_length,
reinterpret_cast<uint8_t*>(&wrapped_private_key->front()),
&wrapped_private_key_length, &oemcrypto_key_type),
metrics_, oemcrypto_generate_certificate_key_pair_, status);
});
public_key->resize(public_key_length);
public_key_signature->resize(public_key_signature_length);
wrapped_private_key->resize(wrapped_private_key_length);
if (oemcrypto_key_type == OEMCrypto_RSA_Private_Key) {
*key_type = CryptoWrappedKey::kRsa;
} else if (oemcrypto_key_type == OEMCrypto_ECC_Private_Key) {
*key_type = CryptoWrappedKey::kEcc;
} else {
LOGE("Unexpected key type returned from GenerateCertificateKeyPair: %d",
static_cast<int>(oemcrypto_key_type));
return MapOEMCryptoResult(status,
GENERATE_CERTIFICATE_KEY_PAIR_UNKNOWN_TYPE_ERROR,
"GenerateCertificateKeyPair");
}
return MapOEMCryptoResult(status, GENERATE_CERTIFICATE_KEY_PAIR_ERROR,
"GenerateCertificateKeyPair");
}
CdmResponseType CryptoSession::LoadOemCertificatePrivateKey(
const CryptoWrappedKey& private_key) {
LOGV("Load OEM cert and private key: id = %u", oec_session_id_);
const OEMCrypto_PrivateKeyType key_type =
(private_key.type() == CryptoWrappedKey::kEcc)
? OEMCrypto_ECC_Private_Key
: OEMCrypto_RSA_Private_Key;
const std::string& wrapped_private_key = private_key.key();
OEMCryptoResult status;
WithOecSessionLock("InstallOemPrivateKey", [&] {
M_TIME(status = OEMCrypto_InstallOemPrivateKey(
oec_session_id_, key_type,
reinterpret_cast<const uint8_t*>(wrapped_private_key.data()),
wrapped_private_key.size()),
metrics_, oemcrypto_install_oem_private_key_, status);
});
return MapOEMCryptoResult(status, LOAD_OEM_CERTIFICATE_PRIVATE_KEY_ERROR,
"InstallOemPrivateKey");
}
// Private.
CdmResponseType CryptoSession::SelectKey(const std::string& key_id,
CdmCipherMode cipher_mode) {
@@ -1502,7 +1648,7 @@ size_t CryptoSession::GetMaxSubsampleRegionSize() {
// Subtract RESOURCE_RATING_TIER_MIN to get a 0-based index into the
// table.
const uint32_t index = tier - RESOURCE_RATING_TIER_MIN;
if (index < ArraySize(kMaxSubsampleRegionSizes)) {
if (index < wvutil::ArraySize(kMaxSubsampleRegionSizes)) {
max_subsample_region_size_ = kMaxSubsampleRegionSizes[index];
}
}
@@ -1563,16 +1709,16 @@ CdmResponseType CryptoSession::Decrypt(
output_descriptor.type = output_descriptor_type;
switch (output_descriptor.type) {
case OEMCrypto_BufferType_Clear:
output_descriptor.buffer.clear.address =
output_descriptor.buffer.clear.clear_buffer =
static_cast<uint8_t*>(sample.decrypt_buffer) +
sample.decrypt_buffer_offset;
output_descriptor.buffer.clear.address_length =
output_descriptor.buffer.clear.clear_buffer_length =
sample.decrypt_buffer_size - sample.decrypt_buffer_offset;
break;
case OEMCrypto_BufferType_Secure:
output_descriptor.buffer.secure.handle = sample.decrypt_buffer;
output_descriptor.buffer.secure.secure_buffer = sample.decrypt_buffer;
output_descriptor.buffer.secure.offset = sample.decrypt_buffer_offset;
output_descriptor.buffer.secure.handle_length =
output_descriptor.buffer.secure.secure_buffer_length =
sample.decrypt_buffer_size;
break;
case OEMCrypto_BufferType_Direct:
@@ -1824,7 +1970,7 @@ CdmResponseType CryptoSession::GenerateUsageReport(
(*usage_report) =
std::string(reinterpret_cast<const char*>(&buffer[0]), buffer.size());
Unpacked_PST_Report pst_report(&buffer[0]);
wvutil::Unpacked_PST_Report pst_report(&buffer[0]);
*usage_duration_status = kUsageDurationsInvalid;
if (usage_length < pst_report.report_size()) {
LOGE(
@@ -1852,7 +1998,7 @@ CdmResponseType CryptoSession::GenerateUsageReport(
pst_report.seconds_since_first_decrypt());
LOGV("OEMCrypto_PST_Report.seconds_since_last_decrypt: %" PRId64 "\n",
pst_report.seconds_since_last_decrypt());
LOGV("OEMCrypto_PST_Report: %s\n", b2a_hex(*usage_report).c_str());
LOGV("OEMCrypto_PST_Report: %s\n", wvutil::b2a_hex(*usage_report).c_str());
if (kInactiveUnused == pst_report.status()) {
*usage_duration_status = kUsageDurationPlaybackNotBegun;
@@ -2096,29 +2242,6 @@ CdmResponseType CryptoSession::GetSrmVersion(uint16_t* srm_version) {
}
}
bool CryptoSession::IsSrmUpdateSupported() {
LOGV("Checking if SRM update is supported");
RETURN_IF_UNINITIALIZED(false);
return WithOecReadLock("IsSrmUpdateSupported",
[&] { return OEMCrypto_IsSRMUpdateSupported(); });
}
CdmResponseType CryptoSession::LoadSrm(const std::string& srm) {
LOGV("Loading SRM");
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
if (srm.empty()) {
LOGE("SRM is empty");
return INVALID_SRM_LIST;
}
const OEMCryptoResult status = WithOecWriteLock("LoadSrm", [&] {
return OEMCrypto_LoadSRM(reinterpret_cast<const uint8_t*>(srm.data()),
srm.size());
});
return MapOEMCryptoResult(status, LOAD_SRM_ERROR, "LoadSRM");
}
bool CryptoSession::GetResourceRatingTier(uint32_t* tier) {
LOGV("Getting resource rating tier");
RETURN_IF_NOT_OPEN(false);
@@ -2160,16 +2283,28 @@ bool CryptoSession::GetBuildInformation(SecurityLevel security_level,
RETURN_IF_UNINITIALIZED(false);
RETURN_IF_NULL(info, false);
const char* build_information;
OEMCryptoResult build_information;
std::string buf;
size_t buf_length = 0;
WithOecReadLock("GetBuildInformation", [&] {
build_information = OEMCrypto_BuildInformation(security_level);
build_information =
OEMCrypto_BuildInformation(&buf[0], &buf_length, security_level);
});
if (build_information == nullptr) {
LOGE("OEMCrypto_BuildInformation failed: Returned null");
if (build_information == OEMCrypto_ERROR_SHORT_BUFFER) {
buf.resize(buf_length);
WithOecReadLock("GetBuildInformation Attempt 2", [&] {
build_information =
OEMCrypto_BuildInformation(&buf[0], &buf_length, security_level);
});
}
if (build_information == OEMCrypto_SUCCESS) {
*info = buf;
} else {
LOGE("Unexpected return value");
return false;
}
info->assign(build_information);
return true;
}
@@ -2892,9 +3027,9 @@ OEMCryptoResult CryptoSession::DecryptSample(
fake_sample.buffers.input_data += length;
AdvanceDestBuffer(&fake_sample.buffers.output_descriptor, length);
if (cipher_mode == kCipherModeCtr) {
AdvanceIvCtr(&fake_sample.iv,
original_subsample.block_offset +
original_subsample.num_bytes_encrypted);
wvutil::AdvanceIvCtr(&fake_sample.iv,
original_subsample.block_offset +
original_subsample.num_bytes_encrypted);
}
}
}
@@ -3049,7 +3184,8 @@ OEMCryptoResult CryptoSession::LegacyDecryptInChunks(
if (cipher_mode == kCipherModeCtr) {
// For 'cenc', update the IV depending on how many encrypted blocks
// we passed.
AdvanceIvCtr(&fake_sample.iv, chunk_size + fake_subsample.block_offset);
wvutil::AdvanceIvCtr(&fake_sample.iv,
chunk_size + fake_subsample.block_offset);
} else if (cipher_mode == kCipherModeCbc) {
// For 'cbcs', use the last ciphertext block as the next IV. The last
// block that was encrypted is probably not the last block of the
@@ -3154,7 +3290,7 @@ template <class Func>
auto CryptoSession::WithStaticFieldWriteLock(const char* tag, Func body)
-> decltype(body()) {
LOGV("Static field write lock: %s", tag);
std::unique_lock<shared_mutex> auto_lock(static_field_mutex_);
std::unique_lock<wvutil::shared_mutex> auto_lock(static_field_mutex_);
return body();
}
@@ -3162,7 +3298,7 @@ template <class Func>
auto CryptoSession::WithStaticFieldReadLock(const char* tag, Func body)
-> decltype(body()) {
LOGV("Static field read lock: %s", tag);
shared_lock<shared_mutex> auto_lock(static_field_mutex_);
wvutil::shared_lock<wvutil::shared_mutex> auto_lock(static_field_mutex_);
return body();
}
@@ -3170,7 +3306,7 @@ template <class Func>
auto CryptoSession::WithOecWriteLock(const char* tag, Func body)
-> decltype(body()) {
LOGV("OEMCrypto write lock: %s", tag);
std::unique_lock<shared_mutex> auto_lock(oem_crypto_mutex_);
std::unique_lock<wvutil::shared_mutex> auto_lock(oem_crypto_mutex_);
return body();
}
@@ -3178,7 +3314,7 @@ template <class Func>
auto CryptoSession::WithOecReadLock(const char* tag, Func body)
-> decltype(body()) {
LOGV("OEMCrypto read lock: %s", tag);
shared_lock<shared_mutex> auto_lock(oem_crypto_mutex_);
wvutil::shared_lock<wvutil::shared_mutex> auto_lock(oem_crypto_mutex_);
return body();
}
@@ -3186,7 +3322,7 @@ template <class Func>
auto CryptoSession::WithOecSessionLock(const char* tag, Func body)
-> decltype(body()) {
LOGV("OEMCrypto session lock: %s", tag);
shared_lock<shared_mutex> oec_auto_lock(oem_crypto_mutex_);
wvutil::shared_lock<wvutil::shared_mutex> oec_auto_lock(oem_crypto_mutex_);
std::unique_lock<std::mutex> session_auto_lock(oem_crypto_session_mutex_);
return body();
}