Builds libwvmdrmengine.so, which is loaded by the new MediaDrm APIs to support playback of Widevine/CENC protected content. Change-Id: I6f57dd37083dfd96c402cb9dd137c7d74edc8f1c
1402 lines
50 KiB
C++
1402 lines
50 KiB
C++
// Copyright 2013 Google Inc. All Rights Reserved.
|
|
|
|
//
|
|
// OEMCrypto unit tests
|
|
//
|
|
#include <arpa/inet.h> // TODO(fredgc): Add ntoh to wv_cdm_utilities.h
|
|
#include <gtest/gtest.h>
|
|
#include <stdint.h>
|
|
#include <sys/types.h>
|
|
#include <algorithm>
|
|
#include <map>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "OEMCryptoCENC.h"
|
|
#include "oemcrypto_key_mock.h"
|
|
#include "openssl/aes.h"
|
|
#include "openssl/cmac.h"
|
|
#include "openssl/hmac.h"
|
|
#include "openssl/rand.h"
|
|
#include "openssl/sha.h"
|
|
#include "string_conversions.h"
|
|
#include "wv_cdm_constants.h"
|
|
#include "wv_keybox.h"
|
|
|
|
using namespace std;
|
|
|
|
namespace wvoec {
|
|
|
|
typedef struct {
|
|
uint8_t verification[4];
|
|
uint32_t duration;
|
|
uint32_t nonce;
|
|
uint32_t control_bits;
|
|
} KeyControlBlock;
|
|
|
|
const size_t kTestKeyIdLength = 12; // pick a length. any length.
|
|
typedef struct {
|
|
uint8_t key_id[kTestKeyIdLength];
|
|
uint8_t key_data[wvcdm::KEY_SIZE];
|
|
uint8_t key_iv[wvcdm::KEY_IV_SIZE];
|
|
uint8_t control_iv[wvcdm::KEY_IV_SIZE];
|
|
KeyControlBlock control;
|
|
} MessageKeyData;
|
|
|
|
template<unsigned int kNumberKeys>
|
|
struct MessageData {
|
|
MessageKeyData keys[kNumberKeys];
|
|
uint8_t mac_key_iv[wvcdm::KEY_IV_SIZE];
|
|
uint8_t mac_key[wvcdm::MAC_KEY_SIZE];
|
|
};
|
|
|
|
const wvoec_mock::WidevineKeybox kDefaultKeybox = {
|
|
// Sample keybox used for test vectors
|
|
{
|
|
// deviceID
|
|
0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x30, // TestKey01
|
|
0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
|
|
}, {
|
|
// key
|
|
0xfb, 0xda, 0x04, 0x89, 0xa1, 0x58, 0x16, 0x0e,
|
|
0xa4, 0x02, 0xe9, 0x29, 0xe3, 0xb6, 0x8f, 0x04,
|
|
}, {
|
|
// data
|
|
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x19,
|
|
0x07, 0xd9, 0xff, 0xde, 0x13, 0xaa, 0x95, 0xc1,
|
|
0x22, 0x67, 0x80, 0x53, 0x36, 0x21, 0x36, 0xbd,
|
|
0xf8, 0x40, 0x8f, 0x82, 0x76, 0xe4, 0xc2, 0xd8,
|
|
0x7e, 0xc5, 0x2b, 0x61, 0xaa, 0x1b, 0x9f, 0x64,
|
|
0x6e, 0x58, 0x73, 0x49, 0x30, 0xac, 0xeb, 0xe8,
|
|
0x99, 0xb3, 0xe4, 0x64, 0x18, 0x9a, 0x14, 0xa8,
|
|
0x72, 0x02, 0xfb, 0x02, 0x57, 0x4e, 0x70, 0x64,
|
|
0x0b, 0xd2, 0x2e, 0xf4, 0x4b, 0x2d, 0x7e, 0x39,
|
|
}, {
|
|
// magic
|
|
0x6b, 0x62, 0x6f, 0x78,
|
|
}, {
|
|
// Crc
|
|
0x0a, 0x7a, 0x2c, 0x35,
|
|
}
|
|
};
|
|
|
|
class OEMCryptoClientTest : public ::testing::Test {
|
|
|
|
protected:
|
|
|
|
class Session;
|
|
|
|
OEMCryptoClientTest() : alive_(false) {}
|
|
|
|
bool init() {
|
|
OEMCryptoResult result;
|
|
if (!alive_) {
|
|
result = OEMCrypto_Initialize();
|
|
alive_ = (OEMCrypto_SUCCESS == result);
|
|
}
|
|
return alive_;
|
|
}
|
|
|
|
bool terminate() {
|
|
OEMCryptoResult result;
|
|
result = OEMCrypto_Terminate();
|
|
if (OEMCrypto_SUCCESS == result) {
|
|
alive_ = false;
|
|
}
|
|
return !alive_;
|
|
}
|
|
|
|
void testSetUp() {
|
|
init();
|
|
}
|
|
|
|
void InstallKeybox(const wvoec_mock::WidevineKeybox& keybox) {
|
|
OEMCryptoResult sts;
|
|
uint8_t wrapped[sizeof(wvoec_mock::WidevineKeybox)];
|
|
size_t length = sizeof(wvoec_mock::WidevineKeybox);
|
|
sts = OEMCrypto_WrapKeybox(reinterpret_cast<const uint8_t*>(&keybox),
|
|
sizeof(keybox),
|
|
wrapped,
|
|
&length,
|
|
NULL, 0);
|
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
|
sts = OEMCrypto_InstallKeybox(wrapped, sizeof(keybox));
|
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
|
}
|
|
|
|
void testTearDown() {
|
|
destroySessions();
|
|
terminate();
|
|
}
|
|
|
|
bool validateKeybox() {
|
|
OEMCryptoResult result;
|
|
result = OEMCrypto_IsKeyboxValid();
|
|
return (OEMCrypto_SUCCESS == result);
|
|
}
|
|
|
|
class Session {
|
|
public:
|
|
Session() : valid_(false), open_(false) {}
|
|
|
|
Session(string sname) : valid_(true), open_(false), sname_(sname),
|
|
mac_key_(wvcdm::MAC_KEY_SIZE),
|
|
enc_key_(wvcdm::KEY_SIZE) {}
|
|
|
|
bool isValid() { return valid_; }
|
|
bool isOpen() { return open_; }
|
|
bool successStatus() { return (OEMCrypto_SUCCESS == session_status_); }
|
|
OEMCryptoResult getStatus() { return session_status_; }
|
|
uint32_t getNonce() { return nonce_; }
|
|
|
|
uint32_t session_id() { return (uint32_t)session_id_; }
|
|
void set_session_id(uint32_t newsession) {
|
|
session_id_ = (OEMCrypto_SESSION)newsession;
|
|
}
|
|
|
|
void open() {
|
|
EXPECT_TRUE(valid_ && !open_);
|
|
session_status_ = OEMCrypto_OpenSession(&session_id_);
|
|
if (OEMCrypto_SUCCESS == session_status_) {
|
|
open_ = true;
|
|
}
|
|
}
|
|
|
|
void close() {
|
|
EXPECT_TRUE(valid_);
|
|
session_status_ = OEMCrypto_CloseSession(session_id_);
|
|
if (OEMCrypto_SUCCESS == session_status_) {
|
|
open_ = false;
|
|
}
|
|
}
|
|
|
|
bool GenerateNonce(uint32_t* nonce) {
|
|
OEMCryptoResult sts;
|
|
sts = OEMCrypto_GenerateNonce(session_id(), nonce);
|
|
return (OEMCrypto_SUCCESS == sts);
|
|
}
|
|
|
|
bool GenerateDerivedKeys() {
|
|
if( !GenerateNonce(&nonce_) ) {
|
|
cout << "Generate Nonce failed." << endl;
|
|
return false;
|
|
}
|
|
vector<uint8_t> mac_context = wvcdm::a2b_hex(
|
|
"41555448454e5449434154494f4e000a4c08001248000000020000101907d9ff"
|
|
"de13aa95c122678053362136bdf8408f8276e4c2d87ec52b61aa1b9f646e5873"
|
|
"4930acebe899b3e464189a14a87202fb02574e70640bd22ef44b2d7e3912250a"
|
|
"230a14080112100915007caa9b5931b76a3a85f046523e10011a093938373635"
|
|
"34333231180120002a0c31383836373837343035000000000100");
|
|
vector<uint8_t> enc_context = wvcdm::a2b_hex(
|
|
"454e4352595054494f4e000a4c08001248000000020000101907d9ffde13aa95"
|
|
"c122678053362136bdf8408f8276e4c2d87ec52b61aa1b9f646e58734930aceb"
|
|
"e899b3e464189a14a87202fb02574e70640bd22ef44b2d7e3912250a230a1408"
|
|
"0112100915007caa9b5931b76a3a85f046523e10011a09393837363534333231"
|
|
"180120002a0c31383836373837343035000000000080");
|
|
OEMCryptoResult sts;
|
|
sts = OEMCrypto_GenerateDerivedKeys(
|
|
session_id(),
|
|
&mac_context[0], mac_context.size(),
|
|
&enc_context[0], enc_context.size());
|
|
if (sts != OEMCrypto_SUCCESS) {
|
|
cout << "GenerateDerivedKeys: Failed OEMCrypto_GenerateDerivedKeys with "
|
|
<< static_cast<long unsigned int>(sts) << endl;
|
|
}
|
|
mac_key_ = wvcdm::a2b_hex(
|
|
"9D41F0A77A76E071841C33B06104D106641421E651FBE55F0AED453CDA7713AC");
|
|
enc_key_ = wvcdm::a2b_hex("D0BFC35DA9E33436E81C4229E78CB9F4");
|
|
return (OEMCrypto_SUCCESS == sts);
|
|
}
|
|
|
|
bool LoadTestKeys() {
|
|
if (!GenerateDerivedKeys()) {
|
|
cout << "LoadTestKeys: Failed GenerateDerivedKeys" << endl;
|
|
return false;
|
|
}
|
|
|
|
return CreateAndLoadKeyMessage();
|
|
}
|
|
|
|
bool CertificateProvision(vector<uint8_t>* wrappedKey) {
|
|
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);
|
|
uint8_t* gen_signature = new uint8_t[gen_signature_length];
|
|
sts = OEMCrypto_GenerateSignature(session_id(), &context[0],
|
|
context.size(), gen_signature,
|
|
&gen_signature_length);
|
|
|
|
if (sts != OEMCrypto_SUCCESS) {
|
|
return false;
|
|
}
|
|
|
|
// 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.
|
|
// TODO: This is not a valid test vector
|
|
vector<uint8_t> message = wvcdm::a2b_hex(
|
|
"000000001248000000020000101907d9ffde13aa95c122678053362136bdf840"
|
|
"8f8276e4c2d87ec52b61aa1b9f646e58734930acebe899b3e464189a14a87202"
|
|
"fb02574e70640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931"
|
|
"b76a3a85f046523e10011a09393837363534333231180120002a0c3138383637"
|
|
"0a4c08001248000000020000101907d9ffde13aa95c122678053362136bdf840"
|
|
"8f8276e4c2d87ec52b61aa1b9f646e58734930acebe899b3e464189a14a87202"
|
|
"fb02574e70640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931"
|
|
"b76a3a85f046523e10011a09393837363534333231180120002a0c3138383637"
|
|
"0a4c08001248000000020000101907d9ffde13aa95c122678053362136bdf840"
|
|
"8f8276e4c2d87ec52b61aa1b9f646e58734930acebe899b3e464189a14a87202"
|
|
"fb02574e70640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931"
|
|
"b76a3a85f046523e10011a09393837363534333231180120002a0c3138383637"
|
|
"0a4c08001248000000020000101907d9ffde13aa95c122678053362136bdf840"
|
|
"8f8276e4c2d87ec52b61aa1b9f646e58734930acebe899b3e464189a14a87202"
|
|
"fb02574e70640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931"
|
|
"b76a3a85f046523e10011a09393837363534333231180120002a0c3138383637"
|
|
"0a4c08001248000000020000101907d9ffde13aa95c122678053362136bdf840"
|
|
"8f8276e4c2d87ec52b61aa1b9f646e58734930acebe899b3e464189a14a87202"
|
|
"fb02574e70640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931"
|
|
"b76a3a85f046523e10011a09393837363534333231180120002a0c3138383637"
|
|
"0a4c08001248000000020000101907d9ffde13aa95c122678053362136bdf840"
|
|
"8f8276e4c2d87ec52b61aa1b9f646e58734930acebe899b3e464189a14a87202"
|
|
"fb02574e70640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931"
|
|
"b76a3a85f046523e10011a09393837363534333231180120002a0c3138383637");
|
|
|
|
memcpy(&message[0], &nonce_, sizeof(uint32_t));
|
|
uint32_t* messageNonce = reinterpret_cast<uint32_t*>(&message[0]);
|
|
uint8_t* key = &message[32];
|
|
size_t key_length = 7;
|
|
uint8_t* key_iv = &message[64];
|
|
|
|
// TODO: In practice, we need to generate a signature here after inserting
|
|
// the right nonce into the message.
|
|
vector<uint8_t> signature = wvcdm::a2b_hex(
|
|
"0a4c08001248000000020000101907d9ffde13aa95c122678053362136bdf840");
|
|
|
|
size_t wrapped_key_length;
|
|
|
|
sts = OEMCrypto_RewrapDeviceRSAKey(session_id(), &message[0],
|
|
message.size(), &signature[0],
|
|
signature.size(), messageNonce, key,
|
|
key_length, key_iv, NULL,
|
|
&wrapped_key_length);
|
|
wrappedKey->clear();
|
|
wrappedKey->resize(wrapped_key_length);
|
|
sts = OEMCrypto_RewrapDeviceRSAKey(session_id(), &message[0],
|
|
message.size(), &signature[0],
|
|
signature.size(), messageNonce, key,
|
|
key_length, key_iv,
|
|
&(wrappedKey->front()),
|
|
&wrapped_key_length);
|
|
delete[] gen_signature;
|
|
return (sts == OEMCrypto_SUCCESS);
|
|
}
|
|
|
|
bool CertificateLicense() {
|
|
OEMCryptoResult sts;
|
|
vector<uint8_t> wrappedKey;
|
|
|
|
if (!CertificateProvision(&wrappedKey)) {
|
|
return false;
|
|
}
|
|
|
|
// Load the Wrapped Key
|
|
sts = OEMCrypto_LoadDeviceRSAKey(session_id(), &wrappedKey[0],
|
|
wrappedKey.size());
|
|
if (sts != OEMCrypto_SUCCESS) {
|
|
return false;
|
|
}
|
|
|
|
// Sign a Message
|
|
vector<uint8_t> licenseRequest = wvcdm::a2b_hex(
|
|
"ba711a51e0c4c995440c28057f7f5e2f2e9c3a1edeb7549aca21e6050b059ac8"
|
|
"6ad64ec1a528eef17b4f5ce781af488d50fb0e60d04b48c78d55847a4e14243c"
|
|
"0023c553b46a2f53995870f351295e3aa2237f153f1415e817ad23e662e547b1"
|
|
"4708b303473813f93ee192353ff22bee54dd0f558bbe4b61b75b387bc310e9d6"
|
|
"8ff2cb3482689c0688570809b756dba4c2697be3132a2da782aa877ed64d8c7d"
|
|
"506525a382bad14d7e797c256c3617c22fa4165482b9742e9b54ffb6c52eda1d");
|
|
size_t signature_length = 0;
|
|
|
|
sts = OEMCrypto_GenerateRSASignature(session_id(), &licenseRequest[0],
|
|
licenseRequest.size(), NULL,
|
|
&signature_length);
|
|
uint8_t* signature = new uint8_t[signature_length];
|
|
sts = OEMCrypto_GenerateRSASignature(session_id(), &licenseRequest[0],
|
|
licenseRequest.size(), signature,
|
|
&signature_length);
|
|
if (sts != OEMCrypto_SUCCESS) {
|
|
return false;
|
|
}
|
|
|
|
// Rewrap Canned Response
|
|
|
|
// In the real world, the signature above would just have been used to contact
|
|
// the license server to get this response.
|
|
// TODO: This is not a valid test vector
|
|
vector<uint8_t> sessionKey = wvcdm::a2b_hex(
|
|
"6fa479c731d2770b6a61a5d1420bb9d1");
|
|
vector<uint8_t> mac_context = wvcdm::a2b_hex(
|
|
"41555448454e5449434154494f4e000a4c08001248000000020000101907d9ff"
|
|
"de13aa95c122678053362136bdf8408f8276e4c2d87ec52b61aa1b9f646e5873"
|
|
"4930acebe899b3e464189a14a87202fb02574e70640bd22ef44b2d7e3912250a"
|
|
"230a14080112100915007caa9b5931b76a3a85f046523e10011a093938373635"
|
|
"34333231180120002a0c31383836373837343035000000000100");
|
|
vector<uint8_t> enc_context = wvcdm::a2b_hex(
|
|
"454e4352595054494f4e000a4c08001248000000020000101907d9ffde13aa95"
|
|
"c122678053362136bdf8408f8276e4c2d87ec52b61aa1b9f646e58734930aceb"
|
|
"e899b3e464189a14a87202fb02574e70640bd22ef44b2d7e3912250a230a1408"
|
|
"0112100915007caa9b5931b76a3a85f046523e10011a09393837363534333231"
|
|
"180120002a0c31383836373837343035000000000080");
|
|
|
|
sts = OEMCrypto_DeriveKeysFromSessionKey(session_id(),
|
|
&sessionKey[0],
|
|
sessionKey.size(),
|
|
&mac_context[0],
|
|
mac_context.size(),
|
|
&enc_context[0],
|
|
enc_context.size());
|
|
if (sts != OEMCrypto_SUCCESS) {
|
|
return false;
|
|
}
|
|
|
|
delete[] signature;
|
|
return CreateAndLoadKeyMessage();
|
|
}
|
|
|
|
template<unsigned int kNumberKeys>
|
|
void fill_simple_message(MessageData<kNumberKeys>* data) {
|
|
OEMCrypto_GetRandom(data->mac_key_iv, wvcdm::KEY_IV_SIZE);
|
|
OEMCrypto_GetRandom(data->mac_key, wvcdm::KEY_IV_SIZE);
|
|
for (unsigned int i = 0; i < kNumberKeys; i++) {
|
|
memset(data->keys[i].key_id, i, kTestKeyIdLength);
|
|
OEMCrypto_GetRandom(data->keys[i].key_data, wvcdm::KEY_SIZE);
|
|
OEMCrypto_GetRandom(data->keys[i].key_iv, wvcdm::KEY_IV_SIZE);
|
|
OEMCrypto_GetRandom(data->keys[i].control_iv, wvcdm::KEY_IV_SIZE);
|
|
memcpy(data->keys[i].control.verification, "kctl", 4);
|
|
data->keys[i].control.duration = htonl(0);
|
|
data->keys[i].control.nonce = htonl(nonce_);
|
|
data->keys[i].control.control_bits = htonl(0);
|
|
}
|
|
// For the canned decryption content, The first key is:
|
|
vector<uint8_t> key = wvcdm::a2b_hex("39AD33E5719656069F9EDE9EBBA7A77D");
|
|
memcpy(data->keys[0].key_data, &key[0], key.size());
|
|
|
|
}
|
|
|
|
template<unsigned int kNumberKeys>
|
|
void encrypt_message(const MessageData<kNumberKeys>& data,
|
|
MessageData<kNumberKeys>* encrypted) {
|
|
*encrypted = data;
|
|
|
|
uint8_t iv_buffer[16];
|
|
memcpy(iv_buffer, &data.mac_key_iv[0], wvcdm::KEY_IV_SIZE);
|
|
AES_KEY aes_key;
|
|
AES_set_encrypt_key(&enc_key_[0], 128, &aes_key);
|
|
AES_cbc_encrypt(&data.mac_key[0], &encrypted->mac_key[0],
|
|
wvcdm::MAC_KEY_SIZE, &aes_key, iv_buffer, AES_ENCRYPT);
|
|
|
|
for (unsigned int i = 0; i < kNumberKeys; i++) {
|
|
memcpy(iv_buffer, &data.keys[i].control_iv[0], wvcdm::KEY_IV_SIZE);
|
|
AES_set_encrypt_key(&data.keys[i].key_data[0], 128, &aes_key);
|
|
AES_cbc_encrypt(reinterpret_cast<const uint8_t*>(&data.keys[i].control),
|
|
reinterpret_cast<uint8_t*>(&encrypted->keys[i].control),
|
|
wvcdm::KEY_SIZE, &aes_key, iv_buffer, AES_ENCRYPT);
|
|
|
|
memcpy(iv_buffer, &data.keys[i].key_iv[0], wvcdm::KEY_IV_SIZE);
|
|
AES_set_encrypt_key(&enc_key_[0], 128, &aes_key);
|
|
AES_cbc_encrypt(&data.keys[i].key_data[0], &encrypted->keys[i].key_data[0],
|
|
wvcdm::KEY_SIZE, &aes_key, iv_buffer, AES_ENCRYPT);
|
|
}
|
|
|
|
}
|
|
|
|
template<unsigned int kNumberKeys>
|
|
void sign_message(MessageData<kNumberKeys> data,
|
|
std::vector<uint8_t>* signature) {
|
|
signature->resize(SHA256_DIGEST_LENGTH);
|
|
unsigned int md_len = SHA256_DIGEST_LENGTH;
|
|
HMAC(EVP_sha256(), &mac_key_[0], SHA256_DIGEST_LENGTH,
|
|
reinterpret_cast<uint8_t*>(&data), sizeof(data),
|
|
&(signature->front()), &md_len);
|
|
}
|
|
|
|
template<unsigned int kNumberKeys>
|
|
void fill_key_array(const MessageData<kNumberKeys>& data,
|
|
OEMCrypto_KeyObject* key_array) {
|
|
for (unsigned int i = 0; i < kNumberKeys; i++) {
|
|
key_array[i].key_id = data.keys[i].key_id;
|
|
key_array[i].key_id_length = kTestKeyIdLength;
|
|
key_array[i].key_data_iv = data.keys[i].key_iv;
|
|
key_array[i].key_data = data.keys[i].key_data;
|
|
key_array[i].key_control_iv = data.keys[i].control_iv;
|
|
key_array[i].key_control
|
|
= reinterpret_cast<const uint8_t*>(&data.keys[i].control);
|
|
}
|
|
}
|
|
|
|
private:
|
|
bool CreateAndLoadKeyMessage() {
|
|
const unsigned int num_keys = 3;
|
|
MessageData<num_keys> data;
|
|
fill_simple_message(&data);
|
|
MessageData<num_keys> encrypted;
|
|
encrypt_message(data, &encrypted);
|
|
std::vector<uint8_t> signature;
|
|
sign_message(encrypted, &signature);
|
|
OEMCrypto_KeyObject key_array[num_keys];
|
|
|
|
const uint8_t* message_ptr = reinterpret_cast<const uint8_t*>(&encrypted);
|
|
fill_key_array(encrypted, key_array);
|
|
|
|
OEMCryptoResult sts = OEMCrypto_LoadKeys(
|
|
session_id(),
|
|
message_ptr, sizeof(encrypted),
|
|
&signature[0], signature.size(),
|
|
encrypted.mac_key_iv,
|
|
encrypted.mac_key,
|
|
num_keys, key_array);
|
|
if (sts != OEMCrypto_SUCCESS) {
|
|
cout << "LoadTestKeys: Failed OEMCrypto_LoadKeys with "
|
|
<< static_cast<long unsigned int>(sts) << endl;
|
|
}
|
|
return sts == OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
bool valid_;
|
|
bool open_;
|
|
string sname_;
|
|
OEMCrypto_SESSION session_id_;
|
|
OEMCryptoResult session_status_;
|
|
vector<uint8_t> mac_key_;
|
|
vector<uint8_t> enc_key_;
|
|
uint32_t nonce_;
|
|
};
|
|
|
|
static Session badSession;
|
|
|
|
Session& findSession(string sname) {
|
|
map<string, Session>::iterator it = _sessions.find(sname);
|
|
if (it != _sessions.end()) {
|
|
return it->second;
|
|
}
|
|
return badSession;
|
|
}
|
|
|
|
Session& createSession(string sname) {
|
|
Session temp(sname);
|
|
_sessions.insert(pair<string, Session>(sname, temp));
|
|
return findSession(sname);
|
|
}
|
|
|
|
bool destroySession(string sname) {
|
|
Session& temp = findSession(sname);
|
|
if (!temp.isValid()) {
|
|
return false;
|
|
}
|
|
_sessions.erase(sname);
|
|
return true;
|
|
}
|
|
|
|
bool destroySessions() {
|
|
_sessions.clear();
|
|
return true;
|
|
}
|
|
|
|
const uint8_t* find(const vector<uint8_t>& message,
|
|
const vector<uint8_t>& substring) {
|
|
vector<uint8_t>::const_iterator pos = search(message.begin(), message.end(),
|
|
substring.begin(), substring.end());
|
|
if (pos == message.end()) {
|
|
return NULL;
|
|
}
|
|
return &(*pos);
|
|
}
|
|
|
|
private:
|
|
bool alive_;
|
|
map<string, Session> _sessions;
|
|
};
|
|
|
|
OEMCryptoClientTest::Session OEMCryptoClientTest::badSession;
|
|
|
|
///////////////////////////////////////////////////
|
|
// initialization tests
|
|
///////////////////////////////////////////////////
|
|
|
|
TEST_F(OEMCryptoClientTest, NormalInitTermination) {
|
|
bool success;
|
|
success = init();
|
|
EXPECT_TRUE(success);
|
|
success = terminate();
|
|
ASSERT_TRUE(success);
|
|
}
|
|
|
|
///////////////////////////////////////////////////
|
|
// Keybox Tests
|
|
///////////////////////////////////////////////////
|
|
|
|
TEST_F(OEMCryptoClientTest, KeyboxValid) {
|
|
bool success;
|
|
success = init();
|
|
EXPECT_TRUE(success);
|
|
success = validateKeybox();
|
|
ASSERT_TRUE(success);
|
|
success = terminate();
|
|
ASSERT_TRUE(success);
|
|
}
|
|
|
|
TEST_F(OEMCryptoClientTest, NormalGetDeviceId) {
|
|
testSetUp();
|
|
|
|
OEMCryptoResult sts;
|
|
uint8_t dev_id[128];
|
|
size_t dev_id_len = 128;
|
|
sts = OEMCrypto_GetDeviceID(dev_id, &dev_id_len);
|
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
|
// cout << "NormalGetDeviceId: dev_id = " << dev_id
|
|
// << " len = " << dev_id_len << endl;
|
|
|
|
testTearDown();
|
|
}
|
|
|
|
TEST_F(OEMCryptoClientTest, GetDeviceIdShortBuffer) {
|
|
testSetUp();
|
|
|
|
OEMCryptoResult sts;
|
|
uint8_t dev_id[128];
|
|
uint32_t req_len = 11;
|
|
for (int i = 0; i < 128; ++i) {
|
|
dev_id[i] = 0x55;
|
|
}
|
|
dev_id[127] = '\0';
|
|
size_t dev_id_len = req_len;
|
|
sts = OEMCrypto_GetDeviceID(dev_id, &dev_id_len);
|
|
// cout << "GetDeviceIdShortBuffer: sts = " << (int)sts << " request = "
|
|
// << req_len << " required = " << dev_id_len << endl;
|
|
|
|
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
|
|
|
|
// On short buffer error, function should return minimum buffer length
|
|
ASSERT_TRUE(dev_id_len > req_len);
|
|
|
|
// cout << "NormalGetDeviceId: dev_id = " << dev_id
|
|
// << " len = " << dev_id_len << endl;
|
|
|
|
testTearDown();
|
|
}
|
|
|
|
TEST_F(OEMCryptoClientTest, NormalGetKeyData) {
|
|
testSetUp();
|
|
|
|
OEMCryptoResult sts;
|
|
uint8_t key_data[256];
|
|
uint32_t req_len = 256;
|
|
size_t key_data_len = req_len;
|
|
sts = OEMCrypto_GetKeyData(key_data, &key_data_len);
|
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
|
|
|
testTearDown();
|
|
}
|
|
|
|
///////////////////////////////////////////////////
|
|
// Session Tests
|
|
///////////////////////////////////////////////////
|
|
|
|
TEST_F(OEMCryptoClientTest, NormalSessionOpenClose) {
|
|
Session& s = createSession("ONE");
|
|
testSetUp();
|
|
|
|
s.open();
|
|
ASSERT_TRUE(s.successStatus());
|
|
ASSERT_TRUE(s.isOpen());
|
|
|
|
s.close();
|
|
ASSERT_TRUE(s.successStatus());
|
|
ASSERT_FALSE(s.isOpen());
|
|
|
|
testTearDown();
|
|
}
|
|
|
|
TEST_F(OEMCryptoClientTest, TwoSessionsOpenClose) {
|
|
Session& s1 = createSession("ONE");
|
|
Session& s2 = createSession("TWO");
|
|
testSetUp();
|
|
|
|
s1.open();
|
|
ASSERT_TRUE(s1.successStatus());
|
|
ASSERT_TRUE(s1.isOpen());
|
|
|
|
s2.open();
|
|
ASSERT_TRUE(s2.successStatus());
|
|
ASSERT_TRUE(s2.isOpen());
|
|
|
|
s1.close();
|
|
ASSERT_TRUE(s1.successStatus());
|
|
ASSERT_FALSE(s1.isOpen());
|
|
|
|
s2.close();
|
|
ASSERT_TRUE(s2.successStatus());
|
|
ASSERT_FALSE(s2.isOpen());
|
|
|
|
testTearDown();
|
|
}
|
|
|
|
TEST_F(OEMCryptoClientTest, EightSessionsOpenClose) {
|
|
Session& s1 = createSession("ONE");
|
|
Session& s2 = createSession("TWO");
|
|
Session& s3 = createSession("THREE");
|
|
Session& s4 = createSession("FOUR");
|
|
Session& s5 = createSession("FIVE");
|
|
Session& s6 = createSession("SIX");
|
|
Session& s7 = createSession("SEVEN");
|
|
Session& s8 = createSession("EIGHT");
|
|
testSetUp();
|
|
|
|
s1.open();
|
|
ASSERT_TRUE(s1.successStatus());
|
|
ASSERT_TRUE(s1.isOpen());
|
|
|
|
s2.open();
|
|
ASSERT_TRUE(s2.successStatus());
|
|
ASSERT_TRUE(s2.isOpen());
|
|
|
|
s3.open();
|
|
ASSERT_TRUE(s3.successStatus());
|
|
ASSERT_TRUE(s3.isOpen());
|
|
|
|
s4.open();
|
|
ASSERT_TRUE(s4.successStatus());
|
|
ASSERT_TRUE(s4.isOpen());
|
|
|
|
s5.open();
|
|
ASSERT_TRUE(s5.successStatus());
|
|
ASSERT_TRUE(s5.isOpen());
|
|
|
|
s6.open();
|
|
ASSERT_TRUE(s6.successStatus());
|
|
ASSERT_TRUE(s6.isOpen());
|
|
|
|
s7.open();
|
|
ASSERT_TRUE(s7.successStatus());
|
|
ASSERT_TRUE(s7.isOpen());
|
|
|
|
s8.open();
|
|
ASSERT_TRUE(s8.successStatus());
|
|
ASSERT_TRUE(s8.isOpen());
|
|
|
|
s1.close();
|
|
ASSERT_TRUE(s1.successStatus());
|
|
ASSERT_FALSE(s1.isOpen());
|
|
|
|
s8.close();
|
|
ASSERT_TRUE(s8.successStatus());
|
|
ASSERT_FALSE(s8.isOpen());
|
|
|
|
s3.close();
|
|
ASSERT_TRUE(s3.successStatus());
|
|
ASSERT_FALSE(s3.isOpen());
|
|
|
|
s6.close();
|
|
ASSERT_TRUE(s6.successStatus());
|
|
ASSERT_FALSE(s6.isOpen());
|
|
|
|
s5.close();
|
|
ASSERT_TRUE(s5.successStatus());
|
|
ASSERT_FALSE(s5.isOpen());
|
|
|
|
s4.close();
|
|
ASSERT_TRUE(s4.successStatus());
|
|
ASSERT_FALSE(s4.isOpen());
|
|
|
|
s7.close();
|
|
ASSERT_TRUE(s7.successStatus());
|
|
ASSERT_FALSE(s7.isOpen());
|
|
|
|
s2.close();
|
|
ASSERT_TRUE(s2.successStatus());
|
|
ASSERT_FALSE(s2.isOpen());
|
|
|
|
testTearDown();
|
|
}
|
|
|
|
///////////////////////////////////////////////////
|
|
// AddKey Tests
|
|
///////////////////////////////////////////////////
|
|
|
|
TEST_F(OEMCryptoClientTest, GenerateNonce) {
|
|
Session& s = createSession("ONE");
|
|
testSetUp();
|
|
s.open();
|
|
uint32_t nonce;
|
|
|
|
ASSERT_TRUE(s.GenerateNonce(&nonce));
|
|
std::cout << "GenerateNonce:: nonce=" << nonce << std::endl;
|
|
|
|
s.close();
|
|
ASSERT_TRUE(s.successStatus());
|
|
ASSERT_FALSE(s.isOpen());
|
|
testTearDown();
|
|
}
|
|
|
|
TEST_F(OEMCryptoClientTest, GenerateTwoNonces) {
|
|
Session& s = createSession("ONE");
|
|
testSetUp();
|
|
s.open();
|
|
uint32_t nonce1;
|
|
uint32_t nonce2;
|
|
|
|
ASSERT_TRUE(s.GenerateNonce(&nonce1));
|
|
ASSERT_TRUE(s.GenerateNonce(&nonce2));
|
|
std::cout << "GenerateNonce:: nonce1=" << nonce1 << std::endl;
|
|
std::cout << "GenerateNonce:: nonce2=" << nonce2 << std::endl;
|
|
|
|
ASSERT_TRUE(nonce1 != nonce2);
|
|
|
|
s.close();
|
|
ASSERT_TRUE(s.successStatus());
|
|
ASSERT_FALSE(s.isOpen());
|
|
testTearDown();
|
|
}
|
|
|
|
TEST_F(OEMCryptoClientTest, GenerateDerivedKeys) {
|
|
Session& s = createSession("ONE");
|
|
testSetUp();
|
|
s.open();
|
|
|
|
ASSERT_TRUE(s.GenerateDerivedKeys());
|
|
|
|
s.close();
|
|
ASSERT_TRUE(s.successStatus());
|
|
ASSERT_FALSE(s.isOpen());
|
|
testTearDown();
|
|
}
|
|
|
|
TEST_F(OEMCryptoClientTest, GenerateSignature) {
|
|
Session& s = createSession("ONE");
|
|
testSetUp();
|
|
s.open();
|
|
|
|
ASSERT_TRUE(s.GenerateDerivedKeys());
|
|
|
|
vector<uint8_t> context = wvcdm::a2b_hex(
|
|
"0a4c08001248000000020000101907d9ffde13aa95c122678053362136bdf840"
|
|
"8f8276e4c2d87ec52b61aa1b9f646e58734930acebe899b3e464189a14a87202"
|
|
"fb02574e70640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931"
|
|
"b76a3a85f046523e10011a09393837363534333231180120002a0c3138383637"
|
|
"38373430350000");
|
|
|
|
static const uint32_t SignatureBufferMaxLength = 256;
|
|
uint8_t signature[SignatureBufferMaxLength];
|
|
size_t signature_length = SignatureBufferMaxLength;
|
|
|
|
OEMCryptoResult sts;
|
|
sts = OEMCrypto_GenerateSignature(
|
|
s.session_id(),
|
|
&context[0], context.size(), signature, &signature_length);
|
|
|
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
|
|
|
static const uint32_t SignatureExpectedLength = 32;
|
|
ASSERT_EQ(signature_length, SignatureExpectedLength);
|
|
|
|
std::string expected_signature =
|
|
"281C3ECC8BD1CAFA5786329471043A388E04AF97B3133D9A8F9B102FBD3CAF1E";
|
|
ASSERT_EQ(expected_signature, wvcdm::HexEncode(signature, signature_length));
|
|
|
|
|
|
s.close();
|
|
ASSERT_TRUE(s.successStatus());
|
|
ASSERT_FALSE(s.isOpen());
|
|
testTearDown();
|
|
}
|
|
|
|
// Define CAN_INSTALL_KEYBOX if you are compiling with the reference
|
|
// implementation of OEMCrypto, or if your version of OEMCrypto supports
|
|
// OEMCrypto_InstallKeybox and OEwith a clear keybox.
|
|
// The Below tests are based on a specific keybox which is installed for testing.
|
|
#if defined(CAN_INSTALL_KEYBOX)
|
|
|
|
TEST_F(OEMCryptoClientTest, LoadKeyNoNonce) {
|
|
testSetUp();
|
|
InstallKeybox(kDefaultKeybox);
|
|
Session& s = createSession("ONE");
|
|
s.open();
|
|
ASSERT_TRUE(s.GenerateDerivedKeys());
|
|
ASSERT_TRUE(s.LoadTestKeys());
|
|
s.close();
|
|
testTearDown();
|
|
}
|
|
|
|
TEST_F(OEMCryptoClientTest, LoadKeyWithNonce) {
|
|
testSetUp();
|
|
InstallKeybox(kDefaultKeybox);
|
|
Session& s = createSession("ONE");
|
|
s.open();
|
|
|
|
ASSERT_TRUE(s.GenerateDerivedKeys());
|
|
|
|
const unsigned int num_keys = 3;
|
|
MessageData<num_keys> data;
|
|
s.fill_simple_message(&data);
|
|
data.keys[0].control.control_bits = wvoec_mock::kControlNonceEnabled;
|
|
data.keys[1].control.control_bits = wvoec_mock::kControlNonceEnabled;
|
|
data.keys[2].control.control_bits = wvoec_mock::kControlNonceEnabled;
|
|
|
|
MessageData<num_keys> encrypted;
|
|
s.encrypt_message(data, &encrypted);
|
|
std::vector<uint8_t> signature;
|
|
s.sign_message(encrypted, &signature);
|
|
OEMCrypto_KeyObject key_array[num_keys];
|
|
const uint8_t* message_ptr = reinterpret_cast<const uint8_t*>(&encrypted);
|
|
s.fill_key_array(encrypted, key_array);
|
|
|
|
OEMCryptoResult sts = OEMCrypto_LoadKeys(
|
|
s.session_id(),
|
|
message_ptr, sizeof(encrypted),
|
|
&signature[0], signature.size(),
|
|
encrypted.mac_key_iv,
|
|
encrypted.mac_key,
|
|
num_keys, key_array);
|
|
|
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
|
|
|
s.close();
|
|
testTearDown();
|
|
}
|
|
|
|
TEST_F(OEMCryptoClientTest, LoadKeyWithBadNonce) {
|
|
testSetUp();
|
|
InstallKeybox(kDefaultKeybox);
|
|
Session& s = createSession("ONE");
|
|
s.open();
|
|
|
|
ASSERT_TRUE(s.GenerateDerivedKeys());
|
|
|
|
const unsigned int num_keys = 3;
|
|
MessageData<num_keys> data;
|
|
s.fill_simple_message(&data);
|
|
data.keys[0].control.control_bits = wvoec_mock::kControlNonceEnabled;
|
|
data.keys[1].control.control_bits = wvoec_mock::kControlNonceEnabled;
|
|
data.keys[2].control.control_bits = wvoec_mock::kControlNonceEnabled;
|
|
data.keys[1].control.nonce = 42; // This one is bad.
|
|
|
|
MessageData<num_keys> encrypted;
|
|
s.encrypt_message(data, &encrypted);
|
|
std::vector<uint8_t> signature;
|
|
s.sign_message(encrypted, &signature);
|
|
OEMCrypto_KeyObject key_array[num_keys];
|
|
const uint8_t* message_ptr = reinterpret_cast<const uint8_t*>(&encrypted);
|
|
s.fill_key_array(encrypted, key_array);
|
|
|
|
OEMCryptoResult sts = OEMCrypto_LoadKeys(
|
|
s.session_id(),
|
|
message_ptr, sizeof(encrypted),
|
|
&signature[0], signature.size(),
|
|
encrypted.mac_key_iv,
|
|
encrypted.mac_key,
|
|
num_keys, key_array);
|
|
|
|
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
|
|
|
s.close();
|
|
testTearDown();
|
|
}
|
|
|
|
TEST_F(OEMCryptoClientTest, LoadKeysBadSignature) {
|
|
testSetUp();
|
|
InstallKeybox(kDefaultKeybox);
|
|
Session& s = createSession("ONE");
|
|
s.open();
|
|
|
|
ASSERT_TRUE(s.GenerateDerivedKeys());
|
|
|
|
const unsigned int num_keys = 3;
|
|
MessageData<num_keys> data;
|
|
s.fill_simple_message(&data);
|
|
|
|
MessageData<num_keys> encrypted;
|
|
s.encrypt_message(data, &encrypted);
|
|
std::vector<uint8_t> signature;
|
|
s.sign_message(encrypted, &signature);
|
|
OEMCrypto_KeyObject key_array[num_keys];
|
|
const uint8_t* message_ptr = reinterpret_cast<const uint8_t*>(&encrypted);
|
|
s.fill_key_array(encrypted, key_array);
|
|
|
|
signature[0] = 42; // Bad signature.
|
|
|
|
OEMCryptoResult sts = OEMCrypto_LoadKeys(
|
|
s.session_id(),
|
|
message_ptr, sizeof(encrypted),
|
|
&signature[0], signature.size(),
|
|
encrypted.mac_key_iv,
|
|
encrypted.mac_key,
|
|
num_keys, key_array);
|
|
|
|
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
|
|
|
s.close();
|
|
testTearDown();
|
|
}
|
|
|
|
TEST_F(OEMCryptoClientTest, LoadKeysWithNoDerivedKeys) {
|
|
testSetUp();
|
|
InstallKeybox(kDefaultKeybox);
|
|
Session& s = createSession("ONE");
|
|
s.open();
|
|
|
|
// ASSERT_TRUE(s.GenerateDerivedKeys());
|
|
|
|
const unsigned int num_keys = 3;
|
|
MessageData<num_keys> data;
|
|
s.fill_simple_message(&data);
|
|
|
|
MessageData<num_keys> encrypted;
|
|
s.encrypt_message(data, &encrypted);
|
|
std::vector<uint8_t> signature;
|
|
s.sign_message(encrypted, &signature);
|
|
OEMCrypto_KeyObject key_array[num_keys];
|
|
const uint8_t* message_ptr = reinterpret_cast<const uint8_t*>(&encrypted);
|
|
s.fill_key_array(encrypted, key_array);
|
|
|
|
OEMCryptoResult sts = OEMCrypto_LoadKeys(
|
|
s.session_id(),
|
|
message_ptr, sizeof(encrypted),
|
|
&signature[0], signature.size(),
|
|
encrypted.mac_key_iv,
|
|
encrypted.mac_key,
|
|
num_keys, key_array);
|
|
|
|
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
|
|
|
s.close();
|
|
testTearDown();
|
|
}
|
|
|
|
///////////////////////////////////////////////////
|
|
// Decrypt Tests
|
|
///////////////////////////////////////////////////
|
|
|
|
TEST_F(OEMCryptoClientTest, Decrypt) {
|
|
OEMCryptoResult sts;
|
|
testSetUp();
|
|
InstallKeybox(kDefaultKeybox);
|
|
Session& s = createSession("ONE");
|
|
s.open();
|
|
|
|
ASSERT_TRUE(s.LoadTestKeys());
|
|
|
|
// Select the key (from fill_simple_message)
|
|
vector<uint8_t> keyId = wvcdm::a2b_hex("000000000000000000000000");
|
|
sts = OEMCrypto_SelectKey(s.session_id(), &keyId[0], keyId.size());
|
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
|
|
|
// Set up our expected input and output
|
|
vector<uint8_t> encryptedData = wvcdm::a2b_hex(
|
|
"ec261c115f9d5cda1d5cc7d33c4e37362d1397c89efdd1da5f0065c4848b0462"
|
|
"337ba14693735203c9b4184e362439c0cea5e5d1a628425eddf8a6bf9ba901ca"
|
|
"46f5a9fd973cffbbe3c276af9919e2e8f6f3f420538b7a0d6dc41487874d96b8"
|
|
"efaedb45a689b91beb8c20d36140ad467d9d620b19a5fc6f223b57e0e6a7f913"
|
|
"00fd899e5e1b89963e83067ca0912aa5b79df683e2530b55a9645be341bc5f07"
|
|
"cffc724790af635c959e2644e51ba7f23bae710eb55a1f2f4e060c3c1dd1387c"
|
|
"74415dc880492dd1d5b9ecf3f01de48a44baeb4d3ea5cc4f8d561d0865afcabb"
|
|
"fc14a9ab9647e6e31adabb72d792f0c9ba99dc3e9205657d28fc7771d64e6d4b");
|
|
vector<uint8_t> encryptionIv = wvcdm::a2b_hex(
|
|
"719dbcb253b2ec702bb8c1b1bc2f3bc6");
|
|
vector<uint8_t> unencryptedData = wvcdm::a2b_hex(
|
|
"19ef4361e16e6825b336e2012ad8ffc9ce176ab2256e1b98aa15b7877bd8c626"
|
|
"fa40b2e88373457cbcf4f1b4b9793434a8ac03a708f85974cff01bddcbdd7a8e"
|
|
"e33fd160c1d5573bfd8104efd23237edcf28205c3673920553f8dd5e916604b0"
|
|
"1082345181dceeae5ea39d829c7f49e1850c460645de33c288723b7ae3d91a17"
|
|
"a3f04195cd1945ba7b0f37fef7e82368be30f04365d877766f6d56f67d22a244"
|
|
"ef2596d3053f657c1b5d90b64e11797edf1c198a23a7bfc20e4d44c74ae41280"
|
|
"a8317f443255f4020eda850ff0954e308f53a634cbce799ae58911bc59ccd6a5"
|
|
"de2ac53ee0fa7ea15fc692cc892acc0090865dc57becacddf362a092dfd3040b");
|
|
|
|
// Describe the output
|
|
uint8_t outputBuffer[256];
|
|
OEMCrypto_DestBufferDesc destBuffer;
|
|
destBuffer.type = OEMCrypto_BufferType_Clear;
|
|
destBuffer.buffer.clear.address = outputBuffer;
|
|
destBuffer.buffer.clear.max_length = sizeof(outputBuffer);
|
|
|
|
// Decrypt the data
|
|
sts = OEMCrypto_DecryptCTR(s.session_id(), &encryptedData[0],
|
|
encryptedData.size(), true, &encryptionIv[0], 0,
|
|
&destBuffer);
|
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
|
ASSERT_EQ(0, memcmp(&unencryptedData[0], outputBuffer,
|
|
unencryptedData.size()));
|
|
|
|
s.close();
|
|
testTearDown();
|
|
}
|
|
|
|
TEST_F(OEMCryptoClientTest, DecryptWithOffset) {
|
|
OEMCryptoResult sts;
|
|
testSetUp();
|
|
InstallKeybox(kDefaultKeybox);
|
|
Session& s = createSession("ONE");
|
|
s.open();
|
|
|
|
ASSERT_TRUE(s.LoadTestKeys());
|
|
|
|
// Select the key (from fill_simple_message)
|
|
vector<uint8_t> keyId = wvcdm::a2b_hex("000000000000000000000000");
|
|
sts = OEMCrypto_SelectKey(s.session_id(),
|
|
&keyId[0],
|
|
keyId.size());
|
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
|
|
|
// Set up our expected input and output
|
|
vector<uint8_t> encryptedData = wvcdm::a2b_hex(
|
|
"c17055d4e3ab8e892b40ca2deed7cd46b406cd41d50f23d5877b36"
|
|
"ad351887df2b3774dc413904afd958ba766cc6ab51a3ffd8f845296c5d8326ee"
|
|
"39c9d0fec79885515e6b8a12911831d9fb158ca2fd3dfcfcf228741a63734685"
|
|
"8dffc30f5871260c5cef8be61cfa08b191c837901f077046664c0c56db81d412"
|
|
"98b59e5655cd94871c3c226dc3565144297f1459cddba069d5d2d6206cfd5798"
|
|
"eda4b82e01a9966d48984d6ef3fbd326ba0f6fcbe52c95786d478c2f33398c62"
|
|
"ae5210c7472d7d8dc7d12f981679f4ea9793736f354747ef14165367b94e07fc"
|
|
"4bcc7bd14746304fea100dc6465ab51241355bb19e6c2cfb2bb6bbf709765d13");
|
|
vector<uint8_t> encryptionIv = wvcdm::a2b_hex(
|
|
"c09454479a280829c946df3c22f25539");
|
|
vector<uint8_t> unencryptedData = wvcdm::a2b_hex(
|
|
"f344d9cfe336c94cf4e3ea9e3446d1427bc02d2debe6dec5b272b8"
|
|
"a4004b696c4b37e01d7418510abf32bb071f9a4bc0d2ad7e874b648e50bd0e4f"
|
|
"7085b70bf9ad2c7f37025dd45f93e90304739b1ce098a52e7b99a90f92544a9b"
|
|
"dca6f49e0006c80a0cfa018600523ad30e483141fe720d045394815d5c875ad4"
|
|
"b4387b8d09b6119bd0943e51b0b9103034496b3a83ba593f79baa188aeb6e08f"
|
|
"f6475933e9ce1bb95fbb526424e7966e25830c20da73c65c6fbff110b08e4def"
|
|
"eae94f98296770275b0d738207a8217cd6118f6ebc6e393428f2268cfedf800e"
|
|
"a7ebc606471b9a9dfccd1589e86d88fde508261eaf190efd20554ce9e14ff3c9");
|
|
|
|
// Describe the output
|
|
uint8_t outputBuffer[256];
|
|
OEMCrypto_DestBufferDesc destBuffer;
|
|
destBuffer.type = OEMCrypto_BufferType_Clear;
|
|
destBuffer.buffer.clear.address = outputBuffer;
|
|
destBuffer.buffer.clear.max_length = sizeof(outputBuffer);
|
|
|
|
// Decrypt the data
|
|
sts = OEMCrypto_DecryptCTR(s.session_id(), &encryptedData[0],
|
|
encryptedData.size(), true, &encryptionIv[0], 5,
|
|
&destBuffer);
|
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
|
ASSERT_EQ(0, memcmp(&unencryptedData[0], outputBuffer,
|
|
unencryptedData.size()));
|
|
|
|
s.close();
|
|
testTearDown();
|
|
}
|
|
|
|
TEST_F(OEMCryptoClientTest, DecryptUnencrypted) {
|
|
OEMCryptoResult sts;
|
|
testSetUp();
|
|
InstallKeybox(kDefaultKeybox);
|
|
Session& s = createSession("ONE");
|
|
s.open();
|
|
|
|
ASSERT_TRUE(s.LoadTestKeys());
|
|
|
|
// Select the key (from fill_simple_message)
|
|
vector<uint8_t> keyId = wvcdm::a2b_hex("000000000000000000000000");
|
|
sts = OEMCrypto_SelectKey(s.session_id(), &keyId[0], keyId.size());
|
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
|
|
|
// Set up our expected input and output
|
|
vector<uint8_t> unencryptedData = wvcdm::a2b_hex(
|
|
"1558497b6d994be343ed1c6d6313e0537b843e9a9c0836d1e83fe33154191ce9"
|
|
"a14d8d95bebaddc03bd471827170f527c0a166b9068b273d1bc57fbb13975ee4"
|
|
"f6b9a31743da6c447acbb712e81b13eddfd4e96c76010ac9b8aa1b6b3152b0fc"
|
|
"39ad33e5719656069f9ede9ebba7a77dd2e2074eec5c1b7ffc427a6f1be168f0"
|
|
"b5857713a44623862c903284bc53417e23c65602b52c1cb699e8352453eb9698"
|
|
"0b31459b90c26c907b549c1ab293725e414d4e45f5b30af7a55f95499a7dc89f"
|
|
"7d13ba90b34aef6b49484b0701bf96ea8b660c24bb4e92a2d1c43beb434fa386"
|
|
"1071380388799ac31d79285f5817687ed3e2eeb73a30744e77b757686c9ba5ad");
|
|
vector<uint8_t> encryptionIv = wvcdm::a2b_hex(
|
|
"49fc3efaaf614ed81d595847b928edd0");
|
|
|
|
// Describe the output
|
|
uint8_t outputBuffer[256];
|
|
OEMCrypto_DestBufferDesc destBuffer;
|
|
destBuffer.type = OEMCrypto_BufferType_Clear;
|
|
destBuffer.buffer.clear.address = outputBuffer;
|
|
destBuffer.buffer.clear.max_length = sizeof(outputBuffer);
|
|
|
|
// Decrypt the data
|
|
sts = OEMCrypto_DecryptCTR(s.session_id(), &unencryptedData[0],
|
|
unencryptedData.size(), false, &encryptionIv[0], 0,
|
|
&destBuffer);
|
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
|
ASSERT_EQ(0, memcmp(&unencryptedData[0], outputBuffer,
|
|
unencryptedData.size()));
|
|
|
|
s.close();
|
|
testTearDown();
|
|
}
|
|
|
|
///////////////////////////////////////////////////
|
|
// Certificate Root of Trust Tests
|
|
///////////////////////////////////////////////////
|
|
|
|
TEST_F(OEMCryptoClientTest, CertificateProvision) {
|
|
OEMCryptoResult sts;
|
|
testSetUp();
|
|
InstallKeybox(kDefaultKeybox);
|
|
Session& s = createSession("ONE");
|
|
s.open();
|
|
|
|
ASSERT_TRUE(s.GenerateDerivedKeys());
|
|
uint32_t nonce = s.getNonce();
|
|
|
|
vector<uint8_t> context = wvcdm::a2b_hex(
|
|
"0a4c08001248000000020000101907d9ffde13aa95c122678053362136bdf840"
|
|
"8f8276e4c2d87ec52b61aa1b9f646e58734930acebe899b3e464189a14a87202"
|
|
"fb02574e70640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931"
|
|
"b76a3a85f046523e10011a09393837363534333231180120002a0c3138383637"
|
|
"38373430350000");
|
|
|
|
// Generate signature
|
|
size_t gen_signature_length = 0;
|
|
sts = OEMCrypto_GenerateSignature(s.session_id(), &context[0], context.size(),
|
|
NULL, &gen_signature_length);
|
|
|
|
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
|
|
ASSERT_EQ(static_cast<size_t>(256), gen_signature_length);
|
|
|
|
uint8_t* gen_signature = new uint8_t[gen_signature_length];
|
|
sts = OEMCrypto_GenerateSignature(s.session_id(), &context[0], context.size(),
|
|
gen_signature, &gen_signature_length);
|
|
|
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
|
|
|
// 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.
|
|
// TODO: This is not a valid test vector
|
|
vector<uint8_t> message = wvcdm::a2b_hex(
|
|
"000000001248000000020000101907d9ffde13aa95c122678053362136bdf840"
|
|
"8f8276e4c2d87ec52b61aa1b9f646e58734930acebe899b3e464189a14a87202"
|
|
"fb02574e70640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931"
|
|
"b76a3a85f046523e10011a09393837363534333231180120002a0c3138383637"
|
|
"0a4c08001248000000020000101907d9ffde13aa95c122678053362136bdf840"
|
|
"8f8276e4c2d87ec52b61aa1b9f646e58734930acebe899b3e464189a14a87202"
|
|
"fb02574e70640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931"
|
|
"b76a3a85f046523e10011a09393837363534333231180120002a0c3138383637"
|
|
"0a4c08001248000000020000101907d9ffde13aa95c122678053362136bdf840"
|
|
"8f8276e4c2d87ec52b61aa1b9f646e58734930acebe899b3e464189a14a87202"
|
|
"fb02574e70640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931"
|
|
"b76a3a85f046523e10011a09393837363534333231180120002a0c3138383637"
|
|
"0a4c08001248000000020000101907d9ffde13aa95c122678053362136bdf840"
|
|
"8f8276e4c2d87ec52b61aa1b9f646e58734930acebe899b3e464189a14a87202"
|
|
"fb02574e70640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931"
|
|
"b76a3a85f046523e10011a09393837363534333231180120002a0c3138383637"
|
|
"0a4c08001248000000020000101907d9ffde13aa95c122678053362136bdf840"
|
|
"8f8276e4c2d87ec52b61aa1b9f646e58734930acebe899b3e464189a14a87202"
|
|
"fb02574e70640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931"
|
|
"b76a3a85f046523e10011a09393837363534333231180120002a0c3138383637"
|
|
"0a4c08001248000000020000101907d9ffde13aa95c122678053362136bdf840"
|
|
"8f8276e4c2d87ec52b61aa1b9f646e58734930acebe899b3e464189a14a87202"
|
|
"fb02574e70640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931"
|
|
"b76a3a85f046523e10011a09393837363534333231180120002a0c3138383637");
|
|
|
|
memcpy(&message[0], &nonce, sizeof(uint32_t));
|
|
uint32_t* messageNonce = reinterpret_cast<uint32_t*>(&message[0]);
|
|
uint8_t* key = &message[32];
|
|
size_t key_length = 7;
|
|
uint8_t* key_iv = &message[64];
|
|
|
|
// TODO: In practice, we need to generate a signature here after inserting
|
|
// the right nonce into the message.
|
|
vector<uint8_t> signature = wvcdm::a2b_hex(
|
|
"0a4c08001248000000020000101907d9ffde13aa95c122678053362136bdf840");
|
|
|
|
size_t wrapped_key_length;
|
|
|
|
sts = OEMCrypto_RewrapDeviceRSAKey(s.session_id(), &message[0],
|
|
message.size(), &signature[0],
|
|
signature.size(), messageNonce, key,
|
|
key_length, key_iv, NULL,
|
|
&wrapped_key_length);
|
|
|
|
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
|
|
ASSERT_NE(static_cast<size_t>(0), wrapped_key_length);
|
|
|
|
vector<uint8_t> wrapped_key;
|
|
wrapped_key.resize(wrapped_key_length);
|
|
|
|
sts = OEMCrypto_RewrapDeviceRSAKey(s.session_id(), &message[0],
|
|
message.size(), &signature[0],
|
|
signature.size(), messageNonce, key,
|
|
key_length, key_iv, &wrapped_key[0],
|
|
&wrapped_key_length);
|
|
|
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
|
|
|
// TODO: This is not a valid test vector
|
|
vector<uint8_t> clear_key = wvcdm::a2b_hex(
|
|
"1558497b6d994be343ed1c6d6313e0537b843e9a9c0836d1e83fe33154191ce9"
|
|
"a14d8d95bebaddc03bd471827170f527c0a166b9068b273d1bc57fbb13975ee4"
|
|
"f6b9a31743da6c447acbb712e81b13eddfd4e96c76010ac9b8aa1b6b3152b0fc"
|
|
"39ad33e5719656069f9ede9ebba7a77dd2e2074eec5c1b7ffc427a6f1be168f0"
|
|
"b5857713a44623862c903284bc53417e23c65602b52c1cb699e8352453eb9698"
|
|
"0b31459b90c26c907b549c1ab293725e414d4e45f5b30af7a55f95499a7dc89f"
|
|
"7d13ba90b34aef6b49484b0701bf96ea8b660c24bb4e92a2d1c43beb434fa386"
|
|
"1071380388799ac31d79285f5817687ed3e2eeb73a30744e77b757686c9ba5ad");;
|
|
ASSERT_EQ(NULL, find(wrapped_key, clear_key));
|
|
|
|
s.close();
|
|
testTearDown();
|
|
|
|
delete[] gen_signature;
|
|
}
|
|
|
|
TEST_F(OEMCryptoClientTest, CertificateLicense) {
|
|
OEMCryptoResult sts;
|
|
InstallKeybox(kDefaultKeybox);
|
|
testSetUp();
|
|
Session& s = createSession("ONE");
|
|
s.open();
|
|
|
|
vector<uint8_t> wrappedKey;
|
|
|
|
ASSERT_TRUE(s.GenerateDerivedKeys());
|
|
ASSERT_TRUE(s.CertificateProvision(&wrappedKey));
|
|
|
|
// Load the Wrapped Key
|
|
sts = OEMCrypto_LoadDeviceRSAKey(s.session_id(), &wrappedKey[0],
|
|
wrappedKey.size());
|
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
|
|
|
// Sign a Message
|
|
vector<uint8_t> licenseRequest = wvcdm::a2b_hex(
|
|
"ba711a51e0c4c995440c28057f7f5e2f2e9c3a1edeb7549aca21e6050b059ac8"
|
|
"6ad64ec1a528eef17b4f5ce781af488d50fb0e60d04b48c78d55847a4e14243c"
|
|
"0023c553b46a2f53995870f351295e3aa2237f153f1415e817ad23e662e547b1"
|
|
"4708b303473813f93ee192353ff22bee54dd0f558bbe4b61b75b387bc310e9d6"
|
|
"8ff2cb3482689c0688570809b756dba4c2697be3132a2da782aa877ed64d8c7d"
|
|
"506525a382bad14d7e797c256c3617c22fa4165482b9742e9b54ffb6c52eda1d");
|
|
size_t signature_length = 0;
|
|
|
|
sts = OEMCrypto_GenerateRSASignature(s.session_id(), &licenseRequest[0],
|
|
licenseRequest.size(), NULL,
|
|
&signature_length);
|
|
|
|
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
|
|
ASSERT_NE(static_cast<size_t>(0), signature_length);
|
|
|
|
uint8_t* signature = new uint8_t[signature_length];
|
|
|
|
sts = OEMCrypto_GenerateRSASignature(s.session_id(), &licenseRequest[0],
|
|
licenseRequest.size(), signature,
|
|
&signature_length);
|
|
|
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
|
// TODO: Validate the signature
|
|
|
|
// Rewrap Canned Response
|
|
|
|
// In the real world, the signature above would just have been used to contact
|
|
// the license server to get this response.
|
|
// TODO: This is not a valid test vector
|
|
vector<uint8_t> sessionKey = wvcdm::a2b_hex(
|
|
"6fa479c731d2770b6a61a5d1420bb9d1");
|
|
vector<uint8_t> mac_context = wvcdm::a2b_hex(
|
|
"41555448454e5449434154494f4e000a4c08001248000000020000101907d9ff"
|
|
"de13aa95c122678053362136bdf8408f8276e4c2d87ec52b61aa1b9f646e5873"
|
|
"4930acebe899b3e464189a14a87202fb02574e70640bd22ef44b2d7e3912250a"
|
|
"230a14080112100915007caa9b5931b76a3a85f046523e10011a093938373635"
|
|
"34333231180120002a0c31383836373837343035000000000100");
|
|
vector<uint8_t> enc_context = wvcdm::a2b_hex(
|
|
"454e4352595054494f4e000a4c08001248000000020000101907d9ffde13aa95"
|
|
"c122678053362136bdf8408f8276e4c2d87ec52b61aa1b9f646e58734930aceb"
|
|
"e899b3e464189a14a87202fb02574e70640bd22ef44b2d7e3912250a230a1408"
|
|
"0112100915007caa9b5931b76a3a85f046523e10011a09393837363534333231"
|
|
"180120002a0c31383836373837343035000000000080");
|
|
|
|
sts = OEMCrypto_DeriveKeysFromSessionKey(s.session_id(), &sessionKey[0],
|
|
sessionKey.size(), &mac_context[0],
|
|
mac_context.size(), &enc_context[0],
|
|
enc_context.size());
|
|
|
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
|
|
|
s.close();
|
|
testTearDown();
|
|
|
|
delete[] signature;
|
|
}
|
|
|
|
TEST_F(OEMCryptoClientTest, CertificateDecrypt) {
|
|
OEMCryptoResult sts;
|
|
testSetUp();
|
|
InstallKeybox(kDefaultKeybox);
|
|
Session& s = createSession("ONE");
|
|
s.open();
|
|
|
|
ASSERT_TRUE(s.GenerateDerivedKeys());
|
|
ASSERT_TRUE(s.CertificateLicense());
|
|
|
|
// Select the key (from fill_simple_message)
|
|
vector<uint8_t> keyId = wvcdm::a2b_hex("000000000000000000000000");
|
|
sts = OEMCrypto_SelectKey(s.session_id(), &keyId[0], keyId.size());
|
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
|
|
|
// Set up our expected input and output
|
|
vector<uint8_t> encryptedData = wvcdm::a2b_hex(
|
|
"ec261c115f9d5cda1d5cc7d33c4e37362d1397c89efdd1da5f0065c4848b0462"
|
|
"337ba14693735203c9b4184e362439c0cea5e5d1a628425eddf8a6bf9ba901ca"
|
|
"46f5a9fd973cffbbe3c276af9919e2e8f6f3f420538b7a0d6dc41487874d96b8"
|
|
"efaedb45a689b91beb8c20d36140ad467d9d620b19a5fc6f223b57e0e6a7f913"
|
|
"00fd899e5e1b89963e83067ca0912aa5b79df683e2530b55a9645be341bc5f07"
|
|
"cffc724790af635c959e2644e51ba7f23bae710eb55a1f2f4e060c3c1dd1387c"
|
|
"74415dc880492dd1d5b9ecf3f01de48a44baeb4d3ea5cc4f8d561d0865afcabb"
|
|
"fc14a9ab9647e6e31adabb72d792f0c9ba99dc3e9205657d28fc7771d64e6d4b");
|
|
vector<uint8_t> encryptionIv = wvcdm::a2b_hex(
|
|
"719dbcb253b2ec702bb8c1b1bc2f3bc6");
|
|
vector<uint8_t> unencryptedData = wvcdm::a2b_hex(
|
|
"19ef4361e16e6825b336e2012ad8ffc9ce176ab2256e1b98aa15b7877bd8c626"
|
|
"fa40b2e88373457cbcf4f1b4b9793434a8ac03a708f85974cff01bddcbdd7a8e"
|
|
"e33fd160c1d5573bfd8104efd23237edcf28205c3673920553f8dd5e916604b0"
|
|
"1082345181dceeae5ea39d829c7f49e1850c460645de33c288723b7ae3d91a17"
|
|
"a3f04195cd1945ba7b0f37fef7e82368be30f04365d877766f6d56f67d22a244"
|
|
"ef2596d3053f657c1b5d90b64e11797edf1c198a23a7bfc20e4d44c74ae41280"
|
|
"a8317f443255f4020eda850ff0954e308f53a634cbce799ae58911bc59ccd6a5"
|
|
"de2ac53ee0fa7ea15fc692cc892acc0090865dc57becacddf362a092dfd3040b");
|
|
|
|
// Describe the output
|
|
uint8_t outputBuffer[256];
|
|
OEMCrypto_DestBufferDesc destBuffer;
|
|
destBuffer.type = OEMCrypto_BufferType_Clear;
|
|
destBuffer.buffer.clear.address = outputBuffer;
|
|
destBuffer.buffer.clear.max_length = sizeof(outputBuffer);
|
|
|
|
// Decrypt the data
|
|
sts = OEMCrypto_DecryptCTR(s.session_id(), &encryptedData[0],
|
|
encryptedData.size(), true, &encryptionIv[0], 0,
|
|
&destBuffer);
|
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
|
ASSERT_EQ(0, memcmp(&unencryptedData[0], outputBuffer,
|
|
unencryptedData.size()));
|
|
|
|
s.close();
|
|
testTearDown();
|
|
}
|
|
#endif // CAN_INSTALL_KEYBOX
|
|
|
|
// TODO(kqyang): Add more unit tests
|
|
|
|
} // namespace wvoec
|