Support CAST V2 authentication - OEMCrypto Interface - DO NOT MERGE

Squashed commit of these CLs from the widevine cdm repo:

Allow Version 8 OEMCrypto to be linked with CDM (KLP Modular Branch)
https://widevine-internal-review.googlesource.com/#/c/9434/

Allow OEMCrypto v8 or v9 (KLP Modular Branch)
https://widevine-internal-review.googlesource.com/#/c/9172/

Add alternate RSA signing (KLP Modular Branch)
https://widevine-internal-review.googlesource.com/#/c/9171/

bug: 12702350
Change-Id: Ifd0c88c566bb10efe2411af49bc83265ed56cb23
This commit is contained in:
Fred Gylys-Colwell
2014-03-24 13:46:38 -07:00
parent f1e87b1b04
commit a59b935928
14 changed files with 1930 additions and 322 deletions

View File

@@ -8,6 +8,7 @@
#include "oemcrypto_engine_mock.h"
#include <arpa/inet.h>
#include <iostream>
#include <vector>
#include <string.h>
@@ -31,8 +32,9 @@
static const int kPssSaltLength = 20;
namespace {
// Increment counter for AES-CTR
void ctr128_inc(uint8_t* counter) {
// Increment counter for AES-CTR. The CENC spec specifies we increment only
// the low 64 bits of the IV counter, and leave the high 64 bits alone.
void ctr128_inc64(uint8_t* counter) {
uint32_t n = 16;
do {
if (++counter[--n] != 0) return;
@@ -252,7 +254,8 @@ size_t SessionContext::RSASignatureSize() {
bool SessionContext::GenerateRSASignature(const uint8_t* message,
size_t message_length,
uint8_t* signature,
size_t* signature_length) {
size_t* signature_length,
RSA_Padding_Scheme padding_scheme) {
if (message == NULL || message_length == 0 ||
signature == NULL || signature_length == 0) {
LOGE("[GenerateRSASignature(): OEMCrypto_ERROR_INVALID_CONTEXT]");
@@ -266,33 +269,55 @@ bool SessionContext::GenerateRSASignature(const uint8_t* message,
*signature_length = RSA_size(rsa_key_);
return false;
}
// 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();
if ((padding_scheme & allowed_schemes_) != padding_scheme) {
LOGE("[GenerateRSASignature(): padding_scheme not allowed]");
return false;
}
// Add PSS padding.
std::vector<uint8_t> padded_digest(*signature_length);
int status = RSA_padding_add_PKCS1_PSS(rsa_key_, &padded_digest[0], hash,
EVP_sha1(), kPssSaltLength);
if (status == -1) {
LOGE("[GeneratRSASignature(): error padding hash.]");
dump_openssl_error();
if (padding_scheme == kSign_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;
}
// Add PSS padding.
std::vector<uint8_t> padded_digest(*signature_length);
int status = RSA_padding_add_PKCS1_PSS(rsa_key_, &padded_digest[0], 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[0], signature,
rsa_key_, RSA_NO_PADDING);
if (status == -1) {
LOGE("[GeneratRSASignature(): error in private encrypt.]");
dump_openssl_error();
return false;
}
} else if (padding_scheme == kSign_PKCS1_Block1) {
if (message_length > 83) {
LOGE("[GeneratRSASignature(): RSA digest too large.]");
return false;
}
// Pad the message with PKCS1 padding, and then encrypt.
int status = RSA_private_encrypt(message_length, message, signature,
rsa_key_, RSA_PKCS1_PADDING);
if (status != *signature_length) {
LOGE("[GeneratRSASignature(): error in RSA private encrypt. status=%d]", status);
dump_openssl_error();
return false;
}
} else { // Bad RSA_Padding_Scheme
return false;
}
// Encrypt PSS padded digest.
status = RSA_private_encrypt(*signature_length, &padded_digest[0], signature,
rsa_key_, RSA_NO_PADDING);
if (status == -1) {
LOGE("[GeneratRSASignature(): error in private encrypt.]");
dump_openssl_error();
return false;
}
return true;
}
@@ -485,6 +510,16 @@ bool SessionContext::LoadRSAKey(uint8_t* pkcs8_rsa_key,
RSA_free(rsa_key_);
rsa_key_ = NULL;
}
if (rsa_key_length < 8) {
LOGE("[LoadRSAKey(): Very Short Buffer]");
return false;
}
if( (memcmp(pkcs8_rsa_key, "SIGN", 4) == 0) ) {
uint32_t *schemes_n = (uint32_t *)(pkcs8_rsa_key + 4);
allowed_schemes_ = htonl(*schemes_n);
pkcs8_rsa_key += 8;
rsa_key_length -= 8;
}
BIO *bio = BIO_new_mem_buf(pkcs8_rsa_key, rsa_key_length);
if( bio == NULL ) {
LOGE("[LoadRSAKey(): Could not allocate bio buffer]");
@@ -899,11 +934,11 @@ bool CryptoEngine::DecryptCTR(SessionContext* session,
const uint8_t* cipher_data,
size_t cipher_data_length,
bool is_encrypted,
void* clear_data,
uint8_t* clear_data,
BufferType buffer_type) {
// If the data is clear, we do not need a current key selected.
if (!is_encrypted) {
if (!is_encrypted && buffer_type != kBufferTypeDirect) {
memcpy(reinterpret_cast<uint8_t*>(clear_data),
cipher_data, cipher_data_length);
return true;
@@ -961,20 +996,20 @@ bool CryptoEngine::DecryptCTR(SessionContext* session,
// Encrypt the IV.
uint8_t ecount_buf[AES_BLOCK_SIZE];
if (block_offset != 0) {
// The context is needed only when not starting a new block.
AES_encrypt(aes_iv, ecount_buf, &aes_key);
ctr128_inc(aes_iv);
}
// Decryption.
unsigned int block_offset_cur = block_offset;
AES_ctr128_encrypt(
cipher_data, reinterpret_cast<uint8_t*>(clear_data), cipher_data_length,
&aes_key, aes_iv, ecount_buf, &block_offset_cur);
if (block_offset_cur != ((block_offset + cipher_data_length) % AES_BLOCK_SIZE)) {
LOGE("[DecryptCTR(): FAILURE: byte offset wrong.]");
return false;
// The CENC spec specifies we increment only the low 64 bits of the IV
// counter, and leave the high 64 bits alone. This is different from the
// OpenSSL implementation, which increments the entire 128 bit iv. That is
// why we implement the CTR loop ourselves.
size_t l = 0;
while (l < cipher_data_length) {
AES_encrypt(aes_iv, ecount_buf, &aes_key);
for (int n = block_offset; n < AES_BLOCK_SIZE && l < cipher_data_length;
++n, ++l) {
clear_data[l] = cipher_data[l] ^ ecount_buf[n];
}
ctr128_inc64(aes_iv);
block_offset = 0;
}
return true;
}

View File

@@ -88,7 +88,7 @@ class SessionContext {
public:
explicit SessionContext(CryptoEngine* ce, SessionId sid)
: valid_(true), ce_(ce), id_(sid), current_content_key_(NULL),
rsa_key_(NULL) {}
rsa_key_(NULL), allowed_schemes_(kSign_RSASSA_PSS) {}
~SessionContext() {}
void Open();
@@ -110,7 +110,8 @@ class SessionContext {
bool GenerateRSASignature(const uint8_t* message,
size_t message_length,
uint8_t* signature,
size_t* signature_length);
size_t* signature_length,
RSA_Padding_Scheme padding_scheme);
bool ValidateMessage(const uint8_t* message,
size_t message_length,
const uint8_t* signature,
@@ -177,6 +178,7 @@ class SessionContext {
encryption_key_ = enc_key;
}
const std::vector<uint8_t>& encryption_key() { return encryption_key_; }
const uint32_t allowed_schemes() { return allowed_schemes_; }
void AddNonce(uint32_t nonce);
bool CheckNonce(uint32_t nonce);
@@ -198,6 +200,7 @@ class SessionContext {
SessionKeyTable session_keys_;
NonceTable nonce_table_;
RSA* rsa_key_;
uint32_t allowed_schemes_; // for RSA signatures.
time_t timer_start_;
CORE_DISALLOW_COPY_AND_ASSIGN(SessionContext);
@@ -251,7 +254,7 @@ class CryptoEngine {
const uint8_t* cipher_data,
size_t cipher_data_length,
bool is_encrypted,
void* clear_data,
uint8_t* clear_data,
BufferType buffer_type);
private:

View File

@@ -18,6 +18,9 @@
namespace wvoec_mock {
const WidevineKeybox kDefaultKeybox = {
// change to #if 0 for test provisioning server with mock library
#if 1
// Sample keybox used for test vectors
{
// deviceID
@@ -47,6 +50,38 @@ const WidevineKeybox kDefaultKeybox = {
// Crc
0x0a, 0x7a, 0x2c, 0x35,
}
#else
// Test keybox for temporary CAST provisioning server
{
// deviceID
0x61, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // a1
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
}, {
// key
0x92, 0x13, 0xa7, 0xb0, 0x0e, 0xd9, 0x2c, 0xb0,
0xba, 0x61, 0xc1, 0x89, 0x1f, 0x45, 0x34, 0x4a,
}, {
// data
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x04,
0x20, 0x8b, 0xf0, 0xba, 0x89, 0x39, 0x73, 0xb6,
0x59, 0x82, 0x62, 0xa4, 0x72, 0x0c, 0xfe, 0xf4,
0x70, 0xa7, 0x0a, 0xc6, 0xe5, 0x7c, 0x5e, 0x04,
0x43, 0x8f, 0xa2, 0x87, 0x2b, 0xe1, 0x01, 0x67,
0xba, 0x04, 0x99, 0x73, 0xe1, 0x92, 0x6e, 0x6e,
0x9a, 0xf7, 0x67, 0x4e, 0xcd, 0xff, 0xb8, 0x43,
0xc0, 0xb7, 0xa5, 0x5e, 0xc4, 0xd7, 0x3f, 0x35,
0xf3, 0xc1, 0x84, 0x22, 0xe6, 0xf8, 0x2e, 0xfc,
}, {
// magic
0x6b, 0x62, 0x6f, 0x78,
}, {
// Crc
0x74, 0x57, 0x35, 0x2f,
}
#endif
};
WvKeybox::WvKeybox() : valid_(false) {

View File

@@ -895,7 +895,7 @@ OEMCryptoResult OEMCrypto_GenerateRSASignature(OEMCrypto_SESSION session,
size_t message_length,
uint8_t* signature,
size_t* signature_length,
RSA_Padding_Scheme algorithm) {
RSA_Padding_Scheme padding_scheme) {
if (trace_all_calls) {
printf("-- OEMCryptoResult OEMCrypto_GenerateRSASignature()\n");
dump_hex("message", message, message_length);
@@ -928,15 +928,11 @@ OEMCryptoResult OEMCrypto_GenerateRSASignature(OEMCrypto_SESSION session,
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (algorithm != kSign_RSASSA_PSS) {
LOGE("[OEMCrypto_GenerateRSASignature(): OEMCrypto_ERROR_NOT_IMPLEMENTED]");
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
if (session_ctx->GenerateRSASignature(message,
message_length,
signature,
signature_length)) {
signature_length,
padding_scheme)) {
if (trace_all_calls) {
dump_hex("signature", signature, *signature_length);
}
@@ -971,6 +967,11 @@ OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(
return OEMCrypto_ERROR_INVALID_SESSION;
}
if (session_ctx->allowed_schemes() != kSign_RSASSA_PSS) {
LOGE("[OEMCrypto_GenerateDerivedKeys(): x509 key used to derive keys]");
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
const std::vector<uint8_t> ssn_key_str(enc_session_key,
enc_session_key + enc_session_key_length);
const std::vector<uint8_t> mac_ctx_str(mac_key_context,