Source release v3.4.1

This commit is contained in:
Gene Morgan
2017-09-01 14:17:56 -07:00
parent 8082775924
commit 183aacf0a3
50 changed files with 1508 additions and 2342 deletions

View File

@@ -26,6 +26,47 @@ std::string EncodeUint32(unsigned int u) {
s.append(1, (u >> 0) & 0xFF);
return s;
}
size_t GetOffset(std::string message, std::string field) {
size_t pos = message.find(field);
if (pos == std::string::npos) {
LOGE("CryptoSession::GetOffset : Cannot find offset for %s", field.c_str());
pos = 0;
}
return pos;
}
void GenerateMacContext(const std::string& input_context,
std::string* deriv_context) {
if (!deriv_context) {
LOGE("CryptoSession::GenerateMacContext : No output destination provided.");
return;
}
const std::string kSigningKeyLabel = "AUTHENTICATION";
const size_t kSigningKeySizeBits = wvcdm::MAC_KEY_SIZE * 8;
deriv_context->assign(kSigningKeyLabel);
deriv_context->append(1, '\0');
deriv_context->append(input_context);
deriv_context->append(EncodeUint32(kSigningKeySizeBits * 2));
}
void GenerateEncryptContext(const std::string& input_context,
std::string* deriv_context) {
if (!deriv_context) {
LOGE(
"CryptoSession::GenerateEncryptContext : No output destination "
"provided.");
return;
}
const std::string kEncryptionKeyLabel = "ENCRYPTION";
const size_t kEncryptionKeySizeBits = wvcdm::KEY_SIZE * 8;
deriv_context->assign(kEncryptionKeyLabel);
deriv_context->append(1, '\0');
deriv_context->append(input_context);
deriv_context->append(EncodeUint32(kEncryptionKeySizeBits));
}
const uint32_t kRsaSignatureLength = 256;
const size_t kMaximumChunkSize = 100 * 1024; // 100 KiB
}
@@ -37,6 +78,464 @@ bool CryptoSession::initialized_ = false;
int CryptoSession::session_count_ = 0;
uint64_t CryptoSession::request_id_index_ = 0;
class DefaultKeySession : public KeySession {
public:
explicit DefaultKeySession(CryptoSessionId oec_session_id)
: oec_session_id_(oec_session_id) {}
virtual ~DefaultKeySession() {}
KeySessionType Type() { return kDefault; }
bool GenerateDerivedKeys(const std::string& message) {
std::string mac_deriv_message;
std::string enc_deriv_message;
GenerateMacContext(message, &mac_deriv_message);
GenerateEncryptContext(message, &enc_deriv_message);
LOGV("GenerateDerivedKeys: id=%ld", (uint32_t)oec_session_id_);
OEMCryptoResult sts = OEMCrypto_GenerateDerivedKeys(
oec_session_id_,
reinterpret_cast<const uint8_t*>(mac_deriv_message.data()),
mac_deriv_message.size(),
reinterpret_cast<const uint8_t*>(enc_deriv_message.data()),
enc_deriv_message.size());
if (OEMCrypto_SUCCESS != sts) {
LOGE("GenerateDerivedKeys: OEMCrypto_GenerateDerivedKeys error=%d", sts);
return false;
}
return true;
}
bool GenerateDerivedKeys(const std::string& message,
const std::string& session_key) {
std::string mac_deriv_message;
std::string enc_deriv_message;
GenerateMacContext(message, &mac_deriv_message);
GenerateEncryptContext(message, &enc_deriv_message);
LOGV("GenerateDerivedKeys: id=%ld", (uint32_t)oec_session_id_);
OEMCryptoResult sts = OEMCrypto_DeriveKeysFromSessionKey(
oec_session_id_,
reinterpret_cast<const uint8_t*>(session_key.data()),
session_key.size(),
reinterpret_cast<const uint8_t*>(mac_deriv_message.data()),
mac_deriv_message.size(),
reinterpret_cast<const uint8_t*>(enc_deriv_message.data()),
enc_deriv_message.size());
if (OEMCrypto_SUCCESS != sts) {
LOGE("GenerateDerivedKeys: OEMCrypto_DeriveKeysFromSessionKey err=%d",
sts);
return false;
}
return true;
}
OEMCryptoResult LoadKeys(const std::string& message,
const std::string& signature,
const std::string& mac_key_iv,
const std::string& mac_key,
const std::vector<CryptoKey>& keys,
const std::string& provider_session_token,
CdmCipherMode* cipher_mode) {
const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data());
const uint8_t* enc_mac_key = NULL;
const uint8_t* enc_mac_key_iv = NULL;
if (mac_key.size() >= MAC_KEY_SIZE && mac_key_iv.size() >= KEY_IV_SIZE) {
enc_mac_key = msg + GetOffset(message, mac_key);
enc_mac_key_iv = msg + GetOffset(message, mac_key_iv);
} else {
LOGV("CryptoSession::LoadKeys: enc_mac_key not set");
}
std::vector<OEMCrypto_KeyObject> load_keys(keys.size());
for (size_t i = 0; i < keys.size(); ++i) {
const CryptoKey* ki = &keys[i];
OEMCrypto_KeyObject* ko = &load_keys[i];
ko->key_id = msg + GetOffset(message, ki->key_id());
ko->key_id_length = ki->key_id().length();
ko->key_data_iv = msg + GetOffset(message, ki->key_data_iv());
ko->key_data = msg + GetOffset(message, ki->key_data());
ko->key_data_length = ki->key_data().length();
if (ki->HasKeyControl()) {
ko->key_control_iv = msg + GetOffset(message, ki->key_control_iv());
ko->key_control = msg + GetOffset(message, ki->key_control());
} else {
LOGE("For key %d: XXX key has no control block. size=%d", i,
ki->key_control().size());
ko->key_control_iv = NULL;
ko->key_control = NULL;
}
ko->cipher_mode = ki->cipher_mode() == kCipherModeCbc
? OEMCrypto_CipherMode_CBC
: OEMCrypto_CipherMode_CTR;
*cipher_mode = ki->cipher_mode();
}
uint8_t* pst = NULL;
if (!provider_session_token.empty()) {
pst = const_cast<uint8_t*>(msg) +
GetOffset(message, provider_session_token);
}
LOGV("LoadKeys: id=%ld", (uint32_t)oec_session_id_);
return OEMCrypto_LoadKeys(
oec_session_id_, msg, message.size(),
reinterpret_cast<const uint8_t*>(signature.data()),
signature.size(), enc_mac_key_iv, enc_mac_key, keys.size(),
&load_keys[0], pst, provider_session_token.length());
}
OEMCryptoResult SelectKey(const std::string& key_id) {
// Crypto session lock already locked.
if (!cached_key_id_.empty() && cached_key_id_ == key_id) {
// Already using the desired key.
return OEMCrypto_SUCCESS;
}
cached_key_id_ = key_id;
const uint8_t* key_id_string =
reinterpret_cast<const uint8_t*>(cached_key_id_.data());
OEMCryptoResult sts = OEMCrypto_SelectKey(oec_session_id_, key_id_string,
cached_key_id_.size());
if (OEMCrypto_SUCCESS != sts) {
cached_key_id_.clear();
}
return sts;
}
OEMCryptoResult Decrypt(
const CdmDecryptionParameters& params,
OEMCrypto_DestBufferDesc& buffer_descriptor,
OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor) {
return OEMCrypto_DecryptCENC(
oec_session_id_, params.encrypt_buffer, params.encrypt_length,
params.is_encrypted, &(*params.iv).front(), params.block_offset,
&buffer_descriptor, &pattern_descriptor, params.subsample_flags);
}
private:
CryptoSessionId oec_session_id_;
KeyId cached_key_id_;
};
// TODO(jfore): Move this class into it's own module.
class SubLicenseKeySession : public KeySession {
typedef enum {
kInitializing,
kInitialLicenseLoaded,
kInitialLicenseFailed,
} SubLicenseState;
public:
SubLicenseKeySession(SubLicenseSessionMap& sub_license_oec_sessions,
std::string& wrapped_private_device_key,
SecurityLevel requested_security_level)
: state_(kInitializing),
wrapped_private_device_key_(wrapped_private_device_key),
sub_license_oec_sessions_(sub_license_oec_sessions),
requested_security_level_(requested_security_level) {}
virtual ~SubLicenseKeySession() {}
KeySessionType Type() { return kSubLicense; }
// This version of GenerateDerivedKeys is for devices using keyboxes. It is
// not supported using sub licenses.
bool GenerateDerivedKeys(const std::string& message) {
return false;
}
// GenerateDerivedKeys is called for each open oemcrypto session and is only
// called once.
bool GenerateDerivedKeys(const std::string& message,
const std::string& session_key) {
std::string mac_deriv_message;
std::string enc_deriv_message;
GenerateMacContext(message, &mac_deriv_message);
GenerateEncryptContext(message, &enc_deriv_message);
for (SubLicenseSessionMap::iterator it = sub_license_oec_sessions_.begin();
it != sub_license_oec_sessions_.end(); it++) {
LOGV("GenerateDerivedKeys: id=%ld", (uint32_t)it->second);
OEMCryptoResult sts = OEMCrypto_DeriveKeysFromSessionKey(
it->second, reinterpret_cast<const uint8_t*>(session_key.data()),
session_key.size(),
reinterpret_cast<const uint8_t*>(mac_deriv_message.data()),
mac_deriv_message.size(),
reinterpret_cast<const uint8_t*>(enc_deriv_message.data()),
enc_deriv_message.size());
if (OEMCrypto_SUCCESS != sts) {
LOGE("GenerateDerivedKeys: OEMCrypto_DeriveKeysFromSessionKey err=%d",
sts);
return false;
}
}
return true;
}
// Load the keys in |keys|. The initial keys are saved for key rotation.
OEMCryptoResult LoadKeys(const std::string& message,
const std::string& signature,
const std::string& mac_key_iv,
const std::string& mac_key,
const std::vector<CryptoKey>& keys,
const std::string& provider_session_token,
CdmCipherMode* cipher_mode) {
if (state_ == kInitializing) {
state_ = kInitialLicenseLoaded;
keys_ = keys;
OEMCryptoResult sts = DoLoadKeys(message,
signature,
mac_key_iv,
mac_key,
keys,
provider_session_token,
cipher_mode);
if (OEMCrypto_SUCCESS != sts) {
state_ = kInitialLicenseFailed;
}
return sts;
}
return DoSubLicenseLoadKeys(message, signature, mac_key_iv, mac_key,
keys[0], provider_session_token,
cipher_mode);
}
// Each oemcrypto session contains a single key. Find the right sub session
// and save it's id as the selected oemcrypto session.
OEMCryptoResult SelectKey(const std::string& key_id) {
for (int i = 0; i < keys_.size(); ++i) {
if (keys_[i].key_id() == key_id) {
cached_sub_session_key_id_ = keys_[i].sub_session_key_id();
}
}
return OEMCrypto_SUCCESS;
}
// Decrypt performs the decryption using the selected oemcrypto session.
// TODO(jfore): Support DecryptInChunks.
OEMCryptoResult Decrypt(
const CdmDecryptionParameters& params,
OEMCrypto_DestBufferDesc& buffer_descriptor,
OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor) {
SubLicenseSessionMap::iterator it =
sub_license_oec_sessions_.find(cached_sub_session_key_id_);
if (it == sub_license_oec_sessions_.end()) {
return OEMCrypto_ERROR_INVALID_SESSION;
}
return OEMCrypto_DecryptCENC(
it->second, params.encrypt_buffer, params.encrypt_length,
params.is_encrypted, &(*params.iv).front(), params.block_offset,
&buffer_descriptor, &pattern_descriptor, params.subsample_flags);
}
private:
// Destroy each open oemcrypto session and relace them with new ones.
OEMCryptoResult ResetCryptoSessions() {
for (SubLicenseSessionMap::iterator it = sub_license_oec_sessions_.begin();
it != sub_license_oec_sessions_.end(); it++) {
OEMCryptoResult sts;
sts = OEMCrypto_CloseSession(it->second);
if (OEMCrypto_SUCCESS != sts) {
return sts;
}
sts = OEMCrypto_OpenSession(&it->second, requested_security_level_);
if (OEMCrypto_SUCCESS != sts) {
return sts;
}
sts = OEMCrypto_LoadDeviceRSAKey(
it->second,
reinterpret_cast<const uint8_t*>(wrapped_private_device_key_.data()),
wrapped_private_device_key_.size());
if (OEMCrypto_SUCCESS != sts) {
return sts;
}
}
return OEMCrypto_SUCCESS;
}
// DoLoadKeys loads a single key into each oemcrypto session.
OEMCryptoResult DoLoadKeys(const std::string& message,
const std::string& signature,
const std::string& mac_key_iv,
const std::string& mac_key,
const std::vector<CryptoKey>& keys,
const std::string& provider_session_token,
CdmCipherMode* cipher_mode) {
const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data());
const uint8_t* enc_mac_key = NULL;
const uint8_t* enc_mac_key_iv = NULL;
if (mac_key.size() >= MAC_KEY_SIZE && mac_key_iv.size() >= KEY_IV_SIZE) {
enc_mac_key = msg + GetOffset(message, mac_key);
enc_mac_key_iv = msg + GetOffset(message, mac_key_iv);
} else {
LOGV("CryptoSession::LoadKeys: enc_mac_key not set");
}
uint8_t* pst = NULL;
if (!provider_session_token.empty()) {
pst = const_cast<uint8_t*>(msg) +
GetOffset(message, provider_session_token);
}
// TODO(jfore): Use C++ 11 range loop?
for (int i = 0; i < keys.size(); i++) {
OEMCrypto_KeyObject key_object;
const CryptoKey& key_data = keys[i];
key_object.key_id = msg + GetOffset(message, key_data.key_id());
key_object.key_id_length = key_data.key_id().length();
key_object.key_data_iv = msg + GetOffset(message, key_data.key_data_iv());
key_object.key_data = msg + GetOffset(message, key_data.key_data());
key_object.key_data_length = key_data.key_data().length();
if (key_data.HasKeyControl()) {
key_object.key_control_iv =
msg + GetOffset(message, key_data.key_control_iv());
key_object.key_control =
msg + GetOffset(message, key_data.key_control());
} else {
LOGE("For key %s: XXX key has no control block. size=%d",
key_data.key_id().c_str(), key_data.key_control().size());
key_object.key_control_iv = NULL;
key_object.key_control = NULL;
}
key_object.cipher_mode = key_data.cipher_mode() == kCipherModeCbc
? OEMCrypto_CipherMode_CBC
: OEMCrypto_CipherMode_CTR;
*cipher_mode = key_data.cipher_mode();
SubLicenseSessionMap::iterator oec_session_id =
sub_license_oec_sessions_.find(key_data.sub_session_key_id());
if (oec_session_id == sub_license_oec_sessions_.end()) {
LOGE("CryptoSession::LoadKeys: Unrecognized sub session %s",
key_data.sub_session_key_id().c_str());
return OEMCrypto_ERROR_INVALID_SESSION;
}
OEMCryptoResult sts;
sts = OEMCrypto_LoadKeys(
oec_session_id->second, msg, message.size(),
reinterpret_cast<const uint8_t*>(signature.data()),
signature.size(), enc_mac_key_iv, enc_mac_key, 1, &key_object,
pst, provider_session_token.length());
if (sts != OEMCrypto_SUCCESS) {
return sts;
}
sts = OEMCrypto_SelectKey(
oec_session_id->second,
reinterpret_cast<const uint8_t*>(key_data.key_id().data()),
key_data.key_id().size());
}
keys_ = keys;
return OEMCrypto_SUCCESS;
}
// DoLoadKeys loads a single key into each oemcrypto session.
OEMCryptoResult DoSubLicenseLoadKeys(
const std::string& message, const std::string& signature,
const std::string& mac_key_iv, const std::string& mac_key,
const CryptoKey& key, const std::string& provider_session_token,
CdmCipherMode* cipher_mode) {
SubLicenseSessionMap::iterator it = sub_license_oec_sessions_.end();
int key_index = 0;
for (; key_index < keys_.size(); key_index++) {
if (keys_[key_index].track_label() == key.track_label()) {
it = sub_license_oec_sessions_.find(
keys_[key_index].sub_session_key_id());
CryptoKey tmp = key;
tmp.set_sub_session_key_id(keys_[key_index].sub_session_key_id());
tmp.set_sub_session_key(keys_[key_index].sub_session_key());
keys_[key_index] = tmp;
break;
}
}
if (it == sub_license_oec_sessions_.end()) {
return OEMCrypto_ERROR_INVALID_SESSION;
}
LOGV("GenerateDerivedKeys: id=%ld", (uint32_t)it->second);
std::string mac_deriv_message;
std::string enc_deriv_message;
GenerateMacContext(key.track_label(), &mac_deriv_message);
GenerateEncryptContext(key.track_label(), &enc_deriv_message);
const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data());
const uint8_t* enc_mac_key = NULL;
const uint8_t* enc_mac_key_iv = NULL;
if (mac_key.size() >= MAC_KEY_SIZE && mac_key_iv.size() >= KEY_IV_SIZE) {
enc_mac_key = msg + GetOffset(message, mac_key);
enc_mac_key_iv = msg + GetOffset(message, mac_key_iv);
} else {
LOGV("CryptoSession::LoadKeys: enc_mac_key not set");
}
uint8_t* pst = NULL;
if (!provider_session_token.empty()) {
pst = const_cast<uint8_t*>(msg) +
GetOffset(message, provider_session_token);
}
OEMCryptoResult sts;
const std::string& sub_session_key = keys_[key_index].sub_session_key();
LOGE("ssksize = %d", sub_session_key.size());
sts = OEMCrypto_DeriveKeysFromSessionKey(
it->second, reinterpret_cast<const uint8_t*>(sub_session_key.data()),
sub_session_key.size(),
reinterpret_cast<const uint8_t*>(mac_deriv_message.data()),
mac_deriv_message.size(),
reinterpret_cast<const uint8_t*>(enc_deriv_message.data()),
enc_deriv_message.size());
if (OEMCrypto_SUCCESS != sts) {
LOGE("GenerateDerivedKeys: OEMCrypto_DeriveKeysFromSessionKey err=%d",
sts);
return sts;
}
OEMCrypto_KeyObject key_object;
key_object.key_id = msg + GetOffset(message, keys_[key_index].key_id());
key_object.key_id_length = keys_[key_index].key_id().length();
key_object.key_data_iv = msg + GetOffset(
message, keys_[key_index].key_data_iv());
key_object.key_data = msg + GetOffset(message, keys_[key_index].key_data());
key_object.key_data_length = keys_[key_index].key_data().length();
if (key.HasKeyControl()) {
key_object.key_control_iv =
msg + GetOffset(message, keys_[key_index].key_control_iv());
key_object.key_control = msg + GetOffset(
message, keys_[key_index].key_control());
}
key_object.cipher_mode = keys_[key_index].cipher_mode() == kCipherModeCbc
? OEMCrypto_CipherMode_CBC
: OEMCrypto_CipherMode_CTR;
sts = OEMCrypto_LoadKeys(
it->second, msg, message.size(),
reinterpret_cast<const uint8_t*>(signature.data()),
signature.size(), enc_mac_key_iv, enc_mac_key, 1, &key_object,
pst, provider_session_token.length());
if (sts != OEMCrypto_SUCCESS) {
return sts;
}
sts = OEMCrypto_SelectKey(
it->second,
reinterpret_cast<const uint8_t*>(keys_[key_index].key_id().data()),
keys_[key_index].key_id().size());
return sts;
}
SubLicenseState state_;
std::string cached_sub_session_key_id_;
std::string wrapped_private_device_key_;
std::string message_;
std::string session_key_;
std::vector<CryptoKey> keys_;
SubLicenseSessionMap& sub_license_oec_sessions_;
SecurityLevel requested_security_level_;
};
CryptoSession::CryptoSession()
: open_(false),
update_usage_table_after_close_session_(false),
@@ -349,6 +848,7 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
OEMCrypto_GetRandom(reinterpret_cast<uint8_t*>(&request_id_base_),
sizeof(request_id_base_));
++request_id_index_;
key_session_.reset(new DefaultKeySession(oec_session_id_));
return NO_ERROR;
}
@@ -424,49 +924,6 @@ bool CryptoSession::PrepareRenewalRequest(const std::string& message,
return true;
}
void CryptoSession::GenerateMacContext(const std::string& input_context,
std::string* deriv_context) {
if (!deriv_context) {
LOGE("CryptoSession::GenerateMacContext : No output destination provided.");
return;
}
const std::string kSigningKeyLabel = "AUTHENTICATION";
const size_t kSigningKeySizeBits = MAC_KEY_SIZE * 8;
deriv_context->assign(kSigningKeyLabel);
deriv_context->append(1, '\0');
deriv_context->append(input_context);
deriv_context->append(EncodeUint32(kSigningKeySizeBits * 2));
}
void CryptoSession::GenerateEncryptContext(const std::string& input_context,
std::string* deriv_context) {
if (!deriv_context) {
LOGE(
"CryptoSession::GenerateEncryptContext : No output destination "
"provided.");
return;
}
const std::string kEncryptionKeyLabel = "ENCRYPTION";
const size_t kEncryptionKeySizeBits = KEY_SIZE * 8;
deriv_context->assign(kEncryptionKeyLabel);
deriv_context->append(1, '\0');
deriv_context->append(input_context);
deriv_context->append(EncodeUint32(kEncryptionKeySizeBits));
}
size_t CryptoSession::GetOffset(std::string message, std::string field) {
size_t pos = message.find(field);
if (pos == std::string::npos) {
LOGE("CryptoSession::GetOffset : Cannot find offset for %s", field.c_str());
pos = 0;
}
return pos;
}
CdmResponseType CryptoSession::LoadKeys(
const std::string& message, const std::string& signature,
const std::string& mac_key_iv, const std::string& mac_key,
@@ -475,49 +932,9 @@ CdmResponseType CryptoSession::LoadKeys(
LOGV("CryptoSession::LoadKeys: Lock");
AutoLock auto_lock(crypto_lock_);
const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data());
const uint8_t* enc_mac_key = NULL;
const uint8_t* enc_mac_key_iv = NULL;
if (mac_key.size() >= MAC_KEY_SIZE && mac_key_iv.size() >= KEY_IV_SIZE) {
enc_mac_key = msg + GetOffset(message, mac_key);
enc_mac_key_iv = msg + GetOffset(message, mac_key_iv);
} else {
LOGV("CryptoSession::LoadKeys: enc_mac_key not set");
}
std::vector<OEMCrypto_KeyObject> load_keys(keys.size());
for (size_t i = 0; i < keys.size(); ++i) {
const CryptoKey* ki = &keys[i];
OEMCrypto_KeyObject* ko = &load_keys[i];
ko->key_id = msg + GetOffset(message, ki->key_id());
ko->key_id_length = ki->key_id().length();
ko->key_data_iv = msg + GetOffset(message, ki->key_data_iv());
ko->key_data = msg + GetOffset(message, ki->key_data());
ko->key_data_length = ki->key_data().length();
if (ki->HasKeyControl()) {
ko->key_control_iv = msg + GetOffset(message, ki->key_control_iv());
ko->key_control = msg + GetOffset(message, ki->key_control());
} else {
LOGE("For key %d: XXX key has no control block. size=%d", i,
ki->key_control().size());
ko->key_control_iv = NULL;
ko->key_control = NULL;
}
ko->cipher_mode = ki->cipher_mode() == kCipherModeCbc
? OEMCrypto_CipherMode_CBC
: OEMCrypto_CipherMode_CTR;
cipher_mode_ = ki->cipher_mode();
}
uint8_t* pst = NULL;
if (!provider_session_token.empty()) {
pst =
const_cast<uint8_t*>(msg) + GetOffset(message, provider_session_token);
}
LOGV("LoadKeys: id=%ld", (uint32_t)oec_session_id_);
OEMCryptoResult sts = OEMCrypto_LoadKeys(
oec_session_id_, msg, message.size(),
reinterpret_cast<const uint8_t*>(signature.data()), signature.size(),
enc_mac_key_iv, enc_mac_key, keys.size(), &load_keys[0], pst,
provider_session_token.length());
OEMCryptoResult sts = key_session_->LoadKeys(
message, signature, mac_key_iv, mac_key, keys, provider_session_token,
&cipher_mode_);
if (OEMCrypto_SUCCESS == sts) {
if (!provider_session_token.empty()) {
@@ -559,6 +976,7 @@ bool CryptoSession::LoadCertificatePrivateKey(std::string& wrapped_key) {
LOGE("LoadCertificatePrivateKey: OEMCrypto_LoadDeviceRSAKey error=%d", sts);
return false;
}
wrapped_key_ = wrapped_key;
return true;
}
@@ -592,79 +1010,47 @@ bool CryptoSession::RefreshKeys(const std::string& message,
}
}
LOGV("RefreshKeys: id=%ld", static_cast<uint32_t>(oec_session_id_));
return (
OEMCrypto_SUCCESS ==
OEMCrypto_RefreshKeys(oec_session_id_, msg, message.size(),
reinterpret_cast<const uint8_t*>(signature.data()),
signature.size(), num_keys, &load_key_array[0]));
OEMCryptoResult sts = OEMCrypto_RefreshKeys(
oec_session_id_, msg, message.size(),
reinterpret_cast<const uint8_t*>(signature.data()),
signature.size(), num_keys, &load_key_array[0]);
return sts == OEMCrypto_SUCCESS;
}
bool CryptoSession::SelectKey(const std::string& key_id) {
// Crypto session lock already locked.
if (!cached_key_id_.empty() && cached_key_id_ == key_id) {
// Already using the desired key.
return true;
CdmResponseType CryptoSession::SelectKey(const std::string& key_id) {
OEMCryptoResult sts = key_session_->SelectKey(key_id);
switch (sts) {
case OEMCrypto_SUCCESS:
return NO_ERROR;
case OEMCrypto_ERROR_KEY_EXPIRED:
return NEED_KEY;
case OEMCrypto_ERROR_INSUFFICIENT_HDCP:
return INSUFFICIENT_OUTPUT_PROTECTION;
case OEMCrypto_ERROR_INVALID_SESSION:
return INVALID_SESSION_1;
case OEMCrypto_ERROR_NO_DEVICE_KEY:
return NO_DEVICE_KEY_1;
case OEMCrypto_ERROR_NO_CONTENT_KEY:
return NO_CONTENT_KEY_2;
case OEMCrypto_ERROR_INSUFFICIENT_RESOURCES:
return INSUFFICIENT_CRYPTO_RESOURCES_2;
case OEMCrypto_ERROR_UNKNOWN_FAILURE:
return UNKNOWN_SELECT_KEY_ERROR_1;
case OEMCrypto_ERROR_CONTROL_INVALID:
case OEMCrypto_ERROR_KEYBOX_INVALID:
default:
return UNKNOWN_SELECT_KEY_ERROR_2;
}
cached_key_id_ = key_id;
const uint8_t* key_id_string =
reinterpret_cast<const uint8_t*>(cached_key_id_.data());
OEMCryptoResult sts =
OEMCrypto_SelectKey(oec_session_id_, key_id_string,
cached_key_id_.size());
if (OEMCrypto_SUCCESS != sts) {
cached_key_id_.clear();
return false;
}
return true;
}
bool CryptoSession::GenerateDerivedKeys(const std::string& message) {
std::string mac_deriv_message;
std::string enc_deriv_message;
GenerateMacContext(message, &mac_deriv_message);
GenerateEncryptContext(message, &enc_deriv_message);
LOGV("GenerateDerivedKeys: id=%ld", (uint32_t)oec_session_id_);
OEMCryptoResult sts = OEMCrypto_GenerateDerivedKeys(
oec_session_id_,
reinterpret_cast<const uint8_t*>(mac_deriv_message.data()),
mac_deriv_message.size(),
reinterpret_cast<const uint8_t*>(enc_deriv_message.data()),
enc_deriv_message.size());
if (OEMCrypto_SUCCESS != sts) {
LOGE("GenerateDerivedKeys: OEMCrypto_GenerateDerivedKeys error=%d", sts);
return false;
}
return true;
return key_session_->GenerateDerivedKeys(message);
}
bool CryptoSession::GenerateDerivedKeys(const std::string& message,
const std::string& session_key) {
std::string mac_deriv_message;
std::string enc_deriv_message;
GenerateMacContext(message, &mac_deriv_message);
GenerateEncryptContext(message, &enc_deriv_message);
LOGV("GenerateDerivedKeys: id=%ld", (uint32_t)oec_session_id_);
OEMCryptoResult sts = OEMCrypto_DeriveKeysFromSessionKey(
oec_session_id_, reinterpret_cast<const uint8_t*>(session_key.data()),
session_key.size(),
reinterpret_cast<const uint8_t*>(mac_deriv_message.data()),
mac_deriv_message.size(),
reinterpret_cast<const uint8_t*>(enc_deriv_message.data()),
enc_deriv_message.size());
if (OEMCrypto_SUCCESS != sts) {
LOGE("GenerateDerivedKeys: OEMCrypto_DeriveKeysFromSessionKey err=%d", sts);
return false;
}
return true;
return key_session_->GenerateDerivedKeys(message, session_key);
}
bool CryptoSession::GenerateSignature(const std::string& message,
@@ -801,7 +1187,7 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) {
AutoLock auto_lock(crypto_lock_);
// Check if key needs to be selected
if (params.is_encrypted) {
if (!SelectKey(*params.key_id)) {
if (NO_ERROR != SelectKey(*params.key_id)) {
return NEED_KEY;
}
}
@@ -810,12 +1196,13 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) {
params.is_encrypted, &(*params.iv).front(), params.block_offset,
&buffer_descriptor, &pattern_descriptor, params.subsample_flags);
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 up
// into sections no more than 100 KiB. The exact chunk size needs to be
// an even number of pattern repetitions long or else the pattern will get
// out of sync.
// OEMCrypto_DecryptCENC rejected the buffer as too large, so chunk it
// up into sections no more than 100 KiB. The exact chunk size needs to
// be an even number of pattern repetitions long or else the pattern
// will get out of sync.
const size_t pattern_length =
(pattern_descriptor.encrypt + pattern_descriptor.skip) *
kAes128BlockSize;
@@ -1015,8 +1402,10 @@ CdmResponseType CryptoSession::DeleteUsageInformation(
reinterpret_cast<const uint8_t*>(provider_session_token.c_str()),
provider_session_token.length());
if (OEMCrypto_SUCCESS != status) {
LOGE("CryptoSession::DeleteUsageInformation: Delete Usage Table error =%ld",
status);
LOGE(
"CryptoSession::DeleteUsageInformation: Delete Usage Table error "
"=%ld",
status);
response = UNKNOWN_ERROR;
}
status = OEMCrypto_UpdateUsageTable();
@@ -1239,7 +1628,9 @@ bool CryptoSession::GetHdcpCapabilities(HdcpCapability* current,
LOGV("GetHdcpCapabilities: id=%ld", (uint32_t)oec_session_id_);
if (!initialized_) return false;
if (current == NULL || max == NULL) {
LOGE("CryptoSession::GetHdcpCapabilities: |current|, |max| cannot be NULL");
LOGE(
"CryptoSession::GetHdcpCapabilities: |current|, |max| cannot be "
"NULL");
return false;
}
OEMCryptoResult status = OEMCrypto_GetHDCPCapability(
@@ -1323,7 +1714,7 @@ CdmResponseType CryptoSession::GenericEncrypt(const std::string& in_buffer,
}
AutoLock auto_lock(crypto_lock_);
if (!SelectKey(key_id)) {
if (NO_ERROR != SelectKey(key_id)) {
return KEY_ERROR_1;
}
@@ -1364,7 +1755,7 @@ CdmResponseType CryptoSession::GenericDecrypt(const std::string& in_buffer,
}
AutoLock auto_lock(crypto_lock_);
if (!SelectKey(key_id)) {
if (NO_ERROR != SelectKey(key_id)) {
return KEY_ERROR_2;
}
@@ -1405,7 +1796,7 @@ CdmResponseType CryptoSession::GenericSign(const std::string& message,
size_t length = signature->size();
AutoLock auto_lock(crypto_lock_);
if (!SelectKey(key_id)) {
if (NO_ERROR != SelectKey(key_id)) {
return KEY_ERROR_3;
}
@@ -1452,7 +1843,7 @@ CdmResponseType CryptoSession::GenericVerify(const std::string& message,
}
AutoLock auto_lock(crypto_lock_);
if (!SelectKey(key_id)) {
if (NO_ERROR != SelectKey(key_id)) {
return KEY_ERROR_4;
}
@@ -1473,6 +1864,65 @@ CdmResponseType CryptoSession::GenericVerify(const std::string& message,
return NO_ERROR;
}
CdmResponseType CryptoSession::AddSubSession(
const std::string& sub_session_key_id) {
size_t exists = sub_license_oec_sessions_.count(sub_session_key_id);
if (exists > 0) {
// TODO(jfore): Should this be an error if the key exists? If so add a new
// error. If not, perhaps this should just print info message.
LOGE("AddSubSession: SubSession already exists for id: %s",
sub_session_key_id.c_str());
return UNKNOWN_ERROR;
}
CryptoSessionId sid;
OEMCryptoResult sts = OEMCrypto_OpenSession(&sid, requested_security_level_);
if (OEMCrypto_ERROR_TOO_MANY_SESSIONS == sts) {
LOGE("OEMCrypto_Open failed: %d, open sessions: %ld, initialized: %d",
sts, session_count_, (int)initialized_);
return INSUFFICIENT_CRYPTO_RESOURCES;
} else if (OEMCrypto_SUCCESS != sts) {
LOGE("OEMCrypto_Open failed: %d, open sessions: %ld, initialized: %d",
sts, session_count_, (int)initialized_);
return UNKNOWN_ERROR;
}
sts = OEMCrypto_LoadDeviceRSAKey(
sid, reinterpret_cast<const uint8_t*>(wrapped_key_.data()),
wrapped_key_.size());
sub_license_oec_sessions_[sub_session_key_id] = sid;
if (key_session_->Type() != KeySession::kSubLicense) {
key_session_.reset(new SubLicenseKeySession(
sub_license_oec_sessions_, wrapped_key_, requested_security_level_));
}
return NO_ERROR;
}
bool CryptoSession::GenerateSubSessionNonce(
const std::string& sub_session_key_id, bool* exists, uint32_t* nonce) {
if (!exists || !nonce) {
LOGE("input parameter is null");
return false;
}
LOGV("CryptoSession::GenerateSubSessionNonce: Lock");
AutoLock auto_lock(crypto_lock_);
SubLicenseSessionMap::iterator it =
sub_license_oec_sessions_.find(sub_session_key_id);
if (it == sub_license_oec_sessions_.end()) {
// A subsession does not exist. Indicate that and return success.
*exists = false;
return true;
}
*exists = true;
OEMCryptoResult result;
result = OEMCrypto_GenerateNonce(it->second, nonce);
return OEMCrypto_SUCCESS == result;
}
OEMCrypto_Algorithm CryptoSession::GenericSigningAlgorithm(
CdmSigningAlgorithm algorithm) {
if (kSigningAlgorithmHmacSha256 == algorithm) {
@@ -1514,8 +1964,8 @@ OEMCryptoResult CryptoSession::CopyBufferInChunks(
const size_t additional_offset =
params.encrypt_length - remaining_encrypt_length;
// Update the remaining length of the original buffer only after calculating
// the new values.
// Update the remaining length of the original buffer only after
// calculating the new values.
remaining_encrypt_length -= chunk_size;
// Update the destination buffer with the new offset.
@@ -1583,8 +2033,8 @@ OEMCryptoResult CryptoSession::DecryptInChunks(
// calculating the new values.
remaining_encrypt_length -= chunk_size;
// Update the destination buffer with the new offset. Because OEMCrypto can
// modify the OEMCrypto_DestBufferDesc during the call to
// Update the destination buffer with the new offset. Because OEMCrypto
// can modify the OEMCrypto_DestBufferDesc during the call to
// OEMCrypto_DecryptCENC, (and is known to do so on some platforms) a new
// OEMCrypto_DestBufferDesc must be allocated for each call.
OEMCrypto_DestBufferDesc buffer_descriptor = full_buffer_descriptor;
@@ -1655,8 +2105,8 @@ OEMCryptoResult CryptoSession::DecryptInChunks(
// For cbcs, we must look for the last encrypted block, which is
// probably not the last block of the subsample. Luckily, since the
// buffer size is guaranteed to be an even number of pattern
// repetitions long, we can use the pattern to know how many blocks to
// look back.
// repetitions long, we can use the pattern to know how many blocks
// to look back.
block_end = buffer_end - kAes128BlockSize * pattern_descriptor.skip;
}