// 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& message, const vector& substring) { vector::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(&fuzzed_structure), sizeof(fuzzed_structure)); AppendToFile(file_name, reinterpret_cast(&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 ""; } } // 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) { // Check for a early null termination. This is common for the device // id in a keybox, which is padded with 0s. const size_t c_len = strnlen(reinterpret_cast(data), length); // If there is any nonzero after the first zero, then just use hex. for (size_t i = c_len; i < length; i++) { if (data[i] != 0) return "0x" + wvutil::HexEncode(data, length); } for (size_t i = 0; i < c_len; i++) { if (!isprint(data[i])) return "0x" + wvutil::HexEncode(data, length); } return std::string(reinterpret_cast(data), c_len); } std::string MaybeHex(const std::vector& data) { return MaybeHex(data.data(), data.size()); } // Get the Device's ID and return it in a printable format. std::string GetDeviceId() { OEMCryptoResult sts; std::vector dev_id(128, 0); size_t dev_id_len = dev_id.size(); sts = OEMCrypto_GetDeviceID(dev_id.data(), &dev_id_len); if (sts == OEMCrypto_ERROR_SHORT_BUFFER) { if (dev_id_len <= 0) return "NO DEVICE ID"; dev_id.resize(dev_id_len); sts = OEMCrypto_GetDeviceID(dev_id.data(), &dev_id_len); } if (sts != OEMCrypto_SUCCESS) return "NO DEVICE ID"; dev_id.resize(dev_id_len); return MaybeHex(dev_id); } /// @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(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; cout << " OEMCrypto Device ID is '" << GetDeviceId() << "'" << 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); } 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(¤t, &maximum); ASSERT_EQ(OEMCrypto_SUCCESS, sts); printf(" Current HDCP Capability: 0x%02x = %s.\n", static_cast(current), HDCPCapabilityAsString(current)); printf(" Maximum HDCP Capability: 0x%02x = %s.\n", static_cast(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 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 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 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 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 input_buffer(kDataSize); GetRandBytes(input_buffer.data(), input_buffer.size()); vector 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 input_buffer(max_size); GetRandBytes(input_buffer.data(), input_buffer.size()); vector 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 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 input_buffer(max_size); GetRandBytes(input_buffer.data(), input_buffer.size()); vector 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