1066 lines
40 KiB
C++
1066 lines
40 KiB
C++
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
|
|
// source code may only be used and distributed under the Widevine Master
|
|
// License Agreement.
|
|
|
|
#include "crypto_session.h"
|
|
|
|
#include <openssl/sha.h>
|
|
|
|
#include <cstring>
|
|
#include <sstream>
|
|
|
|
#include "cas_util.h"
|
|
#include "log.h"
|
|
static const uint32_t kExpectedOEMCryptoVersion = 16;
|
|
|
|
namespace wvcas {
|
|
|
|
namespace {
|
|
|
|
// Find the offset of the |field| within |message|. Notice that if |field| is
|
|
// empty, 0 will be returned as |pos|.
|
|
size_t GetOffset(const std::string& message, const std::string& field) {
|
|
size_t pos = message.find(field);
|
|
if (pos == std::string::npos) {
|
|
LOGE("GetOffset : Cannot find offset for %s", field.c_str());
|
|
pos = 0;
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
OEMCryptoCipherMode CipherModeFromKeyData(CryptoMode key_cipher) {
|
|
switch (key_cipher) {
|
|
case CryptoMode::kAesCBC:
|
|
return OEMCrypto_CipherMode_CBC;
|
|
case CryptoMode::kAesCTR:
|
|
return OEMCrypto_CipherMode_CTR;
|
|
case CryptoMode::kDvbCsa2:
|
|
return OEMCrypto_CipherMode_CSA2;
|
|
case CryptoMode::kDvbCsa3:
|
|
return OEMCrypto_CipherMode_CSA3;
|
|
case CryptoMode::kAesOFB:
|
|
return OEMCrypto_CipherMode_OFB;
|
|
case CryptoMode::kAesSCTE:
|
|
return OEMCrypto_CipherMode_SCTE;
|
|
default:
|
|
return OEMCrypto_CipherMode_CTR;
|
|
};
|
|
}
|
|
|
|
// Fill an oemcrypto entitled key object from the provided key data.
|
|
void FillEntitledContentKeyObjectFromKeyData(
|
|
std::string& message, const KeySlot& src,
|
|
OEMCrypto_EntitledCasKeyObject* dest) {
|
|
if (nullptr == dest) {
|
|
return;
|
|
}
|
|
std::string entitlement_key_id(src.entitlement_key_id.begin(),
|
|
src.entitlement_key_id.end());
|
|
std::string content_key_id(src.key_id.begin(), src.key_id.end());
|
|
std::string content_key_data_iv(src.wrapped_key_iv.begin(),
|
|
src.wrapped_key_iv.end());
|
|
std::string content_key_data(src.wrapped_key.begin(), src.wrapped_key.end());
|
|
std::string content_iv(src.content_iv.begin(), src.content_iv.end());
|
|
|
|
dest->entitlement_key_id.offset = message.size();
|
|
message += entitlement_key_id;
|
|
dest->entitlement_key_id.length = entitlement_key_id.length();
|
|
|
|
dest->content_key_id.offset = message.size();
|
|
message += content_key_id;
|
|
dest->content_key_id.length = content_key_id.length();
|
|
|
|
dest->content_key_data_iv.offset = message.size();
|
|
message += content_key_data_iv;
|
|
dest->content_key_data_iv.length = content_key_data_iv.length();
|
|
|
|
dest->content_key_data.offset = message.size();
|
|
message += content_key_data;
|
|
dest->content_key_data.length = content_key_data.length();
|
|
|
|
dest->content_iv.offset = message.size();
|
|
message += content_iv;
|
|
dest->content_iv.length = content_iv.length();
|
|
|
|
dest->cipher_mode = CipherModeFromKeyData(src.cipher_mode);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
shared_mutex CryptoLock::static_field_mutex_;
|
|
shared_mutex CryptoLock::oem_crypto_mutex_;
|
|
template <class Func>
|
|
auto CryptoLock::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_);
|
|
return body();
|
|
}
|
|
template <class Func>
|
|
auto CryptoLock::WithStaticFieldReadLock(const char* tag, Func body)
|
|
-> decltype(body()) {
|
|
LOGV("Static field read lock: %s", tag);
|
|
shared_lock<shared_mutex> auto_lock(static_field_mutex_);
|
|
return body();
|
|
}
|
|
template <class Func>
|
|
auto CryptoLock::WithOecWriteLock(const char* tag, Func body)
|
|
-> decltype(body()) {
|
|
LOGV("OEMCrypto write lock: %s", tag);
|
|
std::unique_lock<shared_mutex> auto_lock(oem_crypto_mutex_);
|
|
return body();
|
|
}
|
|
template <class Func>
|
|
auto CryptoLock::WithOecReadLock(const char* tag, Func body)
|
|
-> decltype(body()) {
|
|
LOGV("OEMCrypto read lock: %s", tag);
|
|
shared_lock<shared_mutex> auto_lock(oem_crypto_mutex_);
|
|
return body();
|
|
}
|
|
template <class Func>
|
|
auto CryptoLock::WithOecSessionLock(const char* tag, Func body)
|
|
-> decltype(body()) {
|
|
LOGV("OEMCrypto Session Lock - %s", tag);
|
|
shared_lock<shared_mutex> oec_auto_lock(oem_crypto_mutex_);
|
|
std::unique_lock<std::mutex> session_auto_lock(oem_crypto_session_mutex_);
|
|
return body();
|
|
}
|
|
|
|
bool CryptoInterface::initialized_ = false;
|
|
int CryptoInterface::session_count_ = 0;
|
|
std::unique_ptr<CryptoLock> CryptoInterface::lock_ = make_unique<CryptoLock>();
|
|
|
|
OEMCryptoResult CryptoInterface::OEMCrypto_OpenSession(
|
|
OEMCrypto_SESSION* session) {
|
|
return lock_->WithOecWriteLock("OpenSession", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_OpenSession(session);
|
|
});
|
|
}
|
|
|
|
OEMCryptoResult CryptoInterface::OEMCrypto_CloseSession(
|
|
OEMCrypto_SESSION session) {
|
|
return lock_->WithOecWriteLock("CloseSession", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_CloseSession(session);
|
|
});
|
|
}
|
|
|
|
OEMCrypto_ProvisioningMethod
|
|
CryptoInterface::OEMCrypto_GetProvisioningMethod() {
|
|
return lock_->WithOecReadLock("GetProvisioningMethod", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_GetProvisioningMethod();
|
|
});
|
|
}
|
|
|
|
OEMCryptoResult CryptoInterface::OEMCrypto_GetKeyData(uint8_t* keyData,
|
|
size_t* keyDataLength) {
|
|
return lock_->WithOecReadLock("GetKeyData", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_GetKeyData(keyData, keyDataLength);
|
|
});
|
|
}
|
|
|
|
uint32_t CryptoInterface::OEMCrypto_SupportedCertificates() {
|
|
return lock_->WithOecReadLock("SupportedCertificates", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_SupportedCertificates();
|
|
});
|
|
}
|
|
|
|
OEMCryptoResult CryptoInterface::OEMCrypto_GenerateNonce(
|
|
OEMCrypto_SESSION session, uint32_t* nonce) {
|
|
return lock_->WithOecWriteLock("GenerateNonce", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_GenerateNonce(session, nonce);
|
|
});
|
|
}
|
|
|
|
OEMCryptoResult CryptoInterface::OEMCrypto_GenerateDerivedKeys(
|
|
OEMCrypto_SESSION session, const uint8_t* mac_key_context,
|
|
uint32_t mac_key_context_length, const uint8_t* enc_key_context,
|
|
uint32_t enc_key_context_length) {
|
|
return lock_->WithOecSessionLock("GenerateDerivedKeys", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_GenerateDerivedKeys(
|
|
session, mac_key_context, mac_key_context_length, enc_key_context,
|
|
enc_key_context_length);
|
|
});
|
|
}
|
|
|
|
OEMCryptoResult CryptoInterface::OEMCrypto_PrepAndSignLicenseRequest(
|
|
OEMCrypto_SESSION session, uint8_t* message, size_t message_length,
|
|
size_t* core_message_size, uint8_t* signature, size_t* signature_length) {
|
|
return lock_->WithOecSessionLock("PrepAndSignLicenseRequest", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_PrepAndSignLicenseRequest(
|
|
session, message, message_length, core_message_size, signature,
|
|
signature_length);
|
|
});
|
|
}
|
|
|
|
OEMCryptoResult CryptoInterface::OEMCrypto_PrepAndSignRenewalRequest(
|
|
OEMCrypto_SESSION session, uint8_t* message, size_t message_length,
|
|
size_t* core_message_size, uint8_t* signature, size_t* signature_length) {
|
|
return lock_->WithOecSessionLock("PrepareAndSignRenewalRequest", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_PrepAndSignRenewalRequest(
|
|
session, message, message_length, core_message_size, signature,
|
|
signature_length);
|
|
});
|
|
}
|
|
|
|
OEMCryptoResult CryptoInterface::OEMCrypto_PrepAndSignProvisioningRequest(
|
|
OEMCrypto_SESSION session, uint8_t* message, size_t message_length,
|
|
size_t* core_message_size, uint8_t* signature, size_t* signature_length) {
|
|
return lock_->WithOecSessionLock("PrepareAndSignProvisioningRequest", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_PrepAndSignProvisioningRequest(
|
|
session, message, message_length, core_message_size, signature,
|
|
signature_length);
|
|
});
|
|
}
|
|
|
|
OEMCryptoResult CryptoInterface::OEMCrypto_LoadProvisioning(
|
|
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
|
|
size_t core_message_length, const uint8_t* signature,
|
|
size_t signature_length, uint8_t* wrapped_private_key,
|
|
size_t* wrapped_private_key_length) {
|
|
return lock_->WithOecSessionLock("LoadProvisioning", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_LoadProvisioning(
|
|
session, message, message_length, core_message_length, signature,
|
|
signature_length, wrapped_private_key, wrapped_private_key_length);
|
|
});
|
|
}
|
|
|
|
OEMCryptoResult CryptoInterface::OEMCrypto_GetOEMPublicCertificate(
|
|
OEMCrypto_SESSION session, uint8_t* public_cert,
|
|
size_t* public_cert_length) {
|
|
return lock_->WithOecSessionLock("GetOEMPublicCertificate", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_GetOEMPublicCertificate(
|
|
session, public_cert, public_cert_length);
|
|
});
|
|
}
|
|
|
|
OEMCryptoResult CryptoInterface::OEMCrypto_LoadDRMPrivateKey(
|
|
OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type,
|
|
const uint8_t* wrapped_rsa_key, size_t wrapped_rsa_key_length) {
|
|
return lock_->WithOecSessionLock("LoadDRMPrivateKey", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_LoadDRMPrivateKey(
|
|
session, key_type, wrapped_rsa_key, wrapped_rsa_key_length);
|
|
});
|
|
}
|
|
|
|
OEMCryptoResult CryptoInterface::OEMCrypto_GenerateRSASignature(
|
|
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
|
|
uint8_t* signature, size_t* signature_length,
|
|
RSA_Padding_Scheme padding_scheme) {
|
|
return lock_->WithOecSessionLock("GenerateRsaSignature", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_GenerateRSASignature(
|
|
session, message, message_length, signature, signature_length,
|
|
padding_scheme);
|
|
});
|
|
}
|
|
|
|
OEMCryptoResult CryptoInterface::OEMCrypto_DeriveKeysFromSessionKey(
|
|
OEMCrypto_SESSION session, const uint8_t* enc_session_key,
|
|
size_t enc_session_key_length, const uint8_t* mac_key_context,
|
|
size_t mac_key_context_length, const uint8_t* enc_key_context,
|
|
size_t enc_key_context_length) {
|
|
return lock_->WithOecSessionLock("DeriveKeysFromSessionKey", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_DeriveKeysFromSessionKey(
|
|
session, enc_session_key, enc_session_key_length, mac_key_context,
|
|
mac_key_context_length, enc_key_context, enc_key_context_length);
|
|
});
|
|
}
|
|
|
|
OEMCryptoResult CryptoInterface::OEMCrypto_LoadLicense(
|
|
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
|
|
size_t core_message_length, const uint8_t* signature,
|
|
size_t signature_length) {
|
|
return lock_->WithOecSessionLock("LoadLicense", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_LoadLicense(
|
|
session, message, message_length, core_message_length, signature,
|
|
signature_length);
|
|
});
|
|
}
|
|
|
|
OEMCryptoResult CryptoInterface::OEMCrypto_LoadRenewal(
|
|
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
|
|
size_t core_message_length, const uint8_t* signature,
|
|
size_t signature_length) {
|
|
return lock_->WithOecSessionLock("LoadRenewal", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_LoadRenewal(
|
|
session, message, message_length, core_message_length, signature,
|
|
signature_length);
|
|
});
|
|
}
|
|
|
|
OEMCryptoResult CryptoInterface::OEMCrypto_LoadCasECMKeys(
|
|
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
|
|
const OEMCrypto_EntitledCasKeyObject* even_key,
|
|
const OEMCrypto_EntitledCasKeyObject* odd_key) {
|
|
return lock_->WithOecSessionLock("LoadCasECMKeys", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_LoadCasECMKeys(
|
|
session, message, message_length, even_key, odd_key);
|
|
});
|
|
}
|
|
|
|
OEMCryptoResult CryptoInterface::OEMCrypto_SelectKey(
|
|
OEMCrypto_SESSION session, const uint8_t* content_key_id,
|
|
size_t content_key_id_length, OEMCryptoCipherMode cipher_mode) {
|
|
return lock_->WithOecSessionLock("SelectKey", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_SelectKey(
|
|
session, content_key_id, content_key_id_length, cipher_mode);
|
|
});
|
|
}
|
|
|
|
OEMCryptoResult CryptoInterface::OEMCrypto_GetHDCPCapability(
|
|
OEMCrypto_HDCP_Capability* current, OEMCrypto_HDCP_Capability* max) {
|
|
return lock_->WithOecReadLock("GetHdcpCapabilities", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_GetHDCPCapability(current, max);
|
|
});
|
|
}
|
|
|
|
OEMCryptoResult CryptoInterface::OEMCrypto_GetDeviceID(uint8_t* deviceID,
|
|
size_t* idLength) {
|
|
return lock_->WithOecReadLock("GetDeviceID", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_GetDeviceID(deviceID, idLength);
|
|
});
|
|
}
|
|
|
|
const char* CryptoInterface::OEMCrypto_SecurityLevel() {
|
|
return lock_->WithOecReadLock("SecurityLevel", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_SecurityLevel();
|
|
});
|
|
}
|
|
|
|
OEMCryptoResult CryptoInterface::OEMCrypto_CreateEntitledKeySession(
|
|
OEMCrypto_SESSION oec_session, OEMCrypto_SESSION* key_session) {
|
|
return lock_->WithOecSessionLock("CreateEntitledKeySession", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_CreateEntitledKeySession(
|
|
oec_session, key_session);
|
|
});
|
|
}
|
|
|
|
OEMCryptoResult CryptoInterface::OEMCrypto_RemoveEntitledKeySession(
|
|
OEMCrypto_SESSION key_session) {
|
|
return lock_->WithOecSessionLock("RemoveEntitledKeySession", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_RemoveEntitledKeySession(
|
|
key_session);
|
|
});
|
|
}
|
|
|
|
uint32_t CryptoInterface::OEMCrypto_APIVersion() {
|
|
return lock_->WithOecReadLock("APIVersion", [&] {
|
|
return oemcrypto_interface_->OEMCrypto_APIVersion();
|
|
});
|
|
}
|
|
|
|
OEMCryptoResult CryptoInterface::create_internal(
|
|
OEMCryptoInterface* oemcrypto_interface,
|
|
std::unique_ptr<CryptoInterface>* init) {
|
|
static OEMCryptoInterface default_oemcrypto_interface;
|
|
// The oemcrypto interface currently used. It may point to different
|
|
// oemcrypto_interface implementations in normal running v.s. test running.
|
|
static OEMCryptoInterface* oemcrypto_interface_in_use;
|
|
|
|
if (init == nullptr) {
|
|
return OEMCrypto_ERROR_INIT_FAILED;
|
|
}
|
|
|
|
std::unique_ptr<CryptoInterface> new_oemcrypto_interface;
|
|
|
|
OEMCryptoResult status = OEMCrypto_SUCCESS;
|
|
lock_->WithStaticFieldWriteLock("Initialize", [&] {
|
|
if (!oemcrypto_interface)
|
|
oemcrypto_interface = &default_oemcrypto_interface;
|
|
if (session_count_ == 0) {
|
|
lock_->WithOecWriteLock("Initialize", [&] {
|
|
status = oemcrypto_interface->OEMCrypto_Initialize();
|
|
});
|
|
if (status != OEMCrypto_SUCCESS) {
|
|
return;
|
|
}
|
|
oemcrypto_interface_in_use = oemcrypto_interface;
|
|
}
|
|
// Using 'new' to access a non-public constructor.
|
|
new_oemcrypto_interface =
|
|
std::unique_ptr<CryptoInterface>(new CryptoInterface());
|
|
new_oemcrypto_interface->oemcrypto_interface_ = oemcrypto_interface_in_use;
|
|
++session_count_;
|
|
});
|
|
if (status != OEMCrypto_SUCCESS) {
|
|
return status;
|
|
}
|
|
|
|
*init = std::move(new_oemcrypto_interface);
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
CryptoInterface::CryptoInterface() : oemcrypto_interface_(nullptr) {}
|
|
CryptoInterface::~CryptoInterface() {
|
|
lock_->WithStaticFieldWriteLock("Terminate", [&] {
|
|
if (session_count_ > 0) {
|
|
if (--session_count_ == 0) {
|
|
lock_->WithOecWriteLock(
|
|
"Terminate", [&] { oemcrypto_interface_->OEMCrypto_Terminate(); });
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/************************************************************************/
|
|
|
|
CryptoSession::CryptoSession() {}
|
|
CryptoSession::~CryptoSession() {}
|
|
|
|
CasStatus CryptoSession::initialize() {
|
|
OEMCryptoResult result;
|
|
result = getCryptoInterface(&crypto_interface_);
|
|
if (result != OEMCrypto_SUCCESS) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"unable to ceate interface");
|
|
}
|
|
// Open a crypto session here.
|
|
result = crypto_interface_->OEMCrypto_OpenSession(&session_);
|
|
if (result != OEMCrypto_SUCCESS) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_OpenSession returned " << result;
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
return CasStatus::OkStatus();
|
|
}
|
|
|
|
CasStatus CryptoSession::reset() {
|
|
CasStatus status = close();
|
|
if (status.status_code() != CasStatusCode::kNoError) {
|
|
return status;
|
|
}
|
|
return initialize();
|
|
}
|
|
|
|
CasStatus CryptoSession::close() {
|
|
if (!crypto_interface_) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"missing crypto interface");
|
|
}
|
|
OEMCryptoResult result = crypto_interface_->OEMCrypto_CloseSession(session_);
|
|
if (result != OEMCrypto_SUCCESS) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_CloseSession returned " << result;
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
return CasStatus::OkStatus();
|
|
}
|
|
|
|
CasProvisioningMethod CryptoSession::provisioning_method() {
|
|
if (!crypto_interface_) {
|
|
return ProvisioningError;
|
|
}
|
|
switch (crypto_interface_->OEMCrypto_GetProvisioningMethod()) {
|
|
case OEMCrypto_Keybox:
|
|
return Keybox;
|
|
case OEMCrypto_OEMCertificate:
|
|
return OEMCertificate;
|
|
case OEMCrypto_DrmCertificate:
|
|
return DrmCertificate;
|
|
default:
|
|
return ProvisioningError;
|
|
}
|
|
}
|
|
|
|
CasStatus CryptoSession::GetKeyData(uint8_t* keyData, size_t* keyDataLength) {
|
|
if (!crypto_interface_) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"missing crypto interface");
|
|
}
|
|
OEMCryptoResult result =
|
|
crypto_interface_->OEMCrypto_GetKeyData(keyData, keyDataLength);
|
|
if (result != OEMCrypto_SUCCESS) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_GetKeyData returned " << result;
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
return CasStatus::OkStatus();
|
|
}
|
|
|
|
SupportedCertificates CryptoSession::supported_certificates() {
|
|
if (!crypto_interface_) {
|
|
return SupportedCertificates(0);
|
|
}
|
|
return SupportedCertificates(
|
|
crypto_interface_->OEMCrypto_SupportedCertificates());
|
|
}
|
|
|
|
CasStatus CryptoSession::GenerateNonce(uint32_t* nonce) {
|
|
if (!crypto_interface_) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"missing crypto interface");
|
|
}
|
|
OEMCryptoResult result =
|
|
crypto_interface_->OEMCrypto_GenerateNonce(session_, nonce);
|
|
if (result != OEMCrypto_SUCCESS) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_GenerateNonce returned " << result;
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
return CasStatus::OkStatus();
|
|
}
|
|
|
|
CasStatus CryptoSession::GenerateDerivedKeys(const uint8_t* mac_key_context,
|
|
uint32_t mac_key_context_length,
|
|
const uint8_t* enc_key_context,
|
|
uint32_t enc_key_context_length) {
|
|
if (!crypto_interface_) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"missing crypto interface");
|
|
}
|
|
OEMCryptoResult result = crypto_interface_->OEMCrypto_GenerateDerivedKeys(
|
|
session_, mac_key_context, mac_key_context_length, enc_key_context,
|
|
enc_key_context_length);
|
|
if (result != OEMCrypto_SUCCESS) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_GenerateDerivedKeys returned " << result;
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
return CasStatus::OkStatus();
|
|
}
|
|
|
|
CasStatus CryptoSession::PrepareAndSignLicenseRequest(
|
|
const std::string& message, std::string* core_message,
|
|
std::string* signature) {
|
|
if (!crypto_interface_) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"missing crypto interface");
|
|
}
|
|
if (core_message == nullptr || signature == nullptr) {
|
|
LOGE("Missing core_message or signature.");
|
|
return CasStatus(CasStatusCode::kInvalidParameter,
|
|
"Missing core_message or signature.");
|
|
}
|
|
|
|
OEMCryptoResult sts;
|
|
size_t signature_length = 0;
|
|
size_t core_message_length = 0;
|
|
*core_message = "";
|
|
std::string combined_message = *core_message + message;
|
|
// First call is intended to determine the required size of the
|
|
// output buffers.
|
|
sts = crypto_interface_->OEMCrypto_PrepAndSignLicenseRequest(
|
|
session_,
|
|
reinterpret_cast<uint8_t*>(const_cast<char*>(combined_message.data())),
|
|
combined_message.size(), &core_message_length, nullptr,
|
|
&signature_length);
|
|
if (OEMCrypto_ERROR_SHORT_BUFFER != sts) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_PrepareAndSignLicenseRequest returned " << sts;
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
|
|
// Resize.
|
|
core_message->resize(core_message_length);
|
|
signature->resize(signature_length);
|
|
|
|
combined_message = *core_message + message;
|
|
sts = crypto_interface_->OEMCrypto_PrepAndSignLicenseRequest(
|
|
session_,
|
|
reinterpret_cast<uint8_t*>(const_cast<char*>(combined_message.data())),
|
|
combined_message.size(), &core_message_length,
|
|
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())),
|
|
&signature_length);
|
|
if (sts != OEMCrypto_SUCCESS) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_PrepareAndSignLicenseRequest returned " << sts;
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
|
|
signature->resize(signature_length);
|
|
*core_message = std::move(combined_message);
|
|
// Truncate combined message to only contain the core message.
|
|
core_message->resize(core_message_length);
|
|
return CasStatus::OkStatus();
|
|
}
|
|
|
|
CasStatus CryptoSession::PrepareAndSignRenewalRequest(
|
|
const std::string& message, std::string* core_message,
|
|
std::string* signature) {
|
|
if (!crypto_interface_) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"missing crypto interface");
|
|
}
|
|
if (core_message == nullptr || signature == nullptr) {
|
|
LOGE("Missing core_message or signature.");
|
|
return CasStatus(CasStatusCode::kInvalidParameter,
|
|
"Missing core_message or signature.");
|
|
}
|
|
|
|
OEMCryptoResult sts;
|
|
size_t signature_length = 0;
|
|
size_t core_message_length = 0;
|
|
*core_message = "";
|
|
std::string combined_message = *core_message + message;
|
|
// First call is intended to determine the required size of the
|
|
// output buffers.
|
|
sts = crypto_interface_->OEMCrypto_PrepAndSignRenewalRequest(
|
|
session_,
|
|
reinterpret_cast<uint8_t*>(const_cast<char*>(combined_message.data())),
|
|
combined_message.size(), &core_message_length, nullptr,
|
|
&signature_length);
|
|
if (OEMCrypto_ERROR_SHORT_BUFFER != sts) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_PrepAndSignRenewalRequest returned " << sts;
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
|
|
// Resize.
|
|
core_message->resize(core_message_length);
|
|
signature->resize(signature_length);
|
|
|
|
combined_message = *core_message + message;
|
|
sts = crypto_interface_->OEMCrypto_PrepAndSignRenewalRequest(
|
|
session_,
|
|
reinterpret_cast<uint8_t*>(const_cast<char*>(combined_message.data())),
|
|
combined_message.size(), &core_message_length,
|
|
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())),
|
|
&signature_length);
|
|
if (sts != OEMCrypto_SUCCESS) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_PrepAndSignRenewalRequest returned " << sts;
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
|
|
signature->resize(signature_length);
|
|
*core_message = std::move(combined_message);
|
|
// Truncate combined message to only contain the core message.
|
|
core_message->resize(core_message_length);
|
|
return CasStatus::OkStatus();
|
|
}
|
|
|
|
CasStatus CryptoSession::PrepareAndSignProvisioningRequest(
|
|
const std::string& message, std::string* core_message,
|
|
std::string* signature) {
|
|
if (!crypto_interface_) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"missing crypto interface");
|
|
}
|
|
if (core_message == nullptr || signature == nullptr) {
|
|
LOGE("Missing core_message or signature.");
|
|
return CasStatus(CasStatusCode::kInvalidParameter,
|
|
"Missing core_message or signature.");
|
|
}
|
|
|
|
OEMCryptoResult sts;
|
|
size_t signature_length = 0;
|
|
size_t core_message_length = 0;
|
|
*core_message = "";
|
|
std::string combined_message = *core_message + message;
|
|
// First call is intended to determine the required size of the
|
|
// output buffers.
|
|
sts = crypto_interface_->OEMCrypto_PrepAndSignProvisioningRequest(
|
|
session_,
|
|
reinterpret_cast<uint8_t*>(const_cast<char*>(combined_message.data())),
|
|
combined_message.size(), &core_message_length, nullptr,
|
|
&signature_length);
|
|
if (OEMCrypto_ERROR_SHORT_BUFFER != sts) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_PrepAndSignProvisioningRequest returned " << sts;
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
|
|
// Resize.
|
|
core_message->resize(core_message_length);
|
|
signature->resize(signature_length);
|
|
|
|
combined_message = *core_message + message;
|
|
sts = crypto_interface_->OEMCrypto_PrepAndSignProvisioningRequest(
|
|
session_,
|
|
reinterpret_cast<uint8_t*>(const_cast<char*>(combined_message.data())),
|
|
combined_message.size(), &core_message_length,
|
|
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())),
|
|
&signature_length);
|
|
if (sts != OEMCrypto_SUCCESS) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_PrepAndSignProvisioningRequest returned " << sts;
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
|
|
signature->resize(signature_length);
|
|
*core_message = std::move(combined_message);
|
|
// Truncate combined message to only contain the core message.
|
|
core_message->resize(core_message_length);
|
|
return CasStatus::OkStatus();
|
|
}
|
|
|
|
CasStatus CryptoSession::LoadProvisioning(const std::string& signed_message,
|
|
const std::string& core_message,
|
|
const std::string& signature,
|
|
std::string* wrapped_private_key) {
|
|
LOGV("Loading provisioning certificate: id = %u", session_);
|
|
if (!crypto_interface_) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"missing crypto interface");
|
|
}
|
|
if (wrapped_private_key == nullptr) {
|
|
LOGE("Missing wrapped |wrapped_private_key|.");
|
|
return CasStatus(CasStatusCode::kInvalidParameter,
|
|
"Missing wrapped |wrapped_private_key|.");
|
|
}
|
|
|
|
const std::string combined_message = core_message + signed_message;
|
|
// Round 1, get the size of the wrapped private key buffer.
|
|
size_t wrapped_private_key_length = 0;
|
|
OEMCryptoResult result = crypto_interface_->OEMCrypto_LoadProvisioning(
|
|
session_, reinterpret_cast<const uint8_t*>(combined_message.data()),
|
|
combined_message.size(), core_message.size(),
|
|
reinterpret_cast<const uint8_t*>(signature.data()), signature.size(),
|
|
nullptr, &wrapped_private_key_length);
|
|
if (result != OEMCrypto_ERROR_SHORT_BUFFER) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_LoadProvisioning returned " << result;
|
|
return CasStatus(CasStatusCode::kIndividualizationError, err_string.str());
|
|
}
|
|
|
|
wrapped_private_key->resize(wrapped_private_key_length);
|
|
result = crypto_interface_->OEMCrypto_LoadProvisioning(
|
|
session_, reinterpret_cast<const uint8_t*>(combined_message.data()),
|
|
combined_message.size(), core_message.size(),
|
|
reinterpret_cast<const uint8_t*>(signature.data()), signature.size(),
|
|
reinterpret_cast<uint8_t*>(&wrapped_private_key->front()),
|
|
&wrapped_private_key_length);
|
|
if (result != OEMCrypto_SUCCESS) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_LoadProvisioning returned " << result;
|
|
return CasStatus(CasStatusCode::kIndividualizationError, err_string.str());
|
|
}
|
|
return CasStatus::OkStatus();
|
|
}
|
|
|
|
CasStatus CryptoSession::GetOEMPublicCertificate(uint8_t* public_cert,
|
|
size_t* public_cert_length) {
|
|
if (!crypto_interface_) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"missing crypto interface");
|
|
}
|
|
if (!public_cert || !public_cert_length) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, "invalid argument");
|
|
}
|
|
OEMCryptoResult result = crypto_interface_->OEMCrypto_GetOEMPublicCertificate(
|
|
session_, public_cert, public_cert_length);
|
|
if (result != OEMCrypto_SUCCESS) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_GetOEMPublicCertificate returned " << result;
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
return CasStatus::OkStatus();
|
|
}
|
|
|
|
CasStatus CryptoSession::LoadDeviceRSAKey(const uint8_t* wrapped_rsa_key,
|
|
size_t wrapped_rsa_key_length) {
|
|
if (!crypto_interface_) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"missing crypto interface");
|
|
}
|
|
if (!wrapped_rsa_key) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, "invalid argument");
|
|
}
|
|
OEMCryptoResult result = crypto_interface_->OEMCrypto_LoadDRMPrivateKey(
|
|
session_, OEMCrypto_RSA_Private_Key, wrapped_rsa_key,
|
|
wrapped_rsa_key_length);
|
|
if (result != OEMCrypto_SUCCESS) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_LoadDRMPrivateKey returned " << result;
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
return CasStatus::OkStatus();
|
|
}
|
|
|
|
CasStatus CryptoSession::GenerateRSASignature(
|
|
const uint8_t* message, size_t message_length, uint8_t* signature,
|
|
size_t* signature_length, RSA_Padding_Scheme padding_scheme) {
|
|
if (!crypto_interface_) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"missing crypto interface");
|
|
}
|
|
if (!message || !signature || signature_length == 0) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, "invalid argument");
|
|
}
|
|
OEMCryptoResult result = crypto_interface_->OEMCrypto_GenerateRSASignature(
|
|
session_, message, message_length, signature, signature_length,
|
|
padding_scheme);
|
|
if (result != OEMCrypto_SUCCESS) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_GenerateRSASignature returned " << result;
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
return CasStatus::OkStatus();
|
|
}
|
|
|
|
CasStatus CryptoSession::DeriveKeysFromSessionKey(
|
|
const uint8_t* enc_session_key, size_t enc_session_key_length,
|
|
const uint8_t* mac_key_context, size_t mac_key_context_length,
|
|
const uint8_t* enc_key_context, size_t enc_key_context_length) {
|
|
if (!crypto_interface_) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"missing crypto interface");
|
|
}
|
|
if (!enc_session_key || !mac_key_context || !enc_key_context) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, "invalid argument");
|
|
}
|
|
OEMCryptoResult result =
|
|
crypto_interface_->OEMCrypto_DeriveKeysFromSessionKey(
|
|
session_, enc_session_key, enc_session_key_length, mac_key_context,
|
|
mac_key_context_length, enc_key_context, enc_key_context_length);
|
|
if (result != OEMCrypto_SUCCESS) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_DeriveKeysFromSessionKey returned " << result;
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
return CasStatus::OkStatus();
|
|
}
|
|
|
|
CasStatus CryptoSession::LoadLicense(const std::string& signed_message,
|
|
const std::string& core_message,
|
|
const std::string& signature) {
|
|
LOGV("Loading license: id = %u", session_);
|
|
if (!crypto_interface_) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"missing crypto interface");
|
|
}
|
|
|
|
const std::string combined_message = core_message + signed_message;
|
|
OEMCryptoResult result = crypto_interface_->OEMCrypto_LoadLicense(
|
|
session_, reinterpret_cast<const uint8_t*>(combined_message.data()),
|
|
combined_message.size(), core_message.size(),
|
|
reinterpret_cast<const uint8_t*>(signature.data()), signature.size());
|
|
if (result != OEMCrypto_SUCCESS) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_LoadLicense returned " << result;
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
return CasStatus::OkStatus();
|
|
}
|
|
|
|
CasStatus CryptoSession::LoadRenewal(const std::string& signed_message,
|
|
const std::string& core_message,
|
|
const std::string& signature) {
|
|
LOGV("Loading license renewal: id = %u", session_);
|
|
if (!crypto_interface_) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"missing crypto interface");
|
|
}
|
|
|
|
const std::string combined_message = core_message + signed_message;
|
|
OEMCryptoResult result = crypto_interface_->OEMCrypto_LoadRenewal(
|
|
session_, reinterpret_cast<const uint8_t*>(combined_message.data()),
|
|
combined_message.size(), core_message.size(),
|
|
reinterpret_cast<const uint8_t*>(signature.data()), signature.size());
|
|
if (result != OEMCrypto_SUCCESS) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_LoadRenewal returned " << result;
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
return CasStatus::OkStatus();
|
|
}
|
|
|
|
CasStatus CryptoSession::LoadCasECMKeys(OEMCrypto_SESSION session,
|
|
const KeySlot* even_key,
|
|
const KeySlot* odd_key) {
|
|
if (!crypto_interface_) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"missing crypto interface");
|
|
}
|
|
if (nullptr == even_key && nullptr == odd_key) {
|
|
return CasStatus::OkStatus();
|
|
}
|
|
OEMCrypto_EntitledCasKeyObject even_ecko;
|
|
OEMCrypto_EntitledCasKeyObject odd_ecko;
|
|
std::string message;
|
|
if (nullptr != even_key) {
|
|
FillEntitledContentKeyObjectFromKeyData(message, *even_key, &even_ecko);
|
|
}
|
|
if (nullptr != odd_key) {
|
|
FillEntitledContentKeyObjectFromKeyData(message, *odd_key, &odd_ecko);
|
|
}
|
|
OEMCryptoResult result = crypto_interface_->OEMCrypto_LoadCasECMKeys(
|
|
session, reinterpret_cast<const uint8_t*>(message.data()), message.size(),
|
|
(nullptr == even_key ? nullptr : &even_ecko),
|
|
(nullptr == odd_key ? nullptr : &odd_ecko));
|
|
if (result != OEMCrypto_SUCCESS) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_LoadCasECMKeys returned " << result;
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
return CasStatus::OkStatus();
|
|
}
|
|
|
|
CasStatus CryptoSession::SelectKey(OEMCrypto_SESSION session,
|
|
const std::vector<uint8_t>& key_id,
|
|
CryptoMode crypto_mode) {
|
|
if (!crypto_interface_) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"missing crypto interface");
|
|
}
|
|
if (current_key_id_.find(session) != current_key_id_.end() &&
|
|
key_id == current_key_id_.at(session) &&
|
|
current_crypto_mode_.find(session) != current_crypto_mode_.end() &&
|
|
crypto_mode == current_crypto_mode_.at(session)) {
|
|
return CasStatus::OkStatus();
|
|
}
|
|
|
|
OEMCryptoCipherMode oem_crypto_cipher_mode;
|
|
switch (crypto_mode) {
|
|
case CryptoMode::kAesCBC:
|
|
oem_crypto_cipher_mode = OEMCrypto_CipherMode_CBC;
|
|
break;
|
|
case CryptoMode::kAesCTR:
|
|
oem_crypto_cipher_mode = OEMCrypto_CipherMode_CTR;
|
|
break;
|
|
case CryptoMode::kDvbCsa2:
|
|
oem_crypto_cipher_mode = OEMCrypto_CipherMode_CSA2;
|
|
break;
|
|
case CryptoMode::kDvbCsa3:
|
|
oem_crypto_cipher_mode = OEMCrypto_CipherMode_CSA3;
|
|
break;
|
|
case CryptoMode::kAesOFB:
|
|
oem_crypto_cipher_mode = OEMCrypto_CipherMode_OFB;
|
|
break;
|
|
case CryptoMode::kAesSCTE:
|
|
oem_crypto_cipher_mode = OEMCrypto_CipherMode_SCTE;
|
|
break;
|
|
default:
|
|
std::ostringstream err_string;
|
|
err_string << "unsupported crypto mode " << static_cast<int>(crypto_mode);
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
|
|
OEMCryptoResult result = crypto_interface_->OEMCrypto_SelectKey(
|
|
session, key_id.data(), key_id.size(), oem_crypto_cipher_mode);
|
|
if (result != OEMCrypto_SUCCESS) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_SelectKey returned " << result;
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
|
|
current_key_id_[session] = key_id;
|
|
current_crypto_mode_[session] = crypto_mode;
|
|
return CasStatus::OkStatus();
|
|
}
|
|
|
|
bool CryptoSession::GetHdcpCapabilities(HdcpCapability* current,
|
|
HdcpCapability* max) {
|
|
if (!crypto_interface_) {
|
|
return false;
|
|
}
|
|
if (current == nullptr || max == nullptr) {
|
|
LOGE(
|
|
"CryptoSession::GetHdcpCapabilities: |current|, |max| cannot be "
|
|
"NULL");
|
|
return false;
|
|
}
|
|
OEMCryptoResult status =
|
|
crypto_interface_->OEMCrypto_GetHDCPCapability(current, max);
|
|
|
|
if (OEMCrypto_SUCCESS != status) {
|
|
LOGW("OEMCrypto_GetHDCPCapability fails with %d", status);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
OEMCryptoResult CryptoSession::getCryptoInterface(
|
|
std::unique_ptr<CryptoInterface>* interface) {
|
|
return CryptoInterface::create(interface);
|
|
}
|
|
|
|
CasStatus CryptoSession::GetDeviceID(std::string* buffer) {
|
|
if (!crypto_interface_) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"missing crypto interface");
|
|
}
|
|
if (buffer == nullptr) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"missing buffer for device id");
|
|
}
|
|
std::string intermediate;
|
|
intermediate.resize(32);
|
|
size_t buf_size = 32;
|
|
OEMCryptoResult result = crypto_interface_->OEMCrypto_GetDeviceID(
|
|
reinterpret_cast<uint8_t*>(&intermediate[0]), &buf_size);
|
|
// If the error is for a short buffer, resize the destination and retry
|
|
// reading the id. This should never happen.
|
|
if (result == OEMCrypto_ERROR_SHORT_BUFFER) {
|
|
intermediate.resize(buf_size);
|
|
result = crypto_interface_->OEMCrypto_GetDeviceID(
|
|
reinterpret_cast<uint8_t*>(&intermediate[0]), &buf_size);
|
|
}
|
|
if (result != OEMCrypto_SUCCESS) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_GetDeviceID returned " << result;
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
buffer->resize(SHA256_DIGEST_LENGTH);
|
|
SHA256(reinterpret_cast<const uint8_t*>(intermediate.data()),
|
|
intermediate.size(), reinterpret_cast<uint8_t*>(&(*buffer)[0]));
|
|
return CasStatus::OkStatus();
|
|
}
|
|
|
|
const char* CryptoSession::SecurityLevel() {
|
|
if (!crypto_interface_) {
|
|
return nullptr;
|
|
}
|
|
return crypto_interface_->OEMCrypto_SecurityLevel();
|
|
}
|
|
|
|
CasStatus CryptoSession::CreateEntitledKeySession(
|
|
OEMCrypto_SESSION* entitled_key_session_id) {
|
|
if (!crypto_interface_) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"missing crypto interface");
|
|
}
|
|
if (entitled_key_session_id == nullptr) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"entitled_key_session_id is nullptr");
|
|
}
|
|
|
|
OEMCryptoResult result =
|
|
crypto_interface_->OEMCrypto_CreateEntitledKeySession(
|
|
session_, entitled_key_session_id);
|
|
if (result != OEMCrypto_SUCCESS) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_CreateEntitledKeySession returned " << result;
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
return CasStatus::OkStatus();
|
|
}
|
|
|
|
CasStatus CryptoSession::RemoveEntitledKeySession(
|
|
OEMCrypto_SESSION entitled_key_session_id) {
|
|
if (!crypto_interface_) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"missing crypto interface");
|
|
}
|
|
|
|
OEMCryptoResult result =
|
|
crypto_interface_->OEMCrypto_RemoveEntitledKeySession(
|
|
entitled_key_session_id);
|
|
if (result != OEMCrypto_SUCCESS) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_RemoveEntitledKeySession returned " << result;
|
|
return CasStatus(CasStatusCode::kCryptoSessionError, err_string.str());
|
|
}
|
|
return CasStatus::OkStatus();
|
|
}
|
|
|
|
CasStatus CryptoSession::APIVersion(uint32_t* api_version) {
|
|
if (!crypto_interface_) {
|
|
return CasStatus(CasStatusCode::kCryptoSessionError,
|
|
"missing crypto interface");
|
|
}
|
|
uint32_t oemcrypto_api_version = crypto_interface_->OEMCrypto_APIVersion();
|
|
|
|
if (oemcrypto_api_version != kExpectedOEMCryptoVersion) {
|
|
std::ostringstream err_string;
|
|
err_string << "OEMCrypto_APIVersion returned: " << oemcrypto_api_version
|
|
<< ". While the correct API version should be: "
|
|
<< kExpectedOEMCryptoVersion;
|
|
return CasStatus(CasStatusCode::kOEMCryptoVersionMismatch,
|
|
err_string.str());
|
|
}
|
|
*api_version = oemcrypto_api_version;
|
|
return CasStatus::OkStatus();
|
|
}
|
|
|
|
} // namespace wvcas
|