Update LoadTestKeybox

Merge from Widevine repo of http://go/wvgerrit/41662

This CL updates oemcrypto unit tests to use the new test keybox.

bug: 69552641 Update OEMCrypto_LoadTestKeybox

test: Unit tests compile and run -- many tests won't pass until merged
with vendor code

Change-Id: I73bdca3958b2c985d4c61801aa95807a2e6d4299
This commit is contained in:
Fred Gylys-Colwell
2018-01-23 16:06:16 -08:00
parent 19cb1792a4
commit d72f49e31a
11 changed files with 139 additions and 48 deletions

View File

@@ -49,7 +49,10 @@ class AuthenticationRoot {
}
WvKeybox& keybox() { return use_test_keybox_ ? test_keybox_ : keybox_; }
void UseTestKeybox() { use_test_keybox_ = true; }
bool UseTestKeybox(const uint8_t* keybox_data, size_t keybox_length) {
use_test_keybox_ = true;
return test_keybox_.InstallKeybox(keybox_data, keybox_length);
}
RSA_shared_ptr& SharedRsaKey() { return rsa_key_; }
RSA* rsa_key() { return rsa_key_.get(); }

View File

@@ -47,7 +47,9 @@ class CryptoEngine {
return root_of_trust_.InstallKeybox(keybox, keybox_length);
}
void UseTestKeybox() { root_of_trust_.UseTestKeybox(); }
bool UseTestKeybox(const uint8_t* keybox_data, size_t keybox_length) {
return root_of_trust_.UseTestKeybox(keybox_data, keybox_length);
}
bool LoadTestRsaKey() { return root_of_trust_.LoadTestRsaKey(); }

View File

