Import updates to the Widevine CENC DRM Plugin

This change incorporates the following CLs from the Widevine
cdm repository:

    Update the java request/response test app to match Drm API changes
    Don't build the mock liboemcrypto.so by default
    Do not build CDM tests by default
    Fix Build Break in DrmEngine Unit Tests
    Fix Build Break in WVDrmPlugin
    Initial version of roadmap for CDM projects.
    Implement License Query
    Implement Generic DRM in OEMCrypto Reference Implementation
    Add key_data_length field when calling OEMCrypto_LoadKeys
    Policy engine unittests
    Generalized DRM API for OEMCrypto
    Fixes proto buf libraries build.
    Add Version Number to OEMCrypto API
    Test key control block duration field in OEMCrypto
    Add fix for missing crypto offset.
    Fixed android/media*/test builds and added proto files for Cert. provisioning
    Refactor and clean up callback code in CDM.
    Add "device_id" name-value pair to LicenseRequest::ClientIdentification
    Separate unit and end-to-end tests from the top level makefie.
    Includes changes for 'fall back to l3 oemcrypto lib' in top level makefile.
    Fall Back to Level 3 if Level 1 Fails
    Fix compilation error in wvcdm_unittest.
    Fix Android build break due to Decrypt() signature change in cdm_engine.h.
    Wire up callbacks and errors in the Steel proxy.
    Fix lock assert if there is no keybox on the device.
    RSA Certificate Unit Test
    Change Generic_Verify signature to constant.

Change-Id: I2e42db9d0b4f8d4e833675ae81d0714509bbfd2c
This commit is contained in:
Jeff Tinker
2013-04-03 17:54:20 -07:00
parent 998d67fc8c
commit f3ec8c19d6
54 changed files with 5944 additions and 751 deletions

View File

