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

@@ -9,8 +9,10 @@
#include <openssl/aes.h>
#include <openssl/err.h>
#include <openssl/hmac.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include <stdint.h>
#include <gtest/gtest.h>
@@ -18,13 +20,14 @@
#include <string>
#include <vector>
#include "OEMCryptoCENC.h"
#include "log.h"
#include "oec_device_features.h"
#include "oec_test_data.h"
#include "oemcrypto_key_mock.h"
#include "OEMCryptoCENC.h"
#include "string_conversions.h"
#include "wv_cdm_constants.h"
#include "wv_cdm_types.h"
#include "wv_keybox.h"
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()
: open_(false),
forced_session_id_(false),
@@ -113,8 +133,8 @@ void Session::close() {
open_ = false;
}
void Session::GenerateNonce(uint32_t* nonce, int* error_counter) {
if (OEMCrypto_SUCCESS == OEMCrypto_GenerateNonce(session_id(), nonce)) {
void Session::GenerateNonce(int* error_counter) {
if (OEMCrypto_SUCCESS == OEMCrypto_GenerateNonce(session_id(), &nonce_)) {
return;
}
if (error_counter) {
@@ -122,7 +142,7 @@ void Session::GenerateNonce(uint32_t* nonce, int* error_counter) {
} else {
sleep(1); // wait a second, then try again.
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() {
GenerateNonce(&nonce_);
GenerateNonce();
vector<uint8_t> mac_context;
vector<uint8_t> enc_context;
FillDefaultContext(&mac_context, &enc_context);
@@ -168,10 +188,11 @@ void Session::GenerateDerivedKeysFromKeybox() {
void Session::GenerateDerivedKeysFromSessionKey() {
// Uses test certificate.
GenerateNonce(&nonce_);
GenerateNonce();
vector<uint8_t> session_key;
vector<uint8_t> enc_session_key;
PreparePublicKey();
ASSERT_TRUE(GenerateRSASessionKey(&enc_session_key));
ASSERT_TRUE(GenerateRSASessionKey(&session_key, &enc_session_key));
vector<uint8_t> mac_context;
vector<uint8_t> enc_context;
FillDefaultContext(&mac_context, &enc_context);
@@ -190,14 +211,6 @@ void Session::GenerateDerivedKeysFromSessionKey() {
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) {
uint8_t* pst_ptr = NULL;
if (pst.length() > 0) {
@@ -236,9 +249,11 @@ void Session::VerifyTestKeys() {
// control duration and bits stored in network byte order. For printing
// we change to host byte order.
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),
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,
uint32_t nonce, const std::string& pst) {
EXPECT_EQ(1, RAND_pseudo_bytes(license_.mac_key_iv,
sizeof(license_.mac_key_iv)));
EXPECT_EQ(
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)));
for (unsigned int i = 0; i < num_keys_; i++) {
memset(license_.keys[i].key_id, 0, kTestKeyIdMaxLength);
@@ -353,8 +368,10 @@ void Session::EncryptAndSign() {
FillKeyArray(encrypted_license(), key_array_);
}
void Session::EncryptMessage(RSAPrivateKeyMessage* data,
RSAPrivateKeyMessage* encrypted) {
void Session::EncryptProvisioningMessage(
RSAPrivateKeyMessage* data, RSAPrivateKeyMessage* encrypted,
const vector<uint8_t>& encryption_key) {
ASSERT_EQ(encryption_key.size(), wvcdm::KEY_SIZE);
*encrypted = *data;
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),
@@ -363,7 +380,7 @@ void Session::EncryptMessage(RSAPrivateKeyMessage* data,
uint8_t iv_buffer[16];
memcpy(iv_buffer, &data->rsa_key_iv[0], wvcdm::KEY_IV_SIZE);
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],
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);
}
// 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) {
// 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);
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;
size_t gen_signature_length = 0;
sts = OEMCrypto_GenerateSignature(session_id(), &data[0], data.size(),
NULL, &gen_signature_length);
sts = OEMCrypto_GenerateSignature(session_id(), &data[0], data.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);
@@ -520,36 +535,9 @@ void Session::MakeRSACertificate(struct RSAPrivateKeyMessage* encrypted,
size_t message_size,
std::vector<uint8_t>* signature,
uint32_t allowed_schemes,
const vector<uint8_t>& rsa_key) {
// Dummy context for testing signature generation.
vector<uint8_t> context = wvcdm::a2b_hex(
"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.
const vector<uint8_t>& rsa_key,
const vector<uint8_t>* encryption_key) {
if (encryption_key == NULL) encryption_key = &enc_key_;
struct RSAPrivateKeyMessage message;
if (allowed_schemes != kSign_RSASSA_PSS) {
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));
message.nonce = nonce_;
EncryptMessage(&message, encrypted);
EncryptProvisioningMessage(&message, encrypted, *encryption_key);
ServerSignBuffer(reinterpret_cast<const uint8_t*>(encrypted), message_size,
signature);
}
@@ -601,35 +589,29 @@ void Session::PreparePublicKey(const uint8_t* rsa_key, size_t rsa_key_length) {
rsa_key_length = sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048);
}
uint8_t* p = const_cast<uint8_t*>(rsa_key);
BIO* bio = BIO_new_mem_buf(p, rsa_key_length);
ASSERT_TRUE(NULL != bio);
PKCS8_PRIV_KEY_INFO* pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL);
ASSERT_TRUE(NULL != pkcs8_pki);
EVP_PKEY* evp = NULL;
evp = EVP_PKCS82PKEY(pkcs8_pki);
ASSERT_TRUE(NULL != evp);
openssl_ptr<BIO, BIO_vfree> bio(BIO_new_mem_buf(p, rsa_key_length));
ASSERT_TRUE(bio.NotNull());
openssl_ptr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free> pkcs8_pki(
d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), NULL));
ASSERT_TRUE(pkcs8_pki.NotNull());
openssl_ptr<EVP_PKEY, EVP_PKEY_free> evp(EVP_PKCS82PKEY(pkcs8_pki.get()));
ASSERT_TRUE(evp.NotNull());
if (public_rsa_) RSA_free(public_rsa_);
public_rsa_ = EVP_PKEY_get1_RSA(evp);
EVP_PKEY_free(evp);
PKCS8_PRIV_KEY_INFO_free(pkcs8_pki);
BIO_free(bio);
public_rsa_ = EVP_PKEY_get1_RSA(evp.get());
if (!public_rsa_) {
cout << "d2i_RSAPrivateKey failed. ";
dump_openssl_error();
ASSERT_TRUE(false);
FAIL() << "Could not parse public RSA key.";
}
switch (RSA_check_key(public_rsa_)) {
case 1: // valid.
ASSERT_TRUE(true);
return;
case 0: // not valid.
cout << "[rsa key not valid] ";
dump_openssl_error();
ASSERT_TRUE(false);
FAIL() << "[rsa key not valid] ";
default: // -1 == check failed.
cout << "[error checking rsa key] ";
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)
<< "Signature size is wrong. " << signature_length << ", should be "
<< RSA_size(public_rsa_) << "\n";
if (padding_scheme == kSign_RSASSA_PSS) {
EVP_PKEY* pkey = EVP_PKEY_new();
ASSERT_TRUE(EVP_PKEY_set1_RSA(pkey, public_rsa_) == 1);
openssl_ptr<EVP_PKEY, EVP_PKEY_free> pkey(EVP_PKEY_new());
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);
EVP_PKEY_free(pkey);
EXPECT_TRUE(ok) << "PSS signature check failed.";
} else if (padding_scheme == kSign_PKCS1_Block1) {
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_) {
cout << "No public RSA key loaded in test code.\n";
return false;
}
vector<uint8_t> session_key =
wvcdm::a2b_hex("6fa479c731d2770b6a61a5d1420bb9d1");
*session_key = wvcdm::a2b_hex("6fa479c731d2770b6a61a5d1420bb9d1");
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_,
RSA_PKCS1_OAEP_PADDING);
int size = static_cast<int>(RSA_size(public_rsa_));
if (status != size) {
cout << "GenerateRSASessionKey error encrypting session key. ";
cout << "GenerateRSASessionKey error encrypting session key.\n";
dump_openssl_error();
return false;
}
@@ -744,21 +724,6 @@ void Session::InstallRSASessionTestKey(const vector<uint8_t>& wrapped_rsa_key) {
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,
Session* other) {
if (other) { // If other is specified, copy mac keys.