Refactor usage table tests
Merge from Widevine repo of http://go/wvgerrit/169061 Bug: 253779846 Merged from https://widevine-internal-review.googlesource.com/167477 Change-Id: I6046e59449700c8be05641f71dcbb2bba6ce493b
This commit is contained in:
committed by
Fred Gylys-Colwell
parent
6897bc1a1c
commit
26aa378ca5
@@ -19,6 +19,7 @@ LOCAL_SRC_FILES:= \
|
||||
oemcrypto_basic_test.cpp \
|
||||
oemcrypto_license_test.cpp \
|
||||
oemcrypto_provisioning_test.cpp \
|
||||
oemcrypto_usage_table_test.cpp \
|
||||
oemcrypto_test.cpp \
|
||||
oemcrypto_test_android.cpp \
|
||||
oemcrypto_test_main.cpp \
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1707
libwvdrmengine/oemcrypto/test/oemcrypto_usage_table_test.cpp
Normal file
1707
libwvdrmengine/oemcrypto/test/oemcrypto_usage_table_test.cpp
Normal file
File diff suppressed because it is too large
Load Diff
379
libwvdrmengine/oemcrypto/test/oemcrypto_usage_table_test.h
Normal file
379
libwvdrmengine/oemcrypto/test/oemcrypto_usage_table_test.h
Normal file
@@ -0,0 +1,379 @@
|
||||
// Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine
|
||||
// License Agreement.
|
||||
//
|
||||
// Test data for OEMCrypto unit tests.
|
||||
//
|
||||
#ifndef CDM_OEMCRYPTO_USAGE_TABLE_TEST_
|
||||
#define CDM_OEMCRYPTO_USAGE_TABLE_TEST_
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "log.h"
|
||||
#include "oemcrypto_basic_test.h"
|
||||
#include "oemcrypto_license_test.h"
|
||||
#include "test_sleep.h"
|
||||
|
||||
namespace wvoec {
|
||||
|
||||
class OEMCryptoRefreshTest : public OEMCryptoLicenseTest {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
OEMCryptoLicenseTest::SetUp();
|
||||
// These values allow us to run a few simple duration tests or just start
|
||||
// playback right away. All times are in seconds since the license was
|
||||
// signed.
|
||||
// Soft expiry false means timers are strictly enforce.
|
||||
timer_limits_.soft_enforce_rental_duration = true;
|
||||
timer_limits_.soft_enforce_playback_duration = false;
|
||||
// Playback may begin immediately.
|
||||
timer_limits_.earliest_playback_start_seconds = 0;
|
||||
// First playback may be within the first two seconds.
|
||||
timer_limits_.rental_duration_seconds = kDuration;
|
||||
// Once started, playback may last two seconds without a renewal.
|
||||
timer_limits_.initial_renewal_duration_seconds = kDuration;
|
||||
// Total playback is not limited.
|
||||
timer_limits_.total_playback_duration_seconds = 0;
|
||||
}
|
||||
|
||||
void LoadLicense() {
|
||||
license_messages_.core_response().timer_limits = timer_limits_;
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
void MakeRenewalRequest(RenewalRoundTrip* renewal_messages) {
|
||||
ASSERT_NO_FATAL_FAILURE(renewal_messages->SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(renewal_messages->CreateDefaultResponse());
|
||||
}
|
||||
|
||||
void LoadRenewal(RenewalRoundTrip* renewal_messages,
|
||||
OEMCryptoResult expected_result) {
|
||||
ASSERT_NO_FATAL_FAILURE(renewal_messages->EncryptAndSignResponse());
|
||||
ASSERT_EQ(expected_result, renewal_messages->LoadResponse());
|
||||
}
|
||||
|
||||
ODK_TimerLimits timer_limits_;
|
||||
};
|
||||
|
||||
// This class is for testing the generic crypto functionality.
|
||||
class OEMCryptoGenericCryptoTest : public OEMCryptoRefreshTest {
|
||||
protected:
|
||||
// buffer_size_ must be a multiple of encryption block size, 16. We'll use a
|
||||
// reasonable number of blocks for most of the tests.
|
||||
OEMCryptoGenericCryptoTest() : buffer_size_(160) {}
|
||||
|
||||
void SetUp() override {
|
||||
OEMCryptoRefreshTest::SetUp();
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
license_messages_.CreateResponseWithGenericCryptoKeys());
|
||||
InitializeClearBuffer();
|
||||
}
|
||||
|
||||
void InitializeClearBuffer() {
|
||||
clear_buffer_.assign(buffer_size_, 0);
|
||||
for (size_t i = 0; i < clear_buffer_.size(); i++) {
|
||||
clear_buffer_[i] = 1 + i % 250;
|
||||
}
|
||||
for (size_t i = 0; i < wvoec::KEY_IV_SIZE; i++) {
|
||||
iv_[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
void ResizeBuffer(size_t new_size) {
|
||||
buffer_size_ = new_size;
|
||||
InitializeClearBuffer(); // Re-initialize the clear buffer.
|
||||
}
|
||||
|
||||
void EncryptAndLoadKeys() {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
// Encrypt the buffer with the specified key made in
|
||||
// CreateResponseWithGenericCryptoKeys.
|
||||
void EncryptBuffer(unsigned int key_index, const vector<uint8_t>& in_buffer,
|
||||
vector<uint8_t>* out_buffer) {
|
||||
EncryptBufferWithKey(session_.license().keys[key_index].key_data, in_buffer,
|
||||
out_buffer);
|
||||
}
|
||||
// Encrypt the buffer with the specified key.
|
||||
void EncryptBufferWithKey(const uint8_t* key_data,
|
||||
const vector<uint8_t>& in_buffer,
|
||||
vector<uint8_t>* out_buffer) {
|
||||
AES_KEY aes_key;
|
||||
ASSERT_EQ(0, AES_set_encrypt_key(key_data, AES_BLOCK_SIZE * 8, &aes_key));
|
||||
uint8_t iv_buffer[wvoec::KEY_IV_SIZE];
|
||||
memcpy(iv_buffer, iv_, wvoec::KEY_IV_SIZE);
|
||||
out_buffer->resize(in_buffer.size());
|
||||
ASSERT_GT(in_buffer.size(), 0u);
|
||||
ASSERT_EQ(0u, in_buffer.size() % AES_BLOCK_SIZE);
|
||||
AES_cbc_encrypt(in_buffer.data(), out_buffer->data(), in_buffer.size(),
|
||||
&aes_key, iv_buffer, AES_ENCRYPT);
|
||||
}
|
||||
|
||||
// Sign the buffer with the specified key made in
|
||||
// CreateResponseWithGenericCryptoKeys.
|
||||
void SignBuffer(unsigned int key_index, const vector<uint8_t>& in_buffer,
|
||||
vector<uint8_t>* signature) {
|
||||
SignBufferWithKey(session_.license().keys[key_index].key_data, in_buffer,
|
||||
signature);
|
||||
}
|
||||
|
||||
// Sign the buffer with the specified key.
|
||||
void SignBufferWithKey(const uint8_t* key_data,
|
||||
const vector<uint8_t>& in_buffer,
|
||||
vector<uint8_t>* signature) {
|
||||
unsigned int md_len = SHA256_DIGEST_LENGTH;
|
||||
signature->resize(SHA256_DIGEST_LENGTH);
|
||||
HMAC(EVP_sha256(), key_data, wvoec::MAC_KEY_SIZE, in_buffer.data(),
|
||||
in_buffer.size(), signature->data(), &md_len);
|
||||
}
|
||||
|
||||
OEMCryptoResult GenericEncrypt(const uint8_t* key_handle,
|
||||
size_t key_handle_length,
|
||||
const uint8_t* clear_buffer,
|
||||
size_t clear_buffer_length, const uint8_t* iv,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
uint8_t* out_buffer) {
|
||||
if (ShouldGenerateCorpus()) {
|
||||
const std::string file_name =
|
||||
GetFileName("oemcrypto_generic_encrypt_fuzz_seed_corpus");
|
||||
OEMCrypto_Generic_Api_Fuzz fuzzed_structure;
|
||||
fuzzed_structure.cipher_mode = OEMCrypto_CipherMode_CENC;
|
||||
fuzzed_structure.algorithm = algorithm;
|
||||
// Cipher mode and algorithm.
|
||||
AppendToFile(file_name, reinterpret_cast<const char*>(&fuzzed_structure),
|
||||
sizeof(fuzzed_structure));
|
||||
AppendToFile(file_name, reinterpret_cast<const char*>(iv),
|
||||
wvoec::KEY_IV_SIZE);
|
||||
AppendSeparator(file_name);
|
||||
AppendToFile(file_name, reinterpret_cast<const char*>(clear_buffer),
|
||||
clear_buffer_length);
|
||||
}
|
||||
return OEMCrypto_Generic_Encrypt(key_handle, key_handle_length,
|
||||
clear_buffer, clear_buffer_length, iv,
|
||||
algorithm, out_buffer);
|
||||
}
|
||||
|
||||
OEMCryptoResult GenericDecrypt(
|
||||
const uint8_t* key_handle, size_t key_handle_length,
|
||||
const uint8_t* encrypted_buffer, size_t encrypted_buffer_length,
|
||||
const uint8_t* iv, OEMCrypto_Algorithm algorithm, uint8_t* out_buffer) {
|
||||
if (ShouldGenerateCorpus()) {
|
||||
const std::string file_name =
|
||||
GetFileName("oemcrypto_generic_decrypt_fuzz_seed_corpus");
|
||||
OEMCrypto_Generic_Api_Fuzz fuzzed_structure;
|
||||
fuzzed_structure.cipher_mode = OEMCrypto_CipherMode_CENC;
|
||||
fuzzed_structure.algorithm = algorithm;
|
||||
// Cipher mode and algorithm.
|
||||
AppendToFile(file_name, reinterpret_cast<const char*>(&fuzzed_structure),
|
||||
sizeof(fuzzed_structure));
|
||||
AppendToFile(file_name, reinterpret_cast<const char*>(iv),
|
||||
wvoec::KEY_IV_SIZE);
|
||||
AppendSeparator(file_name);
|
||||
AppendToFile(file_name, reinterpret_cast<const char*>(encrypted_buffer),
|
||||
encrypted_buffer_length);
|
||||
}
|
||||
return OEMCrypto_Generic_Decrypt(key_handle, key_handle_length,
|
||||
encrypted_buffer, encrypted_buffer_length,
|
||||
iv, algorithm, out_buffer);
|
||||
}
|
||||
|
||||
OEMCryptoResult GenericVerify(const uint8_t* key_handle,
|
||||
size_t key_handle_length,
|
||||
const uint8_t* clear_buffer,
|
||||
size_t clear_buffer_length,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length) {
|
||||
if (ShouldGenerateCorpus()) {
|
||||
const std::string file_name =
|
||||
GetFileName("oemcrypto_generic_verify_fuzz_seed_corpus");
|
||||
OEMCrypto_Generic_Api_Fuzz fuzzed_structure;
|
||||
fuzzed_structure.cipher_mode = OEMCrypto_CipherMode_CENC;
|
||||
fuzzed_structure.algorithm = algorithm;
|
||||
// Cipher mode and algorithm.
|
||||
AppendToFile(file_name, reinterpret_cast<const char*>(&fuzzed_structure),
|
||||
sizeof(fuzzed_structure));
|
||||
AppendToFile(file_name, reinterpret_cast<const char*>(clear_buffer),
|
||||
clear_buffer_length);
|
||||
AppendSeparator(file_name);
|
||||
AppendToFile(file_name, reinterpret_cast<const char*>(signature),
|
||||
signature_length);
|
||||
}
|
||||
return OEMCrypto_Generic_Verify(key_handle, key_handle_length, clear_buffer,
|
||||
clear_buffer_length, algorithm, signature,
|
||||
signature_length);
|
||||
}
|
||||
|
||||
OEMCryptoResult GenericSign(const uint8_t* key_handle,
|
||||
size_t key_handle_length,
|
||||
const uint8_t* clear_buffer,
|
||||
size_t clear_buffer_length,
|
||||
OEMCrypto_Algorithm algorithm, uint8_t* signature,
|
||||
size_t* signature_length) {
|
||||
if (ShouldGenerateCorpus()) {
|
||||
const std::string file_name =
|
||||
GetFileName("oemcrypto_generic_sign_fuzz_seed_corpus");
|
||||
OEMCrypto_Generic_Api_Fuzz fuzzed_structure;
|
||||
fuzzed_structure.cipher_mode = OEMCrypto_CipherMode_CENC;
|
||||
fuzzed_structure.algorithm = algorithm;
|
||||
// Cipher mode and algorithm.
|
||||
AppendToFile(file_name, reinterpret_cast<const char*>(&fuzzed_structure),
|
||||
sizeof(fuzzed_structure));
|
||||
AppendToFile(file_name, reinterpret_cast<const char*>(clear_buffer),
|
||||
clear_buffer_length);
|
||||
}
|
||||
return OEMCrypto_Generic_Sign(key_handle, key_handle_length, clear_buffer,
|
||||
clear_buffer_length, algorithm, signature,
|
||||
signature_length);
|
||||
}
|
||||
|
||||
// This asks OEMCrypto to encrypt with the specified key, and expects a
|
||||
// failure.
|
||||
void BadEncrypt(unsigned int key_index, OEMCrypto_Algorithm algorithm,
|
||||
size_t buffer_length) {
|
||||
OEMCryptoResult sts;
|
||||
vector<uint8_t> expected_encrypted;
|
||||
EncryptBuffer(key_index, clear_buffer_, &expected_encrypted);
|
||||
vector<uint8_t> key_handle;
|
||||
sts = GetKeyHandleIntoVector(
|
||||
session_.session_id(), session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle);
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
vector<uint8_t> encrypted(buffer_length);
|
||||
sts = GenericEncrypt(key_handle.data(), key_handle.size(),
|
||||
clear_buffer_.data(), buffer_length, iv_, algorithm,
|
||||
encrypted.data());
|
||||
EXPECT_NE(OEMCrypto_SUCCESS, sts);
|
||||
expected_encrypted.resize(buffer_length);
|
||||
EXPECT_NE(encrypted, expected_encrypted);
|
||||
}
|
||||
|
||||
// This asks OEMCrypto to decrypt with the specified key, and expects a
|
||||
// failure.
|
||||
void BadDecrypt(unsigned int key_index, OEMCrypto_Algorithm algorithm,
|
||||
size_t buffer_length) {
|
||||
OEMCryptoResult sts;
|
||||
vector<uint8_t> encrypted;
|
||||
EncryptBuffer(key_index, clear_buffer_, &encrypted);
|
||||
vector<uint8_t> key_handle;
|
||||
sts = GetKeyHandleIntoVector(
|
||||
session_.session_id(), session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle);
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
vector<uint8_t> resultant(encrypted.size());
|
||||
sts = GenericDecrypt(key_handle.data(), key_handle.size(), encrypted.data(),
|
||||
buffer_length, iv_, algorithm, resultant.data());
|
||||
EXPECT_NE(OEMCrypto_SUCCESS, sts);
|
||||
EXPECT_NE(clear_buffer_, resultant);
|
||||
}
|
||||
|
||||
// This asks OEMCrypto to sign with the specified key, and expects a
|
||||
// failure.
|
||||
void BadSign(unsigned int key_index, OEMCrypto_Algorithm algorithm) {
|
||||
OEMCryptoResult sts;
|
||||
vector<uint8_t> expected_signature;
|
||||
SignBuffer(key_index, clear_buffer_, &expected_signature);
|
||||
|
||||
vector<uint8_t> key_handle;
|
||||
sts = GetKeyHandleIntoVector(
|
||||
session_.session_id(), session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle);
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
size_t signature_length = (size_t)SHA256_DIGEST_LENGTH;
|
||||
vector<uint8_t> signature(SHA256_DIGEST_LENGTH);
|
||||
sts = GenericSign(key_handle.data(), key_handle.size(),
|
||||
clear_buffer_.data(), clear_buffer_.size(), algorithm,
|
||||
signature.data(), &signature_length);
|
||||
EXPECT_NE(OEMCrypto_SUCCESS, sts);
|
||||
EXPECT_NE(signature, expected_signature);
|
||||
}
|
||||
|
||||
// This asks OEMCrypto to verify a signature with the specified key, and
|
||||
// expects a failure.
|
||||
void BadVerify(unsigned int key_index, OEMCrypto_Algorithm algorithm,
|
||||
size_t signature_size, bool alter_data) {
|
||||
OEMCryptoResult sts;
|
||||
vector<uint8_t> signature;
|
||||
SignBuffer(key_index, clear_buffer_, &signature);
|
||||
if (alter_data) {
|
||||
signature[0] ^= 42;
|
||||
}
|
||||
if (signature.size() < signature_size) {
|
||||
signature.resize(signature_size);
|
||||
}
|
||||
|
||||
vector<uint8_t> key_handle;
|
||||
sts = GetKeyHandleIntoVector(
|
||||
session_.session_id(), session_.license().keys[key_index].key_id,
|
||||
session_.license().keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle);
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
sts = GenericVerify(key_handle.data(), key_handle.size(),
|
||||
clear_buffer_.data(), clear_buffer_.size(), algorithm,
|
||||
signature.data(), signature_size);
|
||||
EXPECT_NE(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
|
||||
// This must be a multiple of encryption block size.
|
||||
size_t buffer_size_;
|
||||
vector<uint8_t> clear_buffer_;
|
||||
vector<uint8_t> encrypted_buffer_;
|
||||
uint8_t iv_[wvoec::KEY_IV_SIZE];
|
||||
};
|
||||
|
||||
class OEMCryptoUsageTableTest : public OEMCryptoGenericCryptoTest {
|
||||
public:
|
||||
void SetUp() override { OEMCryptoGenericCryptoTest::SetUp(); }
|
||||
|
||||
virtual void ShutDown() {
|
||||
ASSERT_NO_FATAL_FAILURE(session_.close());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Terminate());
|
||||
}
|
||||
|
||||
virtual void Restart() {
|
||||
OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox));
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize());
|
||||
(void)OEMCrypto_SetMaxAPIVersion(kCurrentAPI);
|
||||
(void)OEMCrypto_EnterTestMode();
|
||||
EnsureTestROT();
|
||||
ASSERT_NO_FATAL_FAILURE(session_.open());
|
||||
}
|
||||
|
||||
void PrintDotsWhileSleep(int64_t total_seconds, int64_t interval_seconds) {
|
||||
int64_t dot_time = interval_seconds;
|
||||
int64_t elapsed_time = 0;
|
||||
const int64_t start_time = wvutil::Clock().GetCurrentTime();
|
||||
do {
|
||||
wvutil::TestSleep::Sleep(1);
|
||||
elapsed_time = wvutil::Clock().GetCurrentTime() - start_time;
|
||||
if (elapsed_time >= dot_time) {
|
||||
cout << ".";
|
||||
cout.flush();
|
||||
dot_time += interval_seconds;
|
||||
}
|
||||
} while (elapsed_time < total_seconds);
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
OEMCryptoResult LoadUsageTableHeader(
|
||||
const vector<uint8_t>& encrypted_usage_header) {
|
||||
return OEMCrypto_LoadUsageTableHeader(encrypted_usage_header.data(),
|
||||
encrypted_usage_header.size());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace wvoec
|
||||
|
||||
#endif // CDM_OEMCRYPTO_USAGE_TABLE_TEST_
|
||||
Reference in New Issue
Block a user