Merge "Part of Qualcomm L1 OEMCrypto integration" into jb-mr2-dev

This commit is contained in:
Jeff Tinker
2013-04-22 23:20:14 +00:00
committed by Android (Google) Code Review
14 changed files with 2036 additions and 1389 deletions

View File

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

View File

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

View File

@@ -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_);
}

View File

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

View File

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

View File

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

View File

@@ -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.";
}
}

View File

@@ -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 sessions 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,

View File

@@ -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];

View File

@@ -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_;

View File

@@ -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

View File

@@ -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_; }

View File

@@ -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