Refactor OEMCrypto Unit Tests

Merge from widevine repo of http://go/wvgerrit/21681

This CL refactors some oemcrypto unit tests in preparation for adding
Provisioning 3.0 tests.

- The signature GenerateNonce has changed.  Instead of the caller
  passing in a pointer for the nonce, we store the nonce in a member
  variable of Session.

- GenerateDerivedKeys is being replaced by InstallTestSessionKeys.
  This sets up and calls the appropriate derive keys method.  This
  function is in the test class, instead of the session class so that
  multiple sessions in a class can share the same wrapped rsa key.
  This will be modified for provisioning 3.0 in a future CL.

- Rename tests that require a keybox.  Some tests are specific for
  using a keybox to request a DRM cert. These tests are renamed so we
  can filter them out on devices that use an OEM Cert.  Corresponding
  tests for devices using provisioning 3.0 will be in a future CL.

- Some member variables and methods in the class Session were not
  used.  They are removed.

- Added openssl smart pointer.

- Comments.  I added comments.

- clang format.

Change-Id: Ib579a322858e0ef92652a42167241b35cf85a041
This commit is contained in:
Fred Gylys-Colwell
2016-11-29 15:05:23 -08:00
parent 4cac936b10
commit 0fb76d5c1b
6 changed files with 433 additions and 325 deletions

View File

