diff --git a/libwvdrmengine/oemcrypto/test/fuzz_tests/README.md b/libwvdrmengine/oemcrypto/test/fuzz_tests/README.md index 98ed2a57..8c163fb1 100644 --- a/libwvdrmengine/oemcrypto/test/fuzz_tests/README.md +++ b/libwvdrmengine/oemcrypto/test/fuzz_tests/README.md @@ -104,17 +104,13 @@ oemcrypto_fuzztests.gypi cflags_cc in order to generate additional debug information locally. -* Build and test fuzz scripts locally using: +* Build and test fuzz scripts locally using following commands. The build + script builds fuzz binaries for both oemcrypto reference implementation + as well as odkitee implementation. ```shell - $ export CXX=clang++ - $ export CC=clang - $ export GYP_DEFINES="clang=1" - $ cd /path/to/cdm/repo - $ export PATH_TO_CDM_DIR=. - $ gyp --format=ninja --depth=$(pwd) \ - oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp - $ ninja -C out/Default/ + $ cd PATH_TO_CDM_DIR + $ ./oemcrypto/test/fuzz_tests/build_oemcrypto_fuzztests $ mkdir /tmp/new_interesting_corpus $ ./out/Default/fuzzer_binary /tmp/new_interesting_corpus \ /path/to/fuzz/seed/corpus/folder @@ -127,8 +123,9 @@ $ ./out/Default/fuzzer_binary crash_input_file ``` ## Adding a new OEMCrypto fuzz script -* In order to fuzz a new OEMCrypto API in future, a fuzz script can be added to - oemcrypto/test/fuzz_tests folder which ends with _fuzz.cc. +* In order to fuzz a new OEMCrypto API in future, a fuzz script can be added + to oemcrypto/test/fuzz_tests folder which starts with oemcrypto and ends + with fuzz.cc(GCB build script for oemcrypto fuzzers expects the format). * In the program, define the function LLVMFuzzerTestOneInput with the following signature: ``` @@ -164,50 +161,14 @@ ### Adding a new fuzz script to the build script: -* In order to update build script such as adding a new fuzzer to build script, - we need to update the build script in docker image from cloud repository. - [Build script.](https://widevine-internal.googlesource.com/cloud/+/refs/heads/master/docker - /cloud_build/oemcrypto/release/ubuntu/fuzz/build.sh) +* As long as a new fuzz script is added which starts with oemcrypto and ends + with fuzz, the build command can be added to build_oemcrypto_fuzztests. + GCB script uses build_oemcrypto_fuzztests script to build fuzz binaries + and make them available for clusterfuzz to run continuously. - Add the new fuzz script name to fuzzers variable and follow steps in README - to upload new docker image. Make sure you update the tag to be higher than - latest version in GCR. - - Run the following command from your machine to update the docker image tag - in the git trigger. - - ```shell - stubby call --rpc_creds_file=/tmp/mint.txt \ - blade:alphasource-ci-proctor-metadata-service-prod \ - ProctorMetadataService.UpdateTrigger --proto2 < -void RoundTrip::SignAndVerifyRequest() { +OEMCryptoResult +RoundTrip:: + SignAndCreateRequestWithCustomBufferLengths(bool verify_request) { // In the real world, a message should be signed by the client and // verified by the server. This simulates that. size_t gen_signature_length = 0; size_t core_message_length = 0; constexpr size_t small_size = 42; // arbitrary. - size_t message_size = - std::max(required_message_size_, core_message_length + small_size); - vector data(message_size, 0); - for (size_t i = 0; i < data.size(); i++) data[i] = i & 0xFF; - ASSERT_EQ( - PrepAndSignRequest(session()->session_id(), data.data(), data.size(), - &core_message_length, nullptr, &gen_signature_length), - OEMCrypto_ERROR_SHORT_BUFFER); + uint32_t session_id = session()->session_id(); + GetDefaultRequestSignatureAndCoreMessageLengths( + session_id, required_message_size_, small_size, &gen_signature_length, + &core_message_length); + // Used to test request APIs with varying lengths of core message. + core_message_length = + std::max(core_message_length, required_core_message_size_); + // Used to test request APIs with varying lengths of signature. + gen_signature_length = + std::max(gen_signature_length, required_request_signature_size_); // Make the message buffer a little bigger than the core message, or the // required size, whichever is larger. - message_size = + size_t message_size = std::max(required_message_size_, core_message_length + small_size); - data.resize(message_size); + vector data(message_size); for (size_t i = 0; i < data.size(); i++) data[i] = i & 0xFF; if (ShouldGenerateCorpus()) { WriteRequestApiCorpus(gen_signature_length, @@ -171,17 +174,33 @@ void RoundTrip gen_signature(gen_signature_length); - ASSERT_EQ(PrepAndSignRequest(session()->session_id(), data.data(), - data.size(), &core_message_length, - gen_signature.data(), &gen_signature_length), - OEMCrypto_SUCCESS); + OEMCryptoResult result = PrepAndSignRequest( + session()->session_id(), data.data(), data.size(), &core_message_length, + gen_signature.data(), &gen_signature_length); + // We need to fill in core request and verify signature only for calls other + // than OEMCryptoMemory buffer overflow test. Any test other than buffer + // overflow will pass true. + if (!verify_request || result != OEMCrypto_SUCCESS) return result; if (global_features.api_version >= kCoreMessagesAPI) { - ASSERT_GT(data.size(), core_message_length); std::string core_message(reinterpret_cast(data.data()), core_message_length); FillAndVerifyCoreRequest(core_message); } VerifyRequestSignature(data, gen_signature, core_message_length); + return result; +} + +template +void GetDefaultRequestSignatureAndCoreMessageLengths( + uint32_t& session_id, size_t& required_message_size, + const size_t& small_size, size_t* gen_signature_length, + size_t* core_message_length) { + vector data(small_size); + for (size_t i = 0; i < data.size(); i++) data[i] = i & 0xFF; + ASSERT_EQ( + PrepAndSignRequest(session_id, data.data(), data.size(), + core_message_length, nullptr, gen_signature_length), + OEMCrypto_ERROR_SHORT_BUFFER); } template = kCoreMessagesAPI) { ASSERT_TRUE( oemcrypto_core_message::serialize::CreateCoreProvisioningResponse( core_response_, core_request_, &serialized_core_message_)); + // Resizing for huge core message length unit tests. + serialized_core_message_.resize( + std::max(required_core_message_size_, serialized_core_message_.size())); } // Make the message buffer a just big enough, or the // required size, whichever is larger. @@ -689,6 +724,10 @@ void LicenseRoundTrip::EncryptAndSignResponse() { ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreLicenseResponse( core_response_, core_request_, request_hash_string, &serialized_core_message_)); + // Resize serialize core message to be just big enough or required core + // message size, whichever is larger. + serialized_core_message_.resize( + std::max(required_core_message_size_, serialized_core_message_.size())); } // Make the message buffer a just big enough, or the @@ -701,7 +740,6 @@ void LicenseRoundTrip::EncryptAndSignResponse() { for (size_t i = 0; i < encrypted_response_.size(); i++) { encrypted_response_[i] = i % 0x100; } - ASSERT_GE(kMaxCoreMessage, serialized_core_message_.size()); ASSERT_GE(encrypted_response_.size(), serialized_core_message_.size()); memcpy(encrypted_response_.data(), serialized_core_message_.data(), serialized_core_message_.size()); @@ -716,6 +754,11 @@ void LicenseRoundTrip::EncryptAndSignResponse() { } OEMCryptoResult LicenseRoundTrip::LoadResponse(Session* session) { + return LoadResponse(session, true); +} + +OEMCryptoResult LicenseRoundTrip::LoadResponse(Session* session, + bool verify_keys) { EXPECT_NE(session, nullptr); // Write corpus for oemcrypto_load_license_fuzz. Fuzz script expects // unecnrypted response from license server as input corpus data. @@ -762,7 +805,7 @@ OEMCryptoResult LicenseRoundTrip::LoadResponse(Session* session) { encrypted_response_.size(), serialized_core_message_.size(), response_signature_.data(), response_signature_.size()); } - if (result == OEMCrypto_SUCCESS) { + if (verify_keys && result == OEMCrypto_SUCCESS) { // Give the session object a copy of the license truth data so that it can // call SelectKey, use key control information, and so that it has key data // to verify decrypt operations. @@ -861,6 +904,18 @@ void EntitledMessage::MakeOneKey(size_t entitlement_key_index) { key_data->content_key_data_iv, sizeof(key_data->content_key_data_iv)); } +OEMCrypto_EntitledContentKeyObject* EntitledMessage::entitled_key_array() { + return entitled_key_array_; +} + +EntitledContentKeyData* EntitledMessage::entitled_key_data() { + return entitled_key_data_; +} + +size_t EntitledMessage::entitled_key_data_size() { + return sizeof(entitled_key_data_); +} + void EntitledMessage::SetEntitlementKeyId(unsigned int index, const std::string& key_id) { ASSERT_LT(index, num_keys_); @@ -884,6 +939,32 @@ OEMCrypto_Substring EntitledMessage::FindSubstring(const void* ptr, } void EntitledMessage::LoadKeys(OEMCryptoResult expected_sts) { + EncryptContentKey(); + ASSERT_EQ(expected_sts, + OEMCrypto_LoadEntitledContentKeys( + license_messages_->session()->session_id(), + reinterpret_cast(entitled_key_data_), + sizeof(entitled_key_data_), num_keys_, entitled_key_array_)); + if (expected_sts != OEMCrypto_SUCCESS) { + return; + } + VerifyEntitlementTestKeys(); +} + +OEMCryptoResult EntitledMessage::LoadKeys(const vector& message) { + return OEMCrypto_LoadEntitledContentKeys( + license_messages_->session()->session_id(), message.data(), + message.size(), num_keys_, entitled_key_array_); +} + +OEMCryptoResult EntitledMessage::LoadKeys() { + return OEMCrypto_LoadEntitledContentKeys( + license_messages_->session()->session_id(), + reinterpret_cast(entitled_key_data_), + sizeof(entitled_key_data_), num_keys_, entitled_key_array_); +} + +void EntitledMessage::EncryptContentKey() { for (size_t i = 0; i < num_keys_; ++i) { EntitledContentKeyData* key_data = &entitled_key_data_[i]; const size_t entitlement_key_index = key_data->key_index; @@ -912,15 +993,6 @@ void EntitledMessage::LoadKeys(OEMCryptoResult expected_sts) { AppendToFile(file_name, reinterpret_cast(entitled_key_array_), num_keys_); } - ASSERT_EQ(expected_sts, - OEMCrypto_LoadEntitledContentKeys( - license_messages_->session()->session_id(), - reinterpret_cast(entitled_key_data_), - sizeof(entitled_key_data_), num_keys_, entitled_key_array_)); - if (expected_sts != OEMCrypto_SUCCESS) { - return; - } - VerifyEntitlementTestKeys(); } // This function verifies that the key control block reported by OEMCrypto agree @@ -1035,6 +1107,10 @@ void RenewalRoundTrip::EncryptAndSignResponse() { } else { ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreRenewalResponse( core_request_, renewal_duration_seconds_, &serialized_core_message_)); + // Resize serialize core message to be just big enough or required core + // message size, whichever is larger. + serialized_core_message_.resize( + std::max(required_core_message_size_, serialized_core_message_.size())); } // Make the message buffer a just big enough, or the // required size, whichever is larger. @@ -1047,7 +1123,6 @@ void RenewalRoundTrip::EncryptAndSignResponse() { encrypted_response_[i] = i % 0x100; } // Concatenate the core message and the response. - ASSERT_GE(kMaxCoreMessage, serialized_core_message_.size()); ASSERT_GE(encrypted_response_.size(), serialized_core_message_.size()); memcpy(encrypted_response_.data(), serialized_core_message_.data(), serialized_core_message_.size()); diff --git a/libwvdrmengine/oemcrypto/test/oec_session_util.h b/libwvdrmengine/oemcrypto/test/oec_session_util.h index a3773fd3..264a8ae9 100644 --- a/libwvdrmengine/oemcrypto/test/oec_session_util.h +++ b/libwvdrmengine/oemcrypto/test/oec_session_util.h @@ -155,12 +155,25 @@ class RoundTrip { core_response_(), response_data_(), encrypted_response_data_(), - required_message_size_(0) {} + required_message_size_(0), + required_core_message_size_(0), + required_request_signature_size_(0) {} virtual ~RoundTrip() {} // Have OEMCrypto sign a request message and then verify the signature and the // core message. - virtual void SignAndVerifyRequest(); + virtual void SignAndVerifyRequest() { + // Boolean true generates core request and verifies the request. + // Custom message sizes are 0 by default, so the behavior of following + // functions will be sign and verify request without any custom buffers + // sizes. + ASSERT_EQ(SignAndCreateRequestWithCustomBufferLengths(true), + OEMCrypto_SUCCESS); + } + // Have OEMCrypto sign and call create request APIs. Buffer parameters in API + // can be set to custom values to test with varying lengths of buffers. + virtual OEMCryptoResult SignAndCreateRequestWithCustomBufferLengths( + bool verify_request = false); // Used for OEMCrypto Fuzzing: Function to convert fuzzer data to valid // License/Provisioning/Renwal request data that can be serialized. virtual void InjectFuzzedRequestData(uint8_t* data, size_t size); @@ -189,6 +202,16 @@ class RoundTrip { // Set the size of the buffer used the encrypted license. void set_message_size(size_t size) { required_message_size_ = size; } + // Set core message size to test OEMCrypto request APIs for varying core + // message lengths. + void set_core_message_size(size_t size) { + required_core_message_size_ = size; + } + // Set signature size to test OEMCrypto request APIs for varying signature + // lengths. + void set_request_signature_size(size_t size) { + required_request_signature_size_ = size; + } std::vector& response_signature() { return response_signature_; } const std::string& serialized_core_message() const { return serialized_core_message_; @@ -217,6 +240,8 @@ class RoundTrip { // Message buffers will be at least this big. Tests for loading and signing // messages will increase all buffers to this size. size_t required_message_size_; + size_t required_core_message_size_; + size_t required_request_signature_size_; std::vector response_signature_; std::string serialized_core_message_; std::vector encrypted_response_; @@ -239,6 +264,8 @@ class ProvisioningRoundTrip virtual void PrepareSession(const wvoec::WidevineKeybox& keybox); void CreateDefaultResponse() override; void EncryptAndSignResponse() override; + void EncryptAndSignResponseWithoutUpdatingEncPrivateKeyLength(); + void SignResponse(); OEMCryptoResult LoadResponse() override { return LoadResponse(session_); } OEMCryptoResult LoadResponse(Session* session) override; void VerifyLoadFailed(); @@ -318,6 +345,7 @@ class LicenseRoundTrip void EncryptAndSignResponse() override; OEMCryptoResult LoadResponse() override { return LoadResponse(session_); } OEMCryptoResult LoadResponse(Session* session) override; + OEMCryptoResult LoadResponse(Session* session, bool verify_keys); // Reload an offline license into a different session. This derives new mac // keys and then calls LoadResponse. OEMCryptoResult ReloadResponse(Session* session); @@ -442,11 +470,19 @@ class EntitledMessage { void FillKeyArray(); void MakeOneKey(size_t entitlement_key_index); void LoadKeys(OEMCryptoResult expected_sts); + OEMCryptoResult LoadKeys(const vector& message); + OEMCryptoResult LoadKeys(); + void EncryptContentKey(); void set_num_keys(uint32_t num_keys) { num_keys_ = num_keys; } uint32_t num_keys() const { return num_keys_; } void SetEntitlementKeyId(unsigned int index, const std::string& key_id); // Verify that key control blocks of the loaded keys. void VerifyEntitlementTestKeys(); + OEMCrypto_EntitledContentKeyObject* entitled_key_array(); + // Returns entitled_key_data_ which is used as input message buffer to + // load entitled content keys API. + EntitledContentKeyData* entitled_key_data(); + size_t entitled_key_data_size(); private: // Find the offset of the give pointer, relative to |entitled_key_data_|. @@ -631,6 +667,11 @@ bool ConvertByteToValidBoolean(const bool* in); template void WriteRequestApiCorpus(size_t signature_length, size_t core_message_length, vector& data); +template +void GetDefaultRequestSignatureAndCoreMessageLengths( + uint32_t& session_id, size_t& required_message_size, + const size_t& small_size, size_t* gen_signature_length, + size_t* core_message_length); } // namespace wvoec #endif // CDM_OEC_SESSION_UTIL_H_ diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp index d6ee409e..264d63f3 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp @@ -107,6 +107,9 @@ constexpr size_t MiB = 1024 * 1024; // Huge input buffer length used for OEMCryptoMemory* tests. constexpr size_t kHugeInputBufferLength = 100 * MiB; constexpr bool kCheckStatus = true; +constexpr bool kUpdateCoreMessageSubstringValues = true; +constexpr bool kDecryptCENCSecureBuffer = true; +constexpr size_t kHugeRandomNumber = 541236; // With OEMCrypto v15 and above, we have different resource requirements // depending on the resource rating reported by OEMCrypto. This function looks // up the required value for the specified resource for the target OEMCrypto @@ -209,13 +212,17 @@ class OEMCryptoClientTest : public ::testing::Test, public SessionUtil { */ TEST_F(OEMCryptoClientTest, VersionNumber) { const std::string log_message = - "OEMCrypto unit tests for API 16.3. Tests last updated 2020-06-01"; + "OEMCrypto unit tests for API 16.4. Tests last updated 2020-10-07"; cout << " " << log_message << "\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, 16); - EXPECT_EQ(ODK_MINOR_VERSION, 3); + // 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 + // tables, we strongly recommend 16.4. + EXPECT_GE(ODK_MINOR_VERSION, 3); + EXPECT_LE(ODK_MINOR_VERSION, 4); EXPECT_EQ(kCurrentAPI, 16u); const char* level = OEMCrypto_SecurityLevel(); ASSERT_NE(nullptr, level); @@ -241,6 +248,91 @@ TEST_F(OEMCryptoClientTest, VersionNumber) { ASSERT_LE(version, kCurrentAPI); } +TEST_F(OEMCryptoClientTest, + OEMCryptoMemoryAllocateSecureBufferForHugeBufferSize) { + Session s; + s.open(); + auto oemcrypto_function = [&s](size_t buffer_size) { + OEMCrypto_DestBufferDesc output_descriptor; + int secure_fd; + OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( + s.session_id(), buffer_size, &output_descriptor, &secure_fd); + if (sts == OEMCrypto_SUCCESS) { + OEMCrypto_FreeSecureBuffer(s.session_id(), &output_descriptor, secure_fd); + } + return sts; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); + s.close(); +} + +TEST_F(OEMCryptoClientTest, + OEMCryptoMemoryWrapKeyboxOrOEMCertForHugeKeyboxLength) { + auto oemcrypto_function = [](size_t keybox_length) { + vector keybox_buffer(keybox_length); + size_t wrapped_keybox_length = keybox_length + 50; + vector wrapped_keybox_buffer(wrapped_keybox_length); + vector transport_key_buffer(20); + memcpy(keybox_buffer.data(), &kTestKeybox, sizeof(kTestKeybox)); + return OEMCrypto_WrapKeyboxOrOEMCert( + keybox_buffer.data(), keybox_length, wrapped_keybox_buffer.data(), + &wrapped_keybox_length, transport_key_buffer.data(), + transport_key_buffer.size()); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, sizeof(kTestKeybox), + kHugeInputBufferLength, kCheckStatus); +} + +TEST_F(OEMCryptoClientTest, + OEMCryptoMemoryWrapKeyboxOrOEMCertForHugeWrappedKeyboxLength) { + auto oemcrypto_function = [](size_t buffer_length) { + size_t wrapped_keybox_length = buffer_length; + vector wrapped_keybox_buffer(wrapped_keybox_length); + vector transport_key_buffer(20); + return OEMCrypto_WrapKeyboxOrOEMCert( + reinterpret_cast(&kTestKeybox), sizeof(kTestKeybox), + wrapped_keybox_buffer.data(), &wrapped_keybox_length, + transport_key_buffer.data(), transport_key_buffer.size()); + }; + // API expects keybox length and wrapped keybox length to be equal. We would + // like to test for various values of wrapped keybox lengths, hence skipping + // status check. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +TEST_F(OEMCryptoClientTest, + OEMCryptoMemoryWrapKeyboxOrOEMCertForHugeTransportKey) { + auto oemcrypto_function = [](size_t transport_key_length) { + size_t wrapped_keybox_length = sizeof(&kTestKeybox) + 50; + vector wrapped_keybox_buffer(wrapped_keybox_length); + vector transport_key_buffer(transport_key_length); + return OEMCrypto_WrapKeyboxOrOEMCert( + reinterpret_cast(&kTestKeybox), sizeof(kTestKeybox), + wrapped_keybox_buffer.data(), &wrapped_keybox_length, + transport_key_buffer.data(), transport_key_buffer.size()); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_F( + OEMCryptoClientTest, + OEMCryptoMemoryWrapKeyboxOrOEMCertForHugeKeyboxLengthStartingFromLength1) { + auto oemcrypto_function = [](size_t keybox_length) { + vector keybox_buffer(keybox_length); + size_t wrapped_keybox_length = keybox_length + 50; + vector wrapped_keybox_buffer(wrapped_keybox_length); + vector transport_key_buffer(20); + return OEMCrypto_WrapKeyboxOrOEMCert( + keybox_buffer.data(), keybox_length, wrapped_keybox_buffer.data(), + &wrapped_keybox_length, transport_key_buffer.data(), + transport_key_buffer.size()); + }; + // Cannot check status as keybox will not be valid for this test. + // We still want to test what happens if buffer lengths is less that keybox + // length. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + /** * 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. @@ -314,6 +406,14 @@ TEST_F(OEMCryptoClientTest, CheckSRMCapabilityV13) { OEMCrypto_LoadSRM(bad_srm.data(), bad_srm.size())); } +TEST_F(OEMCryptoClientTest, OEMCryptoMemoryLoadSrmForLargeSrm) { + auto oemcrypto_function = [](size_t buffer_length) { + vector srm_buffer(buffer_length); + return OEMCrypto_LoadSRM(srm_buffer.data(), srm_buffer.size()); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + TEST_F(OEMCryptoClientTest, CheckMaxNumberOfSessionsAPI10) { size_t sessions_count; ASSERT_EQ(OEMCrypto_SUCCESS, @@ -588,6 +688,132 @@ TEST_F(OEMCryptoClientTest, ClearCopyTestLargeSubsample) { ASSERT_EQ(input_buffer, output_buffer); } +TEST_F(OEMCryptoClientTest, OEMCryptoMemoryCopyBufferForHugeBufferLengths) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + vector input_buffer; + OEMCrypto_DestBufferDesc dest_buffer_descriptor; + dest_buffer_descriptor.type = OEMCrypto_BufferType_Secure; + + auto oemcrypto_function = [&s, &dest_buffer_descriptor, + &input_buffer](size_t buffer_length) { + input_buffer.resize(buffer_length); + int secure_fd; + OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( + s.session_id(), buffer_length, &dest_buffer_descriptor, &secure_fd); + if (sts != OEMCrypto_SUCCESS) { + LOGI("Secure buffers are not supported."); + return sts; + } + + dest_buffer_descriptor.buffer.secure.handle_length = buffer_length; + OEMCryptoResult status = 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); + return status; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_F(OEMCryptoClientTest, + OEMCryptoMemoryCopyBufferDirectForHugeBufferLengths) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + vector input_buffer; + OEMCrypto_DestBufferDesc dest_buffer_descriptor; + dest_buffer_descriptor.type = OEMCrypto_BufferType_Direct; + dest_buffer_descriptor.buffer.direct.is_video = false; + + auto oemcrypto_function = [&s, &dest_buffer_descriptor, + &input_buffer](size_t buffer_length) { + input_buffer.resize(buffer_length); + OEMCryptoResult status = OEMCrypto_CopyBuffer( + s.session_id(), input_buffer.data(), buffer_length, + &dest_buffer_descriptor, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample); + return status; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_F(OEMCryptoClientTest, OEMCryptoMemoryCopyBufferForOutOfRangeOffset) { + 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.handle_length = buffer_length; + auto oemcrypto_function = [&s, &dest_buffer_descriptor, &input_buffer, + &buffer_length](size_t offset) { + dest_buffer_descriptor.buffer.secure.offset = offset; + return OEMCrypto_CopyBuffer( + s.session_id(), input_buffer.data(), buffer_length, + &dest_buffer_descriptor, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); + OEMCrypto_FreeSecureBuffer(s.session_id(), &dest_buffer_descriptor, + secure_fd); +} + +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.handle_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.address = output_buffer.data(); + dest_buffer_descriptor.buffer.clear.address_length = output_buffer.size(); + ASSERT_NO_FATAL_FAILURE(OEMCrypto_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."; @@ -611,7 +837,12 @@ class OEMCryptoKeyboxTest : public OEMCryptoClientTest { } }; -// Test that OEMCrypto_InstallKeyboxOrOEMCert doesn't crash for large keybox. +/******** Dangerous Tests - DO NOT RUN ***********/ +/*The following tests try to test InstallKeybox API with random buffers of +varying length in order to catch any overflow issues. These tests override the +actual keybox on the device. Remove the if and endif statement to run these +tests on a device ONLY IF YOU ARE ABLE TO RECOVER THE KEYBOX on the device.*/ +#if 0 TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryInstallKeyboxForHugeKeyboxBuffer) { auto f = [](size_t keybox_length) { vector keybox(keybox_length); @@ -624,8 +855,18 @@ TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryInstallKeyboxForHugeKeyboxBuffer) { kCheckStatus); } -// This test verifies that load test key box doesn't crash for large -// buffer length. +TEST_F(OEMCryptoKeyboxTest, + OEMCryptoMemoryInstallKeyboxForHugeKeyboxBufferStartingFromLength1) { + auto f = [](size_t keybox_length) { + vector keybox(keybox_length); + return OEMCrypto_InstallKeyboxOrOEMCert(keybox.data(), keybox.size()); + }; + // We are testing for keybox lengths starting from 1 which would return error, + // hence skipping status check. + TestHugeLengthDoesNotCrashAPI(f, !kCheckStatus); +} +#endif + TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryLoadTestKeyBoxForHugeKeyboxBuffer) { auto f = [](size_t keybox_length) { vector keybox(keybox_length); @@ -638,6 +879,17 @@ TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryLoadTestKeyBoxForHugeKeyboxBuffer) { kCheckStatus); } +TEST_F(OEMCryptoKeyboxTest, + OEMCryptoMemoryLoadTestKeyBoxForHugeKeyboxBufferStartingFromLength1) { + auto f = [](size_t keybox_length) { + vector keybox(keybox_length); + return OEMCrypto_LoadTestKeybox(keybox.data(), keybox.size()); + }; + // We are testing for keybox lengths starting from 1 which would return error, + // hence skipping status check. + TestHugeLengthDoesNotCrashAPI(f, !kCheckStatus); +} + // This test is used to print the device ID to stdout. TEST_F(OEMCryptoKeyboxTest, NormalGetDeviceId) { OEMCryptoResult sts; @@ -894,7 +1146,7 @@ TEST_F(OEMCryptoProv30Test, OEMCryptoMemoryGetOEMPublicCertForLargeCertLength) { return OEMCrypto_GetOEMPublicCertificate(public_cert.data(), &public_cert_length); }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); } // @@ -936,8 +1188,101 @@ class OEMCryptoSessionTests : public OEMCryptoClientTest { ASSERT_NE(OEMCrypto_SUCCESS, sts); } } + + void TestPrepareLicenseRequestForHugeBufferLengths( + const std::function f, + bool check_status) { + auto oemcrypto_function = [&](size_t message_length) { + Session s; + s.open(); + InstallTestRSAKey(&s); + s.GenerateNonce(); + LicenseRoundTrip license_messages(&s); + f(message_length, &license_messages); + OEMCryptoResult result = + license_messages.SignAndCreateRequestWithCustomBufferLengths(); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); + } + + OEMCryptoResult LoadLicense(Session& s, LicenseRoundTrip& license_messages) { + InstallTestRSAKey(&s); + s.GenerateNonce(); + license_messages.SignAndVerifyRequest(); + license_messages.CreateDefaultResponse(); + license_messages.EncryptAndSignResponse(); + return license_messages.LoadResponse(); + } + + void TestLoadLicenseForHugeBufferLengths( + const std::function f, bool check_status, + bool update_core_message_substring_values) { + auto oemcrypto_function = [&](size_t message_length) { + Session s; + LicenseRoundTrip license_messages(&s); + s.open(); + InstallTestRSAKey(&s); + s.GenerateNonce(); + bool verify_keys_loaded = true; + license_messages.SignAndVerifyRequest(); + license_messages.CreateDefaultResponse(); + if (update_core_message_substring_values) { + // Make the license message big enough so that updated core message + // substring offset and length values from tests are still able to read + // data from license_message buffer rather than reading some garbage + // data. + license_messages.set_message_size( + sizeof(license_messages.response_data()) + message_length); + } + f(message_length, &license_messages); + if (update_core_message_substring_values) { + // We will be updating offset for these tests, which will cause verify + // keys to fail with an assertion. Hence skipping verification. + verify_keys_loaded = false; + } + license_messages.EncryptAndSignResponse(); + OEMCryptoResult result = + license_messages.LoadResponse(&s, verify_keys_loaded); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); + } + + void TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + const std::function f) { + Session s; + LicenseRoundTrip license_messages(&s); + s.open(); + InstallTestRSAKey(&s); + s.GenerateNonce(); + license_messages.SignAndVerifyRequest(); + license_messages.CreateDefaultResponse(); + size_t message_length = sizeof(license_messages.response_data()); + f(message_length, &license_messages); + license_messages.EncryptAndSignResponse(); + OEMCryptoResult result = license_messages.LoadResponse(); + s.close(); + // Verifying error is not due to signature failure which can be caused due + // to test code. + ASSERT_NE(OEMCrypto_ERROR_SIGNATURE_FAILURE, result); + ASSERT_NE(OEMCrypto_SUCCESS, result); + } }; +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryCreateUsageTableHeaderForHugeHeaderBufferLength) { + auto oemcrypto_function = [](size_t buffer_length) { + size_t header_buffer_length = buffer_length; + vector usage_table_header(header_buffer_length); + return OEMCrypto_CreateUsageTableHeader(usage_table_header.data(), + &header_buffer_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + class OEMCryptoSessionTestKeyboxTest : public OEMCryptoSessionTests {}; TEST_F(OEMCryptoSessionTestKeyboxTest, TestKeyboxIsValid) { @@ -968,6 +1313,88 @@ class OEMCryptoLicenseTestAPI16 : public OEMCryptoSessionTests { LicenseRoundTrip license_messages_; }; +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryPrepareLicenseRequestForHugeRequestMessageLength) { + TestPrepareLicenseRequestForHugeBufferLengths( + [](size_t message_size, LicenseRoundTrip* license_messages) { + license_messages->set_message_size(message_size); + }, + kCheckStatus); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryPrepareLicenseRequestForHugeCoreMessageLength) { + TestPrepareLicenseRequestForHugeBufferLengths( + [](size_t core_message_size, LicenseRoundTrip* license_messages) { + license_messages->set_core_message_size(core_message_size); + }, + kCheckStatus); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryPrepareLicenseRequestForHugeSignatureLength) { + // There is a limit of signature length that gets validated. Hence not + // checking status as we would like to test it for all possible signature + // lengths. + TestPrepareLicenseRequestForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->set_request_signature_size(length); + }, + !kCheckStatus); +} + +// This class is for testing a single license with the default API version +// of 16. Used for buffer overflow tests. +class OEMCryptoMemoryLicenseTest : public OEMCryptoLicenseTestAPI16 { + public: + OEMCryptoMemoryLicenseTest() : entitled_message_(&license_messages_) {} + + void SetUp() override { + OEMCryptoLicenseTestAPI16::SetUp(); + SetUpEntitledMessage(); + entitlement_response_length_ = entitled_message_.entitled_key_data_size(); + } + + void LoadLicense() { + ASSERT_NO_FATAL_FAILURE(session_.GenerateNonce()); + 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 SetUpEntitledMessage() { + license_messages_.set_license_type(OEMCrypto_EntitlementLicense); + LoadLicense(); + entitled_message_.FillKeyArray(); + entitled_message_.EncryptContentKey(); + } + + void TearDown() override { OEMCryptoLicenseTestAPI16::TearDown(); } + + protected: + EntitledMessage entitled_message_; + size_t entitlement_response_length_; + + void TestLoadEntitlementKeysForHugeBufferLengths( + const std::function f, + bool check_status) { + size_t entitled_key_data_size = entitled_message_.entitled_key_data_size(); + vector message(entitled_key_data_size); + memcpy(message.data(), entitled_message_.entitled_key_data(), + entitled_key_data_size); + auto oemcrypto_function = [&](size_t length) { + // Make entitled message big enough so that updated substring offset and + // length fields by core message substring tests can still be able to read + // valid data from entitled message buffer rather than some garbage data. + message.resize(entitled_key_data_size + length); + f(length, &entitled_message_); + return entitled_message_.LoadKeys(message); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); + } +}; + // This class is used to test a license that is from a server either that is // current or one version old. class OEMCryptoLicenseTest : public OEMCryptoLicenseTestAPI16, @@ -980,6 +1407,108 @@ class OEMCryptoLicenseTest : public OEMCryptoLicenseTestAPI16, license_messages_.set_api_version(license_api_version_); OEMCryptoLicenseTestAPI16::SetUp(); } + + void LoadLicense() { + session_.GenerateNonce(); + license_messages_.SignAndVerifyRequest(); + license_messages_.CreateDefaultResponse(); + license_messages_.EncryptAndSignResponse(); + license_messages_.LoadResponse(); + } + + void TestDecryptCENCForHugeBufferLengths( + const std::function f, + bool check_status) { + LoadLicense(); + auto oemcrypto_function = [&](size_t message_length) { + 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 in_buffer(input_buffer_size + message_length); + vector 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( + sample_description.subsamples); + // Actual tests modifies either of these fields to match clear + encrypted + // = in_buffer.size(). + sub_samples[0].num_bytes_clear = 0; + sub_samples[0].num_bytes_encrypted = input_buffer_size; + + // Create the pattern description (always 0,0 for CTR) + OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + int secure_fd = 0; + f(message_length, &sample_description); + if (sample_description.buffers.output_descriptor.type == + OEMCrypto_BufferType_Secure) { + OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( + session_.session_id(), in_buffer.size(), + &sample_description.buffers.output_descriptor, &secure_fd); + if (sts != OEMCrypto_SUCCESS) { + LOGI("Secure buffers are not supported."); + return sts; + } + } + // Try to decrypt the data + OEMCryptoResult result = OEMCrypto_DecryptCENC( + session_.session_id(), &sample_description, 1, &pattern); + if (sample_description.buffers.output_descriptor.type == + OEMCrypto_BufferType_Secure) { + OEMCrypto_FreeSecureBuffer( + session_.session_id(), + &sample_description.buffers.output_descriptor, secure_fd); + } + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); + } + + void TestDecryptCENCForOutOfRangeOffsetsAndLengths( + const std::function f, + bool update_secure_buffer) { + LoadLicense(); + OEMCrypto_SelectKey( + session_.session_id(), session_.license().keys[0].key_id, + session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CTR); + + vector in_buffer(256); + vector out_buffer(in_buffer.size()); + + OEMCrypto_SampleDescription sample_description; + OEMCrypto_SubSampleDescription subsample_description; + GenerateSimpleSampleDescription(in_buffer, out_buffer, &sample_description, + &subsample_description); + + // Create the pattern description (always 0,0 for CTR) + OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + int secure_fd = 0; + if (update_secure_buffer) { + OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( + session_.session_id(), in_buffer.size(), + &sample_description.buffers.output_descriptor, &secure_fd); + if (sts != OEMCrypto_SUCCESS) { + LOGI("Secure buffers are not supported."); + return; + } + } + f(&sample_description); + // Try to decrypt the data + OEMCryptoResult result = OEMCrypto_DecryptCENC( + session_.session_id(), &sample_description, 1, &pattern); + if (update_secure_buffer) { + OEMCrypto_FreeSecureBuffer(session_.session_id(), + &sample_description.buffers.output_descriptor, + secure_fd); + } + ASSERT_NE(OEMCrypto_SUCCESS, result); + } }; // This class is used to test a license that is only for v15 license. @@ -1160,6 +1689,238 @@ TEST_P(OEMCryptoLicenseTest, LoadEntitlementKeysWrongEntitlementKeysAPI14) { entitled_message_1.LoadKeys(OEMCrypto_KEY_NOT_ENTITLED)); } +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryPrepareRenewalRequestForHugeBufferLength) { + RenewalRoundTrip renewal_messages(&license_messages_); + auto oemcrypto_function = [&renewal_messages](size_t buffer_length) { + renewal_messages.set_message_size(buffer_length); + return renewal_messages.SignAndCreateRequestWithCustomBufferLengths(); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryPrepareRenewalRequestForHugeSignatureLength) { + RenewalRoundTrip renewal_messages(&license_messages_); + auto oemcrypto_function = [&renewal_messages](size_t buffer_length) { + renewal_messages.set_request_signature_size(buffer_length); + return renewal_messages.SignAndCreateRequestWithCustomBufferLengths(); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryPrepareRenewalRequestForHugeCoreMessageLength) { + RenewalRoundTrip renewal_messages(&license_messages_); + auto oemcrypto_function = [&renewal_messages](size_t buffer_length) { + renewal_messages.set_core_message_size(buffer_length); + return renewal_messages.SignAndCreateRequestWithCustomBufferLengths(); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyIdLength) { + TestLoadEntitlementKeysForHugeBufferLengths( + [](size_t key_id_length, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].content_key_id.length = + key_id_length; + }, + !kCheckStatus); +} + +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyIdOffset) { + TestLoadEntitlementKeysForHugeBufferLengths( + [](size_t key_id_offset, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].content_key_id.offset = + key_id_offset; + }, + !kCheckStatus); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyIdLength) { + auto& content_key_id = + entitled_message_.entitled_key_array()[0].content_key_id; + content_key_id.length = + entitlement_response_length_ - content_key_id.offset + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyIdOffset) { + auto& content_key_id = + entitled_message_.entitled_key_array()[0].content_key_id; + content_key_id.offset = + entitlement_response_length_ - content_key_id.length + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringEntitlementKeyIdLength) { + TestLoadEntitlementKeysForHugeBufferLengths( + [](size_t key_id_length, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].entitlement_key_id.length = + key_id_length; + }, + !kCheckStatus); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringEntitlementKeyIdOffset) { + TestLoadEntitlementKeysForHugeBufferLengths( + [](size_t key_id_offset, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].entitlement_key_id.offset = + key_id_offset; + }, + !kCheckStatus); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringEntitlementKeyIdLength) { + auto& entitlement_key_id = + entitled_message_.entitled_key_array()[0].entitlement_key_id; + entitlement_key_id.length = + entitlement_response_length_ - entitlement_key_id.offset + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringEntitlementKeyIdOffset) { + auto& entitlement_key_id = + entitled_message_.entitled_key_array()[0].entitlement_key_id; + entitlement_key_id.offset = + entitlement_response_length_ - entitlement_key_id.length + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyDataIvLength) { + TestLoadEntitlementKeysForHugeBufferLengths( + [](size_t content_key_data_iv_length, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].content_key_data_iv.length = + content_key_data_iv_length; + }, + !kCheckStatus); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyDataIvOffset) { + TestLoadEntitlementKeysForHugeBufferLengths( + [](size_t content_key_data_iv_offset, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].content_key_data_iv.offset = + content_key_data_iv_offset; + }, + !kCheckStatus); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyDataIvLength) { + auto& content_key_data_iv = + entitled_message_.entitled_key_array()[0].content_key_data_iv; + content_key_data_iv.length = + entitlement_response_length_ - content_key_data_iv.offset + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyDataIvOffset) { + auto& content_key_data_iv = + entitled_message_.entitled_key_array()[0].content_key_data_iv; + content_key_data_iv.offset = + entitlement_response_length_ - content_key_data_iv.length + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyDataLength) { + TestLoadEntitlementKeysForHugeBufferLengths( + [](size_t content_key_data_length, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].content_key_data.length = + content_key_data_length; + }, + !kCheckStatus); +} + +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyDataOffset) { + TestLoadEntitlementKeysForHugeBufferLengths( + [](size_t content_key_data_offset, EntitledMessage* entitled_message) { + entitled_message->entitled_key_array()[0].content_key_data.offset = + content_key_data_offset; + }, + !kCheckStatus); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyDataLength) { + auto& content_key_data = + entitled_message_.entitled_key_array()[0].content_key_data; + content_key_data.length = + entitlement_response_length_ - content_key_data.offset + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +TEST_F( + OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyDataOffset) { + auto& content_key_data = + entitled_message_.entitled_key_array()[0].content_key_data; + content_key_data.offset = + entitlement_response_length_ - content_key_data.length + 1; + ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); +} + +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForHugeEntitlementKeyIdLength) { + TestLoadEntitlementKeysForHugeBufferLengths( + [](size_t key_id_length, EntitledMessage* entitled_message) { + entitled_message->entitled_key_data()->entitlement_key_id_length = + key_id_length; + }, + !kCheckStatus); +} + +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForHugeContentKeyIdLength) { + TestLoadEntitlementKeysForHugeBufferLengths( + [](size_t key_id_length, EntitledMessage* entitled_message) { + entitled_message->entitled_key_data()->content_key_id_length = + key_id_length; + }, + !kCheckStatus); +} + +// This verifies that entitled content keys API does not crash for unreasonable +// input message buffer lengths. +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitlementKeysForHugeBufferLength) { + auto oemcrypto_function = [&](size_t buffer_length) { + size_t entitled_key_data_length = + entitled_message_.entitled_key_data_size(); + vector message(entitled_key_data_length); + memcpy(message.data(), entitled_message_.entitled_key_data(), + entitled_key_data_length); + message.resize(buffer_length); + return entitled_message_.LoadKeys(message); + }; + // We are not constructing a valid message for load entitled content keys. + // Hence skipping status check. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + // This tests load license with an 8k license response. TEST_P(OEMCryptoLicenseTest, LoadKeyLargeBuffer) { ASSERT_NO_FATAL_FAILURE(session_.GenerateNonce()); @@ -1579,6 +2340,90 @@ TEST_P(OEMCryptoLicenseTest, LoadKeyNoKeyWithNonce) { ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); } +// Following two tests will test huge values for num bytes clear, num bytes +// encrypted, input data length and clear address, clear address_length. +TEST_P(OEMCryptoLicenseTest, + OEMCryptoMemoryDecryptCENCForHugeNumBytesClearAndBuffers) { + TestDecryptCENCForHugeBufferLengths( + [](size_t message_size, OEMCrypto_SampleDescription* sample_description) { + OEMCrypto_SubSampleDescription* sub_samples = + const_cast( + sample_description->subsamples); + sub_samples[0].num_bytes_clear = + sub_samples[0].num_bytes_clear + message_size; + }, + !kCheckStatus); +} + +TEST_P(OEMCryptoLicenseTest, + OEMCryptoMemoryDecryptCENCForHugeNumBytesEncryptedAndBuffers) { + TestDecryptCENCForHugeBufferLengths( + [](size_t message_size, OEMCrypto_SampleDescription* sample_description) { + OEMCrypto_SubSampleDescription* sub_samples = + const_cast( + sample_description->subsamples); + sub_samples[0].num_bytes_encrypted = + sub_samples[0].num_bytes_encrypted + message_size; + }, + !kCheckStatus); +} + +TEST_P(OEMCryptoLicenseTest, + OEMCryptoMemoryDecryptCENCForHugeSecureHandleLength) { + TestDecryptCENCForHugeBufferLengths( + [](size_t message_size, OEMCrypto_SampleDescription* sample_description) { + OEMCrypto_SubSampleDescription* sub_samples = + const_cast( + sample_description->subsamples); + // TestDecryptCENCForHugeBufferLengths alloctes huge secure handle + // buffer. + sample_description->buffers.output_descriptor.type = + OEMCrypto_BufferType_Secure; + sub_samples[0].num_bytes_clear = + sub_samples[0].num_bytes_clear + message_size; + }, + !kCheckStatus); +} + +TEST_P(OEMCryptoLicenseTest, + OEMCryptoMemoryDecryptCENCForOutOfRangeNumBytesClear) { + TestDecryptCENCForOutOfRangeOffsetsAndLengths( + [](OEMCrypto_SampleDescription* sample_description) { + OEMCrypto_SubSampleDescription* sub_samples = + const_cast( + sample_description->subsamples); + sub_samples[0].num_bytes_clear = sub_samples[0].num_bytes_clear + 1; + }, + !kDecryptCENCSecureBuffer); +} + +TEST_P(OEMCryptoLicenseTest, + OEMCryptoMemoryDecryptCENCForOutOfRangeNumBytesEncrypted) { + TestDecryptCENCForOutOfRangeOffsetsAndLengths( + [](OEMCrypto_SampleDescription* sample_description) { + OEMCrypto_SubSampleDescription* sub_samples = + const_cast( + sample_description->subsamples); + sub_samples[0].num_bytes_encrypted = + sub_samples[0].num_bytes_encrypted + 1; + }, + !kDecryptCENCSecureBuffer); +} + +TEST_P(OEMCryptoLicenseTest, + OEMCryptoMemoryDecryptCENCForOutOfRangeSecureBufferOffset) { + TestDecryptCENCForOutOfRangeOffsetsAndLengths( + [](OEMCrypto_SampleDescription* sample_description) { + sample_description->buffers.output_descriptor.type = + OEMCrypto_BufferType_Secure; + sample_description->buffers.output_descriptor.buffer.secure.offset = + sample_description->buffers.output_descriptor.buffer.secure + .handle_length + + 1; + }, + kDecryptCENCSecureBuffer); +} + // SelectKey should fail if we attempt to select a key that has not been loaded. // Also, the error should be NO_CONTENT_KEY. // This test should pass for v15 devices, except that the exact error code was @@ -1713,6 +2558,43 @@ TEST_P(OEMCryptoLicenseTest, RejectCbcsWithBlockOffset) { EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts); } +TEST_P(OEMCryptoLicenseTest, RejectOversizedBlockOffset) { + ASSERT_NO_FATAL_FAILURE(session_.GenerateNonce()); + 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()); + + OEMCryptoResult sts; + sts = OEMCrypto_SelectKey( + session_.session_id(), session_.license().keys[0].key_id, + session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CTR); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + + vector in_buffer(256); + vector out_buffer(in_buffer.size()); + OEMCrypto_SampleDescription sample_description; + OEMCrypto_SubSampleDescription subsample_description; + + ASSERT_NO_FATAL_FAILURE(GenerateSimpleSampleDescription( + in_buffer, out_buffer, &sample_description, &subsample_description)); + subsample_description.block_offset = 0xFF; // Anything 16+ + + // Create a zero pattern to indicate this is 'cenc'. + OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + + // Try to decrypt the data + sts = OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, 1, + &pattern); + EXPECT_NE(OEMCrypto_SUCCESS, sts); + + // Try again with the minimum invalid value + subsample_description.block_offset = 16; + sts = OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, 1, + &pattern); + EXPECT_NE(OEMCrypto_SUCCESS, sts); +} + // After loading keys, we should be able to query the key control block. If we // attempt to query a key that has not been loaded, the error should be // NO_CONTENT_KEY. @@ -1742,19 +2624,488 @@ TEST_P(OEMCryptoLicenseTest, QueryKeyControl) { strlen(key_id), reinterpret_cast(&block), &size)); } -// Test OEMCrypto_QueryKeyControl doesn't crash for huge key_id_length. -TEST_F(OEMCryptoLicenseTestAPI16, - OEMCryptoMemoryQueryKeyControlForHugeKeyIdLength) { - ASSERT_NO_FATAL_FAILURE(session_.GenerateNonce()); - 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()); +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeSignatureLength) { + auto oemcrypto_function = [&](size_t signature_size) { + Session s; + LicenseRoundTrip license_messages(&s); + s.open(); + InstallTestRSAKey(&s); + s.GenerateNonce(); + license_messages.SignAndVerifyRequest(); + license_messages.CreateDefaultResponse(); + license_messages.EncryptAndSignResponse(); + vector signature(signature_size); + OEMCryptoResult result = OEMCrypto_LoadLicense( + s.session_id(), license_messages.encrypted_response_buffer().data(), + license_messages.encrypted_response_buffer().size(), + license_messages.serialized_core_message().size(), signature.data(), + signature_size); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} - OEMCrypto_SESSION session_id = session_.session_id(); +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyIdLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_id.length = length; + license_messages->response_data().keys[0].key_id_length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyIdOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_id.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyIdLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_id = license_messages->core_response().key_array[0].key_id; + key_id.length = response_message_length - key_id.offset + 1; + }); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyIdOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_id = license_messages->core_response().key_array[0].key_id; + key_id.offset = response_message_length - key_id.length + 1; + }); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataIvLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_data_iv.length = + length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataIvOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_data_iv.offset = + offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataIvLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_data_iv = + license_messages->core_response().key_array[0].key_data_iv; + key_data_iv.length = response_message_length - key_data_iv.offset + 1; + }); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataIvOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_data_iv = + license_messages->core_response().key_array[0].key_data_iv; + key_data_iv.offset = response_message_length - key_data_iv.length + 1; + }); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_data.length = length; + license_messages->response_data().keys[0].key_data_length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_data.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_data = + license_messages->core_response().key_array[0].key_data; + key_data.length = response_message_length - key_data.offset + 1; + }); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_data = + license_messages->core_response().key_array[0].key_data; + key_data.offset = response_message_length - key_data.length + 1; + }); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlIvLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_control_iv.length = + length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlIvOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_control_iv.offset = + offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlIvLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_control_iv = + license_messages->core_response().key_array[0].key_control_iv; + key_control_iv.length = + response_message_length - key_control_iv.offset + 1; + }); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlIvOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_control_iv = + license_messages->core_response().key_array[0].key_control_iv; + key_control_iv.offset = + response_message_length - key_control_iv.length + 1; + }); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_control.length = + length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().key_array[0].key_control.offset = + offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_control = + license_messages->core_response().key_array[0].key_control; + key_control.length = response_message_length - key_control.offset + 1; + }); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& key_control = + license_messages->core_response().key_array[0].key_control; + key_control.offset = response_message_length - key_control.length + 1; + }); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyIvLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().enc_mac_keys_iv.length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyIvOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().enc_mac_keys_iv.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyIvLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& enc_mac_keys_iv = + license_messages->core_response().enc_mac_keys_iv; + enc_mac_keys_iv.length = + response_message_length - enc_mac_keys_iv.offset + 1; + }); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyIvOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& enc_mac_keys_iv = + license_messages->core_response().enc_mac_keys_iv; + enc_mac_keys_iv.offset = + response_message_length - enc_mac_keys_iv.length + 1; + }); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().enc_mac_keys.length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().enc_mac_keys.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& enc_mac_keys = license_messages->core_response().enc_mac_keys; + enc_mac_keys.length = response_message_length - enc_mac_keys.offset + 1; + }); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& enc_mac_keys = license_messages->core_response().enc_mac_keys; + enc_mac_keys.offset = response_message_length - enc_mac_keys.length + 1; + }); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringPstLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().pst.length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringPstOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().pst.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringPstLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& pst = license_messages->core_response().pst; + pst.length = response_message_length - pst.offset + 1; + }); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringPstOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& pst = license_messages->core_response().pst; + pst.offset = response_message_length - pst.length + 1; + }); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringSrmRestrictionDataLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t length, LicenseRoundTrip* license_messages) { + license_messages->core_response().srm_restriction_data.length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringSrmRestrictionDataOffset) { + TestLoadLicenseForHugeBufferLengths( + [](size_t offset, LicenseRoundTrip* license_messages) { + license_messages->core_response().srm_restriction_data.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringSrmRestrictionDataLength) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& srm_restriction_data = + license_messages->core_response().srm_restriction_data; + srm_restriction_data.length = + response_message_length - srm_restriction_data.offset + 1; + }); +} + +TEST_F( + OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringSrmRestrictionDataOffset) { + TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + [](size_t response_message_length, LicenseRoundTrip* license_messages) { + auto& srm_restriction_data = + license_messages->core_response().srm_restriction_data; + srm_restriction_data.offset = + response_message_length - srm_restriction_data.length + 1; + }); +} + +TEST_F(OEMCryptoSessionTests, OEMCryptoMemoryLoadLicenseForHugeResponseLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t message_size, LicenseRoundTrip* license_messages) { + license_messages->set_message_size(message_size); + }, + !kCheckStatus, !kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadLicenseForHugeCoreMessageLength) { + TestLoadLicenseForHugeBufferLengths( + [](size_t message_size, LicenseRoundTrip* license_messages) { + license_messages->set_core_message_size(message_size); + }, + !kCheckStatus, !kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoSessionTests, OEMCryptoMemoryLoadRenewalForHugeResponseLength) { + auto oemcrypto_function = [&](size_t message_size) { + Session s; + LicenseRoundTrip license_messages(&s); + s.open(); + LoadLicense(s, license_messages); + + RenewalRoundTrip renewal_messages(&license_messages); + renewal_messages.SignAndVerifyRequest(); + renewal_messages.CreateDefaultResponse(); + renewal_messages.set_message_size(message_size); + renewal_messages.EncryptAndSignResponse(); + OEMCryptoResult result = renewal_messages.LoadResponse(); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadRenewalForHugeSignatureLength) { + auto oemcrypto_function = [&](size_t signature_size) { + Session s; + LicenseRoundTrip license_messages(&s); + s.open(); + LoadLicense(s, license_messages); + + RenewalRoundTrip renewal_messages(&license_messages); + renewal_messages.SignAndVerifyRequest(); + renewal_messages.CreateDefaultResponse(); + renewal_messages.EncryptAndSignResponse(); + vector signature(signature_size); + OEMCryptoResult result = OEMCrypto_LoadRenewal( + s.session_id(), renewal_messages.encrypted_response_buffer().data(), + renewal_messages.encrypted_response_buffer().size(), + renewal_messages.serialized_core_message().size(), signature.data(), + signature_size); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryLoadRenewalForHugeCoreMessageLength) { + auto oemcrypto_function = [&](size_t core_message_size) { + Session s; + LicenseRoundTrip license_messages(&s); + s.open(); + LoadLicense(s, license_messages); + + RenewalRoundTrip renewal_messages(&license_messages); + renewal_messages.SignAndVerifyRequest(); + renewal_messages.CreateDefaultResponse(); + renewal_messages.set_core_message_size(core_message_size); + renewal_messages.EncryptAndSignResponse(); + OEMCryptoResult result = renewal_messages.LoadResponse(); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +// Test OEMCrypto_QueryKeyControl doesn't crash for huge key_id_length. +TEST_F(OEMCryptoSessionTests, + OEMCryptoMemoryQueryKeyControlForHugeKeyIdLength) { + Session session; + LicenseRoundTrip license_messages(&session); + session.open(); + LoadLicense(session, license_messages); + OEMCrypto_SESSION session_id = session.session_id(); vector valid_key_id( - license_messages_.response_data().keys[0].key_id, - license_messages_.response_data().keys[0].key_id + kTestKeyIdMaxLength); + license_messages.response_data().keys[0].key_id, + license_messages.response_data().keys[0].key_id + kTestKeyIdMaxLength); auto oemcrypto_function = [&session_id, &valid_key_id](size_t additional_key_id_length) { vector key_id(valid_key_id); @@ -1771,18 +3122,15 @@ TEST_F(OEMCryptoLicenseTestAPI16, // Test OEMCrypto_QueryKeyControl doesn't crash for huge key_control_block // length. -TEST_F(OEMCryptoLicenseTestAPI16, +TEST_F(OEMCryptoSessionTests, OEMCryptoMemoryQueryKeyControlForHugeKeyControlBlockLength) { - ASSERT_NO_FATAL_FAILURE(session_.GenerateNonce()); - 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()); - - OEMCrypto_SESSION session_id = session_.session_id(); - uint8_t* key_id = license_messages_.response_data().keys[0].key_id; - size_t key_id_length = - license_messages_.response_data().keys[0].key_id_length; + Session session; + LicenseRoundTrip license_messages(&session); + session.open(); + LoadLicense(session, license_messages); + OEMCrypto_SESSION session_id = session.session_id(); + uint8_t* key_id = license_messages.response_data().keys[0].key_id; + size_t key_id_length = license_messages.response_data().keys[0].key_id_length; auto oemcrypto_function = [&session_id, &key_id, &key_id_length](size_t buffer_length) { size_t key_control_block_length = buffer_length; @@ -2184,7 +3532,7 @@ TEST_P(OEMCryptoLicenseTest, HashForbiddenAPI15) { // This test verifies that OEMCrypto_SetDecryptHash doesn't crash for a very // large hash buffer. -TEST_F(OEMCryptoLicenseTestAPI16, +TEST_F(OEMCryptoMemoryLicenseTest, OEMCryptoMemoryDecryptHashForLargeHashBuffer) { uint32_t session_id = session_.session_id(); auto f = [session_id](size_t hash_length) { @@ -2193,13 +3541,12 @@ TEST_F(OEMCryptoLicenseTestAPI16, return OEMCrypto_SetDecryptHash(session_id, frame_number, hash_buffer.data(), hash_buffer.size()); }; - TestHugeLengthDoesNotCrashAPI(f, sizeof(uint32_t), kHugeInputBufferLength, - kCheckStatus); + TestHugeLengthDoesNotCrashAPI(f, kCheckStatus); } // This test verifies OEMCrypto_SetDecryptHash for out of range frame number. TEST_P(OEMCryptoLicenseTest, DecryptHashForOutOfRangeFrameNumber) { - uint32_t frame_number = 40; + uint32_t frame_number = kHugeRandomNumber; uint32_t hash = 42; ASSERT_NO_FATAL_FAILURE(OEMCrypto_SetDecryptHash( session_.session_id(), frame_number, @@ -2910,11 +4257,78 @@ INSTANTIATE_TEST_CASE_P(TestAll, OEMCryptoLicenseTest, // // Certificate Root of Trust Tests // -class OEMCryptoLoadsCertificate : public OEMCryptoSessionTestKeyboxTest {}; +class OEMCryptoLoadsCertificate : public OEMCryptoSessionTestKeyboxTest { + protected: + void TestPrepareProvisioningRequestForHugeBufferLengths( + const std::function f, + bool check_status) { + auto oemcrypto_function = [&](size_t message_length) { + Session s; + s.open(); + s.GenerateNonce(); + if (global_features.provisioning_method == OEMCrypto_OEMCertificate) { + s.LoadOEMCert(true); + } else { + s.GenerateDerivedKeysFromKeybox(keybox_); + } + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + f(message_length, &provisioning_messages); + return provisioning_messages + .SignAndCreateRequestWithCustomBufferLengths(); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); + } + + void TestLoadProvisioningForHugeBufferLengths( + const std::function f, + bool check_status, bool update_core_message_substring_values) { + auto oemcrypto_function = [&](size_t message_length) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + provisioning_messages.SignAndVerifyRequest(); + provisioning_messages.CreateDefaultResponse(); + if (update_core_message_substring_values) { + // Make provisioning message big enough so that updated core message + // substring offset and length values from tests are still able to read + // valid data from provisioning_message buffer rather than some garbage + // data. + provisioning_messages.set_message_size( + sizeof(provisioning_messages.response_data()) + message_length); + } + f(message_length, &provisioning_messages); + provisioning_messages + .EncryptAndSignResponseWithoutUpdatingEncPrivateKeyLength(); + OEMCryptoResult result = provisioning_messages.LoadResponse(); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); + } + + void TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( + const std::function f) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + provisioning_messages.SignAndVerifyRequest(); + provisioning_messages.CreateDefaultResponse(); + size_t message_length = sizeof(provisioning_messages.response_data()); + f(message_length, &provisioning_messages); + provisioning_messages + .EncryptAndSignResponseWithoutUpdatingEncPrivateKeyLength(); + OEMCryptoResult result = provisioning_messages.LoadResponse(); + s.close(); + // Verifying error is not due to signature failure which can be caused due + // to test code. + ASSERT_NE(OEMCrypto_ERROR_SIGNATURE_FAILURE, result); + ASSERT_NE(OEMCrypto_SUCCESS, result); + } +}; // This test verifies that we can create a wrapped RSA key, and then reload it. TEST_F(OEMCryptoLoadsCertificate, LoadRSASessionKey) { - CreateWrappedRSAKey(); + ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(s.InstallRSASessionTestKey(wrapped_rsa_key_)); @@ -3130,10 +4544,221 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionLargeBuffer) { provisioning_messages.encoded_rsa_key())); } +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeResponseLength) { + TestLoadProvisioningForHugeBufferLengths( + [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->set_message_size(message_size); + }, + !kCheckStatus, !kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageLength) { + TestLoadProvisioningForHugeBufferLengths( + [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->set_core_message_size(message_size); + }, + !kCheckStatus, !kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyLength) { + TestLoadProvisioningForHugeBufferLengths( + [](size_t length, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().enc_private_key.length = length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyOffset) { + TestLoadProvisioningForHugeBufferLengths( + [](size_t offset, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().enc_private_key.offset = offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyLength) { + TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( + [](size_t response_message_length, + ProvisioningRoundTrip* provisioning_messages) { + auto& enc_private_key = + provisioning_messages->core_response().enc_private_key; + enc_private_key.length = + response_message_length - enc_private_key.offset + 1; + }); +} + +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyOffset) { + TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( + [](size_t response_message_length, + ProvisioningRoundTrip* provisioning_messages) { + auto& enc_private_key = + provisioning_messages->core_response().enc_private_key; + enc_private_key.offset = + response_message_length - enc_private_key.length + 1; + }); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyIvLength) { + TestLoadProvisioningForHugeBufferLengths( + [](size_t length, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().enc_private_key_iv.length = + length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncPrivateKeyIvOffset) { + TestLoadProvisioningForHugeBufferLengths( + [](size_t offset, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().enc_private_key_iv.offset = + offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyIvLength) { + TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( + [](size_t response_message_length, + ProvisioningRoundTrip* provisioning_messages) { + auto& enc_private_key_iv = + provisioning_messages->core_response().enc_private_key_iv; + enc_private_key_iv.length = + response_message_length - enc_private_key_iv.offset + 1; + }); +} + +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncPrivateKeyIvOffset) { + TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( + [](size_t response_message_length, + ProvisioningRoundTrip* provisioning_messages) { + auto& enc_private_key_iv = + provisioning_messages->core_response().enc_private_key_iv; + enc_private_key_iv.offset = + response_message_length - enc_private_key_iv.length + 1; + }); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncMessageKeyLength) { + TestLoadProvisioningForHugeBufferLengths( + [](size_t length, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().encrypted_message_key.length = + length; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeCoreMessageEncMessageKeyOffset) { + TestLoadProvisioningForHugeBufferLengths( + [](size_t offset, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->core_response().encrypted_message_key.offset = + offset; + }, + !kCheckStatus, kUpdateCoreMessageSubstringValues); +} + +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncMessageKeyLength) { + TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( + [](size_t response_message_length, + ProvisioningRoundTrip* provisioning_messages) { + auto& encrypted_message_key = + provisioning_messages->core_response().encrypted_message_key; + encrypted_message_key.length = + response_message_length - encrypted_message_key.offset + 1; + }); +} + +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForOutOfRangeCoreMessageEncMessageKeyOffset) { + TestLoadProvisioningForOutOfRangeSubstringOffsetAndLengths( + [](size_t response_message_length, + ProvisioningRoundTrip* provisioning_messages) { + auto& encrypted_message_key = + provisioning_messages->core_response().encrypted_message_key; + encrypted_message_key.offset = + response_message_length - encrypted_message_key.length + 1; + }); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeSignatureLength) { + auto oemcrypto_function = [&](size_t signature_size) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + provisioning_messages.SignAndVerifyRequest(); + provisioning_messages.CreateDefaultResponse(); + provisioning_messages.EncryptAndSignResponse(); + vector signature(signature_size); + size_t wrapped_private_key_length = 0; + // Find wrapped_private_key_length. + OEMCrypto_LoadProvisioning( + s.session_id(), + provisioning_messages.encrypted_response_buffer().data(), + provisioning_messages.encrypted_response_buffer().size(), + provisioning_messages.serialized_core_message().size(), + signature.data(), signature_size, nullptr, &wrapped_private_key_length); + std::vector wrapped_rsa_key(wrapped_private_key_length); + OEMCryptoResult result = OEMCrypto_LoadProvisioning( + s.session_id(), + provisioning_messages.encrypted_response_buffer().data(), + provisioning_messages.encrypted_response_buffer().size(), + provisioning_messages.serialized_core_message().size(), + signature.data(), signature_size, wrapped_rsa_key.data(), + &wrapped_private_key_length); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadProvisioningForHugeWrappedRsaKeyLength) { + auto oemcrypto_function = [&](size_t buffer_length) { + Session s; + ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_); + provisioning_messages.PrepareSession(keybox_); + provisioning_messages.SignAndVerifyRequest(); + provisioning_messages.CreateDefaultResponse(); + provisioning_messages.EncryptAndSignResponse(); + size_t wrapped_private_key_length = buffer_length; + vector wrapped_private_key(wrapped_private_key_length); + OEMCryptoResult result = OEMCrypto_LoadProvisioning( + s.session_id(), + provisioning_messages.encrypted_response_buffer().data(), + provisioning_messages.encrypted_response_buffer().size(), + provisioning_messages.serialized_core_message().size(), + provisioning_messages.response_signature().data(), + provisioning_messages.response_signature().size(), + wrapped_private_key.data(), &wrapped_private_key_length); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + // Test that a wrapped RSA key can be loaded. TEST_F(OEMCryptoLoadsCertificate, LoadWrappedRSAKey) { OEMCryptoResult sts; - CreateWrappedRSAKey(); + ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); sts = OEMCrypto_LoadDRMPrivateKey(s.session_id(), OEMCrypto_RSA_Private_Key, @@ -3142,12 +4767,54 @@ TEST_F(OEMCryptoLoadsCertificate, LoadWrappedRSAKey) { ASSERT_EQ(OEMCrypto_SUCCESS, sts); } +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadDrmPrivateKeyForHugeWrappedRsaKeyLength) { + ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); + auto oemcrypto_function = [&](size_t wrapped_rsa_key_length) { + Session s; + s.open(); + vector wrapped_rsa_key_buffer(wrapped_rsa_key_length); + memcpy(wrapped_rsa_key_buffer.data(), wrapped_rsa_key_.data(), + wrapped_rsa_key_.size()); + OEMCryptoResult result = OEMCrypto_LoadDRMPrivateKey( + s.session_id(), OEMCrypto_RSA_Private_Key, + wrapped_rsa_key_buffer.data(), wrapped_rsa_key_buffer.size()); + s.close(); + return result; + }; + // It is hard to generate varying length valid wrapped rsa key with valid + // signature. Hence we just call function with random data and do not check + // status to test API with varying length wrapped rsa key. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, wrapped_rsa_key_.size(), + kHugeInputBufferLength, !kCheckStatus); +} + +TEST_F( + OEMCryptoLoadsCertificate, + OEMCryptoMemoryLoadDrmPrivateKeyForHugeWrappedRsaKeyLengthStartingFromLength1) { + ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); + auto oemcrypto_function = [&](size_t wrapped_rsa_key_length) { + Session s; + s.open(); + vector wrapped_rsa_key_buffer(wrapped_rsa_key_length); + OEMCryptoResult result = OEMCrypto_LoadDRMPrivateKey( + s.session_id(), OEMCrypto_RSA_Private_Key, + wrapped_rsa_key_buffer.data(), wrapped_rsa_key_buffer.size()); + s.close(); + return result; + }; + // It is hard to generate varying length valid wrapped rsa key with valid + // signature. Hence we just call function with random data and do not check + // status to test API with varying length wrapped rsa key. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + // Test a 3072 bit RSA key certificate. TEST_F(OEMCryptoLoadsCertificate, TestLargeRSAKey3072) { encoded_rsa_key_.assign(kTestRSAPKCS8PrivateKeyInfo3_3072, kTestRSAPKCS8PrivateKeyInfo3_3072 + sizeof(kTestRSAPKCS8PrivateKeyInfo3_3072)); - CreateWrappedRSAKey(); + ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE( @@ -3169,7 +4836,7 @@ TEST_F(OEMCryptoLoadsCertificate, TestCarmichaelRSAKey) { encoded_rsa_key_.assign( kTestKeyRSACarmichael_2048, kTestKeyRSACarmichael_2048 + sizeof(kTestKeyRSACarmichael_2048)); - CreateWrappedRSAKey(); + ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE( @@ -3187,7 +4854,7 @@ TEST_F(OEMCryptoLoadsCertificate, TestCarmichaelRSAKey) { // This tests that two sessions can use different RSA keys simultaneously. TEST_F(OEMCryptoLoadsCertificate, TestMultipleRSAKeys) { - CreateWrappedRSAKey(); + ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); Session s1; // Session s1 loads the default rsa key, but doesn't use it // until after s2 uses its key. ASSERT_NO_FATAL_FAILURE(s1.open()); @@ -3202,7 +4869,7 @@ TEST_F(OEMCryptoLoadsCertificate, TestMultipleRSAKeys) { encoded_rsa_key_.assign(kTestRSAPKCS8PrivateKeyInfo4_2048, kTestRSAPKCS8PrivateKeyInfo4_2048 + sizeof(kTestRSAPKCS8PrivateKeyInfo4_2048)); - CreateWrappedRSAKey(); + ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); ASSERT_NO_FATAL_FAILURE(s2.open()); ASSERT_NO_FATAL_FAILURE( s2.PreparePublicKey(encoded_rsa_key_.data(), encoded_rsa_key_.size())); @@ -3233,6 +4900,33 @@ TEST_F(OEMCryptoLoadsCertificate, SupportsCertificatesAPI13) { << "Supported certificates is only " << OEMCrypto_SupportedCertificates(); } +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryPrepareProvisioningRequestForHugeRequestMessageLength) { + TestPrepareProvisioningRequestForHugeBufferLengths( + [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->set_message_size(message_size); + }, + kCheckStatus); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryPrepareProvisioningRequestForHugeSignatureLength) { + TestPrepareProvisioningRequestForHugeBufferLengths( + [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->set_request_signature_size(message_size); + }, + !kCheckStatus); +} + +TEST_F(OEMCryptoLoadsCertificate, + OEMCryptoMemoryPrepareProvisioningRequestForHugeCoreMessageLength) { + TestPrepareProvisioningRequestForHugeBufferLengths( + [](size_t message_size, ProvisioningRoundTrip* provisioning_messages) { + provisioning_messages->set_core_message_size(message_size); + }, + kCheckStatus); +} + // These tests are run by all L1 devices that load and use certificates. It is // also run by a few L3 devices that use a baked in certificate, but cannot load // a certificate. @@ -3266,14 +4960,14 @@ TEST_F(OEMCryptoLoadsCertificate, RSAPerformance) { auto start_time = clock.now(); int count = 15; for (int i = 0; i < count; i++) { // Only 20 nonce available. - CreateWrappedRSAKey(); + ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); } auto delta_time = clock.now() - start_time; const double provision_time = delta_time / std::chrono::milliseconds(1) / count; Session session; - CreateWrappedRSAKey(); + ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey()); start_time = clock.now(); count = 0; while (clock.now() - start_time < kTestDuration) { @@ -3401,7 +5095,7 @@ TEST_F(OEMCryptoUsesCertificate, } TEST_F(OEMCryptoUsesCertificate, - OEMCryptoMemoryDeriveKeysFromSessionKeyForLargeEncContext) { + OEMCryptoMemoryDeriveKeysFromSessionKeyForHugeEncContext) { vector session_key; vector enc_session_key; ASSERT_NO_FATAL_FAILURE(session_.PreparePublicKey(encoded_rsa_key_.data(), @@ -3422,6 +5116,29 @@ TEST_F(OEMCryptoUsesCertificate, TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); } +TEST_F(OEMCryptoUsesCertificate, + OEMCryptoMemoryDeriveKeysFromSessionKeyForHugeEncSessionKey) { + vector session_key; + vector enc_session_key; + ASSERT_NO_FATAL_FAILURE(session_.PreparePublicKey(encoded_rsa_key_.data(), + encoded_rsa_key_.size())); + ASSERT_TRUE(session_.GenerateRSASessionKey(&session_key, &enc_session_key)); + vector mac_context; + vector enc_context; + session_.FillDefaultContext(&mac_context, &enc_context); + OEMCrypto_SESSION session_id = session_.session_id(); + auto oemcrypto_function = [&session_id, &session_key, &enc_context, + &mac_context, + &enc_session_key](size_t buffer_length) { + session_key.resize(buffer_length); + return OEMCrypto_DeriveKeysFromSessionKey( + session_id, enc_session_key.data(), enc_session_key.size(), + mac_context.data(), mac_context.size(), enc_context.data(), + enc_context.size()); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + // This test attempts to use alternate algorithms for loaded device certs. class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { protected: @@ -3525,19 +5242,82 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse()); ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse()); OEMCryptoResult sts = provisioning_messages.LoadResponse(); - encoded_rsa_key_ = provisioning_messages.encoded_rsa_key(); - wrapped_rsa_key_ = provisioning_messages.wrapped_rsa_key(); - key_loaded_ = (sts == OEMCrypto_SUCCESS && wrapped_rsa_key_.size() > 0); + key_loaded_ = (OEMCrypto_SUCCESS == sts); + if (key_loaded_) { + encoded_rsa_key_ = provisioning_messages.encoded_rsa_key(); + wrapped_rsa_key_ = provisioning_messages.wrapped_rsa_key(); + EXPECT_GT(wrapped_rsa_key_.size(), 0u); + EXPECT_EQ(nullptr, find(wrapped_rsa_key_, encoded_rsa_key_)); + } if (force) { EXPECT_EQ(OEMCrypto_SUCCESS, sts); - EXPECT_EQ(nullptr, find(wrapped_rsa_key_, encoded_rsa_key_)); - ASSERT_TRUE(key_loaded_); } } bool key_loaded_; }; +TEST_F(OEMCryptoLoadsCertificateAlternates, + OEMCryptoMemoryGenerateRSASignatureForLargeBuffer) { + OEMCryptoResult sts; + LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); + // If the device is a cast receiver, then this scheme is required. + if (global_features.cast_receiver) ASSERT_TRUE(key_loaded_); + if (key_loaded_) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + sts = OEMCrypto_LoadDRMPrivateKey(s.session_id(), OEMCrypto_RSA_Private_Key, + wrapped_rsa_key_.data(), + wrapped_rsa_key_.size()); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + + vector message_buffer(10); + size_t signature_length = 0; + sts = OEMCrypto_GenerateRSASignature(s.session_id(), message_buffer.data(), + message_buffer.size(), nullptr, + &signature_length, kSign_PKCS1_Block1); + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); + ASSERT_NE(static_cast(0), signature_length); + vector signature(signature_length); + + auto oemcrypto_function = [&](size_t buffer_length) { + message_buffer.resize(buffer_length); + return OEMCrypto_GenerateRSASignature( + s.session_id(), message_buffer.data(), message_buffer.size(), + signature.data(), &signature_length, kSign_PKCS1_Block1); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); + s.close(); + } +} + +TEST_F(OEMCryptoLoadsCertificateAlternates, + OEMCryptoMemoryGenerateRSASignatureForLargeSignatureLength) { + OEMCryptoResult sts; + LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); + // If the device is a cast receiver, then this scheme is required. + if (global_features.cast_receiver) ASSERT_TRUE(key_loaded_); + if (key_loaded_) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + sts = OEMCrypto_LoadDRMPrivateKey(s.session_id(), OEMCrypto_RSA_Private_Key, + wrapped_rsa_key_.data(), + wrapped_rsa_key_.size()); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + + vector message_buffer(50); + vector signature; + auto oemcrypto_function = [&](size_t signature_length) { + signature.resize(signature_length); + return OEMCrypto_GenerateRSASignature( + s.session_id(), message_buffer.data(), message_buffer.size(), + signature.data(), &signature_length, kSign_PKCS1_Block1); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); + s.close(); + } +} + // The alternate padding is only required for cast receivers, but all devices // should forbid the alternate padding for regular certificates. TEST_F(OEMCryptoLoadsCertificateAlternates, DisallowForbiddenPaddingAPI09) { @@ -3548,7 +5328,7 @@ TEST_F(OEMCryptoLoadsCertificateAlternates, DisallowForbiddenPaddingAPI09) { // The alternate padding is only required for cast receivers, but if a device // does load an alternate certificate, it should NOT use it for generating // a license request signature. -TEST_F(OEMCryptoLoadsCertificateAlternates, TestSignaturePKCS1_API16) { +TEST_F(OEMCryptoLoadsCertificateAlternates, TestSignaturePKCS1) { // Try to load an RSA key with alternative padding schemes. This signing // scheme is used by cast receivers. LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); @@ -4629,6 +6409,9 @@ class OEMCryptoGenericCryptoTest : public OEMCryptoRefreshTest { if (alter_data) { signature[0] ^= 42; } + if (signature.size() < signature_size) { + signature.resize(signature_size); + } sts = OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, @@ -4715,6 +6498,48 @@ TEST_P(OEMCryptoGenericCryptoTest, OEMCryptoMemorySelectKeyForHugeKeyIdLength) { TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); } +TEST_P(OEMCryptoGenericCryptoTest, + OEMCryptoMemoryGenericKeyEncryptForHugeBuffer) { + EncryptAndLoadKeys(); + unsigned int key_index = 0; + vector expected_encrypted; + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_SelectKey(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); + OEMCrypto_SESSION session_id = session_.session_id(); + auto& iv = iv_; + auto oemcrypto_function = [&session_id, &iv](size_t buffer_length) mutable { + vector buffer(buffer_length); + return OEMCrypto_Generic_Encrypt(session_id, buffer.data(), buffer.size(), + iv, OEMCrypto_AES_CBC_128_NO_PADDING, + buffer.data()); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 16, kHugeInputBufferLength, + kCheckStatus); +} + +TEST_P( + OEMCryptoGenericCryptoTest, + OEMCryptoMemoryGenericKeyEncryptForHugeBufferWithBufferLengthNotMultipleOf16) { + EncryptAndLoadKeys(); + unsigned int key_index = 0; + vector expected_encrypted; + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_SelectKey(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); + OEMCrypto_SESSION session_id = session_.session_id(); + vector buffer(17); + ASSERT_NO_FATAL_FAILURE(OEMCrypto_Generic_Encrypt( + session_id, buffer.data(), buffer.size(), iv_, + OEMCrypto_AES_CBC_128_NO_PADDING, buffer.data())); +} + // Test Generic_Decrypt works correctly. TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecrypt) { EncryptAndLoadKeys(); @@ -4735,6 +6560,29 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecrypt) { ASSERT_EQ(clear_buffer_, resultant); } +TEST_P(OEMCryptoGenericCryptoTest, + OEMCryptoMemoryGenericKeyDecryptForHugeBuffer) { + EncryptAndLoadKeys(); + unsigned int key_index = 1; + OEMCrypto_SelectKey(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR); + OEMCrypto_SESSION session_id = session_.session_id(); + auto iv = iv_; + auto oemcrypto_function = [&session_id, &iv](size_t buffer_length) { + vector encrypted(buffer_length); + vector resultant(encrypted.size()); + + return OEMCrypto_Generic_Decrypt( + session_id, encrypted.data(), encrypted.size(), iv, + OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()); + }; + // API expects length to be multiple of 16. Starting from 16. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 16, kHugeInputBufferLength, + kCheckStatus); +} + // Test that Generic_Decrypt works correctly when the input and output buffers // are the same. TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecryptSameBufferAPI12) { @@ -4817,6 +6665,51 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeySign) { ASSERT_EQ(expected_signature, signature); } +TEST_P(OEMCryptoGenericCryptoTest, OEMCryptoMemoryGenericKeySignForHugeBuffer) { + EncryptAndLoadKeys(); + unsigned int key_index = 2; + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_SelectKey(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); + vector signature(SHA256_DIGEST_LENGTH); + size_t signature_length = signature.size(); + OEMCrypto_SESSION session_id = session_.session_id(); + auto oemcrypto_function = [&session_id, &signature, + &signature_length](size_t buffer_length) { + vector buffer(buffer_length); + return OEMCrypto_Generic_Sign(session_id, buffer.data(), buffer.size(), + OEMCrypto_HMAC_SHA256, signature.data(), + &signature_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_P(OEMCryptoGenericCryptoTest, + OEMCryptoMemoryGenericKeySignForHugeSignatureLength) { + EncryptAndLoadKeys(); + unsigned int key_index = 2; + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_SelectKey(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); + OEMCrypto_SESSION session_id = session_.session_id(); + auto clear_buffer = clear_buffer_; + auto oemcrypto_function = [&session_id, + &clear_buffer](size_t signature_length) { + vector signature(signature_length); + size_t gen_signature_length = signature_length; + return OEMCrypto_Generic_Sign(session_id, clear_buffer.data(), + clear_buffer.size(), OEMCrypto_HMAC_SHA256, + signature.data(), &gen_signature_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + // Test that the Generic_Sign function fails when not allowed. TEST_P(OEMCryptoGenericCryptoTest, GenericKeyBadSign) { EncryptAndLoadKeys(); @@ -4844,6 +6737,51 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyVerify) { signature.data(), signature.size())); } +TEST_P(OEMCryptoGenericCryptoTest, + OEMCryptoMemoryGenericKeyVerifyForHugeBuffer) { + EncryptAndLoadKeys(); + unsigned int key_index = 3; + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_SelectKey(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); + auto oemcrypto_function = [&](size_t buffer_length) { + vector buffer(buffer_length); + vector signature; + SignBuffer(key_index, buffer, &signature); + return OEMCrypto_Generic_Verify(session_.session_id(), buffer.data(), + buffer.size(), OEMCrypto_HMAC_SHA256, + signature.data(), signature.size()); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_P(OEMCryptoGenericCryptoTest, + OEMCryptoMemoryGenericKeyVerifyForHugeSignatureLength) { + EncryptAndLoadKeys(); + unsigned int key_index = 3; + vector signature; + SignBuffer(key_index, clear_buffer_, &signature); + + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_SelectKey(session_.session_id(), + session_.license().keys[key_index].key_id, + session_.license().keys[key_index].key_id_length, + OEMCrypto_CipherMode_CTR)); + OEMCrypto_SESSION session_id = session_.session_id(); + auto clear_buffer = clear_buffer_; + auto oemcrypto_function = [&session_id, &clear_buffer, + &signature](size_t signature_length) { + return OEMCrypto_Generic_Verify(session_id, clear_buffer.data(), + clear_buffer.size(), OEMCrypto_HMAC_SHA256, + signature.data(), signature_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + // Test that the Generic_Verify function fails when not allowed. TEST_P(OEMCryptoGenericCryptoTest, GenericKeyBadVerify) { EncryptAndLoadKeys(); @@ -5303,6 +7241,10 @@ class LicenseWithUsageEntry { 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()); @@ -5332,6 +7274,214 @@ class OEMCryptoUsageTableTest : public OEMCryptoGenericCryptoTest { } }; +TEST_P(OEMCryptoUsageTableTest, + OEMCryptoMemoryUpdateUsageEntryForHugeHeaderBuffer) { + auto oemcrypto_function = [&](size_t buffer_length) { + if (buffer_length < encrypted_usage_header_.size()) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + size_t header_buffer_length = 0; + size_t entry_buffer_length = 0; + // Header buffer length varies as generation_numbers size changes on every + // call. Hence, we need to call update usage entry in every loop to get + // latest value of header_buffer_length. + OEMCrypto_UpdateUsageEntry(s.session_id(), nullptr, &header_buffer_length, + nullptr, &entry_buffer_length); + vector encrypted_usage_entry(entry_buffer_length); + vector header_buffer(encrypted_usage_header_); + header_buffer.resize(buffer_length); + return OEMCrypto_UpdateUsageEntry( + s.session_id(), header_buffer.data(), &buffer_length, + encrypted_usage_entry.data(), &entry_buffer_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_P(OEMCryptoUsageTableTest, + OEMCryptoMemoryUpdateUsageEntryForHugeUsageEntryBuffer) { + auto oemcrypto_function = [&](size_t buffer_length) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + size_t header_buffer_length = 0; + size_t entry_buffer_length = 0; + // Header buffer length varies as generation_numbers size changes on every + // call. Hence, we need to call update usage entry in every loop to get + // latest value of header_buffer_length. + OEMCrypto_UpdateUsageEntry(s.session_id(), nullptr, &header_buffer_length, + nullptr, &entry_buffer_length); + vector header_buffer(encrypted_usage_header_); + header_buffer.resize(header_buffer_length); + vector encrypted_usage_entry(buffer_length); + return OEMCrypto_UpdateUsageEntry( + s.session_id(), header_buffer.data(), &header_buffer_length, + encrypted_usage_entry.data(), &buffer_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_P(OEMCryptoUsageTableTest, + OEMCryptoMemoryDeactivateUsageEntryForHugePstBuffer) { + auto oemcrypto_function = [&](size_t buffer_length) { + LicenseWithUsageEntry entry; + std::string pst("pst"); + pst.resize(buffer_length); + entry.license_messages().set_pst(pst); + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + return OEMCrypto_DeactivateUsageEntry( + s.session_id(), reinterpret_cast(pst.c_str()), + pst.length()); + }; + // The test setup assertions fails if pst length goes beyond kMaxPSTLength. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 1, kMaxPSTLength, + kCheckStatus); +} + +TEST_P(OEMCryptoUsageTableTest, + OEMCryptoMemoryLoadUsageTableHeaderForHugeHeader) { + auto oemcrypto_function = [&](size_t buffer_length) { + if (buffer_length < encrypted_usage_header_.size()) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeOfflineAndClose(this); + vector header_buffer(encrypted_usage_header_); + header_buffer.resize(buffer_length); + return OEMCrypto_LoadUsageTableHeader(header_buffer.data(), + header_buffer.size()); + }; + // We cannot generate an encrypted usage header of varying length with + // valid signature. Hence irrespective of return status, we call API for + // varying buffer lengths. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, + encrypted_usage_header_.size(), + kHugeInputBufferLength, !kCheckStatus); +} + +TEST_P( + OEMCryptoUsageTableTest, + OEMCryptoMemoryLoadUsageTableHeaderForHugeHeaderStartingHeaderLengthFrom1) { + auto oemcrypto_function = [&](size_t buffer_length) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeOfflineAndClose(this); + vector header_buffer(buffer_length); + return OEMCrypto_LoadUsageTableHeader(header_buffer.data(), + header_buffer.size()); + }; + // We cannot generate an encrypted usage header of varying length with + // valid signature. Hence irrespective of return status, we call API for + // varying buffer lengths. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +TEST_P(OEMCryptoUsageTableTest, + OEMCryptoMemoryLoadUsageEntryForHugeUsageEntryBuffer) { + auto oemcrypto_function = [&](size_t buffer_length) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + Session& s = entry.session(); + // Make first entry 0. + entry.MakeOfflineAndClose(this); + if (buffer_length < s.encrypted_usage_entry().size()) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + Session s2; + s2.open(); + InstallTestRSAKey(&s2); + vector encrypted_usage_entry(buffer_length); + memcpy(encrypted_usage_entry.data(), s.encrypted_usage_entry().data(), + s.encrypted_usage_entry().size()); + const uint32_t usage_entry_number = s.usage_entry_number(); + return OEMCrypto_LoadUsageEntry(s2.session_id(), usage_entry_number, + encrypted_usage_entry.data(), + encrypted_usage_entry.size()); + }; + // We cannot generate an encrypted usage enctry of varying length with + // valid signature. Hence irrespective of return status, we call API for + // varying buffer lengths. + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +TEST_P(OEMCryptoUsageTableTest, + OEMCryptoMemoryLoadUsageEntryForHugeInvalidUsageEntryNumber) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + // Make first entry 0. + entry.MakeOfflineAndClose(this); + Session s; + s.open(); + InstallTestRSAKey(&s); + const uint32_t usage_entry_number = kHugeRandomNumber; + ASSERT_NO_FATAL_FAILURE(OEMCrypto_LoadUsageEntry( + s.session_id(), usage_entry_number, s.encrypted_usage_entry().data(), + s.encrypted_usage_entry().size())); +} + +TEST_P(OEMCryptoUsageTableTest, OEMCryptoMemoryReportUsageForHugeReportBuffer) { + auto oemcrypto_function = [&](size_t buffer_length) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + s.UpdateUsageEntry(&encrypted_usage_header_); + size_t length = 0; + OEMCrypto_ReportUsage(s.session_id(), + reinterpret_cast(entry.pst().c_str()), + entry.pst().length(), nullptr, &length); + vector pst_report_buffer(buffer_length); + return OEMCrypto_ReportUsage( + s.session_id(), reinterpret_cast(entry.pst().c_str()), + entry.pst().length(), pst_report_buffer.data(), &buffer_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + +TEST_P(OEMCryptoUsageTableTest, OEMCryptoMemoryReportUsageForHugePstBuffer) { + auto oemcrypto_function = [&](size_t buffer_length) { + LicenseWithUsageEntry entry; + entry.license_messages().set_api_version(license_api_version_); + entry.MakeAndLoadOnline(this); + Session& s = entry.session(); + s.UpdateUsageEntry(&encrypted_usage_header_); + size_t length = 0; + OEMCrypto_ReportUsage(s.session_id(), + reinterpret_cast(entry.pst().c_str()), + entry.pst().length(), nullptr, &length); + vector pst_report_buffer(length); + vector pst(buffer_length); + return OEMCrypto_ReportUsage(s.session_id(), pst.data(), pst.size(), + pst_report_buffer.data(), &length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); +} + +TEST_P(OEMCryptoUsageTableTest, + OEMCryptoMemoryShrinkUsageTableHeaderForHugeHeaderBufferLength) { + LicenseWithUsageEntry entry0; + entry0.set_pst("pst 0"); + entry0.MakeOfflineAndClose(this); + auto oemcrypto_function = [&](size_t buffer_length) { + LicenseWithUsageEntry entry1; + entry1.set_pst("pst 1"); + entry1.MakeOfflineAndClose(this); + size_t header_buffer_length = buffer_length; + encrypted_usage_header_.resize(header_buffer_length); + return OEMCrypto_ShrinkUsageTableHeader(1, encrypted_usage_header_.data(), + &header_buffer_length); + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); +} + // Test an online or streaming license with PST. This license requires a valid // nonce and can only be loaded once. TEST_P(OEMCryptoUsageTableTest, OnlineLicense) { @@ -5520,7 +7670,7 @@ TEST_P(OEMCryptoUsageTableTest, CreateAndLoadMultipleEntriesAPI16) { // Reload entry 0. ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry()); // Create new entry 1 should fail. - ASSERT_EQ(OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES, + ASSERT_NE(OEMCrypto_SUCCESS, OEMCrypto_CreateNewUsageEntry(entry.session().session_id(), &usage_entry_number)); ASSERT_NO_FATAL_FAILURE(s.close()); @@ -5531,7 +7681,7 @@ TEST_P(OEMCryptoUsageTableTest, CreateAndLoadMultipleEntriesAPI16) { // Create entry 1. ASSERT_NO_FATAL_FAILURE(s2.CreateNewUsageEntry()); // Try to reload entry 0. - ASSERT_EQ(OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES, + ASSERT_NE(OEMCrypto_SUCCESS, OEMCrypto_LoadUsageEntry(s2.session_id(), s.usage_entry_number(), s.encrypted_usage_entry().data(), s.encrypted_usage_entry().size())); @@ -5541,7 +7691,7 @@ TEST_P(OEMCryptoUsageTableTest, CreateAndLoadMultipleEntriesAPI16) { // This reloads entry 0. ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry()); - ASSERT_EQ(OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES, + ASSERT_NE(OEMCrypto_SUCCESS, OEMCrypto_LoadUsageEntry(s.session_id(), s.usage_entry_number(), s.encrypted_usage_entry().data(), s.encrypted_usage_entry().size())); @@ -5550,9 +7700,8 @@ TEST_P(OEMCryptoUsageTableTest, CreateAndLoadMultipleEntriesAPI16) { // Create an entry, then try to create a second entry. ASSERT_NO_FATAL_FAILURE(s2.open()); ASSERT_NO_FATAL_FAILURE(s2.CreateNewUsageEntry()); - ASSERT_EQ( - OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES, - OEMCrypto_CreateNewUsageEntry(s2.session_id(), &usage_entry_number)); + ASSERT_NE(OEMCrypto_SUCCESS, OEMCrypto_CreateNewUsageEntry( + s2.session_id(), &usage_entry_number)); } // An entry can be loaded in only one session at a time. @@ -6130,6 +8279,16 @@ TEST_P(OEMCryptoUsageTableDefragTest, MoveUsageEntriesToOpenSession) { 0, &encrypted_usage_header_, OEMCrypto_ERROR_ENTRY_IN_USE)); } +TEST_P(OEMCryptoUsageTableDefragTest, MoveUsageEntriesToInvalidHugeEntryIndex) { + LicenseWithUsageEntry entry0; + entry0.set_pst("pst 0"); + entry0.MakeOfflineAndClose(this); + entry0.session().open(); + entry0.ReloadUsageEntry(); + ASSERT_NO_FATAL_FAILURE( + OEMCrypto_MoveEntry(entry0.session().session_id(), kHugeRandomNumber)); +} + // The usage table cannot be shrunk if any session is using an entry that would // be deleted. TEST_P(OEMCryptoUsageTableDefragTest, ShrinkOverOpenSessions) {