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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user