@@ -25,6 +25,9 @@
#include "string_conversions.h"
#include "wv_cdm_constants.h"
static const int kPssSaltLength = 20;
namespace {
// Increment counter for AES-CTR
void ctr128_inc(uint8_t* counter) {
@@ -36,7 +39,7 @@ void ctr128_inc(uint8_t* counter) {
void dump_openssl_error() {
while (unsigned long err = ERR_get_error()) {
char buffer[120];
LOGE("openssl error: %lu: %s",
LOGE("openssl error -- %lu -- %s",
err, ERR_error_string(err, buffer));
}
}
@@ -139,6 +142,13 @@ bool SessionContext::DeriveKeys(const std::vector<uint8_t>& mac_key_context,
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 << " enc_key = " << wvcdm::b2a_hex(enc_key) << std::endl;
#endif
set_mac_key(mac_key);
set_encryption_key(enc_key);
return true;
@@ -151,21 +161,40 @@ bool SessionContext::RSADeriveKeys(const std::vector<uint8_t>& enc_session_key,
LOGE("[RSADeriveKeys(): no RSA key set]");
return false;
}
session_key_.resize(wvcdm::KEY_SIZE);
if (-1 == RSA_private_decrypt(wvcdm::KEY_SIZE, &enc_session_key[0],
&session_key_[0], rsa_key_,
RSA_PKCS1_OAEP_PADDING)) {
if (enc_session_key.size() != static_cast<size_t>(RSA_size(rsa_key_))) {
LOGE("[RSADeriveKeys(): encrypted session key is wrong size:%zu, should be %d]",
enc_session_key.size(), RSA_size(rsa_key_));
dump_openssl_error();
return false;
}
session_key_.resize(RSA_size(rsa_key_));
int decrypted_size = RSA_private_decrypt(enc_session_key.size(),
&enc_session_key[0],
&session_key_[0], rsa_key_,
RSA_PKCS1_OAEP_PADDING);
if (-1 == decrypted_size) {
LOGE("[RSADeriveKeys(): error decrypting session key.]");
dump_openssl_error();
return false;
}
session_key_.resize(decrypted_size);
if (decrypted_size != static_cast<int>(wvcdm::KEY_SIZE)) {
LOGE("[RSADeriveKeys(): error. session key is wrong size: %d.]",
decrypted_size);
dump_openssl_error();
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());
@@ -173,9 +202,18 @@ bool SessionContext::RSADeriveKeys(const std::vector<uint8_t>& enc_session_key,
// 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;
@@ -212,6 +250,14 @@ bool SessionContext::GenerateSignature(const uint8_t* message,
return false;
}
size_t SessionContext::RSASignatureSize() {
if (!rsa_key_) {
LOGE("[GenerateRSASignature(): no RSA key set]");
return 0;
}
return static_cast<size_t>(RSA_size(rsa_key_));
}
bool SessionContext::GenerateRSASignature(const uint8_t* message,
size_t message_length,
uint8_t* signature,
@@ -229,19 +275,30 @@ bool SessionContext::GenerateRSASignature(const uint8_t* message,
*signature_length = RSA_size(rsa_key_);
return false;
}
// TODO(fredgc): This uses the wrong algorithm for signing.
// This code needs to be fixed!!
LOGE("COmputing signature using RSASSA-PKCS1v1.5 instead of RSASSA-PSS");
// Hash the message using SHA1.
uint8_t hash[SHA_DIGEST_LENGTH];
if (!SHA1(message, message_length, hash)) {
LOGE("[GeneratRSASignature(): error creating signature hash.]");
dump_openssl_error();
return false;
}
int ret = RSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH,
signature, signature_length, rsa_key_);
if (ret != 1) {
LOGE("[GeneratRSASignature(): error signing signature hash.]");
// Add PSS padding.
uint8_t padded_digest[*signature_length];
int status = RSA_padding_add_PKCS1_PSS(rsa_key_, padded_digest, hash,
EVP_sha1(), kPssSaltLength);
if (status == -1) {
LOGE("[GeneratRSASignature(): error padding hash.]");
dump_openssl_error();
return false;
}
// Encrypt PSS padded digest.
status = RSA_private_encrypt(*signature_length, padded_digest, signature,
rsa_key_, RSA_NO_PADDING);
if (status == -1) {
LOGE("[GeneratRSASignature(): error in private encrypt.]");
dump_openssl_error();
return false;
}
@@ -387,10 +444,17 @@ bool SessionContext::EncryptRSAKey(uint8_t* wrapped_rsa_key,
uint8_t* p = &buffer[0];
int len = i2d_RSAPrivateKey(rsa_key_, &p);
if (len < 0) {
LOGE("[RewrapRSAKey(): Could not decode rsa key]");
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);
// Encrypt rsa key with keybox.
uint8_t iv_buffer[ wvcdm::KEY_IV_SIZE];
@@ -409,28 +473,35 @@ bool SessionContext::LoadRSAKey(const uint8_t* enc_rsa_key,
size_t message_length,
const uint8_t* signature,
size_t signature_length) {
std::vector<uint8_t> enc_rsa_key_v(enc_rsa_key,
enc_rsa_key + enc_rsa_key_length);
std::vector<uint8_t> iv(enc_rsa_key_iv, enc_rsa_key_iv + wvcdm::KEY_IV_SIZE);
std::vector<uint8_t> rsa_key; // unencrypted.
// Validate message signature
if (!ValidateMessage(message, message_length, signature, signature_length)) {
LOGE("[LoadRSAKey(): Could not verify signature]");
return false;
}
if (!ce_->DecryptMessage(this, encryption_key_, iv,
enc_rsa_key_v, &rsa_key)) {
LOGE("[LoadRSAKey(): Could not decrypt key data]");
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 = &rsa_key[0];
RSA* rsa = d2i_RSAPrivateKey(0, &p, rsa_key.size());
rsa_key_ = rsa;
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();
@@ -450,6 +521,191 @@ bool SessionContext::LoadRSAKey(const uint8_t* enc_rsa_key,
}
}
bool SessionContext::Generic_Encrypt(const uint8_t* in_buffer,
size_t buffer_length,
const uint8_t* iv,
OEMCrypto_Algorithm algorithm,
uint8_t* out_buffer) {
// Check there is a content key
if (current_content_key() == NULL) {
LOGE("[Generic_Encrypt(): OEMCrypto_ERROR_NO_CONTENT_KEY]");
return false;
}
const std::vector<uint8_t>& key = current_content_key()->value();
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.");
return false;
}
if (!(control.control_bits() & kControlAllowEncrypt)) {
LOGE("[Generic_Encrypt(): control bit says not allowed.");
return false;
}
if (control.duration() > 0) {
if (control.duration() < CurrentTimer()) {
LOGE("[Generic_Encrypt(): key expired.");
return false;
}
}
if( algorithm != OEMCrypto_AES_CBC_128_NO_PADDING ) {
LOGE("[Generic_Encrypt(): algorithm bad.");
return false;
}
if( buffer_length % AES_BLOCK_SIZE != 0 ) {
LOGE("[Generic_Encrypt(): buffers size bad.");
return false;
}
const uint8_t* key_u8 = &key[0];
AES_KEY aes_key;
if (AES_set_encrypt_key(key_u8, AES_BLOCK_SIZE * 8, &aes_key) != 0) {
LOGE("[Generic_Encrypt(): FAILURE]");
return false;
}
uint8_t iv_buffer[ wvcdm::KEY_IV_SIZE];
memcpy(iv_buffer, iv, wvcdm::KEY_IV_SIZE);
AES_cbc_encrypt(in_buffer, out_buffer, buffer_length,
&aes_key, iv_buffer, AES_ENCRYPT);
return true;
}
bool SessionContext::Generic_Decrypt(const uint8_t* in_buffer,
size_t buffer_length,
const uint8_t* iv,
OEMCrypto_Algorithm algorithm,
uint8_t* out_buffer) {
// Check there is a content key
if (current_content_key() == NULL) {
LOGE("[Generic_Decrypt(): OEMCrypto_ERROR_NO_CONTENT_KEY]");
return false;
}
const std::vector<uint8_t>& key = current_content_key()->value();
const KeyControlBlock& control = current_content_key()->control();
// Set the AES key.
if (static_cast<int>(key.size()) != AES_BLOCK_SIZE) {
LOGE("[Generic_Decrypt(): CONTENT_KEY has wrong size.");
return false;
}
if (!(control.control_bits() & kControlAllowDecrypt)) {
LOGE("[Generic_Decrypt(): control bit says not allowed.");
return false;
}
if (control.duration() > 0) {
if (control.duration() < CurrentTimer()) {
LOGE("[Generic_Decrypt(): key expired.");
return false;
}
}
if( algorithm != OEMCrypto_AES_CBC_128_NO_PADDING ) {
LOGE("[Generic_Decrypt(): bad algorithm.");
return false;
}
if( buffer_length % AES_BLOCK_SIZE != 0 ) {
LOGE("[Generic_Decrypt(): bad buffer size.");
return false;
}
const uint8_t* key_u8 = &key[0];
AES_KEY aes_key;
if (AES_set_decrypt_key(key_u8, AES_BLOCK_SIZE * 8, &aes_key) != 0) {
LOGE("[Generic_Decrypt(): FAILURE]");
return false;
}
uint8_t iv_buffer[ wvcdm::KEY_IV_SIZE];
memcpy(iv_buffer, iv, wvcdm::KEY_IV_SIZE);
AES_cbc_encrypt(in_buffer, out_buffer, buffer_length,
&aes_key, iv_buffer, AES_DECRYPT);
return true;
}
bool SessionContext::Generic_Sign(const uint8_t* in_buffer,
size_t buffer_length,
OEMCrypto_Algorithm algorithm,
uint8_t* signature,
size_t* signature_length) {
// Check there is a content key
if (current_content_key() == NULL) {
LOGE("[Generic_Sign(): OEMCrypto_ERROR_NO_CONTENT_KEY]");
return false;
}
if (*signature_length < SHA256_DIGEST_LENGTH) {
*signature_length = SHA256_DIGEST_LENGTH;
LOGE("[Generic_Sign(): bad signature length.");
return false;
}
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.");
return false;
}
if (!(control.control_bits() & kControlAllowSign)) {
LOGE("[Generic_Sign(): control bit says not allowed.");
return false;
}
if (control.duration() > 0) {
if (control.duration() < CurrentTimer()) {
LOGE("[Generic_Sign(): key expired.");
return false;
}
}
if( algorithm != OEMCrypto_HMAC_SHA256 ) {
LOGE("[Generic_Sign(): bad algorithm.");
return false;
}
unsigned int md_len = *signature_length;
if (HMAC(EVP_sha256(), &key[0], SHA256_DIGEST_LENGTH,
in_buffer, buffer_length, signature, &md_len)) {
*signature_length = md_len;
return true;
}
LOGE("[Generic_Sign(): hmac failed.");
dump_openssl_error();
return false;
}
bool SessionContext::Generic_Verify(const uint8_t* in_buffer,
size_t buffer_length,
OEMCrypto_Algorithm algorithm,
const uint8_t* signature,
size_t signature_length) {
// Check there is a content key
if (current_content_key() == NULL) {
LOGE("[Decrypt_Verify(): OEMCrypto_ERROR_NO_CONTENT_KEY]");
return false;
}
if (signature_length < SHA256_DIGEST_LENGTH) {
return false;
}
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.");
return false;
}
if (!(control.control_bits() & kControlAllowVerify)) {
LOGE("[Generic_Verify(): control bit says not allowed.");
return false;
}
if (control.duration() > 0) {
if (control.duration() < CurrentTimer()) {
LOGE("[Generic_Verify(): key expired.");
return false;
}
}
if( algorithm != OEMCrypto_HMAC_SHA256 ) {
LOGE("[Generic_Verify(): bad algorithm.");
return false;
}
unsigned int md_len = signature_length;
uint8_t computed_signature[SHA256_DIGEST_LENGTH];
if (HMAC(EVP_sha256(), &key[0], SHA256_DIGEST_LENGTH,
in_buffer, buffer_length, computed_signature, &md_len)) {
return (0 == memcmp( signature, computed_signature, SHA256_DIGEST_LENGTH));
}
LOGE("[Generic_Verify(): HMAC failed.");
dump_openssl_error();
return false;
}
bool SessionContext::RefreshKey(const KeyId& key_id,
const std::vector<uint8_t>& key_control,
@@ -582,7 +838,6 @@ bool CryptoEngine::DecryptMessage(SessionContext* session,
LOGE("[DecryptMessage(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return false;
}
decrypted->resize(message.size());
uint8_t iv_buffer[16];
memcpy(iv_buffer, &iv[0], 16);