@@ -688,7 +688,8 @@ extern "C" OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox,
return OEMCrypto_ERROR_WRITE_KEYBOX;
}
extern "C" OEMCryptoResult OEMCrypto_LoadTestKeybox() {
extern "C" OEMCryptoResult OEMCrypto_LoadTestKeybox(
const uint8_t* buffer, size_t length) {
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
LOGI("-- OEMCryptoResult OEMCrypto_LoadTestKeybox()\n");
}
@@ -699,7 +700,7 @@ extern "C" OEMCryptoResult OEMCrypto_LoadTestKeybox() {
if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
crypto_engine->UseTestKeybox();
crypto_engine->UseTestKeybox(buffer, length);
return OEMCrypto_SUCCESS;
}

View File

@@ -171,7 +171,7 @@ void DeviceFeatures::PickDerivedKey() {
}
if (uses_keybox) {
// If device uses a keybox, try to load the test keybox.
if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestKeybox()) {
if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestKeybox(NULL, 0)) {
derive_key_method = LOAD_TEST_KEYBOX;
} else if (IsTestKeyboxInstalled()) {
derive_key_method = EXISTING_TEST_KEYBOX;

View File

@@ -7,6 +7,8 @@
#include <arpa/inet.h> // needed for ntoh()
#include <openssl/aes.h>
#include <openssl/bio.h>
#include <openssl/cmac.h>
#include <openssl/err.h>
#include <openssl/hmac.h>
#include <openssl/pem.h>
@@ -172,7 +174,53 @@ void Session::FillDefaultContext(vector<uint8_t>* mac_context,
"180120002a0c31383836373837343035000000000080");
}
void Session::GenerateDerivedKeysFromKeybox() {
void Session::DeriveKey(const uint8_t* key, const vector<uint8_t>& context,
int counter, vector<uint8_t>* out) {
ASSERT_FALSE(context.empty());
ASSERT_GE(4, counter);
ASSERT_NE(static_cast<void*>(NULL), out);
const EVP_CIPHER* cipher = EVP_aes_128_cbc();
CMAC_CTX* cmac_ctx = CMAC_CTX_new();
ASSERT_NE(static_cast<void*>(NULL), cmac_ctx);
ASSERT_EQ(1, CMAC_Init(cmac_ctx, key, wvcdm::KEY_SIZE, cipher, 0));
std::vector<uint8_t> message;
message.push_back(counter);
message.insert(message.end(), context.begin(), context.end());
ASSERT_EQ(1, CMAC_Update(cmac_ctx, &message[0], message.size()));
size_t reslen;
uint8_t res[128];
ASSERT_EQ(1, CMAC_Final(cmac_ctx, res, &reslen));
out->assign(res, res + reslen);
CMAC_CTX_free(cmac_ctx);
}
void Session::DeriveKeys(const uint8_t* master_key,
const vector<uint8_t>& mac_key_context,
const vector<uint8_t>& enc_key_context) {
// Generate derived key for mac key
std::vector<uint8_t> mac_key_part2;
DeriveKey(master_key, mac_key_context, 1, &mac_key_server_);
DeriveKey(master_key, mac_key_context, 2, &mac_key_part2);
mac_key_server_.insert(mac_key_server_.end(), mac_key_part2.begin(),
mac_key_part2.end());
DeriveKey(master_key, mac_key_context, 3, &mac_key_client_);
DeriveKey(master_key, mac_key_context, 4, &mac_key_part2);
mac_key_client_.insert(mac_key_client_.end(), mac_key_part2.begin(),
mac_key_part2.end());
// Generate derived key for encryption key
DeriveKey(master_key, enc_key_context, 1, &enc_key_);
}
void Session::GenerateDerivedKeysFromKeybox(
const wvoec_mock::WidevineKeybox& keybox) {
GenerateNonce();
vector<uint8_t> mac_context;
vector<uint8_t> enc_context;
@@ -182,13 +230,7 @@ void Session::GenerateDerivedKeysFromKeybox() {
mac_context.size(), &enc_context[0],
enc_context.size()));
// Expected MAC and ENC keys generated from context strings
// with test keybox "installed".
mac_key_server_ = wvcdm::a2b_hex(
"3CFD60254786AF350B353B4FBB700AB382558400356866BA16C256BCD8C502BF");
mac_key_client_ = wvcdm::a2b_hex(
"A9DE7B3E4E199ED8D1FBC29CD6B4C772CC4538C8B0D3E208B3E76F2EC0FD6F47");
enc_key_ = wvcdm::a2b_hex("D0BFC35DA9E33436E81C4229E78CB9F4");
DeriveKeys(keybox.device_key_, mac_context, enc_context);
}
void Session::GenerateDerivedKeysFromSessionKey() {
@@ -207,13 +249,7 @@ void Session::GenerateDerivedKeysFromSessionKey() {
&mac_context[0], mac_context.size(), &enc_context[0],
enc_context.size()));
// Expected MAC and ENC keys generated from context strings
// with RSA certificate "installed".
mac_key_server_ = wvcdm::a2b_hex(
"1E451E59CB663DA1646194DD28880788ED8ED2EFF913CBD6A0D535D1D5A90381");
mac_key_client_ = wvcdm::a2b_hex(
"F9AAE74690909F2207B53B13307FCA096CA8C49CC6DFE3659873CB952889A74B");
enc_key_ = wvcdm::a2b_hex("CB477D09014D72C9B8DCE76C33EA43B3");
DeriveKeys(&session_key[0], mac_context, enc_context);
}
void Session::LoadTestKeys(const std::string& pst, bool new_mac_keys) {

View File

@@ -149,7 +149,7 @@ class Session {
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(const wvoec_mock::WidevineKeybox& keybox);
// Generate known mac and enc keys using OEMCrypto_DeriveKeysFromSessionKey
// and also fill out enc_key_, mac_key_server_, and mac_key_client_.
void GenerateDerivedKeysFromSessionKey();
@@ -371,6 +371,14 @@ class Session {
size_t message_size() { return message_size_; }
private:
// Generate mac and enc keys give the master key.
void DeriveKeys(const uint8_t* master_key,
const vector<uint8_t>& mac_key_context,
const vector<uint8_t>& enc_key_context);
// Internal utility function to derive key using CMAC-128
void DeriveKey(const uint8_t* key, const vector<uint8_t>& context,
int counter, vector<uint8_t>* out);
bool open_;
bool forced_session_id_;
OEMCrypto_SESSION session_id_;

View File

@@ -7,10 +7,8 @@
#include <string>
#if 0
#include "OEMCryptoCENC.h"
#include "wv_keybox.h"
#endif
namespace wvoec {
@@ -21,6 +19,41 @@ namespace wvoec {
// the tests. It should be loaded by OEMCrypto when OEMCrypto_LoadTestKeybox
// is called.
static const wvoec_mock::WidevineKeybox kTestKeybox = {
// Sample keybox used for test vectors
{
// deviceID = WidevineTestOnlyKeybox000
0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65,
0x54, 0x65, 0x73, 0x74, 0x4f, 0x6e, 0x6c, 0x79,
0x4b, 0x65, 0x79, 0x62, 0x6f, 0x78, 0x30, 0x30,
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}, {
// key
0xe4, 0xff, 0x57, 0x4c, 0x32, 0x2e, 0xf5, 0x34,
0x26, 0x21, 0x2c, 0xb3, 0xed, 0x37, 0xf3, 0x5e,
}, {
// data (system ID 7912).
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x1e, 0xe8,
0xca, 0x1e, 0x71, 0x7c, 0xfb, 0xe8, 0xa3, 0x94,
0x52, 0x0a, 0x6b, 0x71, 0x37, 0xd2, 0x69, 0xfa,
0x5a, 0xc6, 0xb5, 0x4c, 0x6b, 0x46, 0x63, 0x9b,
0xbe, 0x80, 0x3d, 0xbb, 0x4f, 0xf7, 0x4c, 0x5f,
0x6f, 0x55, 0x0e, 0x3d, 0x3d, 0x9a, 0xcf, 0x81,
0x12, 0x5d, 0x52, 0xe0, 0x47, 0x8c, 0xda, 0x0b,
0xf4, 0x31, 0x41, 0x13, 0xd0, 0xd5, 0x2d, 0xa0,
0x5b, 0x20, 0x9a, 0xed, 0x51, 0x5d, 0x13, 0xd6,
}, {
// magic
0x6b, 0x62, 0x6f, 0x78,
}, {
// Crc
0x39, 0xf2, 0x94, 0xa7,
}
};
// These are old test keyboxes. The first keybox can be used to update an
// older OEMCrypto because it is the same keybox that was previously used in
// unit tests.
static const wvoec_mock::WidevineKeybox kValidKeybox01 = {
// Sample keybox used for test vectors
{
// deviceID

View File

@@ -25,7 +25,7 @@ void SessionUtil::CreateWrappedRSAKeyFromKeybox(uint32_t allowed_schemes,
bool force) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox());
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox(keybox_));
// Provisioning request would be signed by the client and verified by the
// server.
ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature());
@@ -86,6 +86,7 @@ void SessionUtil::InstallKeybox(const wvoec_mock::WidevineKeybox& keybox,
bool good) {
uint8_t wrapped[sizeof(wvoec_mock::WidevineKeybox)];
size_t length = sizeof(wvoec_mock::WidevineKeybox);
keybox_ = keybox;
ASSERT_EQ(
OEMCrypto_SUCCESS,
OEMCrypto_WrapKeybox(reinterpret_cast<const uint8_t*>(&keybox),
@@ -101,16 +102,27 @@ void SessionUtil::InstallKeybox(const wvoec_mock::WidevineKeybox& keybox,
void SessionUtil::EnsureTestKeys() {
switch (global_features.derive_key_method) {
case DeviceFeatures::LOAD_TEST_KEYBOX:
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestKeybox());
keybox_ = kTestKeybox;
/* Note: If you are upgrading from an older version, it may be easier to
* uncomment the following line. This uses the same test keybox as we
* used in older versions of this test.
*/
// keybox_ = kValidKeybox01;
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_LoadTestKeybox(
reinterpret_cast<const uint8_t*>(&keybox_),
sizeof(keybox_)));
break;
case DeviceFeatures::LOAD_TEST_RSA_KEY:
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestRSAKey());
break;
case DeviceFeatures::EXISTING_TEST_KEYBOX:
// already has test keybox.
keybox_ = kTestKeybox;
break;
case DeviceFeatures::FORCE_TEST_KEYBOX:
InstallKeybox(kTestKeybox, true);
keybox_ = kTestKeybox;
InstallKeybox(keybox_, true);
break;
case DeviceFeatures::TEST_PROVISION_30:
// Can use oem certificate to install test rsa key.
@@ -140,7 +152,7 @@ void SessionUtil::InstallTestSessionKeys(Session* s) {
s->GenerateDerivedKeysFromSessionKey());
} else { // Just uses keybox. Test keybox should already be installed.
ASSERT_NO_FATAL_FAILURE(
s->GenerateDerivedKeysFromKeybox());
s->GenerateDerivedKeysFromKeybox(keybox_));
}
}

View File

@@ -34,6 +34,7 @@ public:
std::vector<uint8_t> encoded_rsa_key_;
std::vector<uint8_t> wrapped_rsa_key_;
wvoec_mock::WidevineKeybox keybox_;
};
} // namespace wvoec

View File

@@ -71,7 +71,7 @@ int GetRandBytes(unsigned char* buf, int num) {
namespace wvoec {
class OEMCryptoClientTest : public ::testing::Test {
class OEMCryptoClientTest : public ::testing::Test, public SessionUtil {
protected:
OEMCryptoClientTest() {}
@@ -506,12 +506,6 @@ TEST_F(OEMCryptoKeyboxTest, ProductionKeyboxValid) {
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxValid());
}
TEST_F(OEMCryptoKeyboxTest, GenerateDerivedKeysFromKeybox) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
s.GenerateDerivedKeysFromKeybox();
}
// This tests GenerateDerivedKeys with an 8k context.
TEST_F(OEMCryptoKeyboxTest, GenerateDerivedKeysFromKeyboxLargeBuffer) {
Session s;
@@ -633,8 +627,7 @@ TEST_F(OEMCryptoProv30Test, OEMCertSignatureLargeBuffer) {
//
// These tests will use either a test keybox or a test certificate to derive
// session keys.
class OEMCryptoSessionTests : public OEMCryptoClientTest,
public SessionUtil {
class OEMCryptoSessionTests : public OEMCryptoClientTest {
protected:
OEMCryptoSessionTests() {}
@@ -737,7 +730,7 @@ TEST_F(OEMCryptoSessionTestKeyboxTest, BadDataForceKeybox) {
TEST_F(OEMCryptoSessionTestKeyboxTest, GenerateSignature) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox());
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox(keybox_));
// Dummy context for testing signature generation.
vector<uint8_t> context = wvcdm::a2b_hex(
@@ -1566,14 +1559,14 @@ TEST_F(OEMCryptoSessionTests, SimultaneousDecryptWithLostMessageKeyboxTest) {
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s[i]));
}
for (int i = 0; i < 8; i++) {
ASSERT_NO_FATAL_FAILURE(s[i].GenerateDerivedKeysFromKeybox());
ASSERT_NO_FATAL_FAILURE(s[i].GenerateDerivedKeysFromKeybox(keybox_));
ASSERT_NO_FATAL_FAILURE(
s[i].FillSimpleMessage(kLongDuration, 0, s[i].get_nonce()));
ASSERT_NO_FATAL_FAILURE(s[i].EncryptAndSign());
}
// First set of messages are lost. Generate second set.
for (int i = 0; i < 8; i++) {
ASSERT_NO_FATAL_FAILURE(s[i].GenerateDerivedKeysFromKeybox());
ASSERT_NO_FATAL_FAILURE(s[i].GenerateDerivedKeysFromKeybox(keybox_));
ASSERT_NO_FATAL_FAILURE(
s[i].FillSimpleMessage(kLongDuration, 0, s[i].get_nonce()));
ASSERT_NO_FATAL_FAILURE(s[i].EncryptAndSign());
@@ -2145,7 +2138,7 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvision) {
TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange1KeyboxTest) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox());
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox(keybox_));
ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature());
struct RSAPrivateKeyMessage encrypted;
std::vector<uint8_t> signature;
@@ -2175,7 +2168,7 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange1KeyboxTest) {
TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange2KeyboxTest) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox());
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox(keybox_));
// Provisioning request would be signed by client and verified by server.
ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature());
struct RSAPrivateKeyMessage encrypted;
@@ -2207,7 +2200,7 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange2KeyboxTest) {
TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange3KeyboxTest) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox());
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox(keybox_));
// Provisioning request would be signed by client and verified by server.
ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature());
struct RSAPrivateKeyMessage encrypted;
@@ -2240,7 +2233,7 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange3KeyboxTest) {
TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadSignatureKeyboxTest) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox());
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox(keybox_));
// Provisioning request would be signed by client and verified by server.
ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature());
struct RSAPrivateKeyMessage encrypted;
@@ -2271,7 +2264,7 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadSignatureKeyboxTest) {
TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadNonceKeyboxTest) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox());
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox(keybox_));
// Provisioning request would be signed by client and verified by server.
ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature());
struct RSAPrivateKeyMessage encrypted;
@@ -2302,7 +2295,7 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadNonceKeyboxTest) {
TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRSAKeyKeyboxTest) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox());
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox(keybox_));
// Provisioning request would be signed by client and verified by server.
ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature());
struct RSAPrivateKeyMessage encrypted;
@@ -2333,7 +2326,7 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRSAKeyKeyboxTest) {
TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionLargeBufferKeyboxTest) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox());
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox(keybox_));
// Provisioning request would be signed by client and verified by server.
ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature());
struct LargeRSAPrivateKeyMessage : public RSAPrivateKeyMessage {

View File

@@ -13,7 +13,7 @@
// unit tests in both files.
#include <gtest/gtest.h>
#include "oec_test_data.h"
#include "OEMCryptoCENC.h"
namespace wvoec {
@@ -103,7 +103,9 @@ TEST_F(OEMCryptoAndroidMNCTest, MinVersionNumber10) {
TEST_F(OEMCryptoAndroidMNCTest, LoadsTestKeyboxImplemented) {
if (OEMCrypto_Keybox == OEMCrypto_GetProvisioningMethod()) {
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestKeybox());
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestKeybox(
reinterpret_cast<const uint8_t*>(&kTestKeybox),
sizeof(kTestKeybox)));
} else {
// Android should use keybox or provisioning 3.0.
ASSERT_EQ(OEMCrypto_OEMCertificate, OEMCrypto_GetProvisioningMethod());