Part of Qualcomm L1 OEMCrypto integration

Upgrade to version 2.1 of license protocol in OEMCrypto.

related-to-bug: 8621521

Merge of https://widevine-internal-review.googlesource.com/#/c/4952/
from Widevine CDM repository to android repository.

Change-Id: I0d85dae1981b7525ab17aec5f21cf668d078bf47
This commit is contained in:
Fred Gylys-Colwell
2013-04-22 13:07:34 -07:00
committed by Jeff Tinker
parent bb0c62768a
commit 39ea1df671
14 changed files with 2036 additions and 1389 deletions

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());
}