Source release 14.0.0
This commit is contained in:
@@ -21,7 +21,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
|
||||
Session s;
|
||||
s.open();
|
||||
s.GenerateDerivedKeysFromKeybox();
|
||||
s.GenerateDerivedKeysFromKeybox(session_helper.keybox_);
|
||||
|
||||
static const uint32_t SignatureBufferMaxLength = size;
|
||||
vector<uint8_t> signature(SignatureBufferMaxLength);
|
||||
|
||||
@@ -140,6 +140,7 @@ std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) {
|
||||
if (api_version < 11) FilterOut(&filter, "*API11*");
|
||||
if (api_version < 12) FilterOut(&filter, "*API12*");
|
||||
if (api_version < 13) FilterOut(&filter, "*API13*");
|
||||
if (api_version < 14) FilterOut(&filter, "*API14*");
|
||||
// Performance tests take a long time. Filter them out if they are not
|
||||
// specifically requested.
|
||||
if (filter.find("Performance") == std::string::npos) {
|
||||
@@ -172,7 +173,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;
|
||||
@@ -187,8 +188,8 @@ bool DeviceFeatures::IsTestKeyboxInstalled() {
|
||||
size_t key_data_len = sizeof(key_data);
|
||||
if (OEMCrypto_GetKeyData(key_data, &key_data_len) != OEMCrypto_SUCCESS)
|
||||
return false;
|
||||
if (key_data_len != kKeyboxDataSize) return false;
|
||||
if (memcmp(key_data, &kKeybox[kKeyboxDataOffset], key_data_len)) return false;
|
||||
if (key_data_len != sizeof(wvcdm_test_auth::kValidKeybox01.data_)) return false;
|
||||
if (memcmp(key_data, wvcdm_test_auth::kValidKeybox01.data_, key_data_len)) return false;
|
||||
uint8_t dev_id[128] = {0};
|
||||
size_t dev_id_len = 128;
|
||||
if (OEMCrypto_GetDeviceID(dev_id, &dev_id_len) != OEMCrypto_SUCCESS)
|
||||
@@ -197,8 +198,8 @@ bool DeviceFeatures::IsTestKeyboxInstalled() {
|
||||
// multiple '\0' characters at the end of the device id.
|
||||
return 0 == strncmp(
|
||||
reinterpret_cast<const char*>(dev_id),
|
||||
reinterpret_cast<const char*>(&kKeybox[kKeyboxDeviceIdOffset]),
|
||||
kKeyboxDeviceIdSize);
|
||||
reinterpret_cast<const char*>(wvcdm_test_auth::kValidKeybox01.device_id_),
|
||||
sizeof(wvcdm_test_auth::kValidKeybox01.device_id_));
|
||||
}
|
||||
|
||||
void DeviceFeatures::FilterOut(std::string* current_filter,
|
||||
|
||||
@@ -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>
|
||||
@@ -17,6 +19,7 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -43,29 +46,20 @@ void PrintTo(const vector<uint8_t>& value, ostream* os) {
|
||||
namespace {
|
||||
int GetRandBytes(unsigned char* buf, int num) {
|
||||
// returns 1 on success, -1 if not supported, or 0 if other failure.
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
|
||||
return RAND_pseudo_bytes(buf, num);
|
||||
#else
|
||||
return RAND_bytes(buf, num);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
void DeleteX509Stack(STACK_OF(X509)* stack) {
|
||||
sk_X509_pop_free(stack, X509_free);
|
||||
}
|
||||
|
||||
typedef size_t X509Count;
|
||||
#else
|
||||
typedef int X509Count;
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
namespace wvoec {
|
||||
|
||||
// Increment counter for AES-CTR. The CENC spec specifies we increment only
|
||||
// the low 64 bits of the IV counter, and leave the high 64 bits alone. This
|
||||
// is different from the OpenSSL implementation, so we implement the CTR loop
|
||||
// is different from the BoringSSL implementation, so we implement the CTR loop
|
||||
// ourselves.
|
||||
void ctr128_inc64(int64_t increaseBy, uint8_t* iv) {
|
||||
ASSERT_NE(static_cast<void*>(NULL), iv);
|
||||
@@ -77,19 +71,19 @@ void ctr128_inc64(int64_t increaseBy, uint8_t* iv) {
|
||||
// Some compilers don't like the macro htonl within an ASSERT_EQ.
|
||||
uint32_t htonl_fnc(uint32_t x) { return htonl(x); }
|
||||
|
||||
void dump_openssl_error() {
|
||||
void dump_boringssl_error() {
|
||||
while (unsigned long err = ERR_get_error()) {
|
||||
char buffer[120];
|
||||
ERR_error_string_n(err, buffer, sizeof(buffer));
|
||||
cout << "openssl error -- " << buffer << "\n";
|
||||
cout << "BoringSSL Error -- " << buffer << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, void (*func)(T*)>
|
||||
class openssl_ptr {
|
||||
class boringssl_ptr {
|
||||
public:
|
||||
explicit openssl_ptr(T* p = NULL) : ptr_(p) {}
|
||||
~openssl_ptr() {
|
||||
explicit boringssl_ptr(T* p = NULL) : ptr_(p) {}
|
||||
~boringssl_ptr() {
|
||||
if (ptr_) func(ptr_);
|
||||
}
|
||||
T& operator*() const { return *ptr_; }
|
||||
@@ -99,7 +93,7 @@ class openssl_ptr {
|
||||
|
||||
private:
|
||||
T* ptr_;
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(openssl_ptr);
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(boringssl_ptr);
|
||||
};
|
||||
|
||||
Session::Session()
|
||||
@@ -111,8 +105,9 @@ Session::Session()
|
||||
enc_key_(wvcdm::KEY_SIZE),
|
||||
public_rsa_(0),
|
||||
message_size_(sizeof(MessageData)),
|
||||
num_keys_(4) { // Most tests only use 4 keys.
|
||||
// Other tests will explicitly call set_num_keys.
|
||||
num_keys_(4), // Most tests only use 4 keys.
|
||||
// Other tests will explicitly call set_num_keys.
|
||||
has_entitlement_license_(false) {
|
||||
// Stripe the padded message.
|
||||
for (size_t i = 0; i < sizeof(padded_message_.padding); i++) {
|
||||
padded_message_.padding[i] = i % 0x100;
|
||||
@@ -180,7 +175,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 wvcdm_test_auth::WidevineKeybox& keybox) {
|
||||
GenerateNonce();
|
||||
vector<uint8_t> mac_context;
|
||||
vector<uint8_t> enc_context;
|
||||
@@ -190,15 +231,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() {
|
||||
@@ -217,13 +250,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) {
|
||||
@@ -237,7 +264,8 @@ void Session::LoadTestKeys(const std::string& pst, bool new_mac_keys) {
|
||||
&signature_[0], signature_.size(),
|
||||
encrypted_license().mac_key_iv,
|
||||
encrypted_license().mac_keys, num_keys_,
|
||||
key_array_, pst_ptr, pst.length(), NULL));
|
||||
key_array_, pst_ptr, pst.length(), NULL,
|
||||
OEMCrypto_ContentLicense));
|
||||
// Update new generated keys.
|
||||
memcpy(&mac_key_server_[0], license_.mac_keys, wvcdm::MAC_KEY_SIZE);
|
||||
memcpy(&mac_key_client_[0], license_.mac_keys + wvcdm::MAC_KEY_SIZE,
|
||||
@@ -247,11 +275,114 @@ void Session::LoadTestKeys(const std::string& pst, bool new_mac_keys) {
|
||||
OEMCrypto_SUCCESS,
|
||||
OEMCrypto_LoadKeys(session_id(), message_ptr(), message_size_,
|
||||
&signature_[0], signature_.size(), NULL, NULL,
|
||||
num_keys_, key_array_, pst_ptr, pst.length(), NULL));
|
||||
num_keys_, key_array_, pst_ptr, pst.length(), NULL,
|
||||
OEMCrypto_ContentLicense));
|
||||
}
|
||||
VerifyTestKeys();
|
||||
}
|
||||
|
||||
void Session::LoadEnitlementTestKeys(const std::string& pst,
|
||||
bool new_mac_keys,
|
||||
OEMCryptoResult expected_sts) {
|
||||
uint8_t* pst_ptr = NULL;
|
||||
if (pst.length() > 0) {
|
||||
pst_ptr = encrypted_license().pst;
|
||||
}
|
||||
if (new_mac_keys) {
|
||||
ASSERT_EQ(expected_sts,
|
||||
OEMCrypto_LoadKeys(session_id(), message_ptr(), message_size_,
|
||||
&signature_[0], signature_.size(),
|
||||
encrypted_license().mac_key_iv,
|
||||
encrypted_license().mac_keys, num_keys_,
|
||||
key_array_, pst_ptr, pst.length(), NULL,
|
||||
OEMCrypto_EntitlementLicense));
|
||||
// Update new generated keys.
|
||||
memcpy(&mac_key_server_[0], license_.mac_keys, wvcdm::MAC_KEY_SIZE);
|
||||
memcpy(&mac_key_client_[0], license_.mac_keys + wvcdm::MAC_KEY_SIZE,
|
||||
wvcdm::MAC_KEY_SIZE);
|
||||
} else {
|
||||
ASSERT_EQ(
|
||||
expected_sts,
|
||||
OEMCrypto_LoadKeys(session_id(), message_ptr(), message_size_,
|
||||
&signature_[0], signature_.size(), NULL, NULL,
|
||||
num_keys_, key_array_, pst_ptr, pst.length(), NULL,
|
||||
OEMCrypto_EntitlementLicense));
|
||||
}
|
||||
}
|
||||
|
||||
void Session::FillEntitledKeyArray() {
|
||||
has_entitlement_license_ = true;
|
||||
for (size_t i = 0; i < num_keys_; ++i) {
|
||||
EntitledContentKeyData* key_data = &entitled_key_data_[i];
|
||||
|
||||
entitled_key_array_[i].entitlement_key_id = key_array_[i].key_id;
|
||||
entitled_key_array_[i].entitlement_key_id_length =
|
||||
key_array_[i].key_id_length;
|
||||
|
||||
EXPECT_EQ(
|
||||
1, GetRandBytes(key_data->content_key_id,
|
||||
sizeof(key_data->content_key_id)));
|
||||
entitled_key_array_[i].content_key_id = key_data->content_key_id;
|
||||
entitled_key_array_[i].content_key_id_length =
|
||||
sizeof(key_data->content_key_id);
|
||||
|
||||
EXPECT_EQ(
|
||||
1, GetRandBytes(key_data->content_key_data,
|
||||
sizeof(key_data->content_key_data)));
|
||||
entitled_key_array_[i].content_key_data = key_data->content_key_data;
|
||||
entitled_key_array_[i].content_key_data_length =
|
||||
sizeof(key_data->content_key_data);
|
||||
|
||||
EXPECT_EQ(
|
||||
1, GetRandBytes(entitled_key_data_[i].content_key_data_iv,
|
||||
sizeof(entitled_key_data_[i].content_key_data_iv)));
|
||||
entitled_key_array_[i].content_key_data_iv = key_data->content_key_data_iv;
|
||||
}
|
||||
}
|
||||
|
||||
void Session::LoadEntitledContentKeys(OEMCryptoResult expected_sts) {
|
||||
// Create a copy of the stored |entitled_key_array_|.
|
||||
std::vector<OEMCrypto_EntitledContentKeyObject> encrypted_entitled_key_array;
|
||||
encrypted_entitled_key_array.resize(num_keys_);
|
||||
memcpy(&encrypted_entitled_key_array[0], &entitled_key_array_[0],
|
||||
sizeof(OEMCrypto_EntitledContentKeyObject) * num_keys_);
|
||||
|
||||
// Create a encrypted version of all of the content keys stored in
|
||||
// |entitled_key_array_|.
|
||||
std::vector<std::vector<uint8_t> > encrypted_content_keys;
|
||||
encrypted_content_keys.resize(num_keys_);
|
||||
|
||||
for (size_t i = 0; i < num_keys_; ++i) {
|
||||
// Load the entitlement key from |key_array_|.
|
||||
AES_KEY aes_key;
|
||||
AES_set_encrypt_key(&key_array_[i].key_data[0], 256, &aes_key);
|
||||
encrypted_content_keys[i].resize(
|
||||
encrypted_entitled_key_array[i].content_key_data_length);
|
||||
|
||||
// Encrypt the content key with the entitlement key.
|
||||
uint8_t iv[16];
|
||||
memcpy(&iv[0], &encrypted_entitled_key_array[i].content_key_data[0], 16);
|
||||
AES_cbc_encrypt(
|
||||
&entitled_key_array_[i].content_key_data[0],
|
||||
const_cast<uint8_t*>(
|
||||
&encrypted_entitled_key_array[i].content_key_data[0]),
|
||||
encrypted_entitled_key_array[i].content_key_data_length,
|
||||
&aes_key, iv, AES_ENCRYPT);
|
||||
|
||||
// Set the |encrypted_entitled_key_array| to point to the encrypted copy
|
||||
// of the content key.
|
||||
encrypted_entitled_key_array[i].content_key_data =
|
||||
encrypted_content_keys[i].data();
|
||||
}
|
||||
ASSERT_EQ(expected_sts,
|
||||
OEMCrypto_LoadEntitledContentKeys(
|
||||
session_id(), num_keys_, &encrypted_entitled_key_array[0]));
|
||||
if (expected_sts != OEMCrypto_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
VerifyEntitlementTestKeys();
|
||||
}
|
||||
|
||||
void Session::VerifyTestKeys() {
|
||||
for (unsigned int i = 0; i < num_keys_; i++) {
|
||||
KeyControlBlock block;
|
||||
@@ -274,6 +405,29 @@ void Session::VerifyTestKeys() {
|
||||
}
|
||||
}
|
||||
|
||||
void Session::VerifyEntitlementTestKeys() {
|
||||
for (unsigned int i = 0; i < num_keys_; i++) {
|
||||
KeyControlBlock block;
|
||||
size_t size = sizeof(block);
|
||||
OEMCryptoResult sts = OEMCrypto_QueryKeyControl(
|
||||
session_id(), entitled_key_array_[i].content_key_id,
|
||||
entitled_key_array_[i].content_key_id_length,
|
||||
reinterpret_cast<uint8_t*>(&block), &size);
|
||||
if (sts != OEMCrypto_ERROR_NOT_IMPLEMENTED) {
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
ASSERT_EQ(sizeof(block), size);
|
||||
// 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;
|
||||
ASSERT_EQ(htonl_fnc(license_.keys[i].control.control_bits),
|
||||
htonl_fnc(block.control_bits))
|
||||
<< "For key " << i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Session::RefreshTestKeys(const size_t key_count, uint32_t control_bits,
|
||||
uint32_t nonce, OEMCryptoResult expected_result) {
|
||||
// Note: we store the message in encrypted_license_, but the refresh key
|
||||
@@ -329,7 +483,57 @@ void Session::FillSimpleMessage(uint32_t duration, uint32_t control,
|
||||
sizeof(license_.keys[i].key_iv)));
|
||||
EXPECT_EQ(1, GetRandBytes(license_.keys[i].control_iv,
|
||||
sizeof(license_.keys[i].control_iv)));
|
||||
if (global_features.api_version == 13) {
|
||||
if (global_features.api_version == 14) {
|
||||
// For version 14, we require OEMCrypto to handle kc14 for all licenses.
|
||||
memcpy(license_.keys[i].control.verification, "kc14", 4);
|
||||
} else if (global_features.api_version == 13) {
|
||||
// For version 13, we require OEMCrypto to handle kc13 for all licenses.
|
||||
memcpy(license_.keys[i].control.verification, "kc13", 4);
|
||||
} else if (global_features.api_version == 12) {
|
||||
// For version 12, we require OEMCrypto to handle kc12 for all licenses.
|
||||
memcpy(license_.keys[i].control.verification, "kc12", 4);
|
||||
} else if (control & wvoec_mock::kControlSecurityPatchLevelMask) {
|
||||
// For versions before 12, we require the special key control block only
|
||||
// when there are newer features present.
|
||||
memcpy(license_.keys[i].control.verification, "kc11", 4);
|
||||
} else if (control & wvoec_mock::kControlRequireAntiRollbackHardware) {
|
||||
memcpy(license_.keys[i].control.verification, "kc10", 4);
|
||||
} else if (control & (wvoec_mock::kControlHDCPVersionMask |
|
||||
wvoec_mock::kControlReplayMask)) {
|
||||
memcpy(license_.keys[i].control.verification, "kc09", 4);
|
||||
} else {
|
||||
memcpy(license_.keys[i].control.verification, "kctl", 4);
|
||||
}
|
||||
license_.keys[i].control.duration = htonl(duration);
|
||||
license_.keys[i].control.nonce = htonl(nonce);
|
||||
license_.keys[i].control.control_bits = htonl(control);
|
||||
license_.keys[i].cipher_mode = OEMCrypto_CipherMode_CTR;
|
||||
}
|
||||
memcpy(license_.pst, pst.c_str(), min(sizeof(license_.pst), pst.length()));
|
||||
pst_ = pst;
|
||||
}
|
||||
|
||||
void Session::FillSimpleEntitlementMessage(
|
||||
uint32_t duration, uint32_t control, uint32_t nonce,
|
||||
const std::string& pst) {
|
||||
EXPECT_EQ(
|
||||
1, GetRandBytes(license_.mac_key_iv, sizeof(license_.mac_key_iv)));
|
||||
EXPECT_EQ(1, GetRandBytes(license_.mac_keys, sizeof(license_.mac_keys)));
|
||||
for (unsigned int i = 0; i < num_keys_; i++) {
|
||||
memset(license_.keys[i].key_id, 0, kTestKeyIdMaxLength);
|
||||
license_.keys[i].key_id_length = kDefaultKeyIdLength;
|
||||
memset(license_.keys[i].key_id, i, license_.keys[i].key_id_length);
|
||||
EXPECT_EQ(1, GetRandBytes(license_.keys[i].key_data,
|
||||
sizeof(license_.keys[i].key_data)));
|
||||
license_.keys[i].key_data_length = wvcdm::KEY_SIZE * 2; // AES-256 keys
|
||||
EXPECT_EQ(1, GetRandBytes(license_.keys[i].key_iv,
|
||||
sizeof(license_.keys[i].key_iv)));
|
||||
EXPECT_EQ(1, GetRandBytes(license_.keys[i].control_iv,
|
||||
sizeof(license_.keys[i].control_iv)));
|
||||
if (global_features.api_version == 14) {
|
||||
// For version 13, we require OEMCrypto to handle kc14 for all licenses.
|
||||
memcpy(license_.keys[i].control.verification, "kc14", 4);
|
||||
} else if (global_features.api_version == 13) {
|
||||
// For version 13, we require OEMCrypto to handle kc13 for all licenses.
|
||||
memcpy(license_.keys[i].control.verification, "kc13", 4);
|
||||
} else if (global_features.api_version == 12) {
|
||||
@@ -362,7 +566,10 @@ void Session::FillRefreshMessage(size_t key_count, uint32_t control_bits,
|
||||
encrypted_license().keys[i].key_id_length = license_.keys[i].key_id_length;
|
||||
memcpy(encrypted_license().keys[i].key_id, license_.keys[i].key_id,
|
||||
encrypted_license().keys[i].key_id_length);
|
||||
if (global_features.api_version == 13) {
|
||||
if (global_features.api_version == 14) {
|
||||
// For version 14, we require OEMCrypto to handle kc14 for all licenses.
|
||||
memcpy(encrypted_license().keys[i].control.verification, "kc14", 4);
|
||||
} else if (global_features.api_version == 13) {
|
||||
// For version 13, we require OEMCrypto to handle kc13 for all licenses.
|
||||
memcpy(encrypted_license().keys[i].control.verification, "kc13", 4);
|
||||
} else if (global_features.api_version == 12) {
|
||||
@@ -389,9 +596,10 @@ void Session::EncryptAndSign() {
|
||||
AES_cbc_encrypt(&license_.mac_keys[0], &encrypted_license().mac_keys[0],
|
||||
2 * wvcdm::MAC_KEY_SIZE, &aes_key, iv_buffer, AES_ENCRYPT);
|
||||
|
||||
int key_size = has_entitlement_license() ? 256 : 128;
|
||||
for (unsigned int i = 0; i < num_keys_; i++) {
|
||||
memcpy(iv_buffer, &license_.keys[i].control_iv[0], wvcdm::KEY_IV_SIZE);
|
||||
AES_set_encrypt_key(&license_.keys[i].key_data[0], 128, &aes_key);
|
||||
AES_set_encrypt_key(&license_.keys[i].key_data[0], key_size, &aes_key);
|
||||
AES_cbc_encrypt(
|
||||
reinterpret_cast<const uint8_t*>(&license_.keys[i].control),
|
||||
reinterpret_cast<uint8_t*>(&encrypted_license().keys[i].control),
|
||||
@@ -474,7 +682,6 @@ void Session::FillKeyArray(const MessageData& 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);
|
||||
key_array[i].cipher_mode = data.keys[i].cipher_mode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,7 +731,8 @@ void Session::TestDecryptCTR(bool select_key_first,
|
||||
if (select_key_first) {
|
||||
// Select the key (from FillSimpleMessage)
|
||||
sts = OEMCrypto_SelectKey(session_id(), license_.keys[key_index].key_id,
|
||||
license_.keys[key_index].key_id_length);
|
||||
license_.keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CTR);
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
|
||||
@@ -588,7 +796,8 @@ void Session::TestSelectExpired(unsigned int key_index) {
|
||||
if (global_features.api_version >= 13) {
|
||||
OEMCryptoResult status =
|
||||
OEMCrypto_SelectKey(session_id(), license().keys[key_index].key_id,
|
||||
license().keys[key_index].key_id_length);
|
||||
license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CTR);
|
||||
// It is OK for SelectKey to succeed with an expired key, but if there is
|
||||
// an error, it must be OEMCrypto_ERROR_KEY_EXIRED.
|
||||
if (status != OEMCrypto_SUCCESS) {
|
||||
@@ -610,43 +819,30 @@ void Session::LoadOEMCert(bool verify_cert) {
|
||||
OEMCrypto_GetOEMPublicCertificate(session_id(), &public_cert[0],
|
||||
&public_cert_length));
|
||||
|
||||
// Load the certificate chain into an OpenSSL X509 Stack
|
||||
#ifdef OPENSSL_IS_BORINGSSL
|
||||
const openssl_ptr<STACK_OF(X509), DeleteX509Stack> x509_stack(
|
||||
// Load the certificate chain into a BoringSSL X509 Stack
|
||||
const boringssl_ptr<STACK_OF(X509), DeleteX509Stack> x509_stack(
|
||||
sk_X509_new_null());
|
||||
ASSERT_TRUE(x509_stack.NotNull()) << "Unable to allocate X509 stack.";
|
||||
|
||||
CBS pkcs7;
|
||||
CBS_init(&pkcs7, public_cert.data(), public_cert.size());
|
||||
if (!PKCS7_get_certificates(x509_stack.get(), &pkcs7)) {
|
||||
dump_openssl_error();
|
||||
dump_boringssl_error();
|
||||
FAIL() << "Unable to deserialize certificate chain.";
|
||||
}
|
||||
|
||||
STACK_OF(X509)* certs = x509_stack.get();
|
||||
#else
|
||||
// load the cert into rsa_key_.
|
||||
openssl_ptr<BIO, BIO_vfree> bio(
|
||||
BIO_new_mem_buf(&public_cert[0], public_cert_length));
|
||||
ASSERT_TRUE(bio.NotNull());
|
||||
openssl_ptr<PKCS7, PKCS7_free> cert(
|
||||
d2i_PKCS7_bio(bio.get(), NULL));
|
||||
ASSERT_TRUE(cert.NotNull());
|
||||
|
||||
EXPECT_EQ(OBJ_obj2nid(cert->type), NID_pkcs7_signed);
|
||||
STACK_OF(X509)* certs = cert->d.sign->cert;
|
||||
#endif
|
||||
|
||||
// Load the public cert's key into public_rsa_ and verify, if requested
|
||||
for (X509Count i = 0; certs && i < sk_X509_num(certs); i++) {
|
||||
for (size_t i = 0; certs && i < sk_X509_num(certs); i++) {
|
||||
X509* x509_cert = sk_X509_value(certs, i);
|
||||
openssl_ptr<EVP_PKEY, EVP_PKEY_free> pubkey(X509_get_pubkey(x509_cert));
|
||||
boringssl_ptr<EVP_PKEY, EVP_PKEY_free> pubkey(X509_get_pubkey(x509_cert));
|
||||
ASSERT_TRUE(pubkey.NotNull());
|
||||
if (i == 0) {
|
||||
public_rsa_ = EVP_PKEY_get1_RSA(pubkey.get());
|
||||
if (!public_rsa_) {
|
||||
cout << "d2i_RSAPrivateKey failed.\n";
|
||||
dump_openssl_error();
|
||||
dump_boringssl_error();
|
||||
ASSERT_TRUE(NULL != public_rsa_);
|
||||
}
|
||||
}
|
||||
@@ -656,9 +852,9 @@ void Session::LoadOEMCert(bool verify_cert) {
|
||||
X509_NAME* name = X509_get_subject_name(x509_cert);
|
||||
printf(" OEM Certificate Name: %s\n",
|
||||
X509_NAME_oneline(name, &buffer[0], buffer.size()));
|
||||
openssl_ptr<X509_STORE, X509_STORE_free> store(X509_STORE_new());
|
||||
boringssl_ptr<X509_STORE, X509_STORE_free> store(X509_STORE_new());
|
||||
ASSERT_TRUE(store.NotNull());
|
||||
openssl_ptr<X509_STORE_CTX, X509_STORE_CTX_free> store_ctx(
|
||||
boringssl_ptr<X509_STORE_CTX, X509_STORE_CTX_free> store_ctx(
|
||||
X509_STORE_CTX_new());
|
||||
ASSERT_TRUE(store_ctx.NotNull());
|
||||
|
||||
@@ -667,23 +863,13 @@ void Session::LoadOEMCert(bool verify_cert) {
|
||||
// TODO(fredgc): Verify cert is signed by Google.
|
||||
|
||||
int result = X509_verify_cert(store_ctx.get());
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
|
||||
ASSERT_GE(0, result) << " OEM Cert not valid. " <<
|
||||
X509_verify_cert_error_string(store_ctx->error);
|
||||
#else
|
||||
ASSERT_GE(0, result) << " OEM Cert not valid. " <<
|
||||
X509_verify_cert_error_string(
|
||||
X509_STORE_CTX_get_error(store_ctx.get()));
|
||||
#endif
|
||||
if (result == 0) {
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
|
||||
printf("Cert not verified: %s.\n",
|
||||
X509_verify_cert_error_string(store_ctx->error));
|
||||
#else
|
||||
printf("Cert not verified: %s.\n",
|
||||
X509_verify_cert_error_string(
|
||||
X509_STORE_CTX_get_error(store_ctx.get())));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -767,32 +953,32 @@ void Session::RewrapRSAKey30(const struct RSAPrivateKeyMessage& encrypted,
|
||||
|
||||
void Session::PreparePublicKey(const uint8_t* rsa_key, size_t rsa_key_length) {
|
||||
if (rsa_key == NULL) {
|
||||
rsa_key = wvcdm_test_auth::kRsaPrivateKey_2048;
|
||||
rsa_key_length = wvcdm_test_auth::kRsaPrivateKeySize_2048;
|
||||
rsa_key = wvcdm_test_auth::kTestRSAPKCS8PrivateKeyInfo2_2048;
|
||||
rsa_key_length = wvcdm_test_auth::kTestRSAPKCS8PrivateKeyInfo2_2048_Size;
|
||||
}
|
||||
uint8_t* p = const_cast<uint8_t*>(rsa_key);
|
||||
openssl_ptr<BIO, BIO_vfree> bio(BIO_new_mem_buf(p, rsa_key_length));
|
||||
boringssl_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(
|
||||
boringssl_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()));
|
||||
boringssl_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.get());
|
||||
if (!public_rsa_) {
|
||||
cout << "d2i_RSAPrivateKey failed. ";
|
||||
dump_openssl_error();
|
||||
dump_boringssl_error();
|
||||
FAIL() << "Could not parse public RSA key.";
|
||||
}
|
||||
switch (RSA_check_key(public_rsa_)) {
|
||||
case 1: // valid.
|
||||
return;
|
||||
case 0: // not valid.
|
||||
dump_openssl_error();
|
||||
dump_boringssl_error();
|
||||
FAIL() << "[rsa key not valid] ";
|
||||
default: // -1 == check failed.
|
||||
dump_openssl_error();
|
||||
dump_boringssl_error();
|
||||
FAIL() << "[error checking rsa key] ";
|
||||
}
|
||||
}
|
||||
@@ -801,13 +987,9 @@ bool Session::VerifyPSSSignature(EVP_PKEY* pkey, const uint8_t* message,
|
||||
size_t message_length,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length) {
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
|
||||
EVP_MD_CTX md_ctx_struct;
|
||||
EVP_MD_CTX* md_ctx = &md_ctx_struct;
|
||||
EVP_MD_CTX_init(md_ctx);
|
||||
#else
|
||||
EVP_MD_CTX* md_ctx = EVP_MD_CTX_new();
|
||||
#endif
|
||||
EVP_PKEY_CTX* pkey_ctx = NULL;
|
||||
|
||||
if (EVP_DigestVerifyInit(md_ctx, &pkey_ctx, EVP_sha1(), NULL /* no ENGINE */,
|
||||
@@ -845,20 +1027,12 @@ bool Session::VerifyPSSSignature(EVP_PKEY* pkey, const uint8_t* message,
|
||||
goto err;
|
||||
}
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
|
||||
EVP_MD_CTX_cleanup(md_ctx);
|
||||
#else
|
||||
EVP_MD_CTX_free(md_ctx);
|
||||
#endif
|
||||
return true;
|
||||
|
||||
err:
|
||||
dump_openssl_error();
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
|
||||
dump_boringssl_error();
|
||||
EVP_MD_CTX_cleanup(md_ctx);
|
||||
#else
|
||||
EVP_MD_CTX_free(md_ctx);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -874,7 +1048,7 @@ void Session::VerifyRSASignature(const vector<uint8_t>& message,
|
||||
<< RSA_size(public_rsa_) << "\n";
|
||||
|
||||
if (padding_scheme == kSign_RSASSA_PSS) {
|
||||
openssl_ptr<EVP_PKEY, EVP_PKEY_free> pkey(EVP_PKEY_new());
|
||||
boringssl_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.get(), &message[0], message.size(),
|
||||
@@ -909,7 +1083,7 @@ bool Session::GenerateRSASessionKey(vector<uint8_t>* session_key,
|
||||
int size = static_cast<int>(RSA_size(public_rsa_));
|
||||
if (status != size) {
|
||||
cout << "GenerateRSASessionKey error encrypting session key.\n";
|
||||
dump_openssl_error();
|
||||
dump_boringssl_error();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -1022,15 +1196,17 @@ void Session::VerifyPST(const Test_PST_Report& expected) {
|
||||
char* pst_ptr = reinterpret_cast<char *>(computed.pst());
|
||||
std::string computed_pst(pst_ptr, pst_ptr + computed.pst_length());
|
||||
ASSERT_EQ(expected.pst, computed_pst);
|
||||
EXPECT_NEAR(expected.seconds_since_license_received,
|
||||
time_t now = time(NULL);
|
||||
int64_t age = now - expected.time_created; // How old is this report.
|
||||
EXPECT_NEAR(expected.seconds_since_license_received + age,
|
||||
computed.seconds_since_license_received(),
|
||||
kTimeTolerance);
|
||||
// Decrypt times only valid on licenses that have been active.
|
||||
if (expected.status == kActive || expected.status == kInactiveUsed) {
|
||||
EXPECT_NEAR(expected.seconds_since_first_decrypt,
|
||||
EXPECT_NEAR(expected.seconds_since_first_decrypt + age,
|
||||
computed.seconds_since_first_decrypt(),
|
||||
kUsageTableTimeTolerance);
|
||||
EXPECT_NEAR(expected.seconds_since_last_decrypt,
|
||||
EXPECT_NEAR(expected.seconds_since_last_decrypt + age,
|
||||
computed.seconds_since_last_decrypt(),
|
||||
kUsageTableTimeTolerance);
|
||||
}
|
||||
@@ -1041,7 +1217,7 @@ void Session::VerifyPST(const Test_PST_Report& expected) {
|
||||
pst_report_buffer_.size() - SHA_DIGEST_LENGTH,
|
||||
&signature[0], &md_len)) {
|
||||
cout << "Error computing HMAC.\n";
|
||||
dump_openssl_error();
|
||||
dump_boringssl_error();
|
||||
}
|
||||
EXPECT_EQ(0, memcmp(computed.signature(), &signature[0],
|
||||
SHA_DIGEST_LENGTH));
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "oec_device_features.h"
|
||||
#include "pst_report.h"
|
||||
#include "test_keybox.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
using namespace std;
|
||||
@@ -94,13 +95,21 @@ struct RSAPrivateKeyMessage {
|
||||
struct Test_PST_Report {
|
||||
Test_PST_Report(const std::string& pst_in,
|
||||
OEMCrypto_Usage_Entry_Status status_in)
|
||||
: status(status_in), pst(pst_in) {}
|
||||
: status(status_in), pst(pst_in), time_created(time(NULL)) {}
|
||||
|
||||
OEMCrypto_Usage_Entry_Status status;
|
||||
int64_t seconds_since_license_received;
|
||||
int64_t seconds_since_first_decrypt;
|
||||
int64_t seconds_since_last_decrypt;
|
||||
std::string pst;
|
||||
time_t time_created;
|
||||
};
|
||||
|
||||
struct EntitledContentKeyData {
|
||||
uint8_t entitlement_key_id[wvcdm::KEY_SIZE];
|
||||
uint8_t content_key_id[wvcdm::KEY_SIZE];
|
||||
uint8_t content_key_data_iv[wvcdm::KEY_SIZE];
|
||||
uint8_t content_key_data[wvcdm::KEY_SIZE];
|
||||
};
|
||||
|
||||
// Increment counter for AES-CTR. The CENC spec specifies we increment only
|
||||
@@ -112,8 +121,8 @@ void ctr128_inc64(int64_t increaseBy, uint8_t* iv);
|
||||
// Some compilers don't like the macro htonl within an ASSERT_EQ.
|
||||
uint32_t htonl_fnc(uint32_t x);
|
||||
|
||||
// Prints error string from openSSL
|
||||
void dump_openssl_error();
|
||||
// Prints error string from BoringSSL
|
||||
void dump_boringssl_error();
|
||||
|
||||
class Session {
|
||||
public:
|
||||
@@ -142,7 +151,8 @@ 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 wvcdm_test_auth::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();
|
||||
@@ -151,9 +161,27 @@ class Session {
|
||||
// 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);
|
||||
// Loads the entitlement keys in the message pointed to by message_ptr()
|
||||
// using OEMCrypto_LoadKeys. This message should have already been created
|
||||
// by FillSimpleEntitlementMessage, modified if needed, and then encrypted
|
||||
// and signed by the server's mac key in EncryptAndSign.
|
||||
void LoadEnitlementTestKeys(const std::string& pst = "",
|
||||
bool new_mac_keys = true,
|
||||
OEMCryptoResult expected_sts = OEMCrypto_SUCCESS);
|
||||
// Fills an OEMCrypto_EntitledContentKeyObject using the information from
|
||||
// the license_ and randomly generated content keys. This method should be
|
||||
// called after LoadEnitlementTestKeys.
|
||||
void FillEntitledKeyArray();
|
||||
// Encrypts and loads the entitled content keys via
|
||||
// OEMCrypto_LoadEntitledContentKeys.
|
||||
void LoadEntitledContentKeys(
|
||||
OEMCryptoResult expected_sts = OEMCrypto_SUCCESS);
|
||||
// This uses OEMCrypto_QueryKeyControl to check that the keys in OEMCrypto
|
||||
// have the correct key control data.
|
||||
void VerifyTestKeys();
|
||||
// This uses OEMCrypto_QueryKeyControl to check that the keys in OEMCrypto
|
||||
// have the correct key control data.
|
||||
void VerifyEntitlementTestKeys();
|
||||
// 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,
|
||||
@@ -166,6 +194,12 @@ class Session {
|
||||
// before being loaded in LoadTestKeys.
|
||||
void FillSimpleMessage(uint32_t duration, uint32_t control, uint32_t nonce,
|
||||
const std::string& pst = "");
|
||||
// This fills the data structure license_ with entitlement key information.
|
||||
// This data can be modified, and then should be encrypted and signed in
|
||||
// EncryptAndSign before being loaded in LoadEnitlementTestKeys.
|
||||
void FillSimpleEntitlementMessage(
|
||||
uint32_t duration, uint32_t control,
|
||||
uint32_t nonce, 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.
|
||||
@@ -339,7 +373,18 @@ class Session {
|
||||
// The size of the encrypted message.
|
||||
size_t message_size() { return message_size_; }
|
||||
|
||||
// If this session has an entitlement license.
|
||||
bool has_entitlement_license() const { return has_entitlement_license_; }
|
||||
|
||||
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_;
|
||||
@@ -360,6 +405,13 @@ class Session {
|
||||
vector<uint8_t> encrypted_usage_entry_;
|
||||
uint32_t usage_entry_number_;
|
||||
string pst_;
|
||||
bool has_entitlement_license_;
|
||||
|
||||
// Clear Entitlement key data. This is the backing data for
|
||||
// |entitled_key_array_|.
|
||||
EntitledContentKeyData entitled_key_data_[kMaxNumKeys];
|
||||
// Entitled key object. Pointers are backed by |entitled_key_data_|.
|
||||
OEMCrypto_EntitledContentKeyObject entitled_key_array_[kMaxNumKeys];
|
||||
};
|
||||
|
||||
} // namespace wvoec
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "test_keybox.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace wvoec;
|
||||
|
||||
@@ -26,7 +24,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());
|
||||
@@ -83,14 +81,16 @@ void SessionUtil::CreateWrappedRSAKey(uint32_t allowed_schemes,
|
||||
}
|
||||
}
|
||||
|
||||
void SessionUtil::InstallKeybox(const uint8_t* keybox, bool good) {
|
||||
const size_t keybox_size = wvcdm_test_auth::kKeyboxSize;
|
||||
uint8_t wrapped[keybox_size];
|
||||
size_t length = keybox_size;
|
||||
void SessionUtil::InstallKeybox(const wvcdm_test_auth::WidevineKeybox& keybox,
|
||||
bool good) {
|
||||
uint8_t wrapped[sizeof(wvcdm_test_auth::WidevineKeybox)];
|
||||
size_t length = sizeof(wvcdm_test_auth::WidevineKeybox);
|
||||
keybox_ = keybox;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_SUCCESS,
|
||||
OEMCrypto_WrapKeybox(keybox, keybox_size, wrapped, &length, NULL, 0));
|
||||
OEMCryptoResult sts = OEMCrypto_InstallKeybox(wrapped, length);
|
||||
OEMCrypto_WrapKeybox(reinterpret_cast<const uint8_t*>(&keybox),
|
||||
sizeof(keybox), wrapped, &length, NULL, 0));
|
||||
OEMCryptoResult sts = OEMCrypto_InstallKeybox(wrapped, sizeof(keybox));
|
||||
if (good) {
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
} else {
|
||||
@@ -101,16 +101,30 @@ void SessionUtil::InstallKeybox(const uint8_t* keybox, bool good) {
|
||||
void SessionUtil::EnsureTestKeys() {
|
||||
switch (global_features.derive_key_method) {
|
||||
case DeviceFeatures::LOAD_TEST_KEYBOX:
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestKeybox());
|
||||
keybox_ = wvcdm_test_auth::kTestKeybox;
|
||||
/* Note: If you are upgrading from an older version, it may be easier to
|
||||
* force the following condition. This uses the same test keybox as we
|
||||
* used in older versions of this test.
|
||||
*/
|
||||
if (global_features.api_version < 14) {
|
||||
keybox_ = wvcdm_test_auth::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.
|
||||
// already has old test keybox.
|
||||
keybox_ = wvcdm_test_auth::kValidKeybox01;
|
||||
break;
|
||||
case DeviceFeatures::FORCE_TEST_KEYBOX:
|
||||
InstallKeybox(wvcdm_test_auth::kKeybox, true);
|
||||
keybox_ = wvcdm_test_auth::kTestKeybox;
|
||||
InstallKeybox(keybox_, true);
|
||||
break;
|
||||
case DeviceFeatures::TEST_PROVISION_30:
|
||||
// Can use oem certificate to install test rsa key.
|
||||
@@ -140,7 +154,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_));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "oec_session_util.h"
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "test_keybox.h"
|
||||
#include "test_rsa_key.h"
|
||||
|
||||
namespace wvoec {
|
||||
@@ -14,9 +15,10 @@ namespace wvoec {
|
||||
class SessionUtil {
|
||||
public:
|
||||
SessionUtil()
|
||||
: encoded_rsa_key_(wvcdm_test_auth::kRsaPrivateKey_2048,
|
||||
wvcdm_test_auth::kRsaPrivateKey_2048 +
|
||||
wvcdm_test_auth::kRsaPrivateKeySize_2048) {}
|
||||
: encoded_rsa_key_(
|
||||
wvcdm_test_auth::kTestRSAPKCS8PrivateKeyInfo2_2048,
|
||||
wvcdm_test_auth::kTestRSAPKCS8PrivateKeyInfo2_2048 +
|
||||
wvcdm_test_auth::kTestRSAPKCS8PrivateKeyInfo2_2048_Size) {}
|
||||
|
||||
// If force is true, we assert that the key loads successfully.
|
||||
void CreateWrappedRSAKeyFromKeybox(uint32_t allowed_schemes, bool force);
|
||||
@@ -27,7 +29,7 @@ public:
|
||||
// If force is true, we assert that the key loads successfully.
|
||||
void CreateWrappedRSAKey(uint32_t allowed_schemes, bool force);
|
||||
|
||||
void InstallKeybox(const uint8_t* keybox, bool good);
|
||||
void InstallKeybox(const wvcdm_test_auth::WidevineKeybox& keybox, bool good);
|
||||
|
||||
void EnsureTestKeys();
|
||||
|
||||
@@ -35,6 +37,7 @@ public:
|
||||
|
||||
std::vector<uint8_t> encoded_rsa_key_;
|
||||
std::vector<uint8_t> wrapped_rsa_key_;
|
||||
wvcdm_test_auth::WidevineKeybox keybox_;
|
||||
};
|
||||
|
||||
} // namespace wvoec
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,6 +15,8 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "test_keybox.h"
|
||||
#include "test_rsa_key.h"
|
||||
|
||||
#include "log.h"
|
||||
|
||||
@@ -105,7 +107,9 @@ TEST_F(OEMCryptoAndroidMNCTest, MinVersionNumber10) {
|
||||
|
||||
TEST_F(OEMCryptoAndroidMNCTest, LoadTestKeybox) {
|
||||
if (OEMCrypto_Keybox == OEMCrypto_GetProvisioningMethod()) {
|
||||
OEMCryptoResult status = OEMCrypto_LoadTestKeybox();
|
||||
OEMCryptoResult status = OEMCrypto_LoadTestKeybox(
|
||||
reinterpret_cast<const uint8_t*>(&kTestKeybox),
|
||||
sizeof(kTestKeybox)));
|
||||
// OEMCrypto may return success or not implemented.
|
||||
if (status == OEMCrypto_SUCCESS) {
|
||||
LOGV("OEMCrypto_LoadTestKeybox is implemented.");
|
||||
@@ -149,4 +153,12 @@ TEST_F(OEMCryptoAndroidOCTest, MinVersionNumber13) {
|
||||
ASSERT_GE(version, 13u);
|
||||
}
|
||||
|
||||
// These tests are required for Pi MR1 Android devices.
|
||||
class OEMCryptoAndroidPiMR1Test : public OEMCryptoAndroidOCTest {};
|
||||
|
||||
TEST_F(OEMCryptoAndroidPiMR1Test, MinVersionNumber14) {
|
||||
uint32_t version = OEMCrypto_APIVersion();
|
||||
ASSERT_GE(version, 14u);
|
||||
}
|
||||
|
||||
} // namespace wvoec
|
||||
|
||||
Reference in New Issue
Block a user