Merge "Part of Qualcomm L1 OEMCrypto integration" into jb-mr2-dev
This commit is contained in:
@@ -161,7 +161,7 @@ void CryptoSession::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));
|
||||
deriv_context->append(EncodeUint32(kSigningKeySizeBits*2));
|
||||
}
|
||||
|
||||
void CryptoSession::GenerateEncryptContext(const std::string& input_context,
|
||||
@@ -419,10 +419,15 @@ CdmResponseType CryptoSession::Decrypt(bool is_encrypted,
|
||||
break;
|
||||
}
|
||||
|
||||
OEMCryptoResult sts = OEMCrypto_DecryptCTR(oec_session_id_, encrypt_buffer,
|
||||
encrypt_length, is_encrypted,
|
||||
&iv[0], block_offset,
|
||||
&buffer_descriptor);
|
||||
OEMCryptoResult sts = OEMCrypto_DecryptCTR(
|
||||
oec_session_id_,
|
||||
encrypt_buffer,
|
||||
encrypt_length,
|
||||
is_encrypted,
|
||||
&iv[0],
|
||||
block_offset,
|
||||
&buffer_descriptor,
|
||||
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample);
|
||||
|
||||
if (OEMCrypto_SUCCESS != sts) {
|
||||
return UNKNOWN_ERROR;
|
||||
|
||||
@@ -31,30 +31,31 @@ using video_widevine_server::sdk::ClientIdentification_NameValue;
|
||||
using video_widevine_server::sdk::LicenseRequest;
|
||||
using video_widevine_server::sdk::LicenseRequest_ContentIdentification;
|
||||
using video_widevine_server::sdk::LicenseRequest_ContentIdentification_CENC;
|
||||
using video_widevine_server::sdk::LicenseRequest_ContentIdentification_ExistingLicense;
|
||||
using video_widevine_server::sdk::License;
|
||||
using video_widevine_server::sdk::License_KeyContainer;
|
||||
using video_widevine_server::sdk::LicenseError;
|
||||
using video_widevine_server::sdk::SignedMessage;
|
||||
using video_widevine_server::sdk::STREAMING;
|
||||
using video_widevine_server::sdk::LicenseRequest_ContentIdentification_ExistingLicense;
|
||||
using video_widevine_server::sdk::VERSION_2_1;
|
||||
|
||||
|
||||
static std::vector<CryptoKey> ExtractContentKeys(const License& license) {
|
||||
std::vector<CryptoKey> key_array;
|
||||
|
||||
// Extract content key(s)
|
||||
for (int i = 0; i < license.key_size(); ++i) {
|
||||
// TODO(kqyang): Key ID size is not fixed in spec, but conventionally we
|
||||
// always use 16 bytes key id. We'll need to update oemcrypto to support
|
||||
// variable size key id.
|
||||
if (license.key(i).id().size() == KEY_ID_SIZE &&
|
||||
license.key(i).key().size() == KEY_SIZE + KEY_PAD_SIZE &&
|
||||
license.key(i).type() == License_KeyContainer::CONTENT) {
|
||||
|
||||
// TODO(fredgc): Figure out what key.type is for Generic Keys.
|
||||
// If the generic signing key is CONTENT, then the extra size log below is good.
|
||||
// If it is SIGNING, then we are ignoring it. -- we should fix that by adding
|
||||
// an else clause to this if statement.
|
||||
if (license.key(i).type() == License_KeyContainer::CONTENT) {
|
||||
CryptoKey key;
|
||||
key.set_key_id(license.key(i).id());
|
||||
// Strip off PKCS#5 padding
|
||||
key.set_key_data(
|
||||
license.key(i).key().substr(0, KEY_SIZE));
|
||||
// Strip off PKCS#5 padding - since we know the key is 16 or 32 bytes, the
|
||||
// padding will always be 16 bytes.
|
||||
size_t length = license.key(i).key().size() - 16;
|
||||
key.set_key_data( license.key(i).key().substr(0, length));
|
||||
key.set_key_data_iv(license.key(i).iv());
|
||||
if (license.key(i).has_key_control()) {
|
||||
key.set_key_control(
|
||||
@@ -184,6 +185,7 @@ bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data,
|
||||
}
|
||||
license_request.set_key_control_nonce(UintToString(nonce));
|
||||
LOGD("PrepareKeyRequest: nonce=%u", nonce);
|
||||
license_request.set_protocol_version(VERSION_2_1);
|
||||
|
||||
// License request is complete. Serialize it.
|
||||
std::string serialized_license_req;
|
||||
@@ -240,6 +242,7 @@ bool CdmLicense::PrepareKeyRenewalRequest(CdmKeyMessage* signed_request) {
|
||||
}
|
||||
license_request.set_key_control_nonce(UintToString(nonce));
|
||||
LOGD("PrepareKeyRenewalRequest: nonce=%u", nonce);
|
||||
license_request.set_protocol_version(VERSION_2_1);
|
||||
|
||||
// License request is complete. Serialize it.
|
||||
std::string serialized_license_req;
|
||||
|
||||
@@ -545,7 +545,7 @@ TEST_F(WvCdmRequestLicenseTest, PartialBlockWithOffsetDecryptionTest) {
|
||||
0));
|
||||
|
||||
EXPECT_TRUE(std::equal(data.decrypt_data.begin(), data.decrypt_data.end(),
|
||||
decrypt_buffer.begin()));
|
||||
decrypt_buffer.begin()));
|
||||
|
||||
decryptor_.CloseSession(session_id_);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* mock implementation of OEMCrypto APIs
|
||||
* Wrapper for Level 1 OEMCrypto or Level 3 Fallback APIs
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
#include "log.h"
|
||||
#include "oemcrypto_engine_mock.h"
|
||||
#include "openssl/cmac.h"
|
||||
#include "openssl/evp.h"
|
||||
#include "openssl/hmac.h"
|
||||
#include "openssl/rand.h"
|
||||
#include "openssl/sha.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
@@ -65,7 +68,8 @@ typedef OEMCryptoResult (*L1_DecryptCTR_t)(OEMCrypto_SESSION session,
|
||||
bool is_encrypted,
|
||||
const uint8_t *iv,
|
||||
size_t offset,
|
||||
const OEMCrypto_DestBufferDesc* out_buffer);
|
||||
const OEMCrypto_DestBufferDesc* out_buffer,
|
||||
uint8_t subsample_flags);
|
||||
typedef OEMCryptoResult (*L1_InstallKeybox_t)(const uint8_t *keybox,
|
||||
size_t keyBoxLength);
|
||||
typedef OEMCryptoResult (*L1_IsKeyboxValid_t)(void);
|
||||
@@ -363,7 +367,8 @@ OEMCryptoResult OEMCrypto_GenerateDerivedKeys(OEMCrypto_SESSION session,
|
||||
enc_key_context + enc_key_context_length);
|
||||
|
||||
// Generate mac and encryption keys for current session context
|
||||
if (!session_ctx->DeriveKeys(mac_ctx_str, enc_ctx_str)) {
|
||||
if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key().value(),
|
||||
mac_ctx_str, enc_ctx_str)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
@@ -428,12 +433,12 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length,
|
||||
const uint8_t* enc_mac_key_iv,
|
||||
const uint8_t* enc_mac_key,
|
||||
const uint8_t* enc_mac_keys,
|
||||
size_t num_keys,
|
||||
const OEMCrypto_KeyObject* key_array) {
|
||||
if (level1.library) {
|
||||
return level1.OEMCrypto_LoadKeys(session, message, message_length, signature,
|
||||
signature_length, enc_mac_key_iv, enc_mac_key,
|
||||
signature_length, enc_mac_key_iv, enc_mac_keys,
|
||||
num_keys, key_array);
|
||||
}
|
||||
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
||||
@@ -455,8 +460,8 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
}
|
||||
|
||||
// Range check
|
||||
if (!RangeCheck(message, message_length, enc_mac_key,
|
||||
wvcdm::MAC_KEY_SIZE, true) ||
|
||||
if (!RangeCheck(message, message_length, enc_mac_keys,
|
||||
2*wvcdm::MAC_KEY_SIZE, true) ||
|
||||
!RangeCheck(message, message_length, enc_mac_key_iv,
|
||||
wvcdm::KEY_IV_SIZE, true)) {
|
||||
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_SIGNATURE_FAILURE - range check.]");
|
||||
@@ -471,9 +476,9 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
!RangeCheck(message, message_length, key_array[i].key_data_iv,
|
||||
wvcdm::KEY_IV_SIZE, false) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_control,
|
||||
wvcdm::KEY_CONTROL_SIZE, true) ||
|
||||
wvcdm::KEY_CONTROL_SIZE, false) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_control_iv,
|
||||
wvcdm::KEY_IV_SIZE, true)) {
|
||||
wvcdm::KEY_IV_SIZE, false)) {
|
||||
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_SIGNATURE_FAILURE -range check %d]", i);
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
@@ -521,18 +526,17 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
if (!status) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
|
||||
// enc_mac_key can be NULL if license renewal is not supported
|
||||
if (enc_mac_key == NULL) return OEMCrypto_SUCCESS;
|
||||
if (enc_mac_keys == NULL) return OEMCrypto_SUCCESS;
|
||||
|
||||
// V2 license protocol: update mac key after processing license response
|
||||
const std::vector<uint8_t> enc_mac_key_str = std::vector<uint8_t>(
|
||||
enc_mac_key, enc_mac_key + wvcdm::MAC_KEY_SIZE);
|
||||
// V2.1 license protocol: update mac keys after processing license response
|
||||
const std::vector<uint8_t> enc_mac_keys_str = std::vector<uint8_t>(
|
||||
enc_mac_keys, enc_mac_keys + 2*wvcdm::MAC_KEY_SIZE);
|
||||
const std::vector<uint8_t> enc_mac_key_iv_str = std::vector<uint8_t>(
|
||||
enc_mac_key_iv, enc_mac_key_iv + wvcdm::KEY_IV_SIZE);
|
||||
|
||||
if (!session_ctx->UpdateMacKey(enc_mac_key_str, enc_mac_key_iv_str)) {
|
||||
if (!session_ctx->UpdateMacKeys(enc_mac_keys_str, enc_mac_key_iv_str)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -560,7 +564,8 @@ OEMCryptoResult OEMCrypto_RefreshKeys(OEMCrypto_SESSION session,
|
||||
}
|
||||
|
||||
if (message == NULL || message_length == 0 ||
|
||||
signature == NULL || signature_length == 0) {
|
||||
signature == NULL || signature_length == 0 ||
|
||||
num_keys == 0) {
|
||||
LOGE("[OEMCrypto_RefreshKeys(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
@@ -570,10 +575,10 @@ OEMCryptoResult OEMCrypto_RefreshKeys(OEMCrypto_SESSION session,
|
||||
if (!RangeCheck(message, message_length, key_array[i].key_id,
|
||||
key_array[i].key_id_length, true) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_control,
|
||||
wvcdm::KEY_CONTROL_SIZE, true) ||
|
||||
wvcdm::KEY_CONTROL_SIZE, false) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_control_iv,
|
||||
wvcdm::KEY_IV_SIZE, true)) {
|
||||
LOGE("[OEMCrypto_RefreshKeys(): OEMCrypto_ERROR_SIGNATURE_FAILURE]");
|
||||
LOGE("[OEMCrypto_RefreshKeys(): Range Check %d]", i);
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
}
|
||||
@@ -581,6 +586,7 @@ OEMCryptoResult OEMCrypto_RefreshKeys(OEMCrypto_SESSION session,
|
||||
// Validate message signature
|
||||
if (!session_ctx->ValidateMessage(message, message_length,
|
||||
signature, signature_length)) {
|
||||
LOGE("[OEMCrypto_RefreshKeys(): signature was invalid]");
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
|
||||
@@ -590,24 +596,28 @@ OEMCryptoResult OEMCrypto_RefreshKeys(OEMCrypto_SESSION session,
|
||||
std::vector<uint8_t> key_control;
|
||||
std::vector<uint8_t> key_control_iv;
|
||||
for (unsigned int i = 0; i < num_keys; i++) {
|
||||
// TODO(gmorgan): key_id may be null if special control key type (TBS)
|
||||
if (key_array[i].key_id != NULL) {
|
||||
key_id.assign(key_array[i].key_id,
|
||||
key_array[i].key_id + key_array[i].key_id_length);
|
||||
} else {
|
||||
key_id.clear();
|
||||
}
|
||||
if (key_array[i].key_control != NULL) {
|
||||
key_control.assign(key_array[i].key_control,
|
||||
key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE);
|
||||
key_control_iv.assign(key_array[i].key_control_iv,
|
||||
key_array[i].key_control_iv + wvcdm::KEY_IV_SIZE);
|
||||
if (key_array[i].key_control_iv == NULL ) {
|
||||
key_control_iv.clear();
|
||||
} else {
|
||||
key_control_iv.assign(key_array[i].key_control_iv,
|
||||
key_array[i].key_control_iv + wvcdm::KEY_IV_SIZE);
|
||||
}
|
||||
} else {
|
||||
key_control.clear();
|
||||
// key_id could be null if special control key type
|
||||
// key_control is not encrypted in this case
|
||||
key_id.clear();
|
||||
key_control_iv.clear();
|
||||
key_control.assign(key_array[i].key_control,
|
||||
key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE);
|
||||
}
|
||||
|
||||
if (!session_ctx->RefreshKey(key_id, key_control, key_control_iv)) {
|
||||
LOGE("[OEMCrypto_RefreshKeys(): error in key %i]", i);
|
||||
status = false;
|
||||
break;
|
||||
}
|
||||
@@ -638,8 +648,8 @@ OEMCryptoResult OEMCrypto_SelectKey(const OEMCrypto_SESSION session,
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
|
||||
const std::vector<uint8_t> key_id_str = std::vector<uint8_t>(key_id, key_id + key_id_length);
|
||||
if (!session_ctx->SelectContentKey(key_id_str)) {
|
||||
const std::vector<uint8_t> key_id_vec = std::vector<uint8_t>(key_id, key_id + key_id_length);
|
||||
if (!session_ctx->SelectContentKey(key_id_vec)) {
|
||||
LOGE("[OEMCrypto_SelectKey(): FAIL]");
|
||||
return OEMCrypto_ERROR_NO_CONTENT_KEY;
|
||||
}
|
||||
@@ -653,14 +663,16 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
|
||||
size_t data_length,
|
||||
bool is_encrypted,
|
||||
const uint8_t* iv,
|
||||
size_t offset,
|
||||
const OEMCrypto_DestBufferDesc* out_buffer) {
|
||||
size_t block_offset,
|
||||
const OEMCrypto_DestBufferDesc* out_buffer,
|
||||
uint8_t subsample_flags) {
|
||||
if (level1.library) {
|
||||
return level1.OEMCrypto_DecryptCTR( session, data_addr, data_length,
|
||||
is_encrypted, iv, offset, out_buffer);
|
||||
is_encrypted, iv, block_offset,
|
||||
out_buffer, subsample_flags);
|
||||
}
|
||||
wvoec_mock::BufferType buffer_type = kBufferTypeDirect;
|
||||
void* destination = NULL;
|
||||
uint8_t* destination = NULL;
|
||||
size_t max_length = 0;
|
||||
switch (out_buffer->type) {
|
||||
case OEMCrypto_BufferType_Clear:
|
||||
@@ -670,7 +682,8 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
|
||||
break;
|
||||
case OEMCrypto_BufferType_Secure:
|
||||
buffer_type = kBufferTypeSecure;
|
||||
destination = out_buffer->buffer.secure.handle;
|
||||
destination = ((uint8_t*)out_buffer->buffer.secure.handle
|
||||
+ out_buffer->buffer.secure.offset);
|
||||
max_length = out_buffer->buffer.secure.max_length;
|
||||
break;
|
||||
default:
|
||||
@@ -685,10 +698,12 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
||||
LOGE("[OEMCrypto_DecryptCTR(): ERROR_KEYBOX_INVALID]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
#endif
|
||||
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (!session_ctx || !session_ctx->isValid()) {
|
||||
@@ -702,11 +717,11 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
if (!crypto_engine->DecryptCTR(session_ctx, iv, (int)offset,
|
||||
if (!crypto_engine->DecryptCTR(session_ctx, iv, (int)block_offset,
|
||||
data_addr, data_length, is_encrypted,
|
||||
destination, buffer_type)) {
|
||||
LOGE("[OEMCrypto_DecryptCTR(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
LOGE("[OEMCrypto_DecryptCTR(): OEMCrypto_ERROR_DECRYPT_FAILED]");
|
||||
return OEMCrypto_ERROR_DECRYPT_FAILED;
|
||||
}
|
||||
|
||||
return OEMCrypto_SUCCESS;
|
||||
@@ -744,20 +759,20 @@ OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID,
|
||||
if (level1.library) {
|
||||
return level1.OEMCrypto_GetDeviceID(deviceID, idLength);
|
||||
}
|
||||
std::vector<uint8_t> dev_id_string = crypto_engine->keybox().device_id();
|
||||
if (dev_id_string.empty()) {
|
||||
std::vector<uint8_t> dev_id_vec = crypto_engine->keybox().device_id();
|
||||
if (dev_id_vec.empty()) {
|
||||
LOGE("[OEMCrypto_GetDeviceId(): Keybox Invalid]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
|
||||
size_t dev_id_len = dev_id_string.size();
|
||||
size_t dev_id_len = dev_id_vec.size();
|
||||
if (*idLength < dev_id_len) {
|
||||
*idLength = dev_id_len;
|
||||
LOGE("[OEMCrypto_GetDeviceId(): ERROR_SHORT_BUFFER]");
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
memset(deviceID, 0, *idLength);
|
||||
memcpy(deviceID, &dev_id_string[0], dev_id_len);
|
||||
memcpy(deviceID, &dev_id_vec[0], dev_id_len);
|
||||
*idLength = dev_id_len;
|
||||
LOGD("[OEMCrypto_GetDeviceId(): success]");
|
||||
return OEMCrypto_SUCCESS;
|
||||
@@ -889,46 +904,73 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session,
|
||||
}
|
||||
session_ctx->FlushNonces();
|
||||
|
||||
// Decrypt key and verify signature.
|
||||
if (!session_ctx->LoadRSAKey(enc_rsa_key, enc_rsa_key_length,
|
||||
enc_rsa_key_iv, message, message_length,
|
||||
signature, signature_length)) {
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
// Decrypt RSA key.
|
||||
uint8_t* pkcs8_rsa_key = new uint8_t[enc_rsa_key_length];
|
||||
OEMCryptoResult result = OEMCrypto_SUCCESS;
|
||||
if (!session_ctx->DecryptRSAKey(enc_rsa_key, enc_rsa_key_length,
|
||||
enc_rsa_key_iv, pkcs8_rsa_key)) {
|
||||
result = OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1];
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (padding > 16) {
|
||||
LOGE("[RewrapRSAKey(): Encrypted RSA has bad padding: %d]", padding);
|
||||
result = OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
}
|
||||
size_t rsa_key_length = enc_rsa_key_length - padding;
|
||||
// verify signature, verify RSA key, and load it.
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (!session_ctx->LoadRSAKey(pkcs8_rsa_key, rsa_key_length,
|
||||
message, message_length,
|
||||
signature, signature_length)) {
|
||||
result = OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
// return OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we generate a wrapped keybox.
|
||||
WrappedRSAKey* wrapped = reinterpret_cast<WrappedRSAKey*>(wrapped_rsa_key);
|
||||
// Pick a random context and IV for generating keys.
|
||||
if (!RAND_bytes(wrapped->context, sizeof(wrapped->context))) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (!RAND_bytes(wrapped->context, sizeof(wrapped->context))) {
|
||||
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (!RAND_bytes(wrapped->iv, sizeof(wrapped->iv))) {
|
||||
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
}
|
||||
if (!RAND_bytes(wrapped->iv, sizeof(wrapped->iv))) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
const std::vector<uint8_t> mac_ctx_str(wrapped->context,
|
||||
wrapped->context + sizeof(wrapped->context));
|
||||
const std::vector<uint8_t> context(wrapped->context,
|
||||
wrapped->context + sizeof(wrapped->context));
|
||||
// Generate mac and encryption keys for encrypting the signature.
|
||||
if (!session_ctx->DeriveKeys(mac_ctx_str, mac_ctx_str)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key().value(),
|
||||
context, context)) {
|
||||
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Encrypt rsa key with keybox.
|
||||
if (!session_ctx->EncryptRSAKey(wrapped->enc_rsa_key,
|
||||
enc_rsa_key_length,
|
||||
wrapped->iv)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (!session_ctx->EncryptRSAKey(pkcs8_rsa_key, enc_rsa_key_length,
|
||||
wrapped->iv, wrapped->enc_rsa_key)) {
|
||||
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
}
|
||||
delete[] pkcs8_rsa_key;
|
||||
|
||||
size_t sig_length = sizeof(wrapped->signature);
|
||||
if (!session_ctx->GenerateSignature(wrapped->context, // start signing here.
|
||||
buffer_size - sizeof(wrapped->signature),
|
||||
wrapped->signature,
|
||||
&sig_length)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
// The wrapped keybox must be signed with the same key we verify with. I'll
|
||||
// pick the server key, so I don't have to modify LoadRSAKey.
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
size_t sig_length = sizeof(wrapped->signature);
|
||||
if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0],
|
||||
SHA256_DIGEST_LENGTH, wrapped->context,
|
||||
buffer_size - sizeof(wrapped->signature), wrapped->signature,
|
||||
&sig_length)) {
|
||||
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return OEMCrypto_SUCCESS;
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
@@ -942,40 +984,60 @@ OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session,
|
||||
return level1.OEMCrypto_LoadDeviceRSAKey( session, wrapped_rsa_key,
|
||||
wrapped_rsa_key_length);
|
||||
}
|
||||
const WrappedRSAKey* wrapped
|
||||
= reinterpret_cast<const WrappedRSAKey*>(wrapped_rsa_key);
|
||||
if (wrapped_rsa_key == NULL) {
|
||||
LOGE("[OEMCrypto_LoadDeviceRSAKey(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
const WrappedRSAKey* wrapped
|
||||
= reinterpret_cast<const WrappedRSAKey*>(wrapped_rsa_key);
|
||||
|
||||
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
||||
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): ERROR_KEYBOX_INVALID]");
|
||||
LOGE("[OEMCrypto_LoadDeviceRSAKey(): ERROR_KEYBOX_INVALID]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (!session_ctx || !session_ctx->isValid()) {
|
||||
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): ERROR_NO_INVALID_SESSION]");
|
||||
LOGE("[OEMCrypto_LoadDeviceRSAKey(): ERROR_NO_INVALID_SESSION]");
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
const std::vector<uint8_t> mac_ctx_str(wrapped->context,
|
||||
wrapped->context + sizeof(wrapped->context));
|
||||
const std::vector<uint8_t> context(wrapped->context,
|
||||
wrapped->context + sizeof(wrapped->context));
|
||||
// Generate mac and encryption keys for encrypting the signature.
|
||||
if (!session_ctx->DeriveKeys(mac_ctx_str, mac_ctx_str)) {
|
||||
if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key().value(),
|
||||
context, context)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
// Decrypt key and verify signature.
|
||||
if (!session_ctx->LoadRSAKey(wrapped->enc_rsa_key,
|
||||
wrapped_rsa_key_length - sizeof(WrappedRSAKey),
|
||||
wrapped->iv,
|
||||
wrapped->context,
|
||||
wrapped_rsa_key_length - sizeof(wrapped->signature),
|
||||
wrapped->signature,
|
||||
sizeof(wrapped->signature))) {
|
||||
return OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
// Decrypt RSA key.
|
||||
uint8_t* pkcs8_rsa_key = new uint8_t[wrapped_rsa_key_length
|
||||
- sizeof(wrapped->signature)];
|
||||
size_t enc_rsa_key_length = wrapped_rsa_key_length - sizeof(WrappedRSAKey);
|
||||
OEMCryptoResult result = OEMCrypto_SUCCESS;
|
||||
if (!session_ctx->DecryptRSAKey(wrapped->enc_rsa_key, enc_rsa_key_length,
|
||||
wrapped->iv, pkcs8_rsa_key)) {
|
||||
result = OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1];
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (padding > 16) {
|
||||
LOGE("[LoadDeviceRSAKey(): Encrypted RSA has bad padding: %d]", padding);
|
||||
result = OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
}
|
||||
size_t rsa_key_length = enc_rsa_key_length - padding;
|
||||
// verify signature.
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (!session_ctx->LoadRSAKey(pkcs8_rsa_key, rsa_key_length,
|
||||
wrapped->context,
|
||||
wrapped_rsa_key_length - sizeof(wrapped->signature),
|
||||
wrapped->signature,
|
||||
sizeof(wrapped->signature))) {
|
||||
result = OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
// return OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
}
|
||||
delete[] pkcs8_rsa_key;
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
@@ -1058,15 +1120,15 @@ OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(OEMCrypto_SESSION session,
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
|
||||
const std::vector<uint8_t> ssn_key_str(enc_session_key,
|
||||
const std::vector<uint8_t> ssn_key_vec(enc_session_key,
|
||||
enc_session_key + enc_session_key_length);
|
||||
const std::vector<uint8_t> mac_ctx_str(mac_key_context,
|
||||
const std::vector<uint8_t> mac_ctx_vec(mac_key_context,
|
||||
mac_key_context + mac_key_context_length);
|
||||
const std::vector<uint8_t> enc_ctx_str(enc_key_context,
|
||||
const std::vector<uint8_t> enc_ctx_vec(enc_key_context,
|
||||
enc_key_context + enc_key_context_length);
|
||||
|
||||
// Generate mac and encryption keys for current session context
|
||||
if (!session_ctx->RSADeriveKeys(ssn_key_str, mac_ctx_str, enc_ctx_str)) {
|
||||
if (!session_ctx->RSADeriveKeys(ssn_key_vec, mac_ctx_vec, enc_ctx_vec)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* mock implementation of OEMCrypto APIs
|
||||
* Wrapper for Level 1 OEMCrypto or Level 3 Fallback APIs
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
#include "log.h"
|
||||
#include "oemcrypto_engine_mock.h"
|
||||
#include "openssl/cmac.h"
|
||||
#include "openssl/evp.h"
|
||||
#include "openssl/hmac.h"
|
||||
#include "openssl/rand.h"
|
||||
#include "openssl/sha.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
@@ -65,7 +68,8 @@ typedef OEMCryptoResult (*L1_DecryptCTR_t)(OEMCrypto_SESSION session,
|
||||
bool is_encrypted,
|
||||
const uint8_t *iv,
|
||||
size_t offset,
|
||||
const OEMCrypto_DestBufferDesc* out_buffer);
|
||||
const OEMCrypto_DestBufferDesc* out_buffer,
|
||||
uint8_t subsample_flags);
|
||||
typedef OEMCryptoResult (*L1_InstallKeybox_t)(const uint8_t *keybox,
|
||||
size_t keyBoxLength);
|
||||
typedef OEMCryptoResult (*L1_IsKeyboxValid_t)(void);
|
||||
@@ -363,7 +367,8 @@ OEMCryptoResult OEMCrypto_GenerateDerivedKeys(OEMCrypto_SESSION session,
|
||||
enc_key_context + enc_key_context_length);
|
||||
|
||||
// Generate mac and encryption keys for current session context
|
||||
if (!session_ctx->DeriveKeys(mac_ctx_str, enc_ctx_str)) {
|
||||
if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key().value(),
|
||||
mac_ctx_str, enc_ctx_str)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
@@ -428,12 +433,12 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length,
|
||||
const uint8_t* enc_mac_key_iv,
|
||||
const uint8_t* enc_mac_key,
|
||||
const uint8_t* enc_mac_keys,
|
||||
size_t num_keys,
|
||||
const OEMCrypto_KeyObject* key_array) {
|
||||
if (level1.library) {
|
||||
return level1.OEMCrypto_LoadKeys(session, message, message_length, signature,
|
||||
signature_length, enc_mac_key_iv, enc_mac_key,
|
||||
signature_length, enc_mac_key_iv, enc_mac_keys,
|
||||
num_keys, key_array);
|
||||
}
|
||||
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
||||
@@ -455,8 +460,8 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
}
|
||||
|
||||
// Range check
|
||||
if (!RangeCheck(message, message_length, enc_mac_key,
|
||||
wvcdm::MAC_KEY_SIZE, true) ||
|
||||
if (!RangeCheck(message, message_length, enc_mac_keys,
|
||||
2*wvcdm::MAC_KEY_SIZE, true) ||
|
||||
!RangeCheck(message, message_length, enc_mac_key_iv,
|
||||
wvcdm::KEY_IV_SIZE, true)) {
|
||||
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_SIGNATURE_FAILURE - range check.]");
|
||||
@@ -471,9 +476,9 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
!RangeCheck(message, message_length, key_array[i].key_data_iv,
|
||||
wvcdm::KEY_IV_SIZE, false) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_control,
|
||||
wvcdm::KEY_CONTROL_SIZE, true) ||
|
||||
wvcdm::KEY_CONTROL_SIZE, false) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_control_iv,
|
||||
wvcdm::KEY_IV_SIZE, true)) {
|
||||
wvcdm::KEY_IV_SIZE, false)) {
|
||||
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_SIGNATURE_FAILURE -range check %d]", i);
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
@@ -521,18 +526,17 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
if (!status) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
|
||||
// enc_mac_key can be NULL if license renewal is not supported
|
||||
if (enc_mac_key == NULL) return OEMCrypto_SUCCESS;
|
||||
if (enc_mac_keys == NULL) return OEMCrypto_SUCCESS;
|
||||
|
||||
// V2 license protocol: update mac key after processing license response
|
||||
const std::vector<uint8_t> enc_mac_key_str = std::vector<uint8_t>(
|
||||
enc_mac_key, enc_mac_key + wvcdm::MAC_KEY_SIZE);
|
||||
// V2.1 license protocol: update mac keys after processing license response
|
||||
const std::vector<uint8_t> enc_mac_keys_str = std::vector<uint8_t>(
|
||||
enc_mac_keys, enc_mac_keys + 2*wvcdm::MAC_KEY_SIZE);
|
||||
const std::vector<uint8_t> enc_mac_key_iv_str = std::vector<uint8_t>(
|
||||
enc_mac_key_iv, enc_mac_key_iv + wvcdm::KEY_IV_SIZE);
|
||||
|
||||
if (!session_ctx->UpdateMacKey(enc_mac_key_str, enc_mac_key_iv_str)) {
|
||||
if (!session_ctx->UpdateMacKeys(enc_mac_keys_str, enc_mac_key_iv_str)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -560,7 +564,8 @@ OEMCryptoResult OEMCrypto_RefreshKeys(OEMCrypto_SESSION session,
|
||||
}
|
||||
|
||||
if (message == NULL || message_length == 0 ||
|
||||
signature == NULL || signature_length == 0) {
|
||||
signature == NULL || signature_length == 0 ||
|
||||
num_keys == 0) {
|
||||
LOGE("[OEMCrypto_RefreshKeys(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
@@ -570,10 +575,10 @@ OEMCryptoResult OEMCrypto_RefreshKeys(OEMCrypto_SESSION session,
|
||||
if (!RangeCheck(message, message_length, key_array[i].key_id,
|
||||
key_array[i].key_id_length, true) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_control,
|
||||
wvcdm::KEY_CONTROL_SIZE, true) ||
|
||||
wvcdm::KEY_CONTROL_SIZE, false) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_control_iv,
|
||||
wvcdm::KEY_IV_SIZE, true)) {
|
||||
LOGE("[OEMCrypto_RefreshKeys(): OEMCrypto_ERROR_SIGNATURE_FAILURE]");
|
||||
LOGE("[OEMCrypto_RefreshKeys(): Range Check %d]", i);
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
}
|
||||
@@ -581,6 +586,7 @@ OEMCryptoResult OEMCrypto_RefreshKeys(OEMCrypto_SESSION session,
|
||||
// Validate message signature
|
||||
if (!session_ctx->ValidateMessage(message, message_length,
|
||||
signature, signature_length)) {
|
||||
LOGE("[OEMCrypto_RefreshKeys(): signature was invalid]");
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
|
||||
@@ -590,24 +596,28 @@ OEMCryptoResult OEMCrypto_RefreshKeys(OEMCrypto_SESSION session,
|
||||
std::vector<uint8_t> key_control;
|
||||
std::vector<uint8_t> key_control_iv;
|
||||
for (unsigned int i = 0; i < num_keys; i++) {
|
||||
// TODO(gmorgan): key_id may be null if special control key type (TBS)
|
||||
if (key_array[i].key_id != NULL) {
|
||||
key_id.assign(key_array[i].key_id,
|
||||
key_array[i].key_id + key_array[i].key_id_length);
|
||||
} else {
|
||||
key_id.clear();
|
||||
}
|
||||
if (key_array[i].key_control != NULL) {
|
||||
key_control.assign(key_array[i].key_control,
|
||||
key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE);
|
||||
key_control_iv.assign(key_array[i].key_control_iv,
|
||||
key_array[i].key_control_iv + wvcdm::KEY_IV_SIZE);
|
||||
if (key_array[i].key_control_iv == NULL ) {
|
||||
key_control_iv.clear();
|
||||
} else {
|
||||
key_control_iv.assign(key_array[i].key_control_iv,
|
||||
key_array[i].key_control_iv + wvcdm::KEY_IV_SIZE);
|
||||
}
|
||||
} else {
|
||||
key_control.clear();
|
||||
// key_id could be null if special control key type
|
||||
// key_control is not encrypted in this case
|
||||
key_id.clear();
|
||||
key_control_iv.clear();
|
||||
key_control.assign(key_array[i].key_control,
|
||||
key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE);
|
||||
}
|
||||
|
||||
if (!session_ctx->RefreshKey(key_id, key_control, key_control_iv)) {
|
||||
LOGE("[OEMCrypto_RefreshKeys(): error in key %i]", i);
|
||||
status = false;
|
||||
break;
|
||||
}
|
||||
@@ -638,8 +648,8 @@ OEMCryptoResult OEMCrypto_SelectKey(const OEMCrypto_SESSION session,
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
|
||||
const std::vector<uint8_t> key_id_str = std::vector<uint8_t>(key_id, key_id + key_id_length);
|
||||
if (!session_ctx->SelectContentKey(key_id_str)) {
|
||||
const std::vector<uint8_t> key_id_vec = std::vector<uint8_t>(key_id, key_id + key_id_length);
|
||||
if (!session_ctx->SelectContentKey(key_id_vec)) {
|
||||
LOGE("[OEMCrypto_SelectKey(): FAIL]");
|
||||
return OEMCrypto_ERROR_NO_CONTENT_KEY;
|
||||
}
|
||||
@@ -653,14 +663,16 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
|
||||
size_t data_length,
|
||||
bool is_encrypted,
|
||||
const uint8_t* iv,
|
||||
size_t offset,
|
||||
const OEMCrypto_DestBufferDesc* out_buffer) {
|
||||
size_t block_offset,
|
||||
const OEMCrypto_DestBufferDesc* out_buffer,
|
||||
uint8_t subsample_flags) {
|
||||
if (level1.library) {
|
||||
return level1.OEMCrypto_DecryptCTR( session, data_addr, data_length,
|
||||
is_encrypted, iv, offset, out_buffer);
|
||||
is_encrypted, iv, block_offset,
|
||||
out_buffer, subsample_flags);
|
||||
}
|
||||
wvoec_mock::BufferType buffer_type = kBufferTypeDirect;
|
||||
void* destination = NULL;
|
||||
uint8_t* destination = NULL;
|
||||
size_t max_length = 0;
|
||||
switch (out_buffer->type) {
|
||||
case OEMCrypto_BufferType_Clear:
|
||||
@@ -670,7 +682,8 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
|
||||
break;
|
||||
case OEMCrypto_BufferType_Secure:
|
||||
buffer_type = kBufferTypeSecure;
|
||||
destination = out_buffer->buffer.secure.handle;
|
||||
destination = ((uint8_t*)out_buffer->buffer.secure.handle
|
||||
+ out_buffer->buffer.secure.offset);
|
||||
max_length = out_buffer->buffer.secure.max_length;
|
||||
break;
|
||||
default:
|
||||
@@ -685,10 +698,12 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
||||
LOGE("[OEMCrypto_DecryptCTR(): ERROR_KEYBOX_INVALID]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
#endif
|
||||
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (!session_ctx || !session_ctx->isValid()) {
|
||||
@@ -702,11 +717,11 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
if (!crypto_engine->DecryptCTR(session_ctx, iv, (int)offset,
|
||||
if (!crypto_engine->DecryptCTR(session_ctx, iv, (int)block_offset,
|
||||
data_addr, data_length, is_encrypted,
|
||||
destination, buffer_type)) {
|
||||
LOGE("[OEMCrypto_DecryptCTR(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
LOGE("[OEMCrypto_DecryptCTR(): OEMCrypto_ERROR_DECRYPT_FAILED]");
|
||||
return OEMCrypto_ERROR_DECRYPT_FAILED;
|
||||
}
|
||||
|
||||
return OEMCrypto_SUCCESS;
|
||||
@@ -744,20 +759,20 @@ OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID,
|
||||
if (level1.library) {
|
||||
return level1.OEMCrypto_GetDeviceID(deviceID, idLength);
|
||||
}
|
||||
std::vector<uint8_t> dev_id_string = crypto_engine->keybox().device_id();
|
||||
if (dev_id_string.empty()) {
|
||||
std::vector<uint8_t> dev_id_vec = crypto_engine->keybox().device_id();
|
||||
if (dev_id_vec.empty()) {
|
||||
LOGE("[OEMCrypto_GetDeviceId(): Keybox Invalid]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
|
||||
size_t dev_id_len = dev_id_string.size();
|
||||
size_t dev_id_len = dev_id_vec.size();
|
||||
if (*idLength < dev_id_len) {
|
||||
*idLength = dev_id_len;
|
||||
LOGE("[OEMCrypto_GetDeviceId(): ERROR_SHORT_BUFFER]");
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
memset(deviceID, 0, *idLength);
|
||||
memcpy(deviceID, &dev_id_string[0], dev_id_len);
|
||||
memcpy(deviceID, &dev_id_vec[0], dev_id_len);
|
||||
*idLength = dev_id_len;
|
||||
LOGD("[OEMCrypto_GetDeviceId(): success]");
|
||||
return OEMCrypto_SUCCESS;
|
||||
@@ -889,46 +904,73 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session,
|
||||
}
|
||||
session_ctx->FlushNonces();
|
||||
|
||||
// Decrypt key and verify signature.
|
||||
if (!session_ctx->LoadRSAKey(enc_rsa_key, enc_rsa_key_length,
|
||||
enc_rsa_key_iv, message, message_length,
|
||||
signature, signature_length)) {
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
// Decrypt RSA key.
|
||||
uint8_t* pkcs8_rsa_key = new uint8_t[enc_rsa_key_length];
|
||||
OEMCryptoResult result = OEMCrypto_SUCCESS;
|
||||
if (!session_ctx->DecryptRSAKey(enc_rsa_key, enc_rsa_key_length,
|
||||
enc_rsa_key_iv, pkcs8_rsa_key)) {
|
||||
result = OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1];
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (padding > 16) {
|
||||
LOGE("[RewrapRSAKey(): Encrypted RSA has bad padding: %d]", padding);
|
||||
result = OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
}
|
||||
size_t rsa_key_length = enc_rsa_key_length - padding;
|
||||
// verify signature, verify RSA key, and load it.
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (!session_ctx->LoadRSAKey(pkcs8_rsa_key, rsa_key_length,
|
||||
message, message_length,
|
||||
signature, signature_length)) {
|
||||
result = OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
// return OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we generate a wrapped keybox.
|
||||
WrappedRSAKey* wrapped = reinterpret_cast<WrappedRSAKey*>(wrapped_rsa_key);
|
||||
// Pick a random context and IV for generating keys.
|
||||
if (!RAND_bytes(wrapped->context, sizeof(wrapped->context))) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (!RAND_bytes(wrapped->context, sizeof(wrapped->context))) {
|
||||
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (!RAND_bytes(wrapped->iv, sizeof(wrapped->iv))) {
|
||||
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
}
|
||||
if (!RAND_bytes(wrapped->iv, sizeof(wrapped->iv))) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
const std::vector<uint8_t> mac_ctx_str(wrapped->context,
|
||||
wrapped->context + sizeof(wrapped->context));
|
||||
const std::vector<uint8_t> context(wrapped->context,
|
||||
wrapped->context + sizeof(wrapped->context));
|
||||
// Generate mac and encryption keys for encrypting the signature.
|
||||
if (!session_ctx->DeriveKeys(mac_ctx_str, mac_ctx_str)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key().value(),
|
||||
context, context)) {
|
||||
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Encrypt rsa key with keybox.
|
||||
if (!session_ctx->EncryptRSAKey(wrapped->enc_rsa_key,
|
||||
enc_rsa_key_length,
|
||||
wrapped->iv)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (!session_ctx->EncryptRSAKey(pkcs8_rsa_key, enc_rsa_key_length,
|
||||
wrapped->iv, wrapped->enc_rsa_key)) {
|
||||
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
}
|
||||
delete[] pkcs8_rsa_key;
|
||||
|
||||
size_t sig_length = sizeof(wrapped->signature);
|
||||
if (!session_ctx->GenerateSignature(wrapped->context, // start signing here.
|
||||
buffer_size - sizeof(wrapped->signature),
|
||||
wrapped->signature,
|
||||
&sig_length)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
// The wrapped keybox must be signed with the same key we verify with. I'll
|
||||
// pick the server key, so I don't have to modify LoadRSAKey.
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
size_t sig_length = sizeof(wrapped->signature);
|
||||
if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0],
|
||||
SHA256_DIGEST_LENGTH, wrapped->context,
|
||||
buffer_size - sizeof(wrapped->signature), wrapped->signature,
|
||||
&sig_length)) {
|
||||
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return OEMCrypto_SUCCESS;
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
@@ -942,40 +984,60 @@ OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session,
|
||||
return level1.OEMCrypto_LoadDeviceRSAKey( session, wrapped_rsa_key,
|
||||
wrapped_rsa_key_length);
|
||||
}
|
||||
const WrappedRSAKey* wrapped
|
||||
= reinterpret_cast<const WrappedRSAKey*>(wrapped_rsa_key);
|
||||
if (wrapped_rsa_key == NULL) {
|
||||
LOGE("[OEMCrypto_LoadDeviceRSAKey(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
const WrappedRSAKey* wrapped
|
||||
= reinterpret_cast<const WrappedRSAKey*>(wrapped_rsa_key);
|
||||
|
||||
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
||||
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): ERROR_KEYBOX_INVALID]");
|
||||
LOGE("[OEMCrypto_LoadDeviceRSAKey(): ERROR_KEYBOX_INVALID]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (!session_ctx || !session_ctx->isValid()) {
|
||||
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): ERROR_NO_INVALID_SESSION]");
|
||||
LOGE("[OEMCrypto_LoadDeviceRSAKey(): ERROR_NO_INVALID_SESSION]");
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
const std::vector<uint8_t> mac_ctx_str(wrapped->context,
|
||||
wrapped->context + sizeof(wrapped->context));
|
||||
const std::vector<uint8_t> context(wrapped->context,
|
||||
wrapped->context + sizeof(wrapped->context));
|
||||
// Generate mac and encryption keys for encrypting the signature.
|
||||
if (!session_ctx->DeriveKeys(mac_ctx_str, mac_ctx_str)) {
|
||||
if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key().value(),
|
||||
context, context)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
// Decrypt key and verify signature.
|
||||
if (!session_ctx->LoadRSAKey(wrapped->enc_rsa_key,
|
||||
wrapped_rsa_key_length - sizeof(WrappedRSAKey),
|
||||
wrapped->iv,
|
||||
wrapped->context,
|
||||
wrapped_rsa_key_length - sizeof(wrapped->signature),
|
||||
wrapped->signature,
|
||||
sizeof(wrapped->signature))) {
|
||||
return OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
// Decrypt RSA key.
|
||||
uint8_t* pkcs8_rsa_key = new uint8_t[wrapped_rsa_key_length
|
||||
- sizeof(wrapped->signature)];
|
||||
size_t enc_rsa_key_length = wrapped_rsa_key_length - sizeof(WrappedRSAKey);
|
||||
OEMCryptoResult result = OEMCrypto_SUCCESS;
|
||||
if (!session_ctx->DecryptRSAKey(wrapped->enc_rsa_key, enc_rsa_key_length,
|
||||
wrapped->iv, pkcs8_rsa_key)) {
|
||||
result = OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1];
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (padding > 16) {
|
||||
LOGE("[LoadDeviceRSAKey(): Encrypted RSA has bad padding: %d]", padding);
|
||||
result = OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
}
|
||||
size_t rsa_key_length = enc_rsa_key_length - padding;
|
||||
// verify signature.
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (!session_ctx->LoadRSAKey(pkcs8_rsa_key, rsa_key_length,
|
||||
wrapped->context,
|
||||
wrapped_rsa_key_length - sizeof(wrapped->signature),
|
||||
wrapped->signature,
|
||||
sizeof(wrapped->signature))) {
|
||||
result = OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
// return OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
}
|
||||
delete[] pkcs8_rsa_key;
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
@@ -1058,15 +1120,15 @@ OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(OEMCrypto_SESSION session,
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
|
||||
const std::vector<uint8_t> ssn_key_str(enc_session_key,
|
||||
const std::vector<uint8_t> ssn_key_vec(enc_session_key,
|
||||
enc_session_key + enc_session_key_length);
|
||||
const std::vector<uint8_t> mac_ctx_str(mac_key_context,
|
||||
const std::vector<uint8_t> mac_ctx_vec(mac_key_context,
|
||||
mac_key_context + mac_key_context_length);
|
||||
const std::vector<uint8_t> enc_ctx_str(enc_key_context,
|
||||
const std::vector<uint8_t> enc_ctx_vec(enc_key_context,
|
||||
enc_key_context + enc_key_context_length);
|
||||
|
||||
// Generate mac and encryption keys for current session context
|
||||
if (!session_ctx->RSADeriveKeys(ssn_key_str, mac_ctx_str, enc_ctx_str)) {
|
||||
if (!session_ctx->RSADeriveKeys(ssn_key_vec, mac_ctx_vec, enc_ctx_vec)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* mock implementation of OEMCrypto APIs
|
||||
* Wrapper for Level 1 OEMCrypto or Level 3 Fallback APIs
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
#include "log.h"
|
||||
#include "oemcrypto_engine_mock.h"
|
||||
#include "openssl/cmac.h"
|
||||
#include "openssl/evp.h"
|
||||
#include "openssl/hmac.h"
|
||||
#include "openssl/rand.h"
|
||||
#include "openssl/sha.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
@@ -65,7 +68,8 @@ typedef OEMCryptoResult (*L1_DecryptCTR_t)(OEMCrypto_SESSION session,
|
||||
bool is_encrypted,
|
||||
const uint8_t *iv,
|
||||
size_t offset,
|
||||
const OEMCrypto_DestBufferDesc* out_buffer);
|
||||
const OEMCrypto_DestBufferDesc* out_buffer,
|
||||
uint8_t subsample_flags);
|
||||
typedef OEMCryptoResult (*L1_InstallKeybox_t)(const uint8_t *keybox,
|
||||
size_t keyBoxLength);
|
||||
typedef OEMCryptoResult (*L1_IsKeyboxValid_t)(void);
|
||||
@@ -363,7 +367,8 @@ OEMCryptoResult OEMCrypto_GenerateDerivedKeys(OEMCrypto_SESSION session,
|
||||
enc_key_context + enc_key_context_length);
|
||||
|
||||
// Generate mac and encryption keys for current session context
|
||||
if (!session_ctx->DeriveKeys(mac_ctx_str, enc_ctx_str)) {
|
||||
if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key().value(),
|
||||
mac_ctx_str, enc_ctx_str)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
@@ -428,12 +433,12 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length,
|
||||
const uint8_t* enc_mac_key_iv,
|
||||
const uint8_t* enc_mac_key,
|
||||
const uint8_t* enc_mac_keys,
|
||||
size_t num_keys,
|
||||
const OEMCrypto_KeyObject* key_array) {
|
||||
if (level1.library) {
|
||||
return level1.OEMCrypto_LoadKeys(session, message, message_length, signature,
|
||||
signature_length, enc_mac_key_iv, enc_mac_key,
|
||||
signature_length, enc_mac_key_iv, enc_mac_keys,
|
||||
num_keys, key_array);
|
||||
}
|
||||
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
||||
@@ -455,8 +460,8 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
}
|
||||
|
||||
// Range check
|
||||
if (!RangeCheck(message, message_length, enc_mac_key,
|
||||
wvcdm::MAC_KEY_SIZE, true) ||
|
||||
if (!RangeCheck(message, message_length, enc_mac_keys,
|
||||
2*wvcdm::MAC_KEY_SIZE, true) ||
|
||||
!RangeCheck(message, message_length, enc_mac_key_iv,
|
||||
wvcdm::KEY_IV_SIZE, true)) {
|
||||
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_SIGNATURE_FAILURE - range check.]");
|
||||
@@ -471,9 +476,9 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
!RangeCheck(message, message_length, key_array[i].key_data_iv,
|
||||
wvcdm::KEY_IV_SIZE, false) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_control,
|
||||
wvcdm::KEY_CONTROL_SIZE, true) ||
|
||||
wvcdm::KEY_CONTROL_SIZE, false) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_control_iv,
|
||||
wvcdm::KEY_IV_SIZE, true)) {
|
||||
wvcdm::KEY_IV_SIZE, false)) {
|
||||
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_SIGNATURE_FAILURE -range check %d]", i);
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
@@ -521,18 +526,17 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
if (!status) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
|
||||
// enc_mac_key can be NULL if license renewal is not supported
|
||||
if (enc_mac_key == NULL) return OEMCrypto_SUCCESS;
|
||||
if (enc_mac_keys == NULL) return OEMCrypto_SUCCESS;
|
||||
|
||||
// V2 license protocol: update mac key after processing license response
|
||||
const std::vector<uint8_t> enc_mac_key_str = std::vector<uint8_t>(
|
||||
enc_mac_key, enc_mac_key + wvcdm::MAC_KEY_SIZE);
|
||||
// V2.1 license protocol: update mac keys after processing license response
|
||||
const std::vector<uint8_t> enc_mac_keys_str = std::vector<uint8_t>(
|
||||
enc_mac_keys, enc_mac_keys + 2*wvcdm::MAC_KEY_SIZE);
|
||||
const std::vector<uint8_t> enc_mac_key_iv_str = std::vector<uint8_t>(
|
||||
enc_mac_key_iv, enc_mac_key_iv + wvcdm::KEY_IV_SIZE);
|
||||
|
||||
if (!session_ctx->UpdateMacKey(enc_mac_key_str, enc_mac_key_iv_str)) {
|
||||
if (!session_ctx->UpdateMacKeys(enc_mac_keys_str, enc_mac_key_iv_str)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -560,7 +564,8 @@ OEMCryptoResult OEMCrypto_RefreshKeys(OEMCrypto_SESSION session,
|
||||
}
|
||||
|
||||
if (message == NULL || message_length == 0 ||
|
||||
signature == NULL || signature_length == 0) {
|
||||
signature == NULL || signature_length == 0 ||
|
||||
num_keys == 0) {
|
||||
LOGE("[OEMCrypto_RefreshKeys(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
@@ -570,10 +575,10 @@ OEMCryptoResult OEMCrypto_RefreshKeys(OEMCrypto_SESSION session,
|
||||
if (!RangeCheck(message, message_length, key_array[i].key_id,
|
||||
key_array[i].key_id_length, true) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_control,
|
||||
wvcdm::KEY_CONTROL_SIZE, true) ||
|
||||
wvcdm::KEY_CONTROL_SIZE, false) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_control_iv,
|
||||
wvcdm::KEY_IV_SIZE, true)) {
|
||||
LOGE("[OEMCrypto_RefreshKeys(): OEMCrypto_ERROR_SIGNATURE_FAILURE]");
|
||||
LOGE("[OEMCrypto_RefreshKeys(): Range Check %d]", i);
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
}
|
||||
@@ -581,6 +586,7 @@ OEMCryptoResult OEMCrypto_RefreshKeys(OEMCrypto_SESSION session,
|
||||
// Validate message signature
|
||||
if (!session_ctx->ValidateMessage(message, message_length,
|
||||
signature, signature_length)) {
|
||||
LOGE("[OEMCrypto_RefreshKeys(): signature was invalid]");
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
|
||||
@@ -590,24 +596,28 @@ OEMCryptoResult OEMCrypto_RefreshKeys(OEMCrypto_SESSION session,
|
||||
std::vector<uint8_t> key_control;
|
||||
std::vector<uint8_t> key_control_iv;
|
||||
for (unsigned int i = 0; i < num_keys; i++) {
|
||||
// TODO(gmorgan): key_id may be null if special control key type (TBS)
|
||||
if (key_array[i].key_id != NULL) {
|
||||
key_id.assign(key_array[i].key_id,
|
||||
key_array[i].key_id + key_array[i].key_id_length);
|
||||
} else {
|
||||
key_id.clear();
|
||||
}
|
||||
if (key_array[i].key_control != NULL) {
|
||||
key_control.assign(key_array[i].key_control,
|
||||
key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE);
|
||||
key_control_iv.assign(key_array[i].key_control_iv,
|
||||
key_array[i].key_control_iv + wvcdm::KEY_IV_SIZE);
|
||||
if (key_array[i].key_control_iv == NULL ) {
|
||||
key_control_iv.clear();
|
||||
} else {
|
||||
key_control_iv.assign(key_array[i].key_control_iv,
|
||||
key_array[i].key_control_iv + wvcdm::KEY_IV_SIZE);
|
||||
}
|
||||
} else {
|
||||
key_control.clear();
|
||||
// key_id could be null if special control key type
|
||||
// key_control is not encrypted in this case
|
||||
key_id.clear();
|
||||
key_control_iv.clear();
|
||||
key_control.assign(key_array[i].key_control,
|
||||
key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE);
|
||||
}
|
||||
|
||||
if (!session_ctx->RefreshKey(key_id, key_control, key_control_iv)) {
|
||||
LOGE("[OEMCrypto_RefreshKeys(): error in key %i]", i);
|
||||
status = false;
|
||||
break;
|
||||
}
|
||||
@@ -638,8 +648,8 @@ OEMCryptoResult OEMCrypto_SelectKey(const OEMCrypto_SESSION session,
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
|
||||
const std::vector<uint8_t> key_id_str = std::vector<uint8_t>(key_id, key_id + key_id_length);
|
||||
if (!session_ctx->SelectContentKey(key_id_str)) {
|
||||
const std::vector<uint8_t> key_id_vec = std::vector<uint8_t>(key_id, key_id + key_id_length);
|
||||
if (!session_ctx->SelectContentKey(key_id_vec)) {
|
||||
LOGE("[OEMCrypto_SelectKey(): FAIL]");
|
||||
return OEMCrypto_ERROR_NO_CONTENT_KEY;
|
||||
}
|
||||
@@ -653,14 +663,16 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
|
||||
size_t data_length,
|
||||
bool is_encrypted,
|
||||
const uint8_t* iv,
|
||||
size_t offset,
|
||||
const OEMCrypto_DestBufferDesc* out_buffer) {
|
||||
size_t block_offset,
|
||||
const OEMCrypto_DestBufferDesc* out_buffer,
|
||||
uint8_t subsample_flags) {
|
||||
if (level1.library) {
|
||||
return level1.OEMCrypto_DecryptCTR( session, data_addr, data_length,
|
||||
is_encrypted, iv, offset, out_buffer);
|
||||
is_encrypted, iv, block_offset,
|
||||
out_buffer, subsample_flags);
|
||||
}
|
||||
wvoec_mock::BufferType buffer_type = kBufferTypeDirect;
|
||||
void* destination = NULL;
|
||||
uint8_t* destination = NULL;
|
||||
size_t max_length = 0;
|
||||
switch (out_buffer->type) {
|
||||
case OEMCrypto_BufferType_Clear:
|
||||
@@ -670,7 +682,8 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
|
||||
break;
|
||||
case OEMCrypto_BufferType_Secure:
|
||||
buffer_type = kBufferTypeSecure;
|
||||
destination = out_buffer->buffer.secure.handle;
|
||||
destination = ((uint8_t*)out_buffer->buffer.secure.handle
|
||||
+ out_buffer->buffer.secure.offset);
|
||||
max_length = out_buffer->buffer.secure.max_length;
|
||||
break;
|
||||
default:
|
||||
@@ -685,10 +698,12 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
||||
LOGE("[OEMCrypto_DecryptCTR(): ERROR_KEYBOX_INVALID]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
#endif
|
||||
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (!session_ctx || !session_ctx->isValid()) {
|
||||
@@ -702,11 +717,11 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
if (!crypto_engine->DecryptCTR(session_ctx, iv, (int)offset,
|
||||
if (!crypto_engine->DecryptCTR(session_ctx, iv, (int)block_offset,
|
||||
data_addr, data_length, is_encrypted,
|
||||
destination, buffer_type)) {
|
||||
LOGE("[OEMCrypto_DecryptCTR(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
LOGE("[OEMCrypto_DecryptCTR(): OEMCrypto_ERROR_DECRYPT_FAILED]");
|
||||
return OEMCrypto_ERROR_DECRYPT_FAILED;
|
||||
}
|
||||
|
||||
return OEMCrypto_SUCCESS;
|
||||
@@ -744,20 +759,20 @@ OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID,
|
||||
if (level1.library) {
|
||||
return level1.OEMCrypto_GetDeviceID(deviceID, idLength);
|
||||
}
|
||||
std::vector<uint8_t> dev_id_string = crypto_engine->keybox().device_id();
|
||||
if (dev_id_string.empty()) {
|
||||
std::vector<uint8_t> dev_id_vec = crypto_engine->keybox().device_id();
|
||||
if (dev_id_vec.empty()) {
|
||||
LOGE("[OEMCrypto_GetDeviceId(): Keybox Invalid]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
|
||||
size_t dev_id_len = dev_id_string.size();
|
||||
size_t dev_id_len = dev_id_vec.size();
|
||||
if (*idLength < dev_id_len) {
|
||||
*idLength = dev_id_len;
|
||||
LOGE("[OEMCrypto_GetDeviceId(): ERROR_SHORT_BUFFER]");
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
memset(deviceID, 0, *idLength);
|
||||
memcpy(deviceID, &dev_id_string[0], dev_id_len);
|
||||
memcpy(deviceID, &dev_id_vec[0], dev_id_len);
|
||||
*idLength = dev_id_len;
|
||||
LOGD("[OEMCrypto_GetDeviceId(): success]");
|
||||
return OEMCrypto_SUCCESS;
|
||||
@@ -889,46 +904,73 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session,
|
||||
}
|
||||
session_ctx->FlushNonces();
|
||||
|
||||
// Decrypt key and verify signature.
|
||||
if (!session_ctx->LoadRSAKey(enc_rsa_key, enc_rsa_key_length,
|
||||
enc_rsa_key_iv, message, message_length,
|
||||
signature, signature_length)) {
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
// Decrypt RSA key.
|
||||
uint8_t* pkcs8_rsa_key = new uint8_t[enc_rsa_key_length];
|
||||
OEMCryptoResult result = OEMCrypto_SUCCESS;
|
||||
if (!session_ctx->DecryptRSAKey(enc_rsa_key, enc_rsa_key_length,
|
||||
enc_rsa_key_iv, pkcs8_rsa_key)) {
|
||||
result = OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1];
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (padding > 16) {
|
||||
LOGE("[RewrapRSAKey(): Encrypted RSA has bad padding: %d]", padding);
|
||||
result = OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
}
|
||||
size_t rsa_key_length = enc_rsa_key_length - padding;
|
||||
// verify signature, verify RSA key, and load it.
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (!session_ctx->LoadRSAKey(pkcs8_rsa_key, rsa_key_length,
|
||||
message, message_length,
|
||||
signature, signature_length)) {
|
||||
result = OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
// return OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we generate a wrapped keybox.
|
||||
WrappedRSAKey* wrapped = reinterpret_cast<WrappedRSAKey*>(wrapped_rsa_key);
|
||||
// Pick a random context and IV for generating keys.
|
||||
if (!RAND_bytes(wrapped->context, sizeof(wrapped->context))) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (!RAND_bytes(wrapped->context, sizeof(wrapped->context))) {
|
||||
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (!RAND_bytes(wrapped->iv, sizeof(wrapped->iv))) {
|
||||
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
}
|
||||
if (!RAND_bytes(wrapped->iv, sizeof(wrapped->iv))) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
const std::vector<uint8_t> mac_ctx_str(wrapped->context,
|
||||
wrapped->context + sizeof(wrapped->context));
|
||||
const std::vector<uint8_t> context(wrapped->context,
|
||||
wrapped->context + sizeof(wrapped->context));
|
||||
// Generate mac and encryption keys for encrypting the signature.
|
||||
if (!session_ctx->DeriveKeys(mac_ctx_str, mac_ctx_str)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key().value(),
|
||||
context, context)) {
|
||||
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Encrypt rsa key with keybox.
|
||||
if (!session_ctx->EncryptRSAKey(wrapped->enc_rsa_key,
|
||||
enc_rsa_key_length,
|
||||
wrapped->iv)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (!session_ctx->EncryptRSAKey(pkcs8_rsa_key, enc_rsa_key_length,
|
||||
wrapped->iv, wrapped->enc_rsa_key)) {
|
||||
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
}
|
||||
delete[] pkcs8_rsa_key;
|
||||
|
||||
size_t sig_length = sizeof(wrapped->signature);
|
||||
if (!session_ctx->GenerateSignature(wrapped->context, // start signing here.
|
||||
buffer_size - sizeof(wrapped->signature),
|
||||
wrapped->signature,
|
||||
&sig_length)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
// The wrapped keybox must be signed with the same key we verify with. I'll
|
||||
// pick the server key, so I don't have to modify LoadRSAKey.
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
size_t sig_length = sizeof(wrapped->signature);
|
||||
if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0],
|
||||
SHA256_DIGEST_LENGTH, wrapped->context,
|
||||
buffer_size - sizeof(wrapped->signature), wrapped->signature,
|
||||
&sig_length)) {
|
||||
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return OEMCrypto_SUCCESS;
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
@@ -942,40 +984,60 @@ OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session,
|
||||
return level1.OEMCrypto_LoadDeviceRSAKey( session, wrapped_rsa_key,
|
||||
wrapped_rsa_key_length);
|
||||
}
|
||||
const WrappedRSAKey* wrapped
|
||||
= reinterpret_cast<const WrappedRSAKey*>(wrapped_rsa_key);
|
||||
if (wrapped_rsa_key == NULL) {
|
||||
LOGE("[OEMCrypto_LoadDeviceRSAKey(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
const WrappedRSAKey* wrapped
|
||||
= reinterpret_cast<const WrappedRSAKey*>(wrapped_rsa_key);
|
||||
|
||||
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
||||
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): ERROR_KEYBOX_INVALID]");
|
||||
LOGE("[OEMCrypto_LoadDeviceRSAKey(): ERROR_KEYBOX_INVALID]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (!session_ctx || !session_ctx->isValid()) {
|
||||
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): ERROR_NO_INVALID_SESSION]");
|
||||
LOGE("[OEMCrypto_LoadDeviceRSAKey(): ERROR_NO_INVALID_SESSION]");
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
const std::vector<uint8_t> mac_ctx_str(wrapped->context,
|
||||
wrapped->context + sizeof(wrapped->context));
|
||||
const std::vector<uint8_t> context(wrapped->context,
|
||||
wrapped->context + sizeof(wrapped->context));
|
||||
// Generate mac and encryption keys for encrypting the signature.
|
||||
if (!session_ctx->DeriveKeys(mac_ctx_str, mac_ctx_str)) {
|
||||
if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key().value(),
|
||||
context, context)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
// Decrypt key and verify signature.
|
||||
if (!session_ctx->LoadRSAKey(wrapped->enc_rsa_key,
|
||||
wrapped_rsa_key_length - sizeof(WrappedRSAKey),
|
||||
wrapped->iv,
|
||||
wrapped->context,
|
||||
wrapped_rsa_key_length - sizeof(wrapped->signature),
|
||||
wrapped->signature,
|
||||
sizeof(wrapped->signature))) {
|
||||
return OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
// Decrypt RSA key.
|
||||
uint8_t* pkcs8_rsa_key = new uint8_t[wrapped_rsa_key_length
|
||||
- sizeof(wrapped->signature)];
|
||||
size_t enc_rsa_key_length = wrapped_rsa_key_length - sizeof(WrappedRSAKey);
|
||||
OEMCryptoResult result = OEMCrypto_SUCCESS;
|
||||
if (!session_ctx->DecryptRSAKey(wrapped->enc_rsa_key, enc_rsa_key_length,
|
||||
wrapped->iv, pkcs8_rsa_key)) {
|
||||
result = OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1];
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (padding > 16) {
|
||||
LOGE("[LoadDeviceRSAKey(): Encrypted RSA has bad padding: %d]", padding);
|
||||
result = OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
}
|
||||
size_t rsa_key_length = enc_rsa_key_length - padding;
|
||||
// verify signature.
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (!session_ctx->LoadRSAKey(pkcs8_rsa_key, rsa_key_length,
|
||||
wrapped->context,
|
||||
wrapped_rsa_key_length - sizeof(wrapped->signature),
|
||||
wrapped->signature,
|
||||
sizeof(wrapped->signature))) {
|
||||
result = OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
// return OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
}
|
||||
delete[] pkcs8_rsa_key;
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
@@ -1058,15 +1120,15 @@ OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(OEMCrypto_SESSION session,
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
|
||||
const std::vector<uint8_t> ssn_key_str(enc_session_key,
|
||||
const std::vector<uint8_t> ssn_key_vec(enc_session_key,
|
||||
enc_session_key + enc_session_key_length);
|
||||
const std::vector<uint8_t> mac_ctx_str(mac_key_context,
|
||||
const std::vector<uint8_t> mac_ctx_vec(mac_key_context,
|
||||
mac_key_context + mac_key_context_length);
|
||||
const std::vector<uint8_t> enc_ctx_str(enc_key_context,
|
||||
const std::vector<uint8_t> enc_ctx_vec(enc_key_context,
|
||||
enc_key_context + enc_key_context_length);
|
||||
|
||||
// Generate mac and encryption keys for current session context
|
||||
if (!session_ctx->RSADeriveKeys(ssn_key_str, mac_ctx_str, enc_ctx_str)) {
|
||||
if (!session_ctx->RSADeriveKeys(ssn_key_vec, mac_ctx_vec, enc_ctx_vec)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
|
||||
@@ -130,4 +130,4 @@ TEST_F(WVCryptoPluginTest, AttemptsToDecrypt) {
|
||||
"WVCryptoPlugin decrypted the wrong number of bytes";
|
||||
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
}
|
||||
}
|
||||
@@ -16,9 +16,9 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define OEMCRYPTO_VERSION "7.0"
|
||||
#define OEMCRYPTO_VERSION "8.0"
|
||||
static const char oec_version[] = OEMCRYPTO_VERSION;
|
||||
static const uint32_t oec_latest_version = 7;
|
||||
static const uint32_t oec_latest_version = 8;
|
||||
|
||||
typedef uint32_t OEMCrypto_SESSION;
|
||||
|
||||
@@ -187,6 +187,12 @@ typedef enum OEMCrypto_Algorithm {
|
||||
OEMCrypto_HMAC_SHA256 = 1,
|
||||
} OEMCrypto_Algorithm;
|
||||
|
||||
/*
|
||||
* Flags indicating data endpoints in OEMCrypto_DecryptCTR.
|
||||
*/
|
||||
#define OEMCrypto_FirstSubsample 1
|
||||
#define OEMCrypto_LastSubsample 2
|
||||
|
||||
/* Obfuscation Renames. */
|
||||
#define OEMCrypto_Initialize _oecc01
|
||||
#define OEMCrypto_Terminate _oecc02
|
||||
@@ -214,7 +220,7 @@ typedef enum OEMCrypto_Algorithm {
|
||||
#define OEMCrypto_Generic_Encrypt _oecc24
|
||||
#define OEMCrypto_Generic_Decrypt _oecc25
|
||||
#define OEMCrypto_Generic_Sign _oecc26
|
||||
#define OEMCrypto_Generic_Virify _oecc27
|
||||
#define OEMCrypto_Generic_Verify _oecc27
|
||||
|
||||
/*
|
||||
* OEMCrypto_Initialize
|
||||
@@ -313,16 +319,17 @@ OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session);
|
||||
* OEMCrypto_GenerateDerivedKeys
|
||||
*
|
||||
* Description:
|
||||
* Generates a pair of secondary keys, mac_key and encrypt_key, for handling
|
||||
* signing and content key decryption under the license server protocol
|
||||
* for AES CTR mode.
|
||||
* Generates three secondary keys -- mac_key_server, mac_key_client, and
|
||||
* encrypt_key -- for handling signing and content key decryption under the
|
||||
* license server protocol for AES CTR mode.
|
||||
*
|
||||
* Refer to document "OEMCrypto Changes for V2 License Protocol" for details.
|
||||
* This function computes the AES-128-CMAC of the enc_key_context and stores
|
||||
* it in secure memory as the encrypt_key.
|
||||
* It then computes two cycles of AES-128-CMAC of the mac_key_context and
|
||||
* stores it in the mac_key. These two keys will be stored until the next
|
||||
* call to LoadKeys.
|
||||
* Refer to document "Widevine Modular DRM Security Integration Guide for
|
||||
* CENC" for details. This function computes the AES-128-CMAC of the
|
||||
* enc_key_context and stores it in secure memory as the encrypt_key. It
|
||||
* then computes four cycles of AES-128-CMAC of the mac_key_context and
|
||||
* stores it in the mac_keys. The first two cycles are used for
|
||||
* mac_key_server and the second two cycles are used for mac_key_client.
|
||||
* These three keys will be stored until the next call to LoadKeys.
|
||||
*
|
||||
* Parameters:
|
||||
* session (in) - crypto session identifier.
|
||||
@@ -334,7 +341,8 @@ OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session);
|
||||
* enc_key_context_length (in) - length of the encryption key context data.
|
||||
*
|
||||
* Results:
|
||||
* mac_key: the 256 bit mac key is generated and stored in secure memory.
|
||||
* mac_key_server: the 256 bit mac key is generated and stored in secure memory.
|
||||
* mac_key_client: the 256 bit mac key is generated and stored in secure memory.
|
||||
* enc_key: the 128 bit encryption key is generated and stored in secure memory.
|
||||
*
|
||||
* Threading:
|
||||
@@ -349,7 +357,7 @@ OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session);
|
||||
* OEMCrypto_ERROR_INVALID_CONTEXT
|
||||
*
|
||||
* Version:
|
||||
* This method changed in API version 5.
|
||||
* This method changed in API version 8.
|
||||
*/
|
||||
OEMCryptoResult OEMCrypto_GenerateDerivedKeys(
|
||||
OEMCrypto_SESSION session,
|
||||
@@ -366,8 +374,8 @@ OEMCryptoResult OEMCrypto_GenerateDerivedKeys(
|
||||
* control block. The nonce is stored in secure memory and will be used
|
||||
* for the next call to LoadKeys.
|
||||
*
|
||||
* Refer to documents "OEMCrypto Changes for V2 License Protocol" and "Key
|
||||
* Control Block Definition" for details.
|
||||
* Refer to documents "Widevine Modular DRM Security Integration Guide for
|
||||
* CENC".
|
||||
*
|
||||
* Parameters:
|
||||
* session (in) - crypto session identifier.
|
||||
@@ -399,12 +407,13 @@ OEMCryptoResult OEMCrypto_GenerateNonce(
|
||||
*
|
||||
* Description:
|
||||
* Generates a HMAC-SHA256 signature for license request signing under the
|
||||
* license server protocol for AES CTR mode.
|
||||
* license server protocol for AES CTR mode. This uses the key mac_key_client.
|
||||
*
|
||||
* NOTE: OEMCrypto_GenerateDerivedKeys() must be called first to establish the
|
||||
* mac_key
|
||||
* NOTE: OEMCrypto_GenerateDerivedKeys() must be called first to establish the
|
||||
* mac_key_client.
|
||||
*
|
||||
* Refer to document "OEMCrypto Changes for V2 License Protocol" for details.
|
||||
* Refer to document "Widevine Modular DRM Security Integration Guide for
|
||||
* CENC" for details.
|
||||
*
|
||||
* Parameters:
|
||||
* session (in) - crypto session identifier.
|
||||
@@ -444,10 +453,10 @@ OEMCryptoResult OEMCrypto_GenerateSignature(
|
||||
*
|
||||
* The relevant fields have been extracted from the License Response protocol
|
||||
* message, but the entire message and associated signature are provided so
|
||||
* the message can be verified (using HMAC-SHA256 with the derived mac_key).
|
||||
* If the signature verification fails, ignore all other arguments and return
|
||||
* OEMCrypto_ERROR_SIGNATURE_FAILURE. Otherwise, add the keys to the session
|
||||
* context.
|
||||
* the message can be verified (using HMAC-SHA256 with the derived
|
||||
* mac_key_server). If the signature verification fails, ignore all other
|
||||
* arguments and return OEMCrypto_ERROR_SIGNATURE_FAILURE. Otherwise, add the
|
||||
* keys to the session context.
|
||||
*
|
||||
* The keys will be decrypted using the current encrypt_key (AES-128-CBC) and
|
||||
* the IV given in the KeyObject. Each key control block will be decrypted
|
||||
@@ -461,20 +470,21 @@ OEMCryptoResult OEMCrypto_GenerateSignature(
|
||||
* block is different from the current nonce, return
|
||||
* OEMCrypto_ERROR_INVALID_NONCE. In that case, do not install any keys.
|
||||
*
|
||||
* The new mac_key is decrypted with the current encrypt_key and the offered
|
||||
* IV. It replaces the current mac_key.
|
||||
* The new mac_keys are decrypted with the current encrypt_key and the offered
|
||||
* IV. They replace the current mac_keys.
|
||||
*
|
||||
* The mac_key and encrypt_key were generated and stored by the previous call
|
||||
* The mac_keys and encrypt_key were generated and stored by the previous call
|
||||
* to OEMCrypto_GenerateDerivedKeys(). The nonce was generated and stored by
|
||||
* the previous call to OEMCrypto_GenerateNonce().
|
||||
*
|
||||
* This session’s elapsed time clock is started at 0. The clock will be used
|
||||
* in OEMCrypto_DecryptCTR.
|
||||
*
|
||||
* NOTE: OEMCrypto_GenerateDerivedKeys() must be called first to establish the
|
||||
* mac_key and encrypt_key.
|
||||
* NOTE: OEMCrypto_GenerateDerivedKeys() must be called first to establish
|
||||
* the mac_keys and encrypt_key.
|
||||
*
|
||||
* Refer to document "OEMCrypto Changes for V2 License Protocol" for details.
|
||||
* Refer to document "Widevine Modular DRM Security Integration Guide for
|
||||
* CENC" for details.
|
||||
*
|
||||
* Parameters:
|
||||
* session (in) - crypto session identifier.
|
||||
@@ -482,9 +492,9 @@ OEMCryptoResult OEMCrypto_GenerateSignature(
|
||||
* message_length (in) - length of the message.
|
||||
* signature (in) - pointer to memory containing the signature.
|
||||
* signature_length (in) - length of the signature.
|
||||
* enc_mac_key_iv (in) - IV for decrypting new mac_key. Size is 128 bits.
|
||||
* enc_mac_key (in) - encrypted mac_key for generating new mac_key. Size is
|
||||
* 256 bits.
|
||||
* enc_mac_keys_iv (in) - IV for decrypting new mac_key. Size is 128 bits.
|
||||
* enc_mac_keys (in) - encrypted mac_keys for generating new mac_keys. Size is
|
||||
* 512 bits.
|
||||
* num_keys (in) - number of keys present.
|
||||
* key_array (in) - set of keys to be installed.
|
||||
*
|
||||
@@ -503,15 +513,15 @@ OEMCryptoResult OEMCrypto_GenerateSignature(
|
||||
* OEMCrypto_ERROR_TOO_MANY_KEYS
|
||||
*
|
||||
* Version:
|
||||
* This method changed in API version 5.
|
||||
* This method changed in API version 8.
|
||||
*/
|
||||
OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
const uint8_t* message,
|
||||
size_t message_length,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length,
|
||||
const uint8_t* enc_mac_key_iv,
|
||||
const uint8_t* enc_mac_key,
|
||||
const uint8_t* enc_mac_keys_iv,
|
||||
const uint8_t* enc_mac_keys,
|
||||
size_t num_keys,
|
||||
const OEMCrypto_KeyObject* key_array);
|
||||
|
||||
@@ -524,15 +534,16 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
*
|
||||
* The relevant fields have been extracted from the Renewal Response protocol
|
||||
* message, but the entire message and associated signature are provided so
|
||||
* the message can be verified (using HMAC-SHA256 with the current mac_key).
|
||||
* If the signature verification fails, ignore all other arguments and return
|
||||
* OEMCrypto_ERROR_SIGNATURE_FAILURE. Otherwise, add the keys to the session
|
||||
* context.
|
||||
* the message can be verified (using HMAC-SHA256 with the current
|
||||
* mac_key_server). If the signature verification fails, ignore all other
|
||||
* arguments and return OEMCrypto_ERROR_SIGNATURE_FAILURE. Otherwise, add
|
||||
* the keys to the session context.
|
||||
*
|
||||
* NOTE: OEMCrypto_GenerateDerivedKeys() or OEMCrypto_LoadKeys() must be called
|
||||
* first to establish the mac_key
|
||||
* NOTE: OEMCrypto_GenerateDerivedKeys() or OEMCrypto_LoadKeys() must be
|
||||
* called first to establish the mac_keys.
|
||||
*
|
||||
* Refer to document OEMCrypto Changes for V2 License Protocol for details.
|
||||
* Refer to document "Widevine Modular DRM Security Integration Guide for
|
||||
* CENC" for details.
|
||||
*
|
||||
* Parameters:
|
||||
* session (in) - crypto session identifier.
|
||||
@@ -557,7 +568,7 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
* OEMCrypto_ERROR_SIGNATURE_FAILURE
|
||||
*
|
||||
* Version:
|
||||
* This method changed in API version 5.
|
||||
* This method changed in API version 8.
|
||||
*/
|
||||
OEMCryptoResult
|
||||
OEMCrypto_RefreshKeys(OEMCrypto_SESSION session,
|
||||
@@ -614,7 +625,7 @@ OEMCrypto_RefreshKeys(OEMCrypto_SESSION session,
|
||||
* OEMCrypto_ERROR_KEYBOX_INVALID cannot decrypt and read from Keybox
|
||||
*
|
||||
* Version:
|
||||
* This method changed in API version 5.
|
||||
* This method changed in API version 8.
|
||||
*/
|
||||
OEMCryptoResult OEMCrypto_SelectKey(const OEMCrypto_SESSION session,
|
||||
const uint8_t* key_id,
|
||||
@@ -649,6 +660,10 @@ OEMCryptoResult OEMCrypto_SelectKey(const OEMCrypto_SESSION session,
|
||||
* out_buffer (in) - A caller-owned descriptor that specifies the
|
||||
* handling of the decrypted byte stream. See OEMCrypto_DestbufferDesc
|
||||
* for details.
|
||||
* subsample_flags (in) - bitwise flags indicating if this is the first,
|
||||
* middle, or last subsample in a chunk of data. 1 = first subsample,
|
||||
* 2 = last subsample, 3 = both first and last subsample, 0 = neither
|
||||
* first nor last subsample.
|
||||
*
|
||||
* AES CTR is a stream cipher. The stream may be composed of arbitrary-
|
||||
* length clear and encrypted segments. The encrypted portions of a sample
|
||||
@@ -678,6 +693,15 @@ OEMCryptoResult OEMCrypto_SelectKey(const OEMCrypto_SESSION session,
|
||||
* zero when it reaches its maximum value (0xFFFFFFFFFFFFFFFF).
|
||||
* The upper 64 bits (byte 0-7) of the IV do not change.
|
||||
*
|
||||
* This method may be called several times before the decrypted data is used.
|
||||
* For this reason, the parameter subsample_flags may be used to optimize
|
||||
* decryption. The first buffer in a chunk of data will have the
|
||||
* OEMCrypto_FirstSubsample bit set in subsample_flags. The last buffer in a
|
||||
* chunk of data will have the OEMCrypto_LastSubsample bit set in
|
||||
* subsample_flags. The decrypted data will not be used until after
|
||||
* OEMCrypto_LastSubsample has been set. If an implementation decrypts data
|
||||
* immediately, it may ignore subsample_flags.
|
||||
*
|
||||
* Threading:
|
||||
* This function may be called simultaneously with functions on other sessions,
|
||||
* but not with other functions on this session.
|
||||
@@ -699,7 +723,8 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
|
||||
bool is_encrypted,
|
||||
const uint8_t *iv,
|
||||
size_t block_offset,
|
||||
const OEMCrypto_DestBufferDesc* out_buffer);
|
||||
const OEMCrypto_DestBufferDesc* out_buffer,
|
||||
uint8_t subsample_flags);
|
||||
|
||||
/*
|
||||
* OEMCrypto_InstallKeybox
|
||||
@@ -886,7 +911,8 @@ OEMCryptoResult OEMCrypto_WrapKeybox(const uint8_t *keybox,
|
||||
* private key is decrypted and stored in secure memory. The RSA key is then
|
||||
* re-encrypted for storage on the filesystem. The OEM may either encrypt it
|
||||
* with the private key from the Widevine Keybox, or with an OEM specific
|
||||
* device key.
|
||||
* device key. The signature of the message is verified with the
|
||||
* mac_key_server.
|
||||
*
|
||||
* Parameters:
|
||||
* session (in) - crypto session identifier.
|
||||
@@ -894,13 +920,13 @@ OEMCryptoResult OEMCrypto_WrapKeybox(const uint8_t *keybox,
|
||||
* - verified.
|
||||
* message_length (in) - length of the message, in bytes.
|
||||
* signature (in) - pointer to memory containing the HMAC-SHA256
|
||||
* - signature for
|
||||
* - message, received from the provisioning server.
|
||||
* - signature for message, received from the
|
||||
* - provisioning server.
|
||||
* signature_length (in) - length of the signature, in bytes.
|
||||
* nonce (in) - The nonce provided in the provisioning response.
|
||||
* enc_rsa_key (in) - Encrypted device private RSA key received from
|
||||
* - the provisioning server. Format is PKCS#1, binary
|
||||
* - DER encoded, and encrypted with the derived
|
||||
* - the provisioning server. Format is PKCS#8
|
||||
* - PrivateKeyInfo, encrypted with the derived
|
||||
* - encryption key, using AES-128-CBC with PKCS#5
|
||||
* - padding.
|
||||
* enc_rsa_key_length (in) - length of the encrypted RSA key, in bytes.
|
||||
@@ -909,8 +935,6 @@ OEMCryptoResult OEMCrypto_WrapKeybox(const uint8_t *keybox,
|
||||
* - should be stored. May be null on the first call
|
||||
* - in order to find required buffer size.
|
||||
* wrapped_rsa_key_length (in/out) - length of the encrypted RSA key, in bytes.
|
||||
* wrapped_rsa_key_iv (out) - IV for encrypting/decrypting the RSA private key.
|
||||
* - Size is 128 bits.
|
||||
*
|
||||
* Returns:
|
||||
* OEMCrypto_SUCCESS success
|
||||
@@ -923,7 +947,7 @@ OEMCryptoResult OEMCrypto_WrapKeybox(const uint8_t *keybox,
|
||||
* OEMCrypto_ERROR_SHORT_BUFFER
|
||||
*
|
||||
* Version:
|
||||
* This method changed in API versions 6.
|
||||
* This method changed in API versions 8.
|
||||
*/
|
||||
|
||||
OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session,
|
||||
@@ -950,7 +974,7 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session,
|
||||
* Parameters:
|
||||
* session (in) - crypto session identifier.
|
||||
* wrapped_rsa_key (in) - wrapped device RSA key stored on the device.
|
||||
* - Format is PKCS#1, binary DER encoded, and
|
||||
* - Format is PKCS#8 PrivateKeyInfo, and
|
||||
* - encrypted with a key internal to the OEMCrypto
|
||||
* - instance, using AES-128-CBC with PKCS#5
|
||||
* - padding. This is the wrapped key generated
|
||||
@@ -1016,16 +1040,16 @@ OEMCryptoResult OEMCrypto_GenerateRSASignature(OEMCrypto_SESSION session,
|
||||
* OEMCrypto_DeriveKeysFromSessionKey
|
||||
*
|
||||
* Description:
|
||||
* Generates a pair of secondary keys, mac_key and encrypt_key, for handling
|
||||
* signing and content key decryption under the license server protocol for
|
||||
* AES CTR mode.
|
||||
* Generates three secondary keys -- mac_key_server, mac_key_client, and
|
||||
* encrypt_key -- for handling signing and content key decryption under the
|
||||
* license server protocol for AES CTR mode.
|
||||
*
|
||||
* This function is similar to OEMCrypto_GenerateDerivedKeys, except that it
|
||||
* uses a session key to generate the secondary keys instead of the Widevine
|
||||
* Keybox device key. These two keys will be stored in secure memory until
|
||||
* the next call to LoadKeys. The session key is passed in encrypted by the
|
||||
* device RSA public key, and must be decrypted with the RSA private key
|
||||
* before use. Once the enc_key and mac_key have been generated, all calls
|
||||
* before use. Once the enc_key and mac_keys have been generated, all calls
|
||||
* to LoadKeys and RefreshKeys proceed in the same manner for license
|
||||
* requests using RSA or using a Widevine keybox token.
|
||||
*
|
||||
@@ -1050,7 +1074,7 @@ OEMCryptoResult OEMCrypto_GenerateRSASignature(OEMCrypto_SESSION session,
|
||||
* OEMCrypto_ERROR_INVALID_CONTEXT
|
||||
*
|
||||
* Version:
|
||||
* This method changed in API version 6.
|
||||
* This method changed in API version 8.
|
||||
*/
|
||||
OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(OEMCrypto_SESSION session,
|
||||
const uint8_t* enc_session_key,
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "log.h"
|
||||
#include "oemcrypto_key_mock.h"
|
||||
#include "openssl/aes.h"
|
||||
#include "openssl/bio.h"
|
||||
#include "openssl/cmac.h"
|
||||
#include "openssl/err.h"
|
||||
#include "openssl/evp.h"
|
||||
@@ -22,6 +23,7 @@
|
||||
#include "openssl/rand.h"
|
||||
#include <openssl/rsa.h>
|
||||
#include "openssl/sha.h"
|
||||
#include "openssl/x509.h"
|
||||
#include "string_conversions.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
@@ -75,6 +77,15 @@ void SessionKeyTable::Remove(const KeyId key_id) {
|
||||
}
|
||||
}
|
||||
|
||||
bool SessionKeyTable::UpdateDuration(const KeyControlBlock& control) {
|
||||
for(KeyMap::iterator it = keys_.begin(); it != keys_.end(); ++it) {
|
||||
if (!it->second->UpdateDuration(control)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SessionContext::Open() {
|
||||
}
|
||||
|
||||
@@ -86,7 +97,7 @@ bool SessionContext::DeriveKey(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& context,
|
||||
int counter,
|
||||
std::vector<uint8_t>* out) {
|
||||
if (key.empty() || counter > 2 || context.empty() || out == NULL) {
|
||||
if (key.empty() || counter > 4 || context.empty() || out == NULL) {
|
||||
LOGE("[DeriveKey(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return false;
|
||||
}
|
||||
@@ -122,34 +133,45 @@ bool SessionContext::DeriveKey(const std::vector<uint8_t>& key,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SessionContext::DeriveKeys(const std::vector<uint8_t>& mac_key_context,
|
||||
bool SessionContext::DeriveKeys(const std::vector<uint8_t>& master_key,
|
||||
const std::vector<uint8_t>& mac_key_context,
|
||||
const std::vector<uint8_t>& enc_key_context) {
|
||||
// Generate derived key for mac key
|
||||
std::vector<uint8_t> device_key = ce_->keybox().device_key().value();
|
||||
std::vector<uint8_t> mac_key;
|
||||
std::vector<uint8_t> mac_key_server;
|
||||
std::vector<uint8_t> mac_key_client;
|
||||
std::vector<uint8_t> mac_key_part2;
|
||||
if (!DeriveKey(device_key, mac_key_context, 1, &mac_key)) {
|
||||
if (!DeriveKey(master_key, mac_key_context, 1, &mac_key_server)) {
|
||||
return false;
|
||||
}
|
||||
if (!DeriveKey(device_key, mac_key_context, 2, &mac_key_part2)) {
|
||||
if (!DeriveKey(master_key, mac_key_context, 2, &mac_key_part2)) {
|
||||
return false;
|
||||
}
|
||||
mac_key.insert(mac_key.end(), mac_key_part2.begin(), mac_key_part2.end());
|
||||
mac_key_server.insert(mac_key_server.end(), mac_key_part2.begin(), mac_key_part2.end());
|
||||
|
||||
if (!DeriveKey(master_key, mac_key_context, 3, &mac_key_client)) {
|
||||
return false;
|
||||
}
|
||||
if (!DeriveKey(master_key, mac_key_context, 4, &mac_key_part2)) {
|
||||
return false;
|
||||
}
|
||||
mac_key_client.insert(mac_key_client.end(), mac_key_part2.begin(), mac_key_part2.end());
|
||||
|
||||
// Generate derived key for encryption key
|
||||
std::vector<uint8_t> enc_key;
|
||||
if (!DeriveKey(device_key, enc_key_context, 1, &enc_key)) {
|
||||
if (!DeriveKey(master_key, enc_key_context, 1, &enc_key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if 0 // Print Derived Keys to stdout.
|
||||
std::cout << " mac_key_context = " << wvcdm::b2a_hex(mac_key_context) << std::endl;
|
||||
std::cout << " enc_key_context = " << wvcdm::b2a_hex(enc_key_context) << std::endl;
|
||||
std::cout << " mac_key = " << wvcdm::b2a_hex(mac_key) << std::endl;
|
||||
std::cout << " mac_key_server = " << wvcdm::b2a_hex(mac_key_server) << std::endl;
|
||||
std::cout << " mac_key_client = " << wvcdm::b2a_hex(mac_key_client) << std::endl;
|
||||
std::cout << " enc_key = " << wvcdm::b2a_hex(enc_key) << std::endl;
|
||||
#endif
|
||||
|
||||
set_mac_key(mac_key);
|
||||
set_mac_key_server(mac_key_server);
|
||||
set_mac_key_client(mac_key_client);
|
||||
set_encryption_key(enc_key);
|
||||
return true;
|
||||
}
|
||||
@@ -185,38 +207,7 @@ bool SessionContext::RSADeriveKeys(const std::vector<uint8_t>& enc_session_key,
|
||||
session_key_.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Generate derived key for mac key
|
||||
std::vector<uint8_t> mac_key;
|
||||
std::vector<uint8_t> mac_key_part2;
|
||||
if (!DeriveKey(session_key_, mac_key_context, 1, &mac_key)) {
|
||||
session_key_.clear();
|
||||
return false;
|
||||
}
|
||||
if (!DeriveKey(session_key_, mac_key_context, 2, &mac_key_part2)) {
|
||||
session_key_.clear();
|
||||
return false;
|
||||
}
|
||||
mac_key.insert(mac_key.end(), mac_key_part2.begin(), mac_key_part2.end());
|
||||
|
||||
// Generate derived key for encryption key
|
||||
std::vector<uint8_t> enc_key;
|
||||
if (!DeriveKey(session_key_, enc_key_context, 1, &enc_key)) {
|
||||
session_key_.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
#if 0 // Print Derived Keys to stdout.
|
||||
std::cout << " mac_key_context = " << wvcdm::b2a_hex(mac_key_context) << std::endl;
|
||||
std::cout << " enc_key_context = " << wvcdm::b2a_hex(enc_key_context) << std::endl;
|
||||
std::cout << " session_key = " << wvcdm::b2a_hex(session_key_) << std::endl;
|
||||
std::cout << " mac_key = " << wvcdm::b2a_hex(mac_key) << std::endl;
|
||||
std::cout << " enc_key = " << wvcdm::b2a_hex(enc_key) << std::endl;
|
||||
#endif
|
||||
|
||||
set_mac_key(mac_key);
|
||||
set_encryption_key(enc_key);
|
||||
return true;
|
||||
return DeriveKeys(session_key_, mac_key_context, enc_key_context);
|
||||
}
|
||||
|
||||
// Utility function to generate a message signature
|
||||
@@ -231,7 +222,7 @@ bool SessionContext::GenerateSignature(const uint8_t* message,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mac_key_.empty() || mac_key_.size() != wvcdm::MAC_KEY_SIZE) {
|
||||
if (mac_key_client_.empty() || mac_key_client_.size() != wvcdm::MAC_KEY_SIZE) {
|
||||
LOGE("[GenerateSignature(): No MAC Key]");
|
||||
return false;
|
||||
}
|
||||
@@ -242,7 +233,7 @@ bool SessionContext::GenerateSignature(const uint8_t* message,
|
||||
}
|
||||
|
||||
unsigned int md_len = *signature_length;
|
||||
if (HMAC(EVP_sha256(), &mac_key_[0], SHA256_DIGEST_LENGTH,
|
||||
if (HMAC(EVP_sha256(), &mac_key_client_[0], SHA256_DIGEST_LENGTH,
|
||||
message, message_length, signature, &md_len)) {
|
||||
*signature_length = md_len;
|
||||
return true;
|
||||
@@ -315,8 +306,10 @@ bool SessionContext::ValidateMessage(const uint8_t* given_message,
|
||||
return false;
|
||||
}
|
||||
uint8_t computed_signature[SHA256_DIGEST_LENGTH];
|
||||
if (! GenerateSignature(given_message, message_length,
|
||||
computed_signature, &signature_length)) {
|
||||
unsigned int md_len = SHA256_DIGEST_LENGTH;
|
||||
if (!HMAC(EVP_sha256(), &mac_key_server_[0], SHA256_DIGEST_LENGTH,
|
||||
given_message, message_length, computed_signature, &md_len)) {
|
||||
LOGE("ValidateMessage: Could not compute signature.");
|
||||
return false;
|
||||
}
|
||||
if (memcmp(given_signature, computed_signature, signature_length)) {
|
||||
@@ -336,6 +329,7 @@ bool SessionContext::ParseKeyControl(
|
||||
key_control_block.Invalidate();
|
||||
|
||||
if (key_control_string.size() < wvcdm::KEY_CONTROL_SIZE) {
|
||||
LOGD("ParseKeyControl: wrong size.");
|
||||
return false;
|
||||
}
|
||||
if (!key_control_block.SetFromString(key_control_string)) {
|
||||
@@ -357,6 +351,14 @@ bool SessionContext::ParseKeyControl(
|
||||
LOGD(" duration: %d", key_control_block.duration());
|
||||
LOGD(" nonce: %08X", key_control_block.nonce());
|
||||
LOGD(" bits: %08X", key_control_block.control_bits());
|
||||
LOGD(" bit kControlAllowEncrypt %s.",
|
||||
(key_control_block.control_bits() & kControlAllowEncrypt) ? "set" : "unset");
|
||||
LOGD(" bit kControlAllowDecrypt %s.",
|
||||
(key_control_block.control_bits() & kControlAllowDecrypt) ? "set" : "unset");
|
||||
LOGD(" bit kControlAllowSign %s.",
|
||||
(key_control_block.control_bits() & kControlAllowSign) ? "set" : "unset");
|
||||
LOGD(" bit kControlAllowVerify %s.",
|
||||
(key_control_block.control_bits() & kControlAllowVerify) ? "set" : "unset");
|
||||
LOGD(" bit kControlObserveDataPath %s.",
|
||||
(key_control_block.control_bits() & kControlObserveDataPath) ? "set" : "unset");
|
||||
LOGD(" bit kControlObserveHDCP %s.",
|
||||
@@ -428,6 +430,7 @@ bool SessionContext::InstallKey(const KeyId& key_id,
|
||||
}
|
||||
|
||||
if (!ParseKeyControl(key_control_str, key_control_block)) {
|
||||
LOGE("Error parsing key control.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -437,38 +440,36 @@ bool SessionContext::InstallKey(const KeyId& key_id,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SessionContext::EncryptRSAKey(uint8_t* wrapped_rsa_key,
|
||||
size_t wrapped_rsa_key_length,
|
||||
uint8_t* wrapped_rsa_key_iv) {
|
||||
std::vector<uint8_t> buffer(wrapped_rsa_key_length);
|
||||
uint8_t* p = &buffer[0];
|
||||
int len = i2d_RSAPrivateKey(rsa_key_, &p);
|
||||
if (len < 0) {
|
||||
LOGE("[EncryptRSAKey(): Could not decode rsa key]");
|
||||
dump_openssl_error();
|
||||
return false;
|
||||
}
|
||||
if (static_cast<size_t>(len) >= wrapped_rsa_key_length) {
|
||||
LOGE("[EncryptRSAKey(): padding is wrong size: len=%d, size=%zu",
|
||||
len, wrapped_rsa_key_length);
|
||||
return false;
|
||||
}
|
||||
size_t padding = wrapped_rsa_key_length - len;
|
||||
memset(&buffer[len], static_cast<uint8_t>(padding), padding);
|
||||
bool SessionContext::DecryptRSAKey(const uint8_t* enc_rsa_key,
|
||||
size_t enc_rsa_key_length,
|
||||
const uint8_t* enc_rsa_key_iv,
|
||||
uint8_t* pkcs8_rsa_key) {
|
||||
// Decrypt rsa key with keybox.
|
||||
uint8_t iv_buffer[ wvcdm::KEY_IV_SIZE];
|
||||
memcpy(iv_buffer, enc_rsa_key_iv, wvcdm::KEY_IV_SIZE);
|
||||
AES_KEY aes_key;
|
||||
AES_set_decrypt_key(&encryption_key_[0], 128, &aes_key);
|
||||
AES_cbc_encrypt(enc_rsa_key, pkcs8_rsa_key, enc_rsa_key_length,
|
||||
&aes_key, iv_buffer, AES_DECRYPT);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SessionContext::EncryptRSAKey(const uint8_t* pkcs8_rsa_key,
|
||||
size_t enc_rsa_key_length,
|
||||
const uint8_t* enc_rsa_key_iv,
|
||||
uint8_t* enc_rsa_key) {
|
||||
// Encrypt rsa key with keybox.
|
||||
uint8_t iv_buffer[ wvcdm::KEY_IV_SIZE];
|
||||
memcpy(iv_buffer, wrapped_rsa_key_iv, wvcdm::KEY_IV_SIZE);
|
||||
memcpy(iv_buffer, enc_rsa_key_iv, wvcdm::KEY_IV_SIZE);
|
||||
AES_KEY aes_key;
|
||||
AES_set_encrypt_key(&encryption_key_[0], 128, &aes_key);
|
||||
AES_cbc_encrypt(&buffer[0], wrapped_rsa_key, wrapped_rsa_key_length,
|
||||
AES_cbc_encrypt(pkcs8_rsa_key, enc_rsa_key, enc_rsa_key_length,
|
||||
&aes_key, iv_buffer, AES_ENCRYPT);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SessionContext::LoadRSAKey(const uint8_t* enc_rsa_key,
|
||||
size_t enc_rsa_key_length,
|
||||
const uint8_t* enc_rsa_key_iv,
|
||||
bool SessionContext::LoadRSAKey(uint8_t* pkcs8_rsa_key,
|
||||
size_t rsa_key_length,
|
||||
const uint8_t* message,
|
||||
size_t message_length,
|
||||
const uint8_t* signature,
|
||||
@@ -479,32 +480,44 @@ bool SessionContext::LoadRSAKey(const uint8_t* enc_rsa_key,
|
||||
LOGE("[LoadRSAKey(): Could not verify signature]");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t iv[wvcdm::KEY_IV_SIZE];
|
||||
uint8_t* clear = new uint8_t[enc_rsa_key_length];
|
||||
memcpy(iv, enc_rsa_key_iv, 16);
|
||||
AES_KEY aes_key;
|
||||
AES_set_decrypt_key(&encryption_key_[0], 128, &aes_key);
|
||||
AES_cbc_encrypt(enc_rsa_key, clear, enc_rsa_key_length, &aes_key,
|
||||
iv, AES_DECRYPT);
|
||||
size_t padding = clear[enc_rsa_key_length - 1];
|
||||
if (padding > 16) {
|
||||
LOGE("[LoadRSAKey(): Encrypted RSA has bad padding]");
|
||||
return false;
|
||||
}
|
||||
size_t rsa_key_length = enc_rsa_key_length - padding;
|
||||
|
||||
if (rsa_key_) {
|
||||
RSA_free(rsa_key_);
|
||||
rsa_key_ = NULL;
|
||||
}
|
||||
uint8_t const* p = clear;
|
||||
rsa_key_ = d2i_RSAPrivateKey(0, &p, rsa_key_length);
|
||||
delete[] clear;
|
||||
|
||||
if (! rsa_key_) {
|
||||
LOGE("[LoadRSAKey(): Could decode unencrypted rsa key]");
|
||||
dump_openssl_error();
|
||||
BIO *bio = BIO_new_mem_buf(pkcs8_rsa_key, rsa_key_length);
|
||||
if( bio == NULL ) {
|
||||
LOGE("[LoadRSAKey(): Could not allocate bio buffer]");
|
||||
return false;
|
||||
}
|
||||
bool success = true;
|
||||
PKCS8_PRIV_KEY_INFO *pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL);
|
||||
if (pkcs8_pki == NULL) {
|
||||
LOGE("d2i_PKCS8_PRIV_KEY_INFO_bio returned NULL.");
|
||||
success = false;
|
||||
}
|
||||
EVP_PKEY *evp = NULL;
|
||||
if (success) {
|
||||
evp = EVP_PKCS82PKEY(pkcs8_pki);
|
||||
if (evp == NULL) {
|
||||
LOGE("EVP_PKCS82PKEY returned NULL.");
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
rsa_key_ = EVP_PKEY_get1_RSA(evp);
|
||||
if (rsa_key_ == NULL) {
|
||||
LOGE("PrivateKeyInfo did not contain an RSA key.");
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
if (evp != NULL) {
|
||||
EVP_PKEY_free(evp);
|
||||
}
|
||||
if (pkcs8_pki != NULL) {
|
||||
PKCS8_PRIV_KEY_INFO_free(pkcs8_pki);
|
||||
}
|
||||
BIO_free(bio);
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
switch (RSA_check_key(rsa_key_)) {
|
||||
@@ -535,7 +548,7 @@ bool SessionContext::Generic_Encrypt(const uint8_t* in_buffer,
|
||||
const KeyControlBlock& control = current_content_key()->control();
|
||||
// Set the AES key.
|
||||
if (static_cast<int>(key.size()) != AES_BLOCK_SIZE) {
|
||||
LOGE("[Generic_Encrypt(): CONTENT_KEY has wrong size.");
|
||||
LOGE("[Generic_Encrypt(): CONTENT_KEY has wrong size: %d",key.size());
|
||||
return false;
|
||||
}
|
||||
if (!(control.control_bits() & kControlAllowEncrypt)) {
|
||||
@@ -590,6 +603,10 @@ bool SessionContext::Generic_Decrypt(const uint8_t* in_buffer,
|
||||
LOGE("[Generic_Decrypt(): control bit says not allowed.");
|
||||
return false;
|
||||
}
|
||||
if (control.control_bits() & kControlDataPathSecure) {
|
||||
LOGE("[Generic_Decrypt(): control bit says secure path only.");
|
||||
return false;
|
||||
}
|
||||
if (control.duration() > 0) {
|
||||
if (control.duration() < CurrentTimer()) {
|
||||
LOGE("[Generic_Decrypt(): key expired.");
|
||||
@@ -635,7 +652,7 @@ bool SessionContext::Generic_Sign(const uint8_t* in_buffer,
|
||||
const std::vector<uint8_t>& key = current_content_key()->value();
|
||||
const KeyControlBlock& control = current_content_key()->control();
|
||||
if (static_cast<int>(key.size()) != SHA256_DIGEST_LENGTH) {
|
||||
LOGE("[Generic_Sign(): CONTENT_KEY has wrong size.");
|
||||
LOGE("[Generic_Sign(): CONTENT_KEY has wrong size; %d", key.size());
|
||||
return false;
|
||||
}
|
||||
if (!(control.control_bits() & kControlAllowSign)) {
|
||||
@@ -679,7 +696,7 @@ bool SessionContext::Generic_Verify(const uint8_t* in_buffer,
|
||||
const std::vector<uint8_t>& key = current_content_key()->value();
|
||||
const KeyControlBlock& control = current_content_key()->control();
|
||||
if (static_cast<int>(key.size()) != SHA256_DIGEST_LENGTH) {
|
||||
LOGE("[Generic_Verify(): CONTENT_KEY has wrong size.");
|
||||
LOGE("[Generic_Verify(): CONTENT_KEY has wrong size: %d", key.size());
|
||||
return false;
|
||||
}
|
||||
if (!(control.control_bits() & kControlAllowVerify)) {
|
||||
@@ -711,52 +728,73 @@ bool SessionContext::RefreshKey(const KeyId& key_id,
|
||||
const std::vector<uint8_t>& key_control,
|
||||
const std::vector<uint8_t>& key_control_iv) {
|
||||
if (key_id.empty()) {
|
||||
return false;
|
||||
// Key control is not encrypted if key id is NULL
|
||||
KeyControlBlock key_control_block(true);
|
||||
if (!ParseKeyControl(key_control, key_control_block)) {
|
||||
LOGD("Parse key control error.");
|
||||
return false;
|
||||
}
|
||||
// Apply duration to all keys in this session
|
||||
return session_keys_.UpdateDuration(key_control_block);
|
||||
}
|
||||
|
||||
Key* content_key = session_keys_.Find(key_id);
|
||||
|
||||
if (NULL == content_key) {
|
||||
LOGD("Error: no matching content key.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!key_control.empty()) {
|
||||
const std::vector<uint8_t> content_key_value = content_key->value();
|
||||
if (key_control.empty()) {
|
||||
LOGD("Error: no key_control.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Decrypt encrypted key control block
|
||||
// We don't actually make use of it in Oemcrypto mock, just to verify its
|
||||
// validity
|
||||
std::vector<uint8_t> control;
|
||||
if (key_control_iv.empty()) {
|
||||
control = key_control;
|
||||
} else if (!ce_->DecryptMessage(this, content_key_value, key_control_iv,
|
||||
key_control, &control)) {
|
||||
const std::vector<uint8_t> content_key_value = content_key->value();
|
||||
|
||||
// Decrypt encrypted key control block
|
||||
std::vector<uint8_t> control;
|
||||
if (key_control_iv.empty()) {
|
||||
// TODO(fredg): get confirmation from server team this is valid.
|
||||
LOGD("Key control block is NOT encrypted.");
|
||||
control = key_control;
|
||||
} else {
|
||||
// TODO(fredg): get confirmation from server team this is valid, too.
|
||||
LOGD("Key control block is encrypted.");
|
||||
if (!ce_->DecryptMessage(this, content_key_value, key_control_iv,
|
||||
key_control, &control)) {
|
||||
LOGD("Error decrypting key control block.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
KeyControlBlock key_control_block;
|
||||
if (!ParseKeyControl(control, key_control_block)) {
|
||||
return false;
|
||||
}
|
||||
KeyControlBlock key_control_block(true);
|
||||
if (!ParseKeyControl(control, key_control_block)) {
|
||||
LOGD("Error parsing key control.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!content_key->UpdateControl(key_control_block)) {
|
||||
return false;
|
||||
}
|
||||
if (!content_key->UpdateDuration(key_control_block)) {
|
||||
LOGD("Error updating duration.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SessionContext::UpdateMacKey(const std::vector<uint8_t>& enc_mac_key,
|
||||
const std::vector<uint8_t>& iv) {
|
||||
bool SessionContext::UpdateMacKeys(const std::vector<uint8_t>& enc_mac_keys,
|
||||
const std::vector<uint8_t>& iv) {
|
||||
|
||||
// Decrypt mac key from enc_mac_key using device_key
|
||||
std::vector<uint8_t> mac_key;
|
||||
// Decrypt mac key from enc_mac_key using device_keya
|
||||
std::vector<uint8_t> mac_keys;
|
||||
if (!ce_->DecryptMessage(this, encryption_key_, iv,
|
||||
enc_mac_key, &mac_key)) {
|
||||
enc_mac_keys, &mac_keys)) {
|
||||
return false;
|
||||
}
|
||||
mac_key_ = mac_key;
|
||||
mac_key_server_ = std::vector<uint8_t>(mac_keys.begin(),
|
||||
mac_keys.begin()+wvcdm::MAC_KEY_SIZE);
|
||||
mac_key_client_ = std::vector<uint8_t>(mac_keys.begin()+wvcdm::MAC_KEY_SIZE,
|
||||
mac_keys.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -896,7 +934,7 @@ bool CryptoEngine::DecryptCTR(SessionContext* session,
|
||||
|
||||
// Set the AES key.
|
||||
if (static_cast<int>(content_key.size()) != AES_BLOCK_SIZE) {
|
||||
LOGE("[DecryptCTR(): CONTENT_KEY has wrong size.");
|
||||
LOGE("[DecryptCTR(): CONTENT_KEY has wrong size: %d", content_key.size());
|
||||
return false;
|
||||
}
|
||||
const uint8_t* key_u8 = &content_key[0];
|
||||
|
||||
@@ -50,6 +50,7 @@ class SessionKeyTable {
|
||||
bool Insert(const KeyId key_id, const Key& key_data);
|
||||
Key* Find(const KeyId key_id);
|
||||
void Remove(const KeyId key_id);
|
||||
bool UpdateDuration(const KeyControlBlock& control);
|
||||
|
||||
private:
|
||||
KeyMap keys_;
|
||||
@@ -95,7 +96,8 @@ class SessionContext {
|
||||
|
||||
bool isValid() { return valid_; }
|
||||
|
||||
bool DeriveKeys(const std::vector<uint8_t>& mac_context,
|
||||
bool DeriveKeys(const std::vector<uint8_t>& master_key,
|
||||
const std::vector<uint8_t>& mac_context,
|
||||
const std::vector<uint8_t>& enc_context);
|
||||
bool RSADeriveKeys(const std::vector<uint8_t>& enc_session_key,
|
||||
const std::vector<uint8_t>& mac_context,
|
||||
@@ -140,12 +142,16 @@ class SessionContext {
|
||||
const std::vector<uint8_t>& key_data_iv,
|
||||
const std::vector<uint8_t>& key_control,
|
||||
const std::vector<uint8_t>& key_control_iv);
|
||||
bool EncryptRSAKey(uint8_t* wrapped_rsa_key,
|
||||
size_t wrapped_rsa_key_length,
|
||||
uint8_t* wrapped_rsa_key_iv);
|
||||
bool LoadRSAKey(const uint8_t* enc_rsa_key,
|
||||
size_t enc_rsa_key_length,
|
||||
const uint8_t* enc_rsa_key_iv,
|
||||
bool DecryptRSAKey(const uint8_t* enc_rsa_key,
|
||||
size_t enc_rsa_key_length,
|
||||
const uint8_t* wrapped_rsa_key_iv,
|
||||
uint8_t* pkcs8_rsa_key);
|
||||
bool EncryptRSAKey(const uint8_t* pkcs8_rsa_key,
|
||||
size_t enc_rsa_key_length,
|
||||
const uint8_t* enc_rsa_key_iv,
|
||||
uint8_t* enc_rsa_key);
|
||||
bool LoadRSAKey(uint8_t* pkcs8_rsa_key,
|
||||
size_t rsa_key_length,
|
||||
const uint8_t* message,
|
||||
size_t message_length,
|
||||
const uint8_t* signature,
|
||||
@@ -155,11 +161,17 @@ class SessionContext {
|
||||
bool RefreshKey(const KeyId& key_id,
|
||||
const std::vector<uint8_t>& key_control,
|
||||
const std::vector<uint8_t>& key_control_iv);
|
||||
bool UpdateMacKey(const std::vector<uint8_t>& mac_key, const std::vector<uint8_t>& iv);
|
||||
bool UpdateMacKeys(const std::vector<uint8_t>& mac_keys,
|
||||
const std::vector<uint8_t>& iv);
|
||||
bool SelectContentKey(const KeyId& key_id);
|
||||
const Key* current_content_key(void) {return current_content_key_;}
|
||||
void set_mac_key(const std::vector<uint8_t>& mac_key) { mac_key_ = mac_key; }
|
||||
const std::vector<uint8_t>& mac_key() { return mac_key_; }
|
||||
void set_mac_key_server(const std::vector<uint8_t>& mac_key_server) {
|
||||
mac_key_server_ = mac_key_server;
|
||||
}
|
||||
const std::vector<uint8_t>& mac_key_server() { return mac_key_server_; }
|
||||
void set_mac_key_client(const std::vector<uint8_t>& mac_key_client) {
|
||||
mac_key_client_ = mac_key_client; }
|
||||
const std::vector<uint8_t>& mac_key_client() { return mac_key_client_; }
|
||||
|
||||
void set_encryption_key(const std::vector<uint8_t>& enc_key) {
|
||||
encryption_key_ = enc_key;
|
||||
@@ -178,7 +190,8 @@ class SessionContext {
|
||||
bool valid_;
|
||||
CryptoEngine* ce_;
|
||||
SessionId id_;
|
||||
std::vector<uint8_t> mac_key_;
|
||||
std::vector<uint8_t> mac_key_server_;
|
||||
std::vector<uint8_t> mac_key_client_;
|
||||
std::vector<uint8_t> encryption_key_;
|
||||
std::vector<uint8_t> session_key_;
|
||||
const Key* current_content_key_;
|
||||
|
||||
@@ -23,7 +23,19 @@ bool KeyControlBlock::Validate() {
|
||||
0x6b63746c);
|
||||
return false;
|
||||
}
|
||||
// TODO(gmorgan): validate control bits
|
||||
|
||||
if (refresh_) {
|
||||
if (control_bits_ & kControlObserveDataPath) {
|
||||
LOGW("KCB: data_path_type set for refresh.");
|
||||
}
|
||||
if (control_bits_ & kControlObserveHDCP) {
|
||||
LOGW("KCB: HDCP setting set for refresh.");
|
||||
}
|
||||
if (control_bits_ & kControlObserveCGMS) {
|
||||
LOGW("KCB: CGMS setting set for refresh.");
|
||||
}
|
||||
}
|
||||
|
||||
valid_ = true;
|
||||
return valid_;
|
||||
}
|
||||
@@ -103,4 +115,21 @@ bool Key::setControl(const KeyControlBlock& control) {
|
||||
return valid_;
|
||||
}
|
||||
|
||||
bool Key::UpdateDuration(const KeyControlBlock& control) {
|
||||
valid_ = false;
|
||||
if (!control.valid() || !has_control_) {
|
||||
LOGE("UpdateDuration: control block not valid.");
|
||||
return false;
|
||||
}
|
||||
|
||||
control_.set_duration(control.duration());
|
||||
|
||||
if (isValidType() && !value_.empty()) {
|
||||
valid_ = true;
|
||||
} else {
|
||||
LOGE("UpdateDuration: value or type bad.");
|
||||
}
|
||||
return valid_;
|
||||
}
|
||||
|
||||
}; // namespace wvoec_eng
|
||||
|
||||
@@ -43,10 +43,8 @@ const uint32_t kControlCGMSCopyNever = (0x03);
|
||||
|
||||
class KeyControlBlock {
|
||||
public:
|
||||
KeyControlBlock() {}
|
||||
KeyControlBlock(const std::vector<uint8_t>& key_control_string) {
|
||||
valid_ = SetFromString(key_control_string);
|
||||
}
|
||||
KeyControlBlock() : valid_(false) {}
|
||||
KeyControlBlock(bool refresh) : valid_(false), refresh_(refresh) {}
|
||||
~KeyControlBlock() {}
|
||||
|
||||
bool SetFromString(const std::vector<uint8_t>& key_control_string);
|
||||
@@ -55,6 +53,7 @@ class KeyControlBlock {
|
||||
|
||||
bool valid() const { return valid_; }
|
||||
uint32_t duration() const { return duration_; }
|
||||
void set_duration(uint32_t duration) { duration_ = duration; }
|
||||
uint32_t nonce() const { return nonce_; }
|
||||
uint32_t control_bits() const { return control_bits_; }
|
||||
|
||||
@@ -63,6 +62,7 @@ class KeyControlBlock {
|
||||
uint32_t ExtractField(const std::vector<uint8_t>& str, int idx);
|
||||
|
||||
bool valid_;
|
||||
bool refresh_;
|
||||
uint32_t verification_;
|
||||
uint32_t duration_;
|
||||
uint32_t nonce_;
|
||||
@@ -86,7 +86,7 @@ class Key {
|
||||
bool setValue(const char* key_string, size_t key_string_length);
|
||||
bool setType(KeyType ktype);
|
||||
bool setControl(const KeyControlBlock& control);
|
||||
bool UpdateControl(const KeyControlBlock& control) { return true; }
|
||||
bool UpdateDuration(const KeyControlBlock& control);
|
||||
|
||||
KeyType keyType() { return type_; }
|
||||
const std::vector<uint8_t>& value() const { return value_; }
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* Copyright 2013 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* mock implementation of OEMCrypto APIs
|
||||
* Reference implementation of OEMCrypto APIs
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
#include <string>
|
||||
#include "log.h"
|
||||
#include "oemcrypto_engine_mock.h"
|
||||
#include "openssl/cmac.h"
|
||||
#include "openssl/evp.h"
|
||||
#include "openssl/hmac.h"
|
||||
#include "openssl/rand.h"
|
||||
#include "openssl/sha.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
@@ -75,8 +78,6 @@ OEMCryptoResult OEMCrypto_Initialize(void) {
|
||||
return OEMCrypto_ERROR_INIT_FAILED;
|
||||
}
|
||||
LOGD("[OEMCrypto_Initialize(): success]");
|
||||
LOGW("WARNING -- this is the reference implementation of OEMCrypto.");
|
||||
printf("WARNING -- you are using the reference implementation of OEMCrypto.\n");
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -181,12 +182,15 @@ OEMCryptoResult OEMCrypto_GenerateDerivedKeys(OEMCrypto_SESSION session,
|
||||
enc_key_context + enc_key_context_length);
|
||||
|
||||
// Generate mac and encryption keys for current session context
|
||||
if (!session_ctx->DeriveKeys(mac_ctx_str, enc_ctx_str)) {
|
||||
if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key().value(),
|
||||
mac_ctx_str, enc_ctx_str)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (trace_all_calls) {
|
||||
dump_hex("mac_key", &session_ctx->mac_key()[0],
|
||||
session_ctx->mac_key().size());
|
||||
dump_hex("mac_key_server", &session_ctx->mac_key_server()[0],
|
||||
session_ctx->mac_key_server().size());
|
||||
dump_hex("mac_key_client", &session_ctx->mac_key_client()[0],
|
||||
session_ctx->mac_key_client().size());
|
||||
dump_hex("enc_key", &session_ctx->encryption_key()[0],
|
||||
session_ctx->encryption_key().size());
|
||||
}
|
||||
@@ -257,7 +261,7 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length,
|
||||
const uint8_t* enc_mac_key_iv,
|
||||
const uint8_t* enc_mac_key,
|
||||
const uint8_t* enc_mac_keys,
|
||||
size_t num_keys,
|
||||
const OEMCrypto_KeyObject* key_array) {
|
||||
if (trace_all_calls) {
|
||||
@@ -265,7 +269,7 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
dump_hex("message", message, message_length);
|
||||
dump_hex("signature", signature, signature_length);
|
||||
dump_hex("enc_mac_key_iv", enc_mac_key_iv, wvcdm::KEY_IV_SIZE);
|
||||
dump_hex("enc_mac_key", enc_mac_key, wvcdm::MAC_KEY_SIZE);
|
||||
dump_hex("enc_mac_keys", enc_mac_keys, 2*wvcdm::MAC_KEY_SIZE);
|
||||
for (size_t i = 0; i < num_keys; i++) {
|
||||
printf("key_array[%zu].key_id_length=%zu;\n", i, key_array[i].key_id_length);
|
||||
dump_array_part("key_array", i, "key_id",
|
||||
@@ -273,7 +277,7 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
dump_array_part("key_array", i, "key_data_iv",
|
||||
key_array[i].key_data_iv, wvcdm::KEY_IV_SIZE);
|
||||
dump_array_part("key_array", i, "key_data",
|
||||
key_array[i].key_data, wvcdm::KEY_IV_SIZE);
|
||||
key_array[i].key_data, key_array[i].key_data_length);
|
||||
dump_array_part("key_array", i, "key_control_iv",
|
||||
key_array[i].key_control_iv, wvcdm::KEY_IV_SIZE);
|
||||
dump_array_part("key_array", i, "key_control",
|
||||
@@ -300,8 +304,8 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
}
|
||||
|
||||
// Range check
|
||||
if (!RangeCheck(message, message_length, enc_mac_key,
|
||||
wvcdm::MAC_KEY_SIZE, true) ||
|
||||
if (!RangeCheck(message, message_length, enc_mac_keys,
|
||||
2*wvcdm::MAC_KEY_SIZE, true) ||
|
||||
!RangeCheck(message, message_length, enc_mac_key_iv,
|
||||
wvcdm::KEY_IV_SIZE, true)) {
|
||||
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_SIGNATURE_FAILURE - range check.]");
|
||||
@@ -316,9 +320,9 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
!RangeCheck(message, message_length, key_array[i].key_data_iv,
|
||||
wvcdm::KEY_IV_SIZE, false) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_control,
|
||||
wvcdm::KEY_CONTROL_SIZE, true) ||
|
||||
wvcdm::KEY_CONTROL_SIZE, false) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_control_iv,
|
||||
wvcdm::KEY_IV_SIZE, true)) {
|
||||
wvcdm::KEY_IV_SIZE, false)) {
|
||||
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_SIGNATURE_FAILURE -range check %d]", i);
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
@@ -366,18 +370,17 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
if (!status) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
|
||||
// enc_mac_key can be NULL if license renewal is not supported
|
||||
if (enc_mac_key == NULL) return OEMCrypto_SUCCESS;
|
||||
if (enc_mac_keys == NULL) return OEMCrypto_SUCCESS;
|
||||
|
||||
// V2 license protocol: update mac key after processing license response
|
||||
const std::vector<uint8_t> enc_mac_key_str = std::vector<uint8_t>(
|
||||
enc_mac_key, enc_mac_key + wvcdm::MAC_KEY_SIZE);
|
||||
// V2.1 license protocol: update mac keys after processing license response
|
||||
const std::vector<uint8_t> enc_mac_keys_str = std::vector<uint8_t>(
|
||||
enc_mac_keys, enc_mac_keys + 2*wvcdm::MAC_KEY_SIZE);
|
||||
const std::vector<uint8_t> enc_mac_key_iv_str = std::vector<uint8_t>(
|
||||
enc_mac_key_iv, enc_mac_key_iv + wvcdm::KEY_IV_SIZE);
|
||||
|
||||
if (!session_ctx->UpdateMacKey(enc_mac_key_str, enc_mac_key_iv_str)) {
|
||||
if (!session_ctx->UpdateMacKeys(enc_mac_keys_str, enc_mac_key_iv_str)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -390,7 +393,7 @@ OEMCryptoResult OEMCrypto_RefreshKeys(OEMCrypto_SESSION session,
|
||||
size_t num_keys,
|
||||
const OEMCrypto_KeyRefreshObject* key_array) {
|
||||
if (trace_all_calls) {
|
||||
printf("-- OEMCryptoResult OEMCrypto_RefreshKeys(OEMCrypto_SESSION session,\n");
|
||||
printf("-- OEMCryptoResult OEMCrypto_RefreshKeys(num_keys=%d)\n", num_keys);
|
||||
}
|
||||
|
||||
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
||||
@@ -405,7 +408,8 @@ OEMCryptoResult OEMCrypto_RefreshKeys(OEMCrypto_SESSION session,
|
||||
}
|
||||
|
||||
if (message == NULL || message_length == 0 ||
|
||||
signature == NULL || signature_length == 0) {
|
||||
signature == NULL || signature_length == 0 ||
|
||||
num_keys == 0) {
|
||||
LOGE("[OEMCrypto_RefreshKeys(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
@@ -415,10 +419,10 @@ OEMCryptoResult OEMCrypto_RefreshKeys(OEMCrypto_SESSION session,
|
||||
if (!RangeCheck(message, message_length, key_array[i].key_id,
|
||||
key_array[i].key_id_length, true) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_control,
|
||||
wvcdm::KEY_CONTROL_SIZE, true) ||
|
||||
wvcdm::KEY_CONTROL_SIZE, false) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_control_iv,
|
||||
wvcdm::KEY_IV_SIZE, true)) {
|
||||
LOGE("[OEMCrypto_RefreshKeys(): OEMCrypto_ERROR_SIGNATURE_FAILURE]");
|
||||
LOGE("[OEMCrypto_RefreshKeys(): Range Check %d]", i);
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
}
|
||||
@@ -426,6 +430,7 @@ OEMCryptoResult OEMCrypto_RefreshKeys(OEMCrypto_SESSION session,
|
||||
// Validate message signature
|
||||
if (!session_ctx->ValidateMessage(message, message_length,
|
||||
signature, signature_length)) {
|
||||
LOGE("[OEMCrypto_RefreshKeys(): signature was invalid]");
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
|
||||
@@ -435,24 +440,28 @@ OEMCryptoResult OEMCrypto_RefreshKeys(OEMCrypto_SESSION session,
|
||||
std::vector<uint8_t> key_control;
|
||||
std::vector<uint8_t> key_control_iv;
|
||||
for (unsigned int i = 0; i < num_keys; i++) {
|
||||
// TODO(gmorgan): key_id may be null if special control key type (TBS)
|
||||
if (key_array[i].key_id != NULL) {
|
||||
key_id.assign(key_array[i].key_id,
|
||||
key_array[i].key_id + key_array[i].key_id_length);
|
||||
} else {
|
||||
key_id.clear();
|
||||
}
|
||||
if (key_array[i].key_control != NULL) {
|
||||
key_control.assign(key_array[i].key_control,
|
||||
key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE);
|
||||
key_control_iv.assign(key_array[i].key_control_iv,
|
||||
key_array[i].key_control_iv + wvcdm::KEY_IV_SIZE);
|
||||
if (key_array[i].key_control_iv == NULL ) {
|
||||
key_control_iv.clear();
|
||||
} else {
|
||||
key_control_iv.assign(key_array[i].key_control_iv,
|
||||
key_array[i].key_control_iv + wvcdm::KEY_IV_SIZE);
|
||||
}
|
||||
} else {
|
||||
key_control.clear();
|
||||
// key_id could be null if special control key type
|
||||
// key_control is not encrypted in this case
|
||||
key_id.clear();
|
||||
key_control_iv.clear();
|
||||
key_control.assign(key_array[i].key_control,
|
||||
key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE);
|
||||
}
|
||||
|
||||
if (!session_ctx->RefreshKey(key_id, key_control, key_control_iv)) {
|
||||
LOGE("[OEMCrypto_RefreshKeys(): error in key %i]", i);
|
||||
status = false;
|
||||
break;
|
||||
}
|
||||
@@ -502,12 +511,13 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
|
||||
bool is_encrypted,
|
||||
const uint8_t* iv,
|
||||
size_t block_offset,
|
||||
const OEMCrypto_DestBufferDesc* out_buffer) {
|
||||
const OEMCrypto_DestBufferDesc* out_buffer,
|
||||
uint8_t subsample_flags) {
|
||||
if (trace_all_calls) {
|
||||
printf("-- OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,\n");
|
||||
}
|
||||
wvoec_mock::BufferType buffer_type = kBufferTypeDirect;
|
||||
void* destination = NULL;
|
||||
uint8_t* destination = NULL;
|
||||
size_t max_length = 0;
|
||||
switch (out_buffer->type) {
|
||||
case OEMCrypto_BufferType_Clear:
|
||||
@@ -517,7 +527,7 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
|
||||
break;
|
||||
case OEMCrypto_BufferType_Secure:
|
||||
buffer_type = kBufferTypeSecure;
|
||||
destination = (out_buffer->buffer.secure.handle
|
||||
destination = ((uint8_t*)out_buffer->buffer.secure.handle
|
||||
+ out_buffer->buffer.secure.offset);
|
||||
max_length = out_buffer->buffer.secure.max_length;
|
||||
break;
|
||||
@@ -735,58 +745,89 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session,
|
||||
}
|
||||
session_ctx->FlushNonces();
|
||||
|
||||
// Decrypt key and verify signature.
|
||||
if (!session_ctx->LoadRSAKey(enc_rsa_key, enc_rsa_key_length,
|
||||
enc_rsa_key_iv, message, message_length,
|
||||
signature, signature_length)) {
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
// Decrypt RSA key.
|
||||
uint8_t* pkcs8_rsa_key = new uint8_t[enc_rsa_key_length];
|
||||
OEMCryptoResult result = OEMCrypto_SUCCESS;
|
||||
if (!session_ctx->DecryptRSAKey(enc_rsa_key, enc_rsa_key_length,
|
||||
enc_rsa_key_iv, pkcs8_rsa_key)) {
|
||||
result = OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1];
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (padding > 16) {
|
||||
LOGE("[RewrapRSAKey(): Encrypted RSA has bad padding: %d]", padding);
|
||||
result = OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
}
|
||||
size_t rsa_key_length = enc_rsa_key_length - padding;
|
||||
// verify signature, verify RSA key, and load it.
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (!session_ctx->LoadRSAKey(pkcs8_rsa_key, rsa_key_length,
|
||||
message, message_length,
|
||||
signature, signature_length)) {
|
||||
result = OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
// return OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we generate a wrapped keybox.
|
||||
WrappedRSAKey* wrapped = reinterpret_cast<WrappedRSAKey*>(wrapped_rsa_key);
|
||||
// Pick a random context and IV for generating keys.
|
||||
if (!RAND_bytes(wrapped->context, sizeof(wrapped->context))) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (!RAND_bytes(wrapped->context, sizeof(wrapped->context))) {
|
||||
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (!RAND_bytes(wrapped->iv, sizeof(wrapped->iv))) {
|
||||
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
}
|
||||
if (!RAND_bytes(wrapped->iv, sizeof(wrapped->iv))) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
const std::vector<uint8_t> mac_ctx_str(wrapped->context,
|
||||
wrapped->context + sizeof(wrapped->context));
|
||||
const std::vector<uint8_t> context(wrapped->context,
|
||||
wrapped->context + sizeof(wrapped->context));
|
||||
// Generate mac and encryption keys for encrypting the signature.
|
||||
if (!session_ctx->DeriveKeys(mac_ctx_str, mac_ctx_str)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key().value(),
|
||||
context, context)) {
|
||||
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Encrypt rsa key with keybox.
|
||||
if (!session_ctx->EncryptRSAKey(wrapped->enc_rsa_key,
|
||||
enc_rsa_key_length,
|
||||
wrapped->iv)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (!session_ctx->EncryptRSAKey(pkcs8_rsa_key, enc_rsa_key_length,
|
||||
wrapped->iv, wrapped->enc_rsa_key)) {
|
||||
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
}
|
||||
delete[] pkcs8_rsa_key;
|
||||
|
||||
size_t sig_length = sizeof(wrapped->signature);
|
||||
if (!session_ctx->GenerateSignature(wrapped->context, // start signing here.
|
||||
buffer_size - sizeof(wrapped->signature),
|
||||
wrapped->signature,
|
||||
&sig_length)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
// The wrapped keybox must be signed with the same key we verify with. I'll
|
||||
// pick the server key, so I don't have to modify LoadRSAKey.
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
size_t sig_length = sizeof(wrapped->signature);
|
||||
if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0],
|
||||
SHA256_DIGEST_LENGTH, wrapped->context,
|
||||
buffer_size - sizeof(wrapped->signature), wrapped->signature,
|
||||
&sig_length)) {
|
||||
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (trace_all_calls) {
|
||||
dump_hex("wrapped_rsa_key", wrapped_rsa_key, *wrapped_rsa_key_length);
|
||||
dump_hex("signature", wrapped->signature, sizeof(wrapped->signature));
|
||||
dump_hex("context", wrapped->context, sizeof(wrapped->context));
|
||||
dump_hex("iv", wrapped->iv, sizeof(wrapped->iv));
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session,
|
||||
const uint8_t* wrapped_rsa_key,
|
||||
size_t wrapped_rsa_key_length) {
|
||||
if (wrapped_rsa_key == NULL) {
|
||||
LOGE("[OEMCrypto_LoadDeviceRSAKey(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
const WrappedRSAKey* wrapped
|
||||
= reinterpret_cast<const WrappedRSAKey*>(wrapped_rsa_key);
|
||||
if (trace_all_calls) {
|
||||
@@ -796,39 +837,53 @@ OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session,
|
||||
dump_hex("context", wrapped->context, sizeof(wrapped->context));
|
||||
dump_hex("iv", wrapped->iv, sizeof(wrapped->iv));
|
||||
}
|
||||
|
||||
if (wrapped_rsa_key == NULL) {
|
||||
LOGE("[OEMCrypto_LoadDeviceRSAKey(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
||||
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): ERROR_KEYBOX_INVALID]");
|
||||
LOGE("[OEMCrypto_LoadDeviceRSAKey(): ERROR_KEYBOX_INVALID]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (!session_ctx || !session_ctx->isValid()) {
|
||||
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): ERROR_NO_INVALID_SESSION]");
|
||||
LOGE("[OEMCrypto_LoadDeviceRSAKey(): ERROR_NO_INVALID_SESSION]");
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
const std::vector<uint8_t> mac_ctx_str(wrapped->context,
|
||||
wrapped->context + sizeof(wrapped->context));
|
||||
const std::vector<uint8_t> context(wrapped->context,
|
||||
wrapped->context + sizeof(wrapped->context));
|
||||
// Generate mac and encryption keys for encrypting the signature.
|
||||
if (!session_ctx->DeriveKeys(mac_ctx_str, mac_ctx_str)) {
|
||||
if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key().value(),
|
||||
context, context)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
// Decrypt key and verify signature.
|
||||
if (!session_ctx->LoadRSAKey(wrapped->enc_rsa_key,
|
||||
wrapped_rsa_key_length - sizeof(WrappedRSAKey),
|
||||
wrapped->iv,
|
||||
wrapped->context,
|
||||
wrapped_rsa_key_length - sizeof(wrapped->signature),
|
||||
wrapped->signature,
|
||||
sizeof(wrapped->signature))) {
|
||||
return OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
// Decrypt RSA key.
|
||||
uint8_t* pkcs8_rsa_key = new uint8_t[wrapped_rsa_key_length
|
||||
- sizeof(wrapped->signature)];
|
||||
size_t enc_rsa_key_length = wrapped_rsa_key_length - sizeof(WrappedRSAKey);
|
||||
OEMCryptoResult result = OEMCrypto_SUCCESS;
|
||||
if (!session_ctx->DecryptRSAKey(wrapped->enc_rsa_key, enc_rsa_key_length,
|
||||
wrapped->iv, pkcs8_rsa_key)) {
|
||||
result = OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1];
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (padding > 16) {
|
||||
LOGE("[LoadDeviceRSAKey(): Encrypted RSA has bad padding: %d]", padding);
|
||||
result = OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
}
|
||||
size_t rsa_key_length = enc_rsa_key_length - padding;
|
||||
// verify signature.
|
||||
if( result == OEMCrypto_SUCCESS) {
|
||||
if (!session_ctx->LoadRSAKey(pkcs8_rsa_key, rsa_key_length,
|
||||
wrapped->context,
|
||||
wrapped_rsa_key_length - sizeof(wrapped->signature),
|
||||
wrapped->signature,
|
||||
sizeof(wrapped->signature))) {
|
||||
result = OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
// return OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
}
|
||||
delete[] pkcs8_rsa_key;
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
@@ -919,8 +974,10 @@ OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (trace_all_calls) {
|
||||
dump_hex("mac_key", &session_ctx->mac_key()[0],
|
||||
session_ctx->mac_key().size());
|
||||
dump_hex("mac_key_server", &session_ctx->mac_key_server()[0],
|
||||
session_ctx->mac_key_server().size());
|
||||
dump_hex("mac_key", &session_ctx->mac_key_client()[0],
|
||||
session_ctx->mac_key_client().size());
|
||||
dump_hex("enc_key", &session_ctx->encryption_key()[0],
|
||||
session_ctx->encryption_key().size());
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user