Files
android/libwvdrmengine/oemcrypto/test/oemcrypto_basic_test.cpp
Cong Lin 7277331f92 Update ODK version to 18.4 and unit tests
Test: odk tests, opk_ta, fake_l1_tests
Bug: 294440012
Merged from https://widevine-internal-review.googlesource.com/181150

Change-Id: Ia33962f9d244333b1ca17c9a64efc29de35db093
2024-01-29 12:40:11 -08:00

656 lines
25 KiB
C++

// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
#include "oemcrypto_basic_test.h"
#include "clock.h"
#include "jsmn.h"
#include "log.h"
#include "oemcrypto_corpus_generator_helper.h"
#include "oemcrypto_resource_test.h"
#include "test_sleep.h"
namespace wvoec {
void OEMCryptoClientTest::SetUp() {
::testing::Test::SetUp();
wvutil::TestSleep::SyncFakeClock();
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
LOGD("Running test %s.%s", test_info->test_case_name(), test_info->name());
OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox));
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize());
const OEMCryptoResult api_status = OEMCrypto_SetMaxAPIVersion(kCurrentAPI);
OEMCrypto_EnterTestMode();
if (api_status != OEMCrypto_SUCCESS &&
api_status != OEMCrypto_ERROR_NOT_IMPLEMENTED) {
// Log error, but continue assuming no error.
LOGE("OEMCrypto_SetMaxAPIVersion returned %d", api_status);
}
}
void OEMCryptoClientTest::TearDown() {
OEMCrypto_Terminate();
::testing::Test::TearDown();
}
const uint8_t* OEMCryptoClientTest::find(const vector<uint8_t>& message,
const vector<uint8_t>& substring) {
vector<uint8_t>::const_iterator pos = search(
message.begin(), message.end(), substring.begin(), substring.end());
if (pos == message.end()) {
return nullptr;
}
return &(*pos);
}
OEMCryptoResult OEMCryptoClientTest::CopyBuffer(
OEMCrypto_SESSION session, OEMCrypto_SharedMemory* input_buffer,
size_t input_buffer_size,
const OEMCrypto_DestBufferDesc* dest_buffer_descriptor,
uint8_t subsample_flags) {
if (ShouldGenerateCorpus() && input_buffer != nullptr &&
dest_buffer_descriptor != nullptr) {
const std::string file_name =
GetFileName("oemcrypto_copy_buffer_fuzz_seed_corpus");
OEMCrypto_Copy_Buffer_Fuzz fuzzed_structure;
fuzzed_structure.dest_buffer_desc.type = dest_buffer_descriptor->type;
switch (fuzzed_structure.dest_buffer_desc.type) {
case OEMCrypto_BufferType_Clear:
fuzzed_structure.dest_buffer_desc.buffer_config =
dest_buffer_descriptor->buffer.clear.clear_buffer_length;
break;
case OEMCrypto_BufferType_Secure:
fuzzed_structure.dest_buffer_desc.buffer_config =
dest_buffer_descriptor->buffer.secure.secure_buffer_length;
break;
case OEMCrypto_BufferType_Direct:
fuzzed_structure.dest_buffer_desc.buffer_config =
dest_buffer_descriptor->buffer.direct.is_video;
break;
}
fuzzed_structure.subsample_flags = subsample_flags;
// Corpus for copy buffer fuzzer should be in the format:
// (dest_buffer_descriptor | subsample_flags | input_buffer).
AppendToFile(file_name, reinterpret_cast<const char*>(&fuzzed_structure),
sizeof(fuzzed_structure));
AppendToFile(file_name, reinterpret_cast<const char*>(&input_buffer),
input_buffer_size);
}
return OEMCrypto_CopyBuffer(session, input_buffer, input_buffer_size,
dest_buffer_descriptor, subsample_flags);
}
const char* HDCPCapabilityAsString(OEMCrypto_HDCP_Capability value) {
switch (value) {
case HDCP_NONE:
return "No HDCP supported, no secure data path";
case HDCP_V1:
return "HDCP version 1.x";
case HDCP_V1_0:
return "HDCP version 1.0";
case HDCP_V1_1:
return "HDCP version 1.1";
case HDCP_V1_2:
return "HDCP version 1.2";
case HDCP_V1_3:
return "HDCP version 1.3";
case HDCP_V1_4:
return "HDCP version 1.4";
case HDCP_V2:
return "HDCP version 2.0";
case HDCP_V2_1:
return "HDCP version 2.1";
case HDCP_V2_2:
return "HDCP version 2.2";
case HDCP_V2_3:
return "HDCP version 2.3";
case HDCP_NO_DIGITAL_OUTPUT:
return "No HDCP device attached/using local display with secure path";
default:
return "<INVALID VALUE>";
}
}
// 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" + wvutil::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());
}
/// @addtogroup basic
/// @{
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();
}
/**
* Verifies initialization and logs version information.
* This test is first, because it might give an idea why other
* tests are failing when the device has the wrong keybox installed.
*
* The log message should be updated by Widevine with every release so that it
* is easier to verify which version of the tests a partner is running. Widevine
* should change the API version number when the API changes, but the unit tests
* might be updated more frequently, and are only tracked by the date of the
* last change.
*/
TEST_F(OEMCryptoClientTest, VersionNumber) {
const std::string log_message =
"OEMCrypto unit tests for API 18.4. Tests last updated 2023-08-03";
cout << " " << log_message << "\n";
cout << " "
<< "These tests are part of Android U."
<< "\n";
LOGI("%s", log_message.c_str());
// If any of the following fail, then it is time to update the log message
// above.
EXPECT_EQ(ODK_MAJOR_VERSION, 18);
EXPECT_EQ(ODK_MINOR_VERSION, 4);
EXPECT_EQ(kCurrentAPI, static_cast<unsigned>(ODK_MAJOR_VERSION));
OEMCrypto_Security_Level level = OEMCrypto_SecurityLevel();
EXPECT_GT(level, OEMCrypto_Level_Unknown);
EXPECT_LE(level, OEMCrypto_Level3);
cout << " OEMCrypto Security Level is L" << level << endl;
uint32_t version = OEMCrypto_APIVersion();
uint32_t minor_version = OEMCrypto_MinorAPIVersion();
cout << " OEMCrypto API version is " << version << "."
<< minor_version << endl;
if (OEMCrypto_SupportsUsageTable()) {
cout << " OEMCrypto supports usage tables" << endl;
} else {
cout << " OEMCrypto does not support usage tables" << endl;
}
if (version >= 15) {
const uint32_t tier = OEMCrypto_ResourceRatingTier();
cout << " Resource Rating Tier: " << tier << endl;
}
if (version >= 17) {
OEMCryptoResult sts = OEMCrypto_ProductionReady();
if (sts != OEMCrypto_SUCCESS) {
LOGW("Device is not production ready, returns %d", sts);
}
sts = OEMCrypto_SUCCESS;
std::string build_info;
size_t buf_length = 0;
sts = OEMCrypto_BuildInformation(&build_info[0], &buf_length);
if (sts == OEMCrypto_ERROR_SHORT_BUFFER) {
build_info.resize(buf_length);
sts = OEMCrypto_BuildInformation(&build_info[0], &buf_length);
}
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
if (build_info.size() != buf_length) {
build_info.resize(buf_length);
}
cout << " BuildInformation: " << build_info << endl;
OEMCrypto_WatermarkingSupport support = OEMCrypto_GetWatermarkingSupport();
cout << " WatermarkingSupport: " << support << endl;
}
ASSERT_GE(version, 8u);
ASSERT_LE(version, kCurrentAPI);
}
/**
* The resource rating is a number from 1 to 4. The first three levels
* were initially defined in API 15 and they were expanded in API 16.
*/
TEST_F(OEMCryptoClientTest, ResourceRatingAPI15) {
ASSERT_GE(OEMCrypto_ResourceRatingTier(), 1u);
ASSERT_LE(OEMCrypto_ResourceRatingTier(), 4u);
}
/**
* OEMCrypto must declare what type of provisioning scheme it uses.
*/
TEST_F(OEMCryptoClientTest, ProvisioningDeclaredAPI12) {
OEMCrypto_ProvisioningMethod provisioning_method =
OEMCrypto_GetProvisioningMethod();
cout << " Provisioning method = "
<< ProvisioningMethodName(provisioning_method) << endl;
ASSERT_NE(OEMCrypto_ProvisioningError, provisioning_method);
}
TEST_F(OEMCryptoClientTest, CheckHDCPCapabilityAPI09) {
OEMCryptoResult sts;
OEMCrypto_HDCP_Capability current, maximum;
sts = OEMCrypto_GetHDCPCapability(&current, &maximum);
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
printf(" Current HDCP Capability: 0x%02x = %s.\n",
static_cast<unsigned int>(current), HDCPCapabilityAsString(current));
printf(" Maximum HDCP Capability: 0x%02x = %s.\n",
static_cast<unsigned int>(maximum), HDCPCapabilityAsString(maximum));
}
TEST_F(OEMCryptoClientTest, CheckSRMCapabilityV13) {
// This just tests some trivial functionality of the SRM update functions.
uint16_t version = 0;
OEMCryptoResult current_result = OEMCrypto_GetCurrentSRMVersion(&version);
if (current_result == OEMCrypto_SUCCESS) {
printf(" Current SRM Version: %d.\n", version);
EXPECT_NE(OEMCrypto_SUCCESS, OEMCrypto_GetCurrentSRMVersion(nullptr));
} else if (current_result == OEMCrypto_LOCAL_DISPLAY_ONLY) {
printf(" Current SRM Status: Local Display Only.\n");
} else {
EXPECT_EQ(OEMCrypto_ERROR_NOT_IMPLEMENTED, current_result);
}
}
TEST_F(OEMCryptoClientTest, CheckNullBuildInformationAPI17) {
OEMCryptoResult sts;
std::string build_info;
sts = OEMCrypto_BuildInformation(&build_info[0], nullptr);
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts);
size_t buf_length = 0;
sts = OEMCrypto_BuildInformation(nullptr, &buf_length);
// Previous versions of the test expected the wrong error code.
// Although OEMCrypto_ERROR_INVALID_CONTEXT is still accepted by
// the tests, vendors should return OEMCrypto_ERROR_SHORT_BUFFER if
// |buffer| is null and |buf_length| is zero, assigning
// the correct length to |buf_length|.
// TODO(231514699): Remove case for ERROR_INVALID_CONTEXT.
ASSERT_TRUE(OEMCrypto_ERROR_SHORT_BUFFER == sts ||
OEMCrypto_ERROR_INVALID_CONTEXT == sts);
if (sts == OEMCrypto_ERROR_INVALID_CONTEXT) {
printf(
"Warning: OEMCrypto_BuildInformation should return "
"ERROR_SHORT_BUFFER.\n");
}
if (sts == OEMCrypto_ERROR_SHORT_BUFFER) {
constexpr size_t kZero = 0;
ASSERT_GT(buf_length, kZero);
}
}
TEST_F(OEMCryptoClientTest, CheckJsonBuildInformationAPI18) {
std::string build_info;
OEMCryptoResult sts = OEMCrypto_BuildInformation(&build_info[0], nullptr);
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts);
size_t buf_length = 0;
// OEMCrypto must allow |buffer| to be null so long as |buffer_length|
// is provided and initially set to zero.
sts = OEMCrypto_BuildInformation(nullptr, &buf_length);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
build_info.resize(buf_length);
const size_t max_final_size = buf_length;
sts = OEMCrypto_BuildInformation(&build_info[0], &buf_length);
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
ASSERT_LE(buf_length, max_final_size);
build_info.resize(buf_length);
jsmn_parser p;
jsmn_init(&p);
std::vector<jsmntok_t> tokens;
int32_t num_tokens =
jsmn_parse(&p, build_info.c_str(), build_info.size(), nullptr, 0);
EXPECT_GT(num_tokens, 0)
<< "Failed to parse BuildInformation as JSON, parse returned "
<< num_tokens << "for following build info: " << build_info;
tokens.resize(num_tokens);
jsmn_init(&p);
int32_t jsmn_result = jsmn_parse(&p, build_info.c_str(), build_info.size(),
tokens.data(), num_tokens);
EXPECT_GE(jsmn_result, 0)
<< "Failed to parse BuildInformation as JSON, parse returned "
<< jsmn_result << "for following build info: " << build_info;
std::map<std::string, jsmntype_t> expected;
expected["soc_vendor"] = JSMN_STRING;
expected["soc_model"] = JSMN_STRING;
expected["ta_ver"] = JSMN_STRING;
expected["uses_opk"] = JSMN_PRIMITIVE;
expected["tee_os"] = JSMN_STRING;
expected["tee_os_ver"] = JSMN_STRING;
// for values in token
// build string from start,end
// check for existence in map
// check if value matches expectation
// remove from map
for (int i = 0; i < jsmn_result; i++) {
jsmntok_t token = tokens[i];
std::string key = build_info.substr(token.start, token.end - token.start);
if (expected.find(key) != expected.end()) {
EXPECT_EQ(expected.find(key)->second, tokens[i + 1].type)
<< "Type is incorrect for key " << key;
expected.erase(key);
}
}
// if map is not empty, return false
if (expected.size() > 0) {
std::string missing;
for (auto e : expected) {
missing.append(e.first);
missing.append(" ");
}
FAIL() << "JSON does not contain all required keys. Missing keys: ["
<< missing << "] in string " << build_info;
}
}
TEST_F(OEMCryptoClientTest, CheckMaxNumberOfSessionsAPI10) {
size_t sessions_count;
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_GetNumberOfOpenSessions(&sessions_count));
ASSERT_EQ(0u, sessions_count);
size_t maximum;
OEMCryptoResult sts = OEMCrypto_GetMaxNumberOfSessions(&maximum);
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
printf(" Max Number of Sessions: %zu.\n", maximum);
size_t required_max = GetResourceValue(kMaxConcurrentSession);
ASSERT_GE(maximum, required_max);
}
TEST_F(OEMCryptoClientTest, CheckUsageTableSizeAPI16) {
const size_t maximum = OEMCrypto_MaximumUsageTableHeaderSize();
printf(" Max Usage Table Size: %zu.\n", maximum);
// A maximum of 0 means the table is constrained by dynamic memory allocation.
if (maximum > 0) {
ASSERT_GE(maximum, RequiredUsageSize());
}
}
//
// initialization tests
//
TEST_F(OEMCryptoClientTest, NormalInitTermination) {
// Should be able to terminate OEMCrypto, and then restart it.
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Terminate());
OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox));
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize());
(void)OEMCrypto_SetMaxAPIVersion(kCurrentAPI);
(void)OEMCrypto_EnterTestMode();
}
TEST_F(OEMCryptoClientTest, CheckDTCP2CapabilityAPI17) {
OEMCryptoResult sts;
OEMCrypto_DTCP2_Capability capability;
sts = OEMCrypto_GetDTCP2Capability(&capability);
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
switch (capability) {
case OEMCrypto_NO_DTCP2:
printf(" Current DTCP Support: DTCP2 not supported.\n");
break;
case OEMCrypto_DTCP2_V1:
printf(
" Current DTCP Support: Version 1 (or higher) of "
"DTCP2 is supported.\n");
break;
}
}
//
// Session Tests
//
TEST_F(OEMCryptoClientTest, NormalSessionOpenClose) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(s.close());
}
TEST_F(OEMCryptoClientTest, TwoSessionsOpenClose) {
Session s1;
Session s2;
ASSERT_NO_FATAL_FAILURE(s1.open());
ASSERT_NO_FATAL_FAILURE(s2.open());
ASSERT_NO_FATAL_FAILURE(s1.close());
ASSERT_NO_FATAL_FAILURE(s2.close());
}
// This test verifies that OEMCrypto can open approximately as many sessions as
// it claims.
TEST_F(OEMCryptoClientTest, MaxSessionsOpenCloseAPI10) {
size_t sessions_count;
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_GetNumberOfOpenSessions(&sessions_count));
ASSERT_EQ(0u, sessions_count);
size_t max_sessions;
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_GetMaxNumberOfSessions(&max_sessions));
// We expect OEMCrypto implementations support at least this many sessions.
size_t required_number = GetResourceValue(kMaxConcurrentSession);
ASSERT_GE(max_sessions, required_number);
// We allow GetMaxNumberOfSessions to return an estimate. This tests with a
// pad of 5%. Even if it's just an estimate, we still require 8 sessions.
size_t max_sessions_with_pad = max(max_sessions * 19 / 20, required_number);
vector<OEMCrypto_SESSION> sessions;
// Limit the number of sessions for testing.
const size_t kMaxNumberOfSessionsForTesting = 0x100u;
for (size_t i = 0; i < kMaxNumberOfSessionsForTesting; i++) {
OEMCrypto_SESSION session_id;
OEMCryptoResult sts = OEMCrypto_OpenSession(&session_id);
// GetMaxNumberOfSessions might be an estimate. We allow OEMCrypto to report
// a max that is less than what is actually supported. Assume the number
// returned is |max|. OpenSessions shall not fail if number of active
// sessions is less than |max|; OpenSessions should fail with
// OEMCrypto_ERROR_TOO_MANY_SESSIONS if too many sessions are open.
if (sts != OEMCrypto_SUCCESS) {
ASSERT_EQ(OEMCrypto_ERROR_TOO_MANY_SESSIONS, sts);
ASSERT_GE(i, max_sessions_with_pad);
break;
}
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_GetNumberOfOpenSessions(&sessions_count));
ASSERT_EQ(i + 1, sessions_count);
sessions.push_back(session_id);
}
for (size_t i = 0; i < sessions.size(); i++) {
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CloseSession(sessions[i]));
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_GetNumberOfOpenSessions(&sessions_count));
ASSERT_EQ(sessions.size() - i - 1, sessions_count);
}
if (sessions.size() == kMaxNumberOfSessionsForTesting) {
printf(
" MaxSessionsOpenClose: reaches "
"kMaxNumberOfSessionsForTesting(%zu). GetMaxNumberOfSessions = %zu. "
"ERROR_TOO_MANY_SESSIONS not tested.",
kMaxNumberOfSessionsForTesting, max_sessions);
}
}
TEST_F(OEMCryptoClientTest, GenerateNonce) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
s.GenerateNonce();
}
// Prevent a nonce flood even if each nonce is in a different session.
TEST_F(OEMCryptoClientTest, PreventNonceFlood2API16) {
int error_counter = 0;
const int64_t test_start = wvutil::Clock().GetCurrentTime();
// More than 200 nonces per second should generate an error.
// To allow for some slop, we actually test for more.
const int flood_cutoff = 200;
const int loop_count = flood_cutoff * 2;
for (int i = 0; i < loop_count; i++) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
s.GenerateNonce(&error_counter);
}
const int64_t test_end = wvutil::Clock().GetCurrentTime();
int valid_counter = loop_count - error_counter;
// Either oemcrypto should enforce a delay, or it should return an error from
// GenerateNonce -- in either case the number of valid nonces is rate
// limited. We add two seconds to allow for round off error in both
// test_start and test_end.
EXPECT_LE(valid_counter, flood_cutoff * (test_end - test_start + 2));
error_counter = 0;
// After a pause, we should be able to regenerate nonces.
wvutil::TestSleep::Sleep(2);
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
s.GenerateNonce(&error_counter);
EXPECT_EQ(0, error_counter);
}
// Prevent a nonce flood even if some nonces are in a different session. This
// is different from the test above because there are several session open at
// the same time. We want to make sure you can't get a flood of nonces by
// opening a flood of sessions.
TEST_F(OEMCryptoClientTest, PreventNonceFlood3API16) {
int request_counter = 0;
int error_counter = 0;
const int64_t test_start = wvutil::Clock().GetCurrentTime();
// More than 200 nonces per second should generate an error.
// To allow for some slop, we actually test for more.
const int flood_cutoff = 200;
const size_t session_count = GetResourceValue(kMaxConcurrentSession);
const size_t loop_count = 2 * flood_cutoff / session_count + 1;
for (size_t i = 0; i < loop_count; i++) {
std::vector<Session> s(session_count);
for (size_t j = 0; j < session_count; j++) {
ASSERT_NO_FATAL_FAILURE(s[j].open());
request_counter++;
s[j].GenerateNonce(&error_counter);
}
}
const int64_t test_end = wvutil::Clock().GetCurrentTime();
int valid_counter = request_counter - error_counter;
// Either oemcrypto should enforce a delay, or it should return an error from
// GenerateNonce -- in either case the number of valid nonces is rate
// limited. We add two seconds to allow for round off error in both
// test_start and test_end.
EXPECT_LE(valid_counter, flood_cutoff * (test_end - test_start + 2));
error_counter = 0;
// After a pause, we should be able to regenerate nonces.
wvutil::TestSleep::Sleep(2);
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
s.GenerateNonce(&error_counter);
EXPECT_EQ(0, error_counter);
}
// This verifies that CopyBuffer works, even before a license has been loaded.
TEST_F(OEMCryptoClientTest, ClearCopyTestAPI10) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
const int kDataSize = 256;
vector<uint8_t> input_buffer(kDataSize);
GetRandBytes(input_buffer.data(), input_buffer.size());
vector<uint8_t> output_buffer(kDataSize);
OEMCrypto_DestBufferDesc dest_buffer_descriptor;
dest_buffer_descriptor.type = OEMCrypto_BufferType_Clear;
dest_buffer_descriptor.buffer.clear.clear_buffer = output_buffer.data();
dest_buffer_descriptor.buffer.clear.clear_buffer_length =
output_buffer.size();
ASSERT_EQ(OEMCrypto_SUCCESS,
CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(),
&dest_buffer_descriptor,
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample));
ASSERT_EQ(input_buffer, output_buffer);
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
CopyBuffer(s.session_id(), nullptr, input_buffer.size(),
&dest_buffer_descriptor,
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample));
ASSERT_EQ(
OEMCrypto_ERROR_INVALID_CONTEXT,
CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(),
nullptr, OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample));
dest_buffer_descriptor.buffer.clear.clear_buffer = nullptr;
ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(),
&dest_buffer_descriptor,
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample));
dest_buffer_descriptor.buffer.clear.clear_buffer = output_buffer.data();
dest_buffer_descriptor.buffer.clear.clear_buffer_length =
output_buffer.size() - 1;
ASSERT_NE(OEMCrypto_SUCCESS,
CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(),
&dest_buffer_descriptor,
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample));
}
// This verifies that CopyBuffer works on the maximum required buffer size.
TEST_F(OEMCryptoClientTest, ClearCopyTestLargeSubsample) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
size_t max_size = GetResourceValue(kMaxSubsampleSize);
vector<uint8_t> input_buffer(max_size);
GetRandBytes(input_buffer.data(), input_buffer.size());
vector<uint8_t> output_buffer(max_size);
OEMCrypto_DestBufferDesc dest_buffer_descriptor;
dest_buffer_descriptor.type = OEMCrypto_BufferType_Clear;
dest_buffer_descriptor.buffer.clear.clear_buffer = output_buffer.data();
dest_buffer_descriptor.buffer.clear.clear_buffer_length =
output_buffer.size();
ASSERT_EQ(OEMCrypto_SUCCESS,
CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(),
&dest_buffer_descriptor,
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample));
ASSERT_EQ(input_buffer, output_buffer);
}
TEST_F(OEMCryptoClientTest,
OEMCryptoMemoryCopyBufferForOutOfRangeHandleLength) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
vector<uint8_t> input_buffer;
OEMCrypto_DestBufferDesc dest_buffer_descriptor;
dest_buffer_descriptor.type = OEMCrypto_BufferType_Secure;
size_t buffer_length = KiB;
input_buffer.resize(buffer_length);
int secure_fd;
if (OEMCrypto_AllocateSecureBuffer(s.session_id(), buffer_length,
&dest_buffer_descriptor,
&secure_fd) != OEMCrypto_SUCCESS) {
LOGI("Secure buffers are not supported.");
return;
}
dest_buffer_descriptor.buffer.secure.secure_buffer_length =
kHugeInputBufferLength;
ASSERT_NO_FATAL_FAILURE(
OEMCrypto_CopyBuffer(s.session_id(), input_buffer.data(), buffer_length,
&dest_buffer_descriptor,
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample));
OEMCrypto_FreeSecureBuffer(s.session_id(), &dest_buffer_descriptor,
secure_fd);
}
TEST_F(OEMCryptoClientTest, ClearCopyTestInvalidSubsampleFlag) {
uint8_t oemcrypto_invalid_subsample_flag = 85;
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
size_t max_size = GetResourceValue(kMaxSubsampleSize);
vector<uint8_t> input_buffer(max_size);
GetRandBytes(input_buffer.data(), input_buffer.size());
vector<uint8_t> output_buffer(max_size);
OEMCrypto_DestBufferDesc dest_buffer_descriptor;
dest_buffer_descriptor.type = OEMCrypto_BufferType_Clear;
dest_buffer_descriptor.buffer.clear.clear_buffer = output_buffer.data();
dest_buffer_descriptor.buffer.clear.clear_buffer_length =
output_buffer.size();
ASSERT_NO_FATAL_FAILURE(
CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(),
&dest_buffer_descriptor, oemcrypto_invalid_subsample_flag));
}
TEST_F(OEMCryptoClientTest, CanLoadTestKeys) {
ASSERT_NE(DeviceFeatures::NO_METHOD, global_features.derive_key_method)
<< "Session tests cannot run with out a test keybox or RSA cert.";
}
/// @}
} // namespace wvoec