Update OEMCrypto test comments and logs
Merge from Widevine repo of http://go/wvgerrit/121886 This CL merges some changes from branch rvc-dev to sc-dev that prepared it for merge. One change is that the unit tests now say they are part of Android S instead of R. Bug: 180546871 Change-Id: I2ebbd8f7b8586389ebb75f3743a2dc2ad8caa214
This commit is contained in:
125
libwvdrmengine/oemcrypto/test/README.md
Normal file
125
libwvdrmengine/oemcrypto/test/README.md
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
# OEMCrypto Unit Tests
|
||||||
|
|
||||||
|
## Basic Functionality Tests
|
||||||
|
|
||||||
|
Most unit tests in this category verify that the basic functionality of opening
|
||||||
|
sessions, initializing and terminating the system, and reporting status work
|
||||||
|
correctly.
|
||||||
|
|
||||||
|
## Decrypt Tests
|
||||||
|
|
||||||
|
The decrypt tests verify that encrypted data is correctly decrypted with the
|
||||||
|
desired key. These tests cover a large variety of patterns, sample sizes, and
|
||||||
|
subsample sizes.
|
||||||
|
|
||||||
|
## Secure Buffers
|
||||||
|
|
||||||
|
If OEMCrypto implements the function `OEMCrypto_AllocateSecureBuffer`, then all
|
||||||
|
of the decrypt tests will also run with the output buffer being a secure
|
||||||
|
buffer. If the function `OEMCrypto_SupportsDecryptHash` returns
|
||||||
|
`OEMCrypto_CRC_Clear_Buffer`, then the secure buffer decryption will be verified
|
||||||
|
with the CRC32 hash of the input data.
|
||||||
|
|
||||||
|
## Usage Table Tests
|
||||||
|
|
||||||
|
Usage table tests verify that the usage table is correctly procesed. The usage
|
||||||
|
table is used to control reloading keys for offline playback, and for reporting
|
||||||
|
secure stops for online playback.
|
||||||
|
|
||||||
|
## Duration Tests
|
||||||
|
|
||||||
|
Duration tests verify that license durations are enforced correctly. Most of
|
||||||
|
this functionality can be met by keeping an accurate system time, and calling
|
||||||
|
the ODK functions as described in the document "License Duration and Renewal".
|
||||||
|
|
||||||
|
## OEMCrypto Memory Unit Tests
|
||||||
|
|
||||||
|
### Objective
|
||||||
|
|
||||||
|
* Add OEMCrypto buffer overflow unit tests (indirect way of fuzzing) to verify
|
||||||
|
OEMCrypto API behavior when the parameters passed to the API are out of
|
||||||
|
range or not reasonable. The API can return an error code, but shouldn't
|
||||||
|
crash.
|
||||||
|
|
||||||
|
* A lot of OEMCrypto APIs take buffers and their length as inputs to the APIs
|
||||||
|
and we have added unit tests with buffers of varying lengths (small
|
||||||
|
to huge) to verify API behavior which is an indirect and simplest way of
|
||||||
|
fuzz testing to detect buffer overflows.
|
||||||
|
|
||||||
|
* Add the tests for OEMCrypto APIs with prefix `OEMCryptoMemory` in the
|
||||||
|
following format. Huge length is set at 100 MB as of now.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
for (size_t length=small_length; length<huge_length; length=length * 2) {
|
||||||
|
Create buffer of size length.
|
||||||
|
Call api expecting it not to crash or segfault.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* Add tests for OEMCrypto APIs with out of range values for length and offsets
|
||||||
|
of OEMCryptoSubstring struct. This length and offset fields are used to read
|
||||||
|
values from an input buffer in most of the APIs. This can cause buffer
|
||||||
|
overflows if the length and offset fields are not validated against the
|
||||||
|
input buffer.
|
||||||
|
|
||||||
|
### Background
|
||||||
|
|
||||||
|
* Security is the top priority for Widevine. We came up with a simple approach
|
||||||
|
to catch most common issues with widevine's implementations. A simplest
|
||||||
|
approach is to add OEMCrypto unit tests to verify OEMCrypto API behavior
|
||||||
|
when the parameters are out of range, meaning for an unreasonable length
|
||||||
|
which can cause buffer overflows. Most of the implementation either does not
|
||||||
|
validate input length parameters or copies data to secure buffers out of TA
|
||||||
|
space causing memory corruptions, buffer overflows. Partners who implement
|
||||||
|
OEMCrypto implementations will run OEMCrypto unit tests as part of the
|
||||||
|
process.
|
||||||
|
|
||||||
|
* We have added unit tests with parameters that can cause buffer overflows if
|
||||||
|
the parameters are not validated. This way partners can catch issues
|
||||||
|
earlier in the process when they run OEMCrypto unit tests. All the unit
|
||||||
|
tests with prefix `OEMCryptoMemory` are added to test the above scenario.
|
||||||
|
|
||||||
|
### What to expect from these tests
|
||||||
|
|
||||||
|
* `OEMCryptoMemory*` tests are designed to fail if API doesn't have enough
|
||||||
|
validations around input buffer lengths, parameters or OEMCryptoSubstring
|
||||||
|
struct. If the API doesn't have validations which might lead to a crash, the
|
||||||
|
test fails with a segfault or an appropriate crash message based on the API
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
* Find out for what buffer length, the API is crashing and then debugging the
|
||||||
|
test against the OEMCrypto implementation should be able to provide
|
||||||
|
information about the error.
|
||||||
|
|
||||||
|
* Another way to debug would be to compile the tests with sanitizer flags,
|
||||||
|
which will be able to provide detailed information about the crash.
|
||||||
|
|
||||||
|
* Partners are expected to fix issues with the API so that the tests don't
|
||||||
|
fail.
|
||||||
|
|
||||||
|
* As these tests run for varying lengths from small to huge buffer lengths,
|
||||||
|
some of the tests might take longer to run(~3 minutes).
|
||||||
|
|
||||||
|
* `OEMCryptoMemoryInstallKeyboxForHugeKeyboxBuffer*` tests which tries to
|
||||||
|
call install keybox API with varying buffer lengths. This test by default
|
||||||
|
is not compiled as it overwrites the keybox on the device. Uncomment,
|
||||||
|
compile and run the tests only if you have ability to recover the keybox
|
||||||
|
on device where the test is ran.
|
||||||
|
|
||||||
|
## Filtering out tests
|
||||||
|
|
||||||
|
The source code will check for functionality of OEMCrypto and filter out tests
|
||||||
|
that are not required. For example, if a device uses a keybox, then Provisioning
|
||||||
|
3.0 tests are skipped, and vice versa.
|
||||||
|
|
||||||
|
If you wish to skip slow tests because you only want to verify basic
|
||||||
|
functionality, then you can set the environment variable `GTEST_FILTER`,
|
||||||
|
as documented
|
||||||
|
[here](https://github.com/google/googletest/blob/master/docs/advanced.md#running-a-subset-of-the-tests).
|
||||||
|
|
||||||
|
For example, to skip the duration tests, buffer overflow tests and long running
|
||||||
|
stress tests, you would set
|
||||||
|
|
||||||
|
```
|
||||||
|
GTEST_FILTER="*-*Duration*:*TimingTest*:*Memory*:*Huge*:*NonceFlood*:*ManyUsageEntries*:*Defrag*"
|
||||||
|
```
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "oemcrypto_fuzz_helper.h"
|
#include "oemcrypto_fuzz_helper.h"
|
||||||
#include "oemcrypto_fuzz_structs.h"
|
#include "oemcrypto_fuzz_structs.h"
|
||||||
|
#include "oemcrypto_overflow.h"
|
||||||
|
|
||||||
namespace wvoec {
|
namespace wvoec {
|
||||||
const size_t MAX_FUZZ_SAMPLE_SIZE = 5 * MB;
|
const size_t MAX_FUZZ_SAMPLE_SIZE = 5 * MB;
|
||||||
@@ -137,13 +138,16 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
|||||||
|
|
||||||
// Copy sub sample data.
|
// Copy sub sample data.
|
||||||
sample_descriptions[i].subsamples = &subsamples[input_subsample_index];
|
sample_descriptions[i].subsamples = &subsamples[input_subsample_index];
|
||||||
input_subsample_index += sample_descriptions[i].subsamples_length;
|
if (AddOverflowUX(input_subsample_index,
|
||||||
|
sample_descriptions[i].subsamples_length,
|
||||||
|
&input_subsample_index)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (input_subsample_index > subsamples.size()) return 0;
|
if (input_subsample_index > subsamples.size()) return 0;
|
||||||
} // Sample loop.
|
} // Sample loop.
|
||||||
|
|
||||||
// Allocate input/output buffers for each sample description.
|
// Allocate input/output buffers for each sample description.
|
||||||
vector<OEMCrypto_SharedMemory> input_buffer(total_input_data_length);
|
vector<OEMCrypto_SharedMemory> input_buffer(total_input_data_length);
|
||||||
RAND_bytes(input_buffer.data(), total_input_data_length);
|
|
||||||
size_t input_buffer_index = 0;
|
size_t input_buffer_index = 0;
|
||||||
for (size_t i = 0; i < samples_length; i++) {
|
for (size_t i = 0; i < samples_length; i++) {
|
||||||
sample_descriptions[i].buffers.input_data =
|
sample_descriptions[i].buffers.input_data =
|
||||||
|
|||||||
@@ -36,9 +36,7 @@ class OEMCryptoLicenseAPIFuzz : public InitializeFuzz {
|
|||||||
session_.GenerateNonce();
|
session_.GenerateNonce();
|
||||||
}
|
}
|
||||||
|
|
||||||
~OEMCryptoLicenseAPIFuzz() {
|
~OEMCryptoLicenseAPIFuzz() { session_.close(); }
|
||||||
session_.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
LicenseRoundTrip& license_messages() { return license_messages_; }
|
LicenseRoundTrip& license_messages() { return license_messages_; }
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "dispatcher.h"
|
||||||
|
#include "marshaller_base.h"
|
||||||
|
#include "transport_interface.h"
|
||||||
|
|
||||||
|
namespace wvoec {
|
||||||
|
|
||||||
|
void InitializeODKMessage(ODK_Message* message, uint8_t* data, size_t size) {
|
||||||
|
ODK_Message_Impl* impl = (ODK_Message_Impl*)message;
|
||||||
|
impl->base = data;
|
||||||
|
impl->size = size;
|
||||||
|
impl->capacity = size;
|
||||||
|
impl->read_offset = 0;
|
||||||
|
impl->status = MESSAGE_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenOEMCryptoTASession() {
|
||||||
|
ODK_Message request;
|
||||||
|
ODK_Message* response = NULL;
|
||||||
|
uint8_t response_buffer[0x1000];
|
||||||
|
uint8_t request_body[] = {
|
||||||
|
0x06, // TAG_UINT32
|
||||||
|
0x09, 0x00, 0x00, 0x00, // API value (0x09)
|
||||||
|
0x01, // TAG_BOOL
|
||||||
|
0x00, // value (false)
|
||||||
|
0x0a // TAG_EOM
|
||||||
|
};
|
||||||
|
|
||||||
|
InitializeODKMessage(&request, request_body, sizeof(request_body));
|
||||||
|
|
||||||
|
ODK_DispatchMessage(&request, &response);
|
||||||
|
if (response != NULL) ODK_Transport_DeallocateMessage(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeOEMCryptoTA() {
|
||||||
|
ODK_Message init_request;
|
||||||
|
ODK_Message* init_response = NULL;
|
||||||
|
uint8_t response_buffer[0x1000];
|
||||||
|
uint8_t init_request_body[] = {
|
||||||
|
0x06, // TAG_UINT32
|
||||||
|
0x01, 0x00, 0x00, 0x00, // API value(0x01)
|
||||||
|
0x0a // TAG_EOM
|
||||||
|
};
|
||||||
|
|
||||||
|
InitializeODKMessage(&init_request, init_request_body,
|
||||||
|
sizeof(init_request_body));
|
||||||
|
|
||||||
|
ODK_DispatchMessage(&init_request, &init_response);
|
||||||
|
if (init_response != NULL) ODK_Transport_DeallocateMessage(init_response);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
|
||||||
|
ODK_InitializeDispatcher();
|
||||||
|
InitializeOEMCryptoTA();
|
||||||
|
OpenOEMCryptoTASession();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||||
|
ODK_Message request;
|
||||||
|
ODK_Message* response = NULL;
|
||||||
|
unsigned char response_buffer[0x1000];
|
||||||
|
|
||||||
|
uint8_t* input = new uint8_t[size];
|
||||||
|
memcpy(input, data, size);
|
||||||
|
|
||||||
|
InitializeODKMessage(&request, input, size);
|
||||||
|
|
||||||
|
ODK_DispatchMessage(&request, &response);
|
||||||
|
if (response != NULL) ODK_Transport_DeallocateMessage(response);
|
||||||
|
|
||||||
|
delete[] input;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace wvoec
|
||||||
@@ -129,6 +129,7 @@ std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) {
|
|||||||
if (!generic_crypto) FilterOut(&filter, "*GenericCrypto*");
|
if (!generic_crypto) FilterOut(&filter, "*GenericCrypto*");
|
||||||
if (!cast_receiver) FilterOut(&filter, "*CastReceiver*");
|
if (!cast_receiver) FilterOut(&filter, "*CastReceiver*");
|
||||||
if (!usage_table) FilterOut(&filter, "*UsageTable*");
|
if (!usage_table) FilterOut(&filter, "*UsageTable*");
|
||||||
|
if (!usage_table) FilterOut(&filter, "*BadRange_pst*");
|
||||||
if (derive_key_method == NO_METHOD) FilterOut(&filter, "*SessionTest*");
|
if (derive_key_method == NO_METHOD) FilterOut(&filter, "*SessionTest*");
|
||||||
if (provisioning_method
|
if (provisioning_method
|
||||||
!= OEMCrypto_OEMCertificate) FilterOut(&filter, "*Prov30*");
|
!= OEMCrypto_OEMCertificate) FilterOut(&filter, "*Prov30*");
|
||||||
|
|||||||
@@ -154,8 +154,7 @@ RoundTrip<CoreRequest, PrepAndSignRequest, CoreResponse, ResponseData>::
|
|||||||
constexpr size_t small_size = 42; // arbitrary.
|
constexpr size_t small_size = 42; // arbitrary.
|
||||||
uint32_t session_id = session()->session_id();
|
uint32_t session_id = session()->session_id();
|
||||||
GetDefaultRequestSignatureAndCoreMessageLengths<PrepAndSignRequest>(
|
GetDefaultRequestSignatureAndCoreMessageLengths<PrepAndSignRequest>(
|
||||||
session_id, required_message_size_, small_size, &gen_signature_length,
|
session_id, small_size, &gen_signature_length, &core_message_length);
|
||||||
&core_message_length);
|
|
||||||
// Used to test request APIs with varying lengths of core message.
|
// Used to test request APIs with varying lengths of core message.
|
||||||
core_message_length =
|
core_message_length =
|
||||||
std::max(core_message_length, required_core_message_size_);
|
std::max(core_message_length, required_core_message_size_);
|
||||||
@@ -192,9 +191,8 @@ RoundTrip<CoreRequest, PrepAndSignRequest, CoreResponse, ResponseData>::
|
|||||||
|
|
||||||
template <PrepAndSignRequest_t PrepAndSignRequest>
|
template <PrepAndSignRequest_t PrepAndSignRequest>
|
||||||
void GetDefaultRequestSignatureAndCoreMessageLengths(
|
void GetDefaultRequestSignatureAndCoreMessageLengths(
|
||||||
uint32_t& session_id, size_t& required_message_size,
|
uint32_t& session_id, const size_t& small_size,
|
||||||
const size_t& small_size, size_t* gen_signature_length,
|
size_t* gen_signature_length, size_t* core_message_length) {
|
||||||
size_t* core_message_length) {
|
|
||||||
vector<uint8_t> data(small_size);
|
vector<uint8_t> data(small_size);
|
||||||
for (size_t i = 0; i < data.size(); i++) data[i] = i & 0xFF;
|
for (size_t i = 0; i < data.size(); i++) data[i] = i & 0xFF;
|
||||||
ASSERT_EQ(
|
ASSERT_EQ(
|
||||||
|
|||||||
@@ -669,9 +669,8 @@ void WriteRequestApiCorpus(size_t signature_length, size_t core_message_length,
|
|||||||
vector<uint8_t>& data);
|
vector<uint8_t>& data);
|
||||||
template <PrepAndSignRequest_t PrepAndSignRequest>
|
template <PrepAndSignRequest_t PrepAndSignRequest>
|
||||||
void GetDefaultRequestSignatureAndCoreMessageLengths(
|
void GetDefaultRequestSignatureAndCoreMessageLengths(
|
||||||
uint32_t& session_id, size_t& required_message_size,
|
uint32_t& session_id, const size_t& small_size,
|
||||||
const size_t& small_size, size_t* gen_signature_length,
|
size_t* gen_signature_length, size_t* core_message_length);
|
||||||
size_t* core_message_length);
|
|
||||||
} // namespace wvoec
|
} // namespace wvoec
|
||||||
|
|
||||||
#endif // CDM_OEC_SESSION_UTIL_H_
|
#endif // CDM_OEC_SESSION_UTIL_H_
|
||||||
|
|||||||
@@ -137,6 +137,11 @@ void TestHugeLengthDoesNotCrashAPI(oemcrypto_function f,
|
|||||||
!check_status);
|
!check_status);
|
||||||
buffer_length *= 2) {
|
buffer_length *= 2) {
|
||||||
sts = f(buffer_length);
|
sts = f(buffer_length);
|
||||||
|
if (check_status && sts != OEMCrypto_SUCCESS &&
|
||||||
|
sts != OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||||
|
LOGI("Test exits huge buffer loop for length:%zu, status:%d",
|
||||||
|
buffer_length, sts);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,6 +175,17 @@ const size_t kLargeMessageSize[] = { 8*KiB, 8*KiB, 16*KiB, 32*KiB};
|
|||||||
// const size_t kAV1NumberSubsamples[] = { 72, 144, 288, 576};
|
// const size_t kAV1NumberSubsamples[] = { 72, 144, 288, 576};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
// Return a printable string from data. If all the characters are printable,
|
||||||
|
// then just use the string. Otherwise, convert to hex.
|
||||||
|
std::string MaybeHex(const uint8_t* data, size_t length) {
|
||||||
|
for (size_t i = 0; i < length; i++) {
|
||||||
|
if (!isprint(data[i])) return "0x" + wvcdm::HexEncode(data, length);
|
||||||
|
}
|
||||||
|
return std::string(reinterpret_cast<const char*>(data), length);
|
||||||
|
}
|
||||||
|
std::string MaybeHex(const std::vector<uint8_t>& data) {
|
||||||
|
return MaybeHex(data.data(), data.size());
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
class OEMCryptoClientTest : public ::testing::Test, public SessionUtil {
|
class OEMCryptoClientTest : public ::testing::Test, public SessionUtil {
|
||||||
@@ -202,6 +218,17 @@ class OEMCryptoClientTest : public ::testing::Test, public SessionUtil {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TEST_F(OEMCryptoClientTest, FreeUnallocatedSecureBufferNoFailure) {
|
||||||
|
Session s;
|
||||||
|
s.open();
|
||||||
|
OEMCrypto_DestBufferDesc output_descriptor;
|
||||||
|
int secure_fd = kHugeRandomNumber;
|
||||||
|
ASSERT_NE(OEMCrypto_SUCCESS,
|
||||||
|
OEMCrypto_FreeSecureBuffer(s.session_id(), &output_descriptor,
|
||||||
|
secure_fd));
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
/// @addtogroup basic
|
/// @addtogroup basic
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
@@ -212,15 +239,20 @@ class OEMCryptoClientTest : public ::testing::Test, public SessionUtil {
|
|||||||
*/
|
*/
|
||||||
TEST_F(OEMCryptoClientTest, VersionNumber) {
|
TEST_F(OEMCryptoClientTest, VersionNumber) {
|
||||||
const std::string log_message =
|
const std::string log_message =
|
||||||
"OEMCrypto unit tests for API 16.4. Tests last updated 2020-10-07";
|
"OEMCrypto unit tests for API 16.3 or 4. Tests last updated 2021-02-22";
|
||||||
cout << " " << log_message << "\n";
|
cout << " " << log_message << "\n";
|
||||||
|
cout << " "
|
||||||
|
<< "These tests are part of Android S."
|
||||||
|
<< "\n";
|
||||||
LOGI("%s", log_message.c_str());
|
LOGI("%s", log_message.c_str());
|
||||||
// If any of the following fail, then it is time to update the log message
|
// If any of the following fail, then it is time to update the log message
|
||||||
// above.
|
// above.
|
||||||
EXPECT_EQ(ODK_MAJOR_VERSION, 16);
|
EXPECT_EQ(ODK_MAJOR_VERSION, 16);
|
||||||
// Note on minor versions. Widevine requires version 16.3 or greater for CE
|
// Note on minor versions. Widevine requires version 16.3 or greater for CE
|
||||||
// CDM and Android devices. For CE CDM devices that do not support usage
|
// CDM and Android devices. For CE CDM devices that do not support usage
|
||||||
// tables, we strongly recommend 16.4.
|
// tables, we strongly recommend 16.4. Note: This is the version of the ODK
|
||||||
|
// library built into the tests, which might be different from the version
|
||||||
|
// that is pre-compiled into liboemcrypto.so.
|
||||||
EXPECT_GE(ODK_MINOR_VERSION, 3);
|
EXPECT_GE(ODK_MINOR_VERSION, 3);
|
||||||
EXPECT_LE(ODK_MINOR_VERSION, 4);
|
EXPECT_LE(ODK_MINOR_VERSION, 4);
|
||||||
EXPECT_EQ(kCurrentAPI, 16u);
|
EXPECT_EQ(kCurrentAPI, 16u);
|
||||||
@@ -229,7 +261,9 @@ TEST_F(OEMCryptoClientTest, VersionNumber) {
|
|||||||
ASSERT_EQ('L', level[0]);
|
ASSERT_EQ('L', level[0]);
|
||||||
cout << " OEMCrypto Security Level is " << level << endl;
|
cout << " OEMCrypto Security Level is " << level << endl;
|
||||||
uint32_t version = OEMCrypto_APIVersion();
|
uint32_t version = OEMCrypto_APIVersion();
|
||||||
cout << " OEMCrypto API version is " << version << endl;
|
uint32_t minor_version = OEMCrypto_MinorAPIVersion();
|
||||||
|
cout << " OEMCrypto API version is " << version << "."
|
||||||
|
<< minor_version << endl;
|
||||||
if (OEMCrypto_SupportsUsageTable()) {
|
if (OEMCrypto_SupportsUsageTable()) {
|
||||||
cout << " OEMCrypto supports usage tables" << endl;
|
cout << " OEMCrypto supports usage tables" << endl;
|
||||||
} else {
|
} else {
|
||||||
@@ -661,8 +695,8 @@ TEST_F(OEMCryptoClientTest, ClearCopyTestAPI10) {
|
|||||||
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample));
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample));
|
||||||
dest_buffer_descriptor.buffer.clear.address = output_buffer.data();
|
dest_buffer_descriptor.buffer.clear.address = output_buffer.data();
|
||||||
dest_buffer_descriptor.buffer.clear.address_length = output_buffer.size() - 1;
|
dest_buffer_descriptor.buffer.clear.address_length = output_buffer.size() - 1;
|
||||||
ASSERT_EQ(
|
ASSERT_NE(
|
||||||
OEMCrypto_ERROR_SHORT_BUFFER,
|
OEMCrypto_SUCCESS,
|
||||||
OEMCrypto_CopyBuffer(s.session_id(), input_buffer.data(),
|
OEMCrypto_CopyBuffer(s.session_id(), input_buffer.data(),
|
||||||
input_buffer.size(), &dest_buffer_descriptor,
|
input_buffer.size(), &dest_buffer_descriptor,
|
||||||
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample));
|
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample));
|
||||||
@@ -896,8 +930,8 @@ TEST_F(OEMCryptoKeyboxTest, NormalGetDeviceId) {
|
|||||||
uint8_t dev_id[128] = {0};
|
uint8_t dev_id[128] = {0};
|
||||||
size_t dev_id_len = 128;
|
size_t dev_id_len = 128;
|
||||||
sts = OEMCrypto_GetDeviceID(dev_id, &dev_id_len);
|
sts = OEMCrypto_GetDeviceID(dev_id, &dev_id_len);
|
||||||
cout << " NormalGetDeviceId: dev_id = " << dev_id
|
cout << " NormalGetDeviceId: dev_id = "
|
||||||
<< " len = " << dev_id_len << endl;
|
<< MaybeHex(dev_id, dev_id_len) << " len = " << dev_id_len << endl;
|
||||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1039,7 +1073,7 @@ TEST_F(OEMCryptoProv30Test, GetDeviceId) {
|
|||||||
}
|
}
|
||||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||||
dev_id.resize(dev_id_len);
|
dev_id.resize(dev_id_len);
|
||||||
cout << " NormalGetDeviceId: dev_id = " << dev_id.data()
|
cout << " NormalGetDeviceId: dev_id = " << MaybeHex(dev_id)
|
||||||
<< " len = " << dev_id_len << endl;
|
<< " len = " << dev_id_len << endl;
|
||||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||||
}
|
}
|
||||||
@@ -2355,6 +2389,39 @@ TEST_P(OEMCryptoLicenseTest,
|
|||||||
!kCheckStatus);
|
!kCheckStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(OEMCryptoLicenseTest,
|
||||||
|
DecryptCENCForNumBytesClearPlusEncryptedOverflowsSize) {
|
||||||
|
LoadLicense();
|
||||||
|
OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[0].key_id,
|
||||||
|
session_.license().keys[0].key_id_length,
|
||||||
|
OEMCrypto_CipherMode_CTR);
|
||||||
|
|
||||||
|
size_t input_buffer_size = 1;
|
||||||
|
vector<uint8_t> in_buffer(input_buffer_size);
|
||||||
|
vector<uint8_t> out_buffer(in_buffer.size());
|
||||||
|
|
||||||
|
OEMCrypto_SampleDescription sample_description;
|
||||||
|
OEMCrypto_SubSampleDescription subsample_description;
|
||||||
|
GenerateSimpleSampleDescription(in_buffer, out_buffer, &sample_description,
|
||||||
|
&subsample_description);
|
||||||
|
|
||||||
|
OEMCrypto_SubSampleDescription* sub_samples =
|
||||||
|
const_cast<OEMCrypto_SubSampleDescription*>(
|
||||||
|
sample_description.subsamples);
|
||||||
|
// If Decrypt cenc API does not check for overflow on clear + encrypted
|
||||||
|
// addition operation. This will result in 1 which will match with input data
|
||||||
|
// length, which causes validation to pass.
|
||||||
|
sub_samples[0].num_bytes_clear = 2;
|
||||||
|
sub_samples[0].num_bytes_encrypted = 0xFFFFFFFFFFFFFFFF;
|
||||||
|
|
||||||
|
// Create the pattern description (always 0,0 for CTR)
|
||||||
|
OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0};
|
||||||
|
// Try to decrypt the data
|
||||||
|
ASSERT_NE(OEMCrypto_SUCCESS,
|
||||||
|
OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, 1,
|
||||||
|
&pattern));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_P(OEMCryptoLicenseTest,
|
TEST_P(OEMCryptoLicenseTest,
|
||||||
OEMCryptoMemoryDecryptCENCForHugeNumBytesEncryptedAndBuffers) {
|
OEMCryptoMemoryDecryptCENCForHugeNumBytesEncryptedAndBuffers) {
|
||||||
TestDecryptCENCForHugeBufferLengths(
|
TestDecryptCENCForHugeBufferLengths(
|
||||||
@@ -3850,50 +3917,17 @@ class OEMCryptoSessionTestsDecryptTests
|
|||||||
OEMCrypto_SUCCESS);
|
OEMCrypto_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestDecryptCENC() {
|
void TestDecryptCENC() { ASSERT_EQ(DecryptCENC(), OEMCrypto_SUCCESS); }
|
||||||
OEMCryptoResult sts;
|
|
||||||
|
|
||||||
// OEMCrypto only supports providing a decrypt hash for one sample.
|
void ValidateDecryptedData() {
|
||||||
if (samples_.size() > 1) verify_crc_ = false;
|
|
||||||
|
|
||||||
// If supported, check the decrypt hashes.
|
|
||||||
if (verify_crc_) {
|
|
||||||
const TestSample& sample = samples_[0];
|
|
||||||
|
|
||||||
uint32_t hash =
|
|
||||||
wvcrc32(sample.truth_buffer.data(), sample.truth_buffer.size());
|
|
||||||
ASSERT_EQ(OEMCrypto_SetDecryptHash(
|
|
||||||
session_.session_id(), 1,
|
|
||||||
reinterpret_cast<const uint8_t*>(&hash), sizeof(hash)),
|
|
||||||
OEMCrypto_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build an array of just the sample descriptions.
|
|
||||||
std::vector<OEMCrypto_SampleDescription> sample_descriptions;
|
|
||||||
sample_descriptions.reserve(samples_.size());
|
|
||||||
for (TestSample& sample : samples_) {
|
|
||||||
// This must be deferred until this point in case the test modifies the
|
|
||||||
// buffer before testing decrypt.
|
|
||||||
sample.description.buffers.input_data = sample.encrypted_buffer.data();
|
|
||||||
// Append to the description array.
|
|
||||||
sample_descriptions.push_back(sample.description);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perform decryption using the test data that was previously set up.
|
|
||||||
sts = DecryptFallbackChain::Decrypt(
|
|
||||||
session_.session_id(), sample_descriptions.data(),
|
|
||||||
sample_descriptions.size(), cipher_mode_, &pattern_);
|
|
||||||
ASSERT_EQ(sts, OEMCrypto_SUCCESS);
|
|
||||||
|
|
||||||
// Validate the decrypted data.
|
|
||||||
for (TestSample& sample : samples_) {
|
for (TestSample& sample : samples_) {
|
||||||
if (sample.description.buffers.output_descriptor.type ==
|
if (sample.description.buffers.output_descriptor.type ==
|
||||||
OEMCrypto_BufferType_Clear) {
|
OEMCrypto_BufferType_Clear) {
|
||||||
const size_t total_size = sample.description.buffers.input_data_length;
|
const size_t total_size = sample.description.buffers.input_data_length;
|
||||||
// To verify there is no buffer overrun after decrypting, look at the
|
// To verify there is no buffer overrun after decrypting, look at the
|
||||||
// padded bytes just after the data buffer that was written. It should
|
// padded bytes just after the data buffer that was written. It
|
||||||
// not have changed from the original 0xaa that we set in MakeBuffer
|
// should not have changed from the original 0xaa that we set in
|
||||||
// function.
|
// MakeBuffer function.
|
||||||
if (decrypt_inplace_) {
|
if (decrypt_inplace_) {
|
||||||
EXPECT_EQ(std::count(sample.encrypted_buffer.begin() + total_size,
|
EXPECT_EQ(std::count(sample.encrypted_buffer.begin() + total_size,
|
||||||
sample.encrypted_buffer.end(), 0xaa),
|
sample.encrypted_buffer.end(), 0xaa),
|
||||||
@@ -3919,6 +3953,41 @@ class OEMCryptoSessionTestsDecryptTests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult DecryptCENC() {
|
||||||
|
// OEMCrypto only supports providing a decrypt hash for one sample.
|
||||||
|
if (samples_.size() > 1) verify_crc_ = false;
|
||||||
|
|
||||||
|
// If supported, check the decrypt hashes.
|
||||||
|
if (verify_crc_) {
|
||||||
|
const TestSample& sample = samples_[0];
|
||||||
|
|
||||||
|
uint32_t hash =
|
||||||
|
wvcrc32(sample.truth_buffer.data(), sample.truth_buffer.size());
|
||||||
|
OEMCrypto_SetDecryptHash(session_.session_id(), 1,
|
||||||
|
reinterpret_cast<const uint8_t*>(&hash),
|
||||||
|
sizeof(hash));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build an array of just the sample descriptions.
|
||||||
|
std::vector<OEMCrypto_SampleDescription> sample_descriptions;
|
||||||
|
sample_descriptions.reserve(samples_.size());
|
||||||
|
for (TestSample& sample : samples_) {
|
||||||
|
// This must be deferred until this point in case the test modifies the
|
||||||
|
// buffer before testing decrypt.
|
||||||
|
sample.description.buffers.input_data = sample.encrypted_buffer.data();
|
||||||
|
// Append to the description array.
|
||||||
|
sample_descriptions.push_back(sample.description);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform decryption using the test data that was previously set up.
|
||||||
|
OEMCryptoResult result = DecryptFallbackChain::Decrypt(
|
||||||
|
session_.session_id(), sample_descriptions.data(),
|
||||||
|
sample_descriptions.size(), cipher_mode_, &pattern_);
|
||||||
|
if (result != OEMCrypto_SUCCESS) return result;
|
||||||
|
ValidateDecryptedData();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Parameters of test case
|
// Parameters of test case
|
||||||
OEMCrypto_CENCEncryptPatternDesc pattern_;
|
OEMCrypto_CENCEncryptPatternDesc pattern_;
|
||||||
OEMCryptoCipherMode cipher_mode_;
|
OEMCryptoCipherMode cipher_mode_;
|
||||||
@@ -4094,7 +4163,6 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptMaxSampleAPI16) {
|
|||||||
// max_sample_size.
|
// max_sample_size.
|
||||||
const size_t subsample_size =
|
const size_t subsample_size =
|
||||||
std::min(max_sample_size / max_num_subsamples + 1, max_subsample_size);
|
std::min(max_sample_size / max_num_subsamples + 1, max_subsample_size);
|
||||||
|
|
||||||
size_t bytes_remaining = max_sample_size;
|
size_t bytes_remaining = max_sample_size;
|
||||||
std::vector<SubsampleSize> subsample_sizes;
|
std::vector<SubsampleSize> subsample_sizes;
|
||||||
while (bytes_remaining > 0 && subsample_sizes.size() < max_num_subsamples) {
|
while (bytes_remaining > 0 && subsample_sizes.size() < max_num_subsamples) {
|
||||||
@@ -4113,6 +4181,103 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptMaxSampleAPI16) {
|
|||||||
ASSERT_NO_FATAL_FAILURE(TestDecryptCENC());
|
ASSERT_NO_FATAL_FAILURE(TestDecryptCENC());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(OEMCryptoSessionTestsDecryptTests,
|
||||||
|
OEMCryptoMemoryDecryptCENCForHugeNumberOfSubSamples) {
|
||||||
|
auto oemcrypto_function = [&](size_t number_of_subsamples) {
|
||||||
|
std::vector<SubsampleSize> subsample_sizes;
|
||||||
|
while (number_of_subsamples-- > 0) {
|
||||||
|
subsample_sizes.push_back({1, 1});
|
||||||
|
}
|
||||||
|
SetSubsampleSizes(subsample_sizes);
|
||||||
|
LoadLicense();
|
||||||
|
MakeBuffers();
|
||||||
|
EncryptData();
|
||||||
|
OEMCryptoResult result = DecryptCENC();
|
||||||
|
// Closing the session and opening it for next iteration.
|
||||||
|
// If it is last iteration, session will be closed in teardown method of
|
||||||
|
// class.
|
||||||
|
session_.close();
|
||||||
|
session_.open();
|
||||||
|
InstallTestRSAKey(&session_);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 1, 2 * MiB, kCheckStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(OEMCryptoSessionTestsDecryptTests,
|
||||||
|
OEMCryptoMemoryCheckDecryptCENCStatusForHugeNumberOfSubSamples) {
|
||||||
|
size_t number_of_subsamples = 10000;
|
||||||
|
std::vector<SubsampleSize> subsample_sizes;
|
||||||
|
while (number_of_subsamples-- > 0) {
|
||||||
|
subsample_sizes.push_back({100, 100});
|
||||||
|
}
|
||||||
|
SetSubsampleSizes(subsample_sizes);
|
||||||
|
LoadLicense();
|
||||||
|
MakeBuffers();
|
||||||
|
EncryptData();
|
||||||
|
// Build an array of just the sample descriptions.
|
||||||
|
std::vector<OEMCrypto_SampleDescription> sample_descriptions;
|
||||||
|
sample_descriptions.reserve(samples_.size());
|
||||||
|
for (TestSample& sample : samples_) {
|
||||||
|
// This must be deferred until this point in case the test modifies the
|
||||||
|
// buffer before testing decrypt.
|
||||||
|
sample.description.buffers.input_data = sample.encrypted_buffer.data();
|
||||||
|
// Append to the description array.
|
||||||
|
sample_descriptions.push_back(sample.description);
|
||||||
|
}
|
||||||
|
OEMCryptoResult result = OEMCrypto_DecryptCENC(
|
||||||
|
session_.session_id(), sample_descriptions.data(), 1, &pattern_);
|
||||||
|
LOGD("Large number of subsamples test has return code %d", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(OEMCryptoSessionTestsDecryptTests,
|
||||||
|
OEMCryptoMemoryCheckDecryptCENCStatusForHugeSubSample) {
|
||||||
|
std::vector<SubsampleSize> subsample_sizes;
|
||||||
|
subsample_sizes.push_back({100000, 100000});
|
||||||
|
SetSubsampleSizes(subsample_sizes);
|
||||||
|
LoadLicense();
|
||||||
|
MakeBuffers();
|
||||||
|
EncryptData();
|
||||||
|
// Build an array of just the sample descriptions.
|
||||||
|
std::vector<OEMCrypto_SampleDescription> sample_descriptions;
|
||||||
|
sample_descriptions.reserve(samples_.size());
|
||||||
|
for (TestSample& sample : samples_) {
|
||||||
|
// This must be deferred until this point in case the test modifies the
|
||||||
|
// buffer before testing decrypt.
|
||||||
|
sample.description.buffers.input_data = sample.encrypted_buffer.data();
|
||||||
|
// Append to the description array.
|
||||||
|
sample_descriptions.push_back(sample.description);
|
||||||
|
}
|
||||||
|
OEMCryptoResult result = OEMCrypto_DecryptCENC(
|
||||||
|
session_.session_id(), sample_descriptions.data(), 1, &pattern_);
|
||||||
|
LOGD("Large subsample test has return code %d", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(OEMCryptoSessionTestsDecryptTests,
|
||||||
|
OEMCryptoMemoryDecryptCENCForHugeNumberOfSamples) {
|
||||||
|
auto oemcrypto_function = [&](size_t number_of_samples) {
|
||||||
|
std::vector<std::vector<SubsampleSize>> samples;
|
||||||
|
std::vector<SubsampleSize> subsample_sizes;
|
||||||
|
subsample_sizes.push_back({1, 1});
|
||||||
|
while (number_of_samples-- > 0) {
|
||||||
|
samples.push_back(subsample_sizes);
|
||||||
|
}
|
||||||
|
SetSampleSizes(samples);
|
||||||
|
LoadLicense();
|
||||||
|
MakeBuffers();
|
||||||
|
EncryptData();
|
||||||
|
OEMCryptoResult result = DecryptCENC();
|
||||||
|
// Closing the session and opening it for next iteration.
|
||||||
|
// If it is last iteration, session will be closed in teardown method of
|
||||||
|
// class.
|
||||||
|
session_.close();
|
||||||
|
session_.open();
|
||||||
|
InstallTestRSAKey(&session_);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 1, 2 * MiB, kCheckStatus);
|
||||||
|
}
|
||||||
|
|
||||||
// Based on the resource rating, OEMCrypto should be able to handle the maximum
|
// Based on the resource rating, OEMCrypto should be able to handle the maximum
|
||||||
// subsample size.
|
// subsample size.
|
||||||
TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptMaxSubsample) {
|
TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptMaxSubsample) {
|
||||||
|
|||||||
Reference in New Issue
Block a user