@@ -33,6 +33,7 @@ class WvGenericOperationsTest : public testing::Test {
virtual void SetUp() { virtual void SetUp() {
::testing::Test::SetUp(); ::testing::Test::SetUp();
// TODO(fredgc or gmorgan): This should be updated for provisioning 3.0
// Load test keybox. This keybox will be used by any CryptoSession // Load test keybox. This keybox will be used by any CryptoSession
// created by the CDM under test. // created by the CDM under test.
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestKeybox()); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestKeybox());
@@ -72,7 +73,8 @@ class WvGenericOperationsTest : public testing::Test {
void OecSessionSetup(uint32_t oec_session_id) { void OecSessionSetup(uint32_t oec_session_id) {
buffer_size_ = 160; buffer_size_ = 160;
oec_util_session_.SetSessionId(oec_session_id); oec_util_session_.SetSessionId(oec_session_id);
oec_util_session_.GenerateTestSessionKeys(); // TODO(fredgc or gmorgan): This should be updated for provisioning 3.0
oec_util_session_.GenerateDerivedKeysFromKeybox();
MakeFourKeys(); MakeFourKeys();
} }
@@ -202,7 +204,8 @@ TEST_F(WvGenericOperationsTest, NormalSessionOpenClose) {
TEST_F(WvGenericOperationsTest, GenerateSessionKeys) { TEST_F(WvGenericOperationsTest, GenerateSessionKeys) {
wvoec::Session s; wvoec::Session s;
ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); // TODO(fredgc or gmorgan): This should be updated for provisioning 3.0
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox());
ASSERT_NO_FATAL_FAILURE(s.close()); ASSERT_NO_FATAL_FAILURE(s.close());
} }

View File

@@ -9,8 +9,10 @@
#include <openssl/aes.h> #include <openssl/aes.h>
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/hmac.h> #include <openssl/hmac.h>
#include <openssl/pem.h>
#include <openssl/rand.h> #include <openssl/rand.h>
#include <openssl/x509.h> #include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include <stdint.h> #include <stdint.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
@@ -18,13 +20,14 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "OEMCryptoCENC.h"
#include "log.h" #include "log.h"
#include "oec_device_features.h" #include "oec_device_features.h"
#include "oec_test_data.h" #include "oec_test_data.h"
#include "oemcrypto_key_mock.h" #include "oemcrypto_key_mock.h"
#include "OEMCryptoCENC.h"
#include "string_conversions.h" #include "string_conversions.h"
#include "wv_cdm_constants.h" #include "wv_cdm_constants.h"
#include "wv_cdm_types.h"
#include "wv_keybox.h" #include "wv_keybox.h"
using namespace std; using namespace std;
@@ -69,6 +72,23 @@ void dump_openssl_error() {
} }
} }
template <typename T, void (*func)(T*)>
class openssl_ptr {
public:
explicit openssl_ptr(T* p = NULL) : ptr_(p) {}
~openssl_ptr() {
if (ptr_) func(ptr_);
}
T& operator*() const { return *ptr_; }
T* operator->() const { return ptr_; }
T* get() const { return ptr_; }
bool NotNull() { return ptr_; }
private:
T* ptr_;
CORE_DISALLOW_COPY_AND_ASSIGN(openssl_ptr);
};
Session::Session() Session::Session()
: open_(false), : open_(false),
forced_session_id_(false), forced_session_id_(false),
@@ -113,8 +133,8 @@ void Session::close() {
open_ = false; open_ = false;
} }
void Session::GenerateNonce(uint32_t* nonce, int* error_counter) { void Session::GenerateNonce(int* error_counter) {
if (OEMCrypto_SUCCESS == OEMCrypto_GenerateNonce(session_id(), nonce)) { if (OEMCrypto_SUCCESS == OEMCrypto_GenerateNonce(session_id(), &nonce_)) {
return; return;
} }
if (error_counter) { if (error_counter) {
@@ -122,7 +142,7 @@ void Session::GenerateNonce(uint32_t* nonce, int* error_counter) {
} else { } else {
sleep(1); // wait a second, then try again. sleep(1); // wait a second, then try again.
ASSERT_EQ(OEMCrypto_SUCCESS, ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_GenerateNonce(session_id(), nonce)); OEMCrypto_GenerateNonce(session_id(), &nonce_));
} }
} }
@@ -148,7 +168,7 @@ void Session::FillDefaultContext(vector<uint8_t>* mac_context,
} }
void Session::GenerateDerivedKeysFromKeybox() { void Session::GenerateDerivedKeysFromKeybox() {
GenerateNonce(&nonce_); GenerateNonce();
vector<uint8_t> mac_context; vector<uint8_t> mac_context;
vector<uint8_t> enc_context; vector<uint8_t> enc_context;
FillDefaultContext(&mac_context, &enc_context); FillDefaultContext(&mac_context, &enc_context);
@@ -168,10 +188,11 @@ void Session::GenerateDerivedKeysFromKeybox() {
void Session::GenerateDerivedKeysFromSessionKey() { void Session::GenerateDerivedKeysFromSessionKey() {
// Uses test certificate. // Uses test certificate.
GenerateNonce(&nonce_); GenerateNonce();
vector<uint8_t> session_key;
vector<uint8_t> enc_session_key; vector<uint8_t> enc_session_key;
PreparePublicKey(); PreparePublicKey();
ASSERT_TRUE(GenerateRSASessionKey(&enc_session_key)); ASSERT_TRUE(GenerateRSASessionKey(&session_key, &enc_session_key));
vector<uint8_t> mac_context; vector<uint8_t> mac_context;
vector<uint8_t> enc_context; vector<uint8_t> enc_context;
FillDefaultContext(&mac_context, &enc_context); FillDefaultContext(&mac_context, &enc_context);
@@ -190,14 +211,6 @@ void Session::GenerateDerivedKeysFromSessionKey() {
enc_key_ = wvcdm::a2b_hex("CB477D09014D72C9B8DCE76C33EA43B3"); enc_key_ = wvcdm::a2b_hex("CB477D09014D72C9B8DCE76C33EA43B3");
} }
void Session::GenerateTestSessionKeys() {
if (global_features.derive_key_method == DeviceFeatures::LOAD_TEST_RSA_KEY) {
GenerateDerivedKeysFromSessionKey();
} else {
GenerateDerivedKeysFromKeybox();
}
}
void Session::LoadTestKeys(const std::string& pst, bool new_mac_keys) { void Session::LoadTestKeys(const std::string& pst, bool new_mac_keys) {
uint8_t* pst_ptr = NULL; uint8_t* pst_ptr = NULL;
if (pst.length() > 0) { if (pst.length() > 0) {
@@ -236,9 +249,11 @@ void Session::VerifyTestKeys() {
// control duration and bits stored in network byte order. For printing // control duration and bits stored in network byte order. For printing
// we change to host byte order. // we change to host byte order.
ASSERT_EQ((htonl_fnc(license_.keys[i].control.duration)), ASSERT_EQ((htonl_fnc(license_.keys[i].control.duration)),
(htonl_fnc(block.duration))) << "For key " << i; (htonl_fnc(block.duration)))
<< "For key " << i;
ASSERT_EQ(htonl_fnc(license_.keys[i].control.control_bits), ASSERT_EQ(htonl_fnc(license_.keys[i].control.control_bits),
htonl_fnc(block.control_bits)) << "For key " << i; htonl_fnc(block.control_bits))
<< "For key " << i;
} }
} }
} }
@@ -278,8 +293,8 @@ void Session::SetKeyId(int index, const string& key_id) {
void Session::FillSimpleMessage(uint32_t duration, uint32_t control, void Session::FillSimpleMessage(uint32_t duration, uint32_t control,
uint32_t nonce, const std::string& pst) { uint32_t nonce, const std::string& pst) {
EXPECT_EQ(1, RAND_pseudo_bytes(license_.mac_key_iv, EXPECT_EQ(
sizeof(license_.mac_key_iv))); 1, RAND_pseudo_bytes(license_.mac_key_iv, sizeof(license_.mac_key_iv)));
EXPECT_EQ(1, RAND_pseudo_bytes(license_.mac_keys, sizeof(license_.mac_keys))); EXPECT_EQ(1, RAND_pseudo_bytes(license_.mac_keys, sizeof(license_.mac_keys)));
for (unsigned int i = 0; i < num_keys_; i++) { for (unsigned int i = 0; i < num_keys_; i++) {
memset(license_.keys[i].key_id, 0, kTestKeyIdMaxLength); memset(license_.keys[i].key_id, 0, kTestKeyIdMaxLength);
@@ -353,8 +368,10 @@ void Session::EncryptAndSign() {
FillKeyArray(encrypted_license(), key_array_); FillKeyArray(encrypted_license(), key_array_);
} }
void Session::EncryptMessage(RSAPrivateKeyMessage* data, void Session::EncryptProvisioningMessage(
RSAPrivateKeyMessage* encrypted) { RSAPrivateKeyMessage* data, RSAPrivateKeyMessage* encrypted,
const vector<uint8_t>& encryption_key) {
ASSERT_EQ(encryption_key.size(), wvcdm::KEY_SIZE);
*encrypted = *data; *encrypted = *data;
size_t padding = wvcdm::KEY_SIZE - (data->rsa_key_length % wvcdm::KEY_SIZE); size_t padding = wvcdm::KEY_SIZE - (data->rsa_key_length % wvcdm::KEY_SIZE);
memset(data->rsa_key + data->rsa_key_length, static_cast<uint8_t>(padding), memset(data->rsa_key + data->rsa_key_length, static_cast<uint8_t>(padding),
@@ -363,7 +380,7 @@ void Session::EncryptMessage(RSAPrivateKeyMessage* data,
uint8_t iv_buffer[16]; uint8_t iv_buffer[16];
memcpy(iv_buffer, &data->rsa_key_iv[0], wvcdm::KEY_IV_SIZE); memcpy(iv_buffer, &data->rsa_key_iv[0], wvcdm::KEY_IV_SIZE);
AES_KEY aes_key; AES_KEY aes_key;
AES_set_encrypt_key(&enc_key_[0], 128, &aes_key); AES_set_encrypt_key(&encryption_key[0], 128, &aes_key);
AES_cbc_encrypt(&data->rsa_key[0], &encrypted->rsa_key[0], AES_cbc_encrypt(&data->rsa_key[0], &encrypted->rsa_key[0],
encrypted->rsa_key_length, &aes_key, iv_buffer, AES_ENCRYPT); encrypted->rsa_key_length, &aes_key, iv_buffer, AES_ENCRYPT);
} }
@@ -385,17 +402,15 @@ void Session::ClientSignMessage(const vector<uint8_t>& data,
&(data.front()), data.size(), &(signature->front()), &md_len); &(data.front()), data.size(), &(signature->front()), &md_len);
} }
// This verifies the signature computed by OEMCrypto using the client mac keys.
// This is used when a device requests a license renewal. It is also used for
// a license request authenticated by a keybox. The first use case is needed
// for devices with a keybox or without.
void Session::VerifyClientSignature(size_t data_length) { void Session::VerifyClientSignature(size_t data_length) {
// In the real world, a message should be signed by the client and
// verified by the server. This simulates that.
vector<uint8_t> data(data_length); vector<uint8_t> data(data_length);
for(int i=0; i < data.size(); i++) data[i] = i % 0xFF; for (int i = 0; i < data.size(); i++) data[i] = i % 0xFF;
OEMCryptoResult sts; OEMCryptoResult sts;
size_t gen_signature_length = 0; size_t gen_signature_length = 0;
sts = OEMCrypto_GenerateSignature(session_id(), &data[0], data.size(), sts = OEMCrypto_GenerateSignature(session_id(), &data[0], data.size(), NULL,
NULL, &gen_signature_length); &gen_signature_length);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
ASSERT_EQ(static_cast<size_t>(32), gen_signature_length); ASSERT_EQ(static_cast<size_t>(32), gen_signature_length);
vector<uint8_t> gen_signature(gen_signature_length); vector<uint8_t> gen_signature(gen_signature_length);
@@ -520,36 +535,9 @@ void Session::MakeRSACertificate(struct RSAPrivateKeyMessage* encrypted,
size_t message_size, size_t message_size,
std::vector<uint8_t>* signature, std::vector<uint8_t>* signature,
uint32_t allowed_schemes, uint32_t allowed_schemes,
const vector<uint8_t>& rsa_key) { const vector<uint8_t>& rsa_key,
// Dummy context for testing signature generation. const vector<uint8_t>* encryption_key) {
vector<uint8_t> context = wvcdm::a2b_hex( if (encryption_key == NULL) encryption_key = &enc_key_;
"0a4c08001248000000020000101907d9ffde13aa95c122678053362136bdf840"
"8f8276e4c2d87ec52b61aa1b9f646e58734930acebe899b3e464189a14a87202"
"fb02574e70640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931"
"b76a3a85f046523e10011a09393837363534333231180120002a0c3138383637"
"38373430350000");
OEMCryptoResult sts;
// Generate signature
size_t gen_signature_length = 0;
sts = OEMCrypto_GenerateSignature(session_id(), &context[0], context.size(),
NULL, &gen_signature_length);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
ASSERT_EQ(static_cast<size_t>(32), gen_signature_length);
vector<uint8_t> gen_signature(gen_signature_length);
sts = OEMCrypto_GenerateSignature(session_id(), &context[0], context.size(),
&gen_signature[0], &gen_signature_length);
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
std::vector<uint8_t> expected_signature;
ClientSignMessage(context, &expected_signature);
ASSERT_EQ(expected_signature, gen_signature);
// Rewrap Canned Response
// In the real world, the signature above would just have been used to
// contact the certificate provisioning server to get this response.
struct RSAPrivateKeyMessage message; struct RSAPrivateKeyMessage message;
if (allowed_schemes != kSign_RSASSA_PSS) { if (allowed_schemes != kSign_RSASSA_PSS) {
uint32_t algorithm_n = htonl(allowed_schemes); uint32_t algorithm_n = htonl(allowed_schemes);
@@ -564,7 +552,7 @@ void Session::MakeRSACertificate(struct RSAPrivateKeyMessage* encrypted,
EXPECT_EQ(1, RAND_pseudo_bytes(message.rsa_key_iv, wvcdm::KEY_IV_SIZE)); EXPECT_EQ(1, RAND_pseudo_bytes(message.rsa_key_iv, wvcdm::KEY_IV_SIZE));
message.nonce = nonce_; message.nonce = nonce_;
EncryptMessage(&message, encrypted); EncryptProvisioningMessage(&message, encrypted, *encryption_key);
ServerSignBuffer(reinterpret_cast<const uint8_t*>(encrypted), message_size, ServerSignBuffer(reinterpret_cast<const uint8_t*>(encrypted), message_size,
signature); signature);
} }
@@ -601,35 +589,29 @@ void Session::PreparePublicKey(const uint8_t* rsa_key, size_t rsa_key_length) {
rsa_key_length = sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048); rsa_key_length = sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048);
} }
uint8_t* p = const_cast<uint8_t*>(rsa_key); uint8_t* p = const_cast<uint8_t*>(rsa_key);
BIO* bio = BIO_new_mem_buf(p, rsa_key_length); openssl_ptr<BIO, BIO_vfree> bio(BIO_new_mem_buf(p, rsa_key_length));
ASSERT_TRUE(NULL != bio); ASSERT_TRUE(bio.NotNull());
PKCS8_PRIV_KEY_INFO* pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL); openssl_ptr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free> pkcs8_pki(
ASSERT_TRUE(NULL != pkcs8_pki); d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), NULL));
EVP_PKEY* evp = NULL; ASSERT_TRUE(pkcs8_pki.NotNull());
evp = EVP_PKCS82PKEY(pkcs8_pki); openssl_ptr<EVP_PKEY, EVP_PKEY_free> evp(EVP_PKCS82PKEY(pkcs8_pki.get()));
ASSERT_TRUE(NULL != evp); ASSERT_TRUE(evp.NotNull());
if (public_rsa_) RSA_free(public_rsa_); if (public_rsa_) RSA_free(public_rsa_);
public_rsa_ = EVP_PKEY_get1_RSA(evp); public_rsa_ = EVP_PKEY_get1_RSA(evp.get());
EVP_PKEY_free(evp);
PKCS8_PRIV_KEY_INFO_free(pkcs8_pki);
BIO_free(bio);
if (!public_rsa_) { if (!public_rsa_) {
cout << "d2i_RSAPrivateKey failed. "; cout << "d2i_RSAPrivateKey failed. ";
dump_openssl_error(); dump_openssl_error();
ASSERT_TRUE(false); FAIL() << "Could not parse public RSA key.";
} }
switch (RSA_check_key(public_rsa_)) { switch (RSA_check_key(public_rsa_)) {
case 1: // valid. case 1: // valid.
ASSERT_TRUE(true);
return; return;
case 0: // not valid. case 0: // not valid.
cout << "[rsa key not valid] ";
dump_openssl_error(); dump_openssl_error();
ASSERT_TRUE(false); FAIL() << "[rsa key not valid] ";
default: // -1 == check failed. default: // -1 == check failed.
cout << "[error checking rsa key] ";
dump_openssl_error(); dump_openssl_error();
ASSERT_TRUE(false); FAIL() << "[error checking rsa key] ";
} }
} }
@@ -693,14 +675,12 @@ void Session::VerifyRSASignature(const vector<uint8_t>& message,
EXPECT_EQ(static_cast<size_t>(RSA_size(public_rsa_)), signature_length) EXPECT_EQ(static_cast<size_t>(RSA_size(public_rsa_)), signature_length)
<< "Signature size is wrong. " << signature_length << ", should be " << "Signature size is wrong. " << signature_length << ", should be "
<< RSA_size(public_rsa_) << "\n"; << RSA_size(public_rsa_) << "\n";
if (padding_scheme == kSign_RSASSA_PSS) { if (padding_scheme == kSign_RSASSA_PSS) {
EVP_PKEY* pkey = EVP_PKEY_new(); openssl_ptr<EVP_PKEY, EVP_PKEY_free> pkey(EVP_PKEY_new());
ASSERT_TRUE(EVP_PKEY_set1_RSA(pkey, public_rsa_) == 1); ASSERT_EQ(1, EVP_PKEY_set1_RSA(pkey.get(), public_rsa_));
const bool ok = VerifyPSSSignature(pkey, &message[0], message.size(), const bool ok = VerifyPSSSignature(pkey.get(), &message[0], message.size(),
signature, signature_length); signature, signature_length);
EVP_PKEY_free(pkey);
EXPECT_TRUE(ok) << "PSS signature check failed."; EXPECT_TRUE(ok) << "PSS signature check failed.";
} else if (padding_scheme == kSign_PKCS1_Block1) { } else if (padding_scheme == kSign_PKCS1_Block1) {
vector<uint8_t> padded_digest(signature_length); vector<uint8_t> padded_digest(signature_length);
@@ -717,20 +697,20 @@ void Session::VerifyRSASignature(const vector<uint8_t>& message,
} }
} }
bool Session::GenerateRSASessionKey(vector<uint8_t>* enc_session_key) { bool Session::GenerateRSASessionKey(vector<uint8_t>* session_key,
vector<uint8_t>* enc_session_key) {
if (!public_rsa_) { if (!public_rsa_) {
cout << "No public RSA key loaded in test code.\n"; cout << "No public RSA key loaded in test code.\n";
return false; return false;
} }
vector<uint8_t> session_key = *session_key = wvcdm::a2b_hex("6fa479c731d2770b6a61a5d1420bb9d1");
wvcdm::a2b_hex("6fa479c731d2770b6a61a5d1420bb9d1");
enc_session_key->assign(RSA_size(public_rsa_), 0); enc_session_key->assign(RSA_size(public_rsa_), 0);
int status = RSA_public_encrypt(session_key.size(), &session_key[0], int status = RSA_public_encrypt(session_key->size(), &(session_key->front()),
&(enc_session_key->front()), public_rsa_, &(enc_session_key->front()), public_rsa_,
RSA_PKCS1_OAEP_PADDING); RSA_PKCS1_OAEP_PADDING);
int size = static_cast<int>(RSA_size(public_rsa_)); int size = static_cast<int>(RSA_size(public_rsa_));
if (status != size) { if (status != size) {
cout << "GenerateRSASessionKey error encrypting session key. "; cout << "GenerateRSASessionKey error encrypting session key.\n";
dump_openssl_error(); dump_openssl_error();
return false; return false;
} }
@@ -744,21 +724,6 @@ void Session::InstallRSASessionTestKey(const vector<uint8_t>& wrapped_rsa_key) {
GenerateDerivedKeysFromSessionKey(); GenerateDerivedKeysFromSessionKey();
} }
void Session::DisallowDeriveKeys() {
GenerateNonce(&nonce_);
vector<uint8_t> enc_session_key;
PreparePublicKey();
ASSERT_TRUE(GenerateRSASessionKey(&enc_session_key));
vector<uint8_t> mac_context;
vector<uint8_t> enc_context;
FillDefaultContext(&mac_context, &enc_context);
ASSERT_NE(OEMCrypto_SUCCESS,
OEMCrypto_DeriveKeysFromSessionKey(
session_id(), &enc_session_key[0], enc_session_key.size(),
&mac_context[0], mac_context.size(), &enc_context[0],
enc_context.size()));
}
void Session::GenerateReport(const std::string& pst, bool expect_success, void Session::GenerateReport(const std::string& pst, bool expect_success,
Session* other) { Session* other) {
if (other) { // If other is specified, copy mac keys. if (other) { // If other is specified, copy mac keys.

View File

@@ -66,10 +66,10 @@ const size_t kTestKeyIdMaxLength = 16;
// Most content will use a key id that is 16 bytes long. // Most content will use a key id that is 16 bytes long.
const int kDefaultKeyIdLength = 16; const int kDefaultKeyIdLength = 16;
const size_t kMaxTestRSAKeyLength = 2000; // Rough estimate. const size_t kMaxTestRSAKeyLength = 2000; // Rough estimate.
const size_t kMaxPSTLength = 255; // In specification. const size_t kMaxPSTLength = 255; // In specification.
const size_t kMaxMessageSize = 8 * 1024; // In specification. const size_t kMaxMessageSize = 8 * 1024; // In specification.
const size_t kMaxDecryptSize = 100 * 1024; // In specification. const size_t kMaxDecryptSize = 100 * 1024; // In specification.
typedef struct { typedef struct {
uint8_t key_id[kTestKeyIdMaxLength]; uint8_t key_id[kTestKeyIdMaxLength];
@@ -92,6 +92,8 @@ struct MessageData {
uint8_t pst[kMaxPSTLength]; uint8_t pst[kMaxPSTLength];
}; };
// This structure will be signed to simulate a provisioning response from the
// server.
struct RSAPrivateKeyMessage { struct RSAPrivateKeyMessage {
uint8_t rsa_key[kMaxTestRSAKeyLength]; uint8_t rsa_key[kMaxTestRSAKeyLength];
uint8_t rsa_key_iv[wvcdm::KEY_IV_SIZE]; uint8_t rsa_key_iv[wvcdm::KEY_IV_SIZE];
@@ -116,84 +118,166 @@ class Session {
Session(); Session();
~Session(); ~Session();
// Returns the most recently generated nonce.
// Valid after call to GenerateNonce.
uint32_t get_nonce() { return nonce_; } uint32_t get_nonce() { return nonce_; }
// Valid after call to open().
uint32_t session_id() { return (uint32_t)session_id_; } uint32_t session_id() { return (uint32_t)session_id_; }
// Call OEMCrypto_OpenSession, with GTest ASSERTs.
void open(); void open();
// Call OEMCrypto_CloseSession, with GTest ASSERTs.
void close(); void close();
// Artifically set session id without calling OEMCrypto_OpenSession. This is
// used in core/test/generic_crypto_unittest.cpp.
void SetSessionId(uint32_t session_id); void SetSessionId(uint32_t session_id);
uint32_t GetOecSessionId() { return session_id_; } uint32_t GetOecSessionId() { return session_id_; }
void GenerateNonce(uint32_t* nonce, int* error_counter = NULL); // Generates one nonce. If error_counter is null, this will sleep 1 second
// and try again if a nonce flood has been detected. If error_counter is
// not null, it will be incremented when a nonce flood is detected.
void GenerateNonce(int* error_counter = NULL);
// Fill the vectors with test context which generate known mac and enc keys.
void FillDefaultContext(vector<uint8_t>* mac_context, void FillDefaultContext(vector<uint8_t>* mac_context,
vector<uint8_t>* enc_context); vector<uint8_t>* enc_context);
// Generate known mac and enc keys using OEMCrypto_GenerateDerivedKeys and
// also fill out enc_key_, mac_key_server_, and mac_key_client_.
void GenerateDerivedKeysFromKeybox(); void GenerateDerivedKeysFromKeybox();
// Generate known mac and enc keys using OEMCrypto_DeriveKeysFromSessionKey
// and also fill out enc_key_, mac_key_server_, and mac_key_client_.
void GenerateDerivedKeysFromSessionKey(); void GenerateDerivedKeysFromSessionKey();
void GenerateTestSessionKeys(); // Loads and verifies the keys in the message pointed to by message_ptr()
// using OEMCrypto_LoadKeys. This message should have already been created
// by FillSimpleMessage, modified if needed, and then encrypted and signed by
// the server's mac key in EncryptAndSign.
void LoadTestKeys(const std::string& pst = "", bool new_mac_keys = true); void LoadTestKeys(const std::string& pst = "", bool new_mac_keys = true);
// This uses OEMCrypto_QueryKeyControl to check that the keys in OEMCrypto
// have the correct key control data.
void VerifyTestKeys(); void VerifyTestKeys();
// This creates a refresh key or license renewal message, signs it with the
// server's mac key, and calls OEMCrypto_RefreshKeys.
void RefreshTestKeys(const size_t key_count, uint32_t control_bits, void RefreshTestKeys(const size_t key_count, uint32_t control_bits,
uint32_t nonce, OEMCryptoResult expected_result); uint32_t nonce, OEMCryptoResult expected_result);
// This sets the key id in the current message data to the specified string.
// This is used to test with different key id lengths.
void SetKeyId(int index, const string& key_id); void SetKeyId(int index, const string& key_id);
// This fills the data structure license_ with key information. This data
// can be modified, and then should be encrypted and signed in EncryptAndSign
// before being loaded in LoadTestKeys.
void FillSimpleMessage(uint32_t duration, uint32_t control, uint32_t nonce, void FillSimpleMessage(uint32_t duration, uint32_t control, uint32_t nonce,
const std::string& pst = ""); const std::string& pst = "");
// Like FillSimpleMessage, this fills encrypted_license_ with data. The name
// is a little misleading: the license renewal message is not encrypted, it
// is just signed. The signature is computed in RefreshTestKeys, above.
void FillRefreshMessage(size_t key_count, uint32_t control_bits, void FillRefreshMessage(size_t key_count, uint32_t control_bits,
uint32_t nonce); uint32_t nonce);
// This copies data from license_ to encrypted_license_, and then encrypts
// each field in the key array appropriately. It then signes the buffer with
// the server mac keys. It then fills out the key_array_ so that pointers in
// that array point to the locations in the encrypted message.
void EncryptAndSign(); void EncryptAndSign();
void EncryptMessage(RSAPrivateKeyMessage* data, // This encrypts an RSAPrivateKeyMessage with encryption_key so that it may be
RSAPrivateKeyMessage* encrypted); // loaded with OEMCrypto_RewrapDeviceRSAKey.
void EncryptProvisioningMessage(RSAPrivateKeyMessage* data,
RSAPrivateKeyMessage* encrypted,
const vector<uint8_t>& encryption_key);
// Sign the buffer with server's mac key.
void ServerSignBuffer(const uint8_t* data, size_t data_length, void ServerSignBuffer(const uint8_t* data, size_t data_length,
std::vector<uint8_t>* signature); std::vector<uint8_t>* signature);
// Sign the buffer with client's known mac key. Known test keys must be
// installed first.
void ClientSignMessage(const vector<uint8_t>& data, void ClientSignMessage(const vector<uint8_t>& data,
std::vector<uint8_t>* signature); std::vector<uint8_t>* signature);
// This checks the signature generated by OEMCrypto_GenerateSignature against
// that generaged by ClientSignMessage.
void VerifyClientSignature(size_t data_length = 400); void VerifyClientSignature(size_t data_length = 400);
// Set the pointers in key_array[*] to point values inside data. This is
// needed to satisfy range checks in OEMCrypto_LoadKeys.
void FillKeyArray(const MessageData& data, OEMCrypto_KeyObject* key_array); void FillKeyArray(const MessageData& data, OEMCrypto_KeyObject* key_array);
// As in FillKeyArray but for the license renewal message passed to
// OEMCrypto_RefreshKeys.
void FillRefreshArray(OEMCrypto_KeyRefreshObject* key_array, void FillRefreshArray(OEMCrypto_KeyRefreshObject* key_array,
size_t key_count); size_t key_count);
// Encrypt a block of data using CTR mode.
void EncryptCTR(const vector<uint8_t>& in_buffer, const uint8_t* key, void EncryptCTR(const vector<uint8_t>& in_buffer, const uint8_t* key,
const uint8_t* starting_iv, vector<uint8_t>* out_buffer); const uint8_t* starting_iv, vector<uint8_t>* out_buffer);
// Encrypt some data and pass to OEMCrypto_DecryptCENC to verify decryption.
void TestDecryptCTR(bool select_key_first = true, void TestDecryptCTR(bool select_key_first = true,
OEMCryptoResult expected_result = OEMCrypto_SUCCESS, OEMCryptoResult expected_result = OEMCrypto_SUCCESS,
int key_index = 0); int key_index = 0);
// Creates RSAPrivateKeyMessage for the specified rsa_key, encrypts it with
// the specified encryption key, and then signs it with the server's mac key.
// If encryption_key is null, use the session's enc_key_.
void MakeRSACertificate(struct RSAPrivateKeyMessage* encrypted, void MakeRSACertificate(struct RSAPrivateKeyMessage* encrypted,
size_t message_size, std::vector<uint8_t>* signature, size_t message_size, std::vector<uint8_t>* signature,
uint32_t allowed_schemes, uint32_t allowed_schemes,
const vector<uint8_t>& rsa_key); const vector<uint8_t>& rsa_key,
const vector<uint8_t>* encryption_key = NULL);
// Calls OEMCrypto_RewrapDeviceRSAKey with the given provisioning response
// message.
void RewrapRSAKey(const struct RSAPrivateKeyMessage& encrypted, void RewrapRSAKey(const struct RSAPrivateKeyMessage& encrypted,
size_t message_size, const std::vector<uint8_t>& signature, size_t message_size, const std::vector<uint8_t>& signature,
vector<uint8_t>* wrapped_key, bool force); vector<uint8_t>* wrapped_key, bool force);
// Loads the specified RSA public key into public_rsa_. If rsa_key is null,
// the default test key is loaded.
void PreparePublicKey(const uint8_t* rsa_key = NULL, void PreparePublicKey(const uint8_t* rsa_key = NULL,
size_t rsa_key_length = 0); size_t rsa_key_length = 0);
// Verifies the given signature is from the given message and RSA key, pkey.
static bool VerifyPSSSignature(EVP_PKEY* pkey, const uint8_t* message, static bool VerifyPSSSignature(EVP_PKEY* pkey, const uint8_t* message,
size_t message_length, size_t message_length,
const uint8_t* signature, const uint8_t* signature,
size_t signature_length); size_t signature_length);
// Verify that the message was signed by the private key associated with
// |public_rsa_| using the specified padding scheme.
void VerifyRSASignature(const vector<uint8_t>& message, void VerifyRSASignature(const vector<uint8_t>& message,
const uint8_t* signature, size_t signature_length, const uint8_t* signature, size_t signature_length,
RSA_Padding_Scheme padding_scheme); RSA_Padding_Scheme padding_scheme);
bool GenerateRSASessionKey(vector<uint8_t>* enc_session_key); // Encrypts a known session key with public_rsa_ for use in future calls to
// OEMCrypto_DeriveKeysFromSessionKey or OEMCrypto_RewrapDeviceRSAKey30.
// The unencrypted session key is stored in session_key.
bool GenerateRSASessionKey(vector<uint8_t>* session_key,
vector<uint8_t>* enc_session_key);
// Loads the specified wrapped_rsa_key into OEMCrypto, and then runs
// GenerateDerivedKeysFromSessionKey to install known encryption and mac keys.
void InstallRSASessionTestKey(const vector<uint8_t>& wrapped_rsa_key); void InstallRSASessionTestKey(const vector<uint8_t>& wrapped_rsa_key);
void DisallowDeriveKeys(); // Generates a usage report for the specified pst. If expect_success is true,
// the report's signature is verified, and several fields are given sanity
// checks. If other is not null, then the mac keys are copied from other in
// order to verify signatures.
void GenerateReport(const std::string& pst, bool expect_success = true, void GenerateReport(const std::string& pst, bool expect_success = true,
Session* other = 0); Session* other = 0);
// Returns a pointer to the usage report generated by the previous call to
// GenerateReport.
OEMCrypto_PST_Report* pst_report(); OEMCrypto_PST_Report* pst_report();
// Creates a signed delete usage table entry message and calls
// OEMCrypto_DeleteUsageEntry on it.
void DeleteEntry(const std::string& pst); void DeleteEntry(const std::string& pst);
// Calls OEMCrypto_ForceDeleteUsageEntry to delete a usage table entry without
// a signed message.
void ForceDeleteEntry(const std::string& pst); void ForceDeleteEntry(const std::string& pst);
// The unencrypted license response or license renewal response.
MessageData& license() { return license_; } MessageData& license() { return license_; }
// The encrypted license response or license renewal response.
MessageData& encrypted_license() { return padded_message_; } MessageData& encrypted_license() { return padded_message_; }
// A pointer to the buffer holding encrypted_license.
const uint8_t* message_ptr(); const uint8_t* message_ptr();
// An array of key objects for use in LoadKeys.
OEMCrypto_KeyObject* key_array() { return key_array_; } OEMCrypto_KeyObject* key_array() { return key_array_; }
// The last signature generated with the server's mac key.
std::vector<uint8_t>& signature() { return signature_; } std::vector<uint8_t>& signature() { return signature_; }
// Set the number of keys to use in the license(), encrypted_license()
// and key_array().
void set_num_keys(int num_keys) { num_keys_ = num_keys; } void set_num_keys(int num_keys) { num_keys_ = num_keys; }
// The current number of keys to use in the license(), encrypted_license()
// and key_array().
int num_keys() const { return num_keys_; } int num_keys() const { return num_keys_; }
// Set the size of the buffer used the encrypted license.
// Must be between sizeof(MessageData) and kMaxMessageSize.
void set_message_size(size_t size); void set_message_size(size_t size);
// The size of the encrypted message.
size_t message_size() { return message_size_; } size_t message_size() { return message_size_; }
private: private:

File diff suppressed because it is too large Load Diff

View File

@@ -54,9 +54,9 @@ TEST_F(OEMCryptoAndroidLMPTest, RewrapDeviceRSAKeyImplemented) {
} }
TEST_F(OEMCryptoAndroidLMPTest, RSASignatureImplemented) { TEST_F(OEMCryptoAndroidLMPTest, RSASignatureImplemented) {
ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED, ASSERT_NE(
OEMCrypto_GenerateRSASignature(0, NULL, 0, NULL, NULL, OEMCrypto_ERROR_NOT_IMPLEMENTED,
kSign_RSASSA_PSS)); OEMCrypto_GenerateRSASignature(0, NULL, 0, NULL, NULL, kSign_RSASSA_PSS));
} }
TEST_F(OEMCryptoAndroidLMPTest, GenericCryptoImplemented) { TEST_F(OEMCryptoAndroidLMPTest, GenericCryptoImplemented) {
@@ -66,12 +66,12 @@ TEST_F(OEMCryptoAndroidLMPTest, GenericCryptoImplemented) {
ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED, ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED,
OEMCrypto_Generic_Decrypt(0, NULL, 0, NULL, OEMCrypto_Generic_Decrypt(0, NULL, 0, NULL,
OEMCrypto_AES_CBC_128_NO_PADDING, NULL)); OEMCrypto_AES_CBC_128_NO_PADDING, NULL));
ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED, ASSERT_NE(
OEMCrypto_Generic_Sign(0, NULL, 0, OEMCrypto_ERROR_NOT_IMPLEMENTED,
OEMCrypto_HMAC_SHA256, NULL, NULL)); OEMCrypto_Generic_Sign(0, NULL, 0, OEMCrypto_HMAC_SHA256, NULL, NULL));
ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED, ASSERT_NE(
OEMCrypto_Generic_Verify(0, NULL, 0, OEMCrypto_ERROR_NOT_IMPLEMENTED,
OEMCrypto_HMAC_SHA256, NULL, 0)); OEMCrypto_Generic_Verify(0, NULL, 0, OEMCrypto_HMAC_SHA256, NULL, 0));
} }
TEST_F(OEMCryptoAndroidLMPTest, SupportsUsageTable) { TEST_F(OEMCryptoAndroidLMPTest, SupportsUsageTable) {

View File

@@ -1,9 +1,9 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <iostream> #include <iostream>
#include "OEMCryptoCENC.h"
#include "log.h" #include "log.h"
#include "oec_device_features.h" #include "oec_device_features.h"
#include "OEMCryptoCENC.h"
#include "properties.h" #include "properties.h"
static void acknowledge_cast() { static void acknowledge_cast() {
@@ -20,7 +20,7 @@ int main(int argc, char** argv) {
bool is_cast_receiver = false; bool is_cast_receiver = false;
bool force_load_test_keybox = false; bool force_load_test_keybox = false;
bool filter_tests = true; bool filter_tests = true;
for(int i=0; i < argc; i++) { for (int i = 0; i < argc; i++) {
if (!strcmp(argv[i], "--cast")) { if (!strcmp(argv[i], "--cast")) {
acknowledge_cast(); acknowledge_cast();
is_cast_receiver = true; is_cast_receiver = true;
@@ -29,15 +29,15 @@ int main(int argc, char** argv) {
force_load_test_keybox = true; force_load_test_keybox = true;
} }
if (!strcmp(argv[i], "--no_filter")) { if (!strcmp(argv[i], "--no_filter")) {
filter_tests = false; filter_tests = false;
} }
} }
wvoec::global_features.Initialize(is_cast_receiver, force_load_test_keybox); wvoec::global_features.Initialize(is_cast_receiver, force_load_test_keybox);
// If the user requests --no_filter, we don't change the filter, otherwise, we // If the user requests --no_filter, we don't change the filter, otherwise, we
// filter out features that are not supported. // filter out features that are not supported.
if (filter_tests) { if (filter_tests) {
::testing::GTEST_FLAG(filter) ::testing::GTEST_FLAG(filter) =
= wvoec::global_features.RestrictFilter(::testing::GTEST_FLAG(filter)); wvoec::global_features.RestrictFilter(::testing::GTEST_FLAG(filter));
} }
return RUN_ALL_TESTS(); return RUN_ALL_TESTS();
} }