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:
@@ -32,6 +32,7 @@ LOCAL_SHARED_LIBRARIES := \
|
||||
libutils \
|
||||
libz \
|
||||
|
||||
LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_SHARED_LIBRARIES)
|
||||
LOCAL_MODULE := liboemcrypto
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
@@ -17,7 +17,7 @@ typedef enum {
|
||||
LOG_VERBOSE
|
||||
} LogPriority;
|
||||
|
||||
void log_write(LogPriority priority, const char *fmt, ...);
|
||||
void log_write(LogPriority priority, const char* fmt, ...);
|
||||
|
||||
// Log APIs
|
||||
#define LOGE(...) ((void)log_write(wvcdm::LOG_ERROR, __VA_ARGS__))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
#include "oemcrypto_keybox_mock.h"
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
// TODO(fredgc,gmorgan): Revisit the need to keep interface separate.
|
||||
// For now, we need to include the enum OEMCrypto_Algorithm.
|
||||
#include "OEMCryptoCENC.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
enum BufferType {
|
||||
@@ -100,15 +104,35 @@ class SessionContext {
|
||||
size_t message_length,
|
||||
uint8_t* signature,
|
||||
size_t* signature_length);
|
||||
size_t RSASignatureSize();
|
||||
bool GenerateRSASignature(const uint8_t* message,
|
||||
size_t message_length,
|
||||
uint8_t* signature,
|
||||
size_t* signature_length);
|
||||
|
||||
bool ValidateMessage(const uint8_t* message,
|
||||
size_t message_length,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length);
|
||||
bool Generic_Encrypt(const uint8_t* in_buffer,
|
||||
size_t buffer_length,
|
||||
const uint8_t* iv,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
uint8_t* out_buffer);
|
||||
bool Generic_Decrypt(const uint8_t* in_buffer,
|
||||
size_t buffer_length,
|
||||
const uint8_t* iv,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
uint8_t* out_buffer);
|
||||
bool Generic_Sign(const uint8_t* in_buffer,
|
||||
size_t buffer_length,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
uint8_t* signature,
|
||||
size_t* signature_length);
|
||||
bool Generic_Verify(const uint8_t* in_buffer,
|
||||
size_t buffer_length,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length);
|
||||
void StartTimer();
|
||||
uint32_t CurrentTimer(); // (seconds).
|
||||
bool InstallKey(const KeyId& key_id,
|
||||
|
||||
@@ -29,6 +29,10 @@ enum KeyType {
|
||||
const uint32_t kControlObserveDataPath = (1<<31);
|
||||
const uint32_t kControlObserveHDCP = (1<<30);
|
||||
const uint32_t kControlObserveCGMS = (1<<29);
|
||||
const uint32_t kControlAllowEncrypt = (1<<8);
|
||||
const uint32_t kControlAllowDecrypt = (1<<7);
|
||||
const uint32_t kControlAllowSign = (1<<6);
|
||||
const uint32_t kControlAllowVerify = (1<<5);
|
||||
const uint32_t kControlDataPathSecure = (1<<4);
|
||||
const uint32_t kControlNonceEnabled = (1<<3);
|
||||
const uint32_t kControlHDCPRequired = (1<<2);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "log.h"
|
||||
#include "oemcrypto_engine_mock.h"
|
||||
#include "openssl/rand.h"
|
||||
#include "openssl/sha.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace wvoec_mock {
|
||||
@@ -207,6 +208,11 @@ OEMCryptoResult OEMCrypto_GenerateSignature(
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
|
||||
if (*signature_length < SHA256_DIGEST_LENGTH) {
|
||||
*signature_length = SHA256_DIGEST_LENGTH;
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
|
||||
if (message == NULL || message_length == 0 ||
|
||||
signature == NULL || signature_length == 0) {
|
||||
LOGE("[OEMCrypto_GenerateSignature(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
@@ -304,7 +310,7 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
if (!RangeCheck(message, message_length, key_array[i].key_id,
|
||||
key_array[i].key_id_length, false) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_data,
|
||||
wvcdm::KEY_SIZE, false) ||
|
||||
key_array[i].key_data_length, false) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_data_iv,
|
||||
wvcdm::KEY_IV_SIZE, false) ||
|
||||
!RangeCheck(message, message_length, key_array[i].key_control,
|
||||
@@ -334,7 +340,7 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
|
||||
key_id.assign(key_array[i].key_id,
|
||||
key_array[i].key_id + key_array[i].key_id_length);
|
||||
enc_key_data.assign(key_array[i].key_data,
|
||||
key_array[i].key_data + wvcdm::KEY_SIZE);
|
||||
key_array[i].key_data + key_array[i].key_data_length);
|
||||
key_data_iv.assign(key_array[i].key_data_iv,
|
||||
key_array[i].key_data_iv + wvcdm::KEY_IV_SIZE);
|
||||
if (key_array[i].key_control == NULL) {
|
||||
@@ -653,7 +659,7 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session,
|
||||
size_t message_length,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length,
|
||||
uint32_t* nonce,
|
||||
const uint32_t* nonce,
|
||||
const uint8_t* enc_rsa_key,
|
||||
size_t enc_rsa_key_length,
|
||||
const uint8_t* enc_rsa_key_iv,
|
||||
@@ -673,12 +679,12 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session,
|
||||
}
|
||||
// For the reference implementation, the wrapped key and the encrypted
|
||||
// key are the same size -- just encrypted with different keys.
|
||||
// We add 32 bytes for a context, and 32 bytes for a signature.
|
||||
// We add 32 bytes for a context, 32 for iv, and 32 bytes for a signature.
|
||||
// Important: This layout must match OEMCrypto_LoadDeviceRSAKey below.
|
||||
size_t buffer_size = enc_rsa_key_length + sizeof(WrappedRSAKey);
|
||||
|
||||
if (wrapped_rsa_key == NULL || *wrapped_rsa_key_length < buffer_size) {
|
||||
LOGW("[OEMCrypto_RewrapDeviceRSAKey(): ERROR_KEYBOX_INVALID]");
|
||||
LOGW("[OEMCrypto_RewrapDeviceRSAKey(): Wrapped Keybox Short Buffer]");
|
||||
*wrapped_rsa_key_length = buffer_size;
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
@@ -699,13 +705,13 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session,
|
||||
}
|
||||
|
||||
// Range check
|
||||
if (!RangeCheck(message, message_length, reinterpret_cast<uint8_t*>(nonce),
|
||||
if (!RangeCheck(message, message_length, reinterpret_cast<const uint8_t*>(nonce),
|
||||
sizeof(uint32_t), true) ||
|
||||
!RangeCheck(message, message_length, enc_rsa_key, enc_rsa_key_length,
|
||||
true) ||
|
||||
!RangeCheck(message, message_length, enc_rsa_key_iv, wvcdm::KEY_IV_SIZE,
|
||||
true)) {
|
||||
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_SIGNATURE_FAILURE - range check.]");
|
||||
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): - range check.]");
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
|
||||
@@ -739,13 +745,6 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session,
|
||||
if (!session_ctx->DeriveKeys(mac_ctx_str, mac_ctx_str)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// Encrypt rsa key with keybox.
|
||||
if (!session_ctx->EncryptRSAKey(wrapped->enc_rsa_key,
|
||||
@@ -754,8 +753,19 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session,
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -764,9 +774,14 @@ extern "C"
|
||||
OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session,
|
||||
const uint8_t* wrapped_rsa_key,
|
||||
size_t wrapped_rsa_key_length) {
|
||||
const WrappedRSAKey* wrapped
|
||||
= reinterpret_cast<const WrappedRSAKey*>(wrapped_rsa_key);
|
||||
if (trace_all_calls) {
|
||||
printf("-- OEMCryptoResult OEMCrypto_LoadDeviceRSAKey()\n");
|
||||
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));
|
||||
}
|
||||
|
||||
if (wrapped_rsa_key == NULL) {
|
||||
@@ -784,9 +799,6 @@ OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session,
|
||||
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): ERROR_NO_INVALID_SESSION]");
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
// Now we generate a wrapped keybox.
|
||||
const WrappedRSAKey* wrapped
|
||||
= reinterpret_cast<const WrappedRSAKey*>(wrapped_rsa_key);
|
||||
const std::vector<uint8_t> mac_ctx_str(wrapped->context,
|
||||
wrapped->context + sizeof(wrapped->context));
|
||||
// Generate mac and encryption keys for encrypting the signature.
|
||||
@@ -821,8 +833,7 @@ OEMCryptoResult OEMCrypto_GenerateRSASignature(OEMCrypto_SESSION session,
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
|
||||
if (message == NULL || message_length == 0 ||
|
||||
signature == NULL || signature_length == 0) {
|
||||
if (signature_length == 0) {
|
||||
LOGE("[OEMCrypto_GenerateRSASignature(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
@@ -832,6 +843,19 @@ OEMCryptoResult OEMCrypto_GenerateRSASignature(OEMCrypto_SESSION session,
|
||||
LOGE("[OEMCrypto_GenerateRSASignature(): ERROR_NO_INVALID_SESSION]");
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
|
||||
size_t required_size = session_ctx->RSASignatureSize();
|
||||
if (*signature_length < required_size) {
|
||||
*signature_length = required_size;
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
|
||||
if (message == NULL || message_length == 0 ||
|
||||
signature == NULL || signature_length == 0) {
|
||||
LOGE("[OEMCrypto_GenerateRSASignature(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
if (session_ctx->GenerateRSASignature(message,
|
||||
message_length,
|
||||
signature,
|
||||
@@ -890,4 +914,133 @@ OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
uint32_t OEMCrypto_APIVersion() {
|
||||
return oec_latest_version;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
const char* OEMCrypto_SecurityLevel() {
|
||||
return "L3";
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult OEMCrypto_Generic_Encrypt(OEMCrypto_SESSION session,
|
||||
const uint8_t* in_buffer,
|
||||
size_t buffer_length,
|
||||
const uint8_t* iv,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
uint8_t* out_buffer) {
|
||||
|
||||
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
||||
LOGE("[OEMCrypto_Generic_Enrypt(): ERROR_KEYBOX_INVALID]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (!session_ctx || !session_ctx->isValid()) {
|
||||
LOGE("[OEMCrypto_Generic_Enrypt(): ERROR_NO_INVALID_SESSION]");
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
if (in_buffer == NULL || buffer_length == 0 ||
|
||||
iv == NULL || out_buffer == NULL) {
|
||||
LOGE("[OEMCrypto_Generic_Enrypt(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
if (!session_ctx->Generic_Encrypt(in_buffer, buffer_length, iv, algorithm,
|
||||
out_buffer)) {
|
||||
LOGE("[OEMCrypto_Generic_Enrypt(): OEMCrypto_ERROR_UNKNOWN_FAILURE]");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult OEMCrypto_Generic_Decrypt(OEMCrypto_SESSION session,
|
||||
const uint8_t* in_buffer,
|
||||
size_t buffer_length,
|
||||
const uint8_t* iv,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
uint8_t* out_buffer) {
|
||||
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
||||
LOGE("[OEMCrypto_Generic_Decrypt(): ERROR_KEYBOX_INVALID]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (!session_ctx || !session_ctx->isValid()) {
|
||||
LOGE("[OEMCrypto_Generic_Decrypt(): ERROR_NO_INVALID_SESSION]");
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
if (!session_ctx->Generic_Decrypt(in_buffer, buffer_length, iv, algorithm,
|
||||
out_buffer)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (in_buffer == NULL || buffer_length == 0 ||
|
||||
iv == NULL || out_buffer == NULL) {
|
||||
LOGE("[OEMCrypto_Generic_Decrypt(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session,
|
||||
const uint8_t* in_buffer,
|
||||
size_t buffer_length,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
uint8_t* signature,
|
||||
size_t* signature_length) {
|
||||
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
||||
LOGE("[OEMCrypto_Generic_Sign(): ERROR_KEYBOX_INVALID]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (!session_ctx || !session_ctx->isValid()) {
|
||||
LOGE("[OEMCrypto_Generic_Sign(): ERROR_NO_INVALID_SESSION]");
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
if (*signature_length < SHA256_DIGEST_LENGTH) {
|
||||
*signature_length = SHA256_DIGEST_LENGTH;
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
if (in_buffer == NULL || buffer_length == 0 || signature == NULL) {
|
||||
LOGE("[OEMCrypto_Generic_Sign(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
if (!session_ctx->Generic_Sign(in_buffer, buffer_length, algorithm,
|
||||
signature, signature_length)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
OEMCryptoResult OEMCrypto_Generic_Verify(OEMCrypto_SESSION session,
|
||||
const uint8_t* in_buffer,
|
||||
size_t buffer_length,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length) {
|
||||
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
|
||||
LOGE("[OEMCrypto_Generic_Verify(): ERROR_KEYBOX_INVALID]");
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
SessionContext* session_ctx = crypto_engine->FindSession(session);
|
||||
if (!session_ctx || !session_ctx->isValid()) {
|
||||
LOGE("[OEMCrypto_Generic_Verify(): ERROR_NO_INVALID_SESSION]");
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
if (signature_length != SHA256_DIGEST_LENGTH) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (in_buffer == NULL || buffer_length == 0 || signature == NULL) {
|
||||
LOGE("[OEMCrypto_Generic_Verify(): OEMCrypto_ERROR_INVALID_CONTEXT]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
if (!session_ctx->Generic_Verify(in_buffer, buffer_length, algorithm,
|
||||
signature, signature_length)) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
}; // namespace wvoec_mock
|
||||
|
||||
@@ -38,7 +38,7 @@ std::vector<uint8_t> a2b_hex(const std::string& byte) {
|
||||
unsigned char lsb = 0; // least significant 4 bits
|
||||
if (!CharToDigit(byte[i * 2], &msb) ||
|
||||
!CharToDigit(byte[i * 2 + 1], &lsb)) {
|
||||
LOGE("Invalid hex value %c%c at index %d", byte[i*2], byte[i*2+1], i);
|
||||
LOGE("Invalid hex value %c%c at index %d", byte[i * 2], byte[i * 2 + 1], i);
|
||||
return array;
|
||||
}
|
||||
array.push_back((msb << 4) | lsb);
|
||||
|
||||
@@ -80,7 +80,7 @@ uint32_t wvrunningcrc32(uint8_t* p_begin, int i_count, uint32_t i_crc) {
|
||||
|
||||
/* Calculate the CRC */
|
||||
while (i_count > 0) {
|
||||
i_crc = (i_crc << 8) ^ CRC32[(i_crc >> 24) ^ ((uint32_t) * p_begin) ];
|
||||
i_crc = (i_crc << 8) ^ CRC32[(i_crc >> 24) ^ ((uint32_t) * p_begin)];
|
||||
p_begin++;
|
||||
i_count--;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user