diff --git a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_copy_buffer_fuzz.cc b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_copy_buffer_fuzz.cc index a9e6bfb7..b9a1ce83 100644 --- a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_copy_buffer_fuzz.cc +++ b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_copy_buffer_fuzz.cc @@ -2,50 +2,12 @@ // source code may only be used and distributed under the Widevine Master // License Agreement. +#include "FuzzedDataProvider.h" #include "OEMCryptoCENC.h" -#include "log.h" #include "oemcrypto_fuzz_helper.h" #include "oemcrypto_fuzz_structs.h" namespace wvoec { -// Free dynamic memory allocated by fuzzer script. -void FreeOutputBuffers(OEMCrypto_SESSION session_id, - OEMCrypto_DestBufferDesc& output_descriptor, - int* secure_fd) { - switch (output_descriptor.type) { - case OEMCrypto_BufferType_Clear: { - delete[] output_descriptor.buffer.clear.clear_buffer; - break; - } - case OEMCrypto_BufferType_Secure: { - OEMCrypto_FreeSecureBuffer(session_id, &output_descriptor, *secure_fd); - break; - } - case OEMCrypto_BufferType_Direct: { - break; - } - } -} - -bool InitializeOutputBuffers(OEMCrypto_SESSION session_id, - OEMCrypto_DestBufferDesc& output_descriptor, - int* secure_fd, size_t input_buffer_size) { - switch (output_descriptor.type) { - case OEMCrypto_BufferType_Clear: { - output_descriptor.buffer.clear.clear_buffer = - new OEMCrypto_SharedMemory[input_buffer_size]; - return true; - } - case OEMCrypto_BufferType_Secure: { - OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( - session_id, input_buffer_size, &output_descriptor, secure_fd); - return sts == OEMCrypto_SUCCESS; - } - case OEMCrypto_BufferType_Direct: { - return true; - } - } -} extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // Redirect printf and log statements from oemcrypto functions to a file to @@ -54,39 +16,68 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // OEMCrypto_DestBufferDesc and a buffer from which data needs to be copied // are expected as inputs to copy buffer API. - // Input fuzzed data is interpreted as + // Input fuzzed data is interpreted as: // (OEMCrypto_DestBufferDesc | subsample_flags | input_buffer) OEMCrypto_Copy_Buffer_Fuzz fuzzed_structure; - if (size <= sizeof(fuzzed_structure)) { + if (size < sizeof(fuzzed_structure)) { return 0; } - memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure)); + FuzzedDataProvider fuzzed_data(data, size); + fuzzed_data.ConsumeData(&fuzzed_structure, sizeof(fuzzed_structure)); ConvertDataToValidEnum(OEMCrypto_BufferType_MaxValue, &fuzzed_structure.dest_buffer_desc.type); + fuzzed_structure.dest_buffer_desc.buffer_config %= MAX_FUZZ_OUTPUT_LENGTH + 1; + const std::vector input_buffer = + fuzzed_data.ConsumeRemainingBytes(); OEMCryptoLicenseAPIFuzz license_api_fuzz; - Session* session = license_api_fuzz.session(); - // Fuzz input buffer to be copied. - size_t input_buffer_size = size - sizeof(fuzzed_structure); + const uint32_t session_id = license_api_fuzz.session()->session_id(); + + // Initialize output buffer. + OEMCrypto_DestBufferDesc dest_buffer_desc; int secure_fd = 0; - // Create output buffer pointers. If secure buffer is not supported, we - // explicitly convert to clear buffer and fuzz. - if (!InitializeOutputBuffers(session->session_id(), - fuzzed_structure.dest_buffer_desc, &secure_fd, - input_buffer_size)) { - LOGI( - "[OEMCrypto decrypt CENC fuzz] Secure buffers are not supported. Use " - "clear buffer instead."); - fuzzed_structure.dest_buffer_desc.type = OEMCrypto_BufferType_Clear; - InitializeOutputBuffers(session->session_id(), - fuzzed_structure.dest_buffer_desc, &secure_fd, - input_buffer_size); + dest_buffer_desc.type = fuzzed_structure.dest_buffer_desc.type; + switch (dest_buffer_desc.type) { + case OEMCrypto_BufferType_Clear: + dest_buffer_desc.buffer.clear.clear_buffer = + new OEMCrypto_SharedMemory[fuzzed_structure.dest_buffer_desc + .buffer_config]; + dest_buffer_desc.buffer.clear.clear_buffer_length = + fuzzed_structure.dest_buffer_desc.buffer_config; + break; + + case OEMCrypto_BufferType_Secure: + if (OEMCrypto_AllocateSecureBuffer( + session_id, fuzzed_structure.dest_buffer_desc.buffer_config, + &dest_buffer_desc, &secure_fd) != OEMCrypto_SUCCESS) { + return 0; + } + break; + + case OEMCrypto_BufferType_Direct: + dest_buffer_desc.buffer.direct.is_video = + fuzzed_structure.dest_buffer_desc.buffer_config & 1; + break; } - OEMCrypto_CopyBuffer(session->session_id(), data + sizeof(fuzzed_structure), - input_buffer_size, &fuzzed_structure.dest_buffer_desc, - fuzzed_structure.subsample_flags); - FreeOutputBuffers(session->session_id(), fuzzed_structure.dest_buffer_desc, - &secure_fd); + + OEMCrypto_CopyBuffer(session_id, input_buffer.data(), input_buffer.size(), + &dest_buffer_desc, fuzzed_structure.subsample_flags); + + // Free output buffer. + switch (dest_buffer_desc.type) { + case OEMCrypto_BufferType_Clear: + delete[] dest_buffer_desc.buffer.clear.clear_buffer; + break; + + case OEMCrypto_BufferType_Secure: + OEMCrypto_FreeSecureBuffer(session_id, &dest_buffer_desc, secure_fd); + break; + + case OEMCrypto_BufferType_Direct: + break; + } + return 0; } + } // namespace wvoec diff --git a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_decrypt_cenc_fuzz.cc b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_decrypt_cenc_fuzz.cc index eb1465ea..19f8be86 100644 --- a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_decrypt_cenc_fuzz.cc +++ b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_decrypt_cenc_fuzz.cc @@ -4,184 +4,166 @@ #include "FuzzedDataProvider.h" #include "OEMCryptoCENC.h" -#include "log.h" #include "oemcrypto_fuzz_helper.h" #include "oemcrypto_fuzz_structs.h" -#include "oemcrypto_overflow.h" namespace wvoec { -const size_t MAX_FUZZ_SAMPLE_SIZE = 5 * MB; -// Free dynamic memory allocated by fuzzer script. -void FreeOutputBuffers(OEMCrypto_SESSION session_id, - OEMCrypto_SampleDescription* sample_description, - size_t sample_index, int* secure_fd_array) { - for (size_t i = 0; i < sample_index; i++) { - OEMCrypto_DestBufferDesc fuzzed_output_descriptor = - sample_description[i].buffers.output_descriptor; - switch (fuzzed_output_descriptor.type) { - case OEMCrypto_BufferType_Clear: { - delete[] fuzzed_output_descriptor.buffer.clear.clear_buffer; - break; - } - case OEMCrypto_BufferType_Secure: { - OEMCrypto_FreeSecureBuffer(session_id, &fuzzed_output_descriptor, - secure_fd_array[i]); - break; - } - case OEMCrypto_BufferType_Direct: { - break; - } - } - } -} -// Function to initialize output buffer pointers by allocating memory. -// Limiting output buffer size to 5 MB as 4 MB is maximum size specified -// by resource rating tier documentation. -bool InitializeOutputBuffers(OEMCrypto_SESSION session_id, - OEMCrypto_DestBufferDesc& output_descriptor, - size_t sample_index, - vector& secure_fd_array) { - switch (output_descriptor.type) { - case OEMCrypto_BufferType_Clear: { - output_descriptor.buffer.clear.clear_buffer = - new OEMCrypto_SharedMemory[std::min( - MAX_FUZZ_SAMPLE_SIZE, - output_descriptor.buffer.clear.clear_buffer_length)]; - return true; - } - case OEMCrypto_BufferType_Secure: { - int* secure_fd; - OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( - session_id, - std::min(MAX_FUZZ_SAMPLE_SIZE, - output_descriptor.buffer.secure.secure_buffer_length), - &output_descriptor, secure_fd); - if (sts == OEMCrypto_SUCCESS) secure_fd_array[sample_index] = *secure_fd; - return sts == OEMCrypto_SUCCESS; - } - case OEMCrypto_BufferType_Direct: { - return true; - } - } -} +// Limit output buffer size to 5 MB as 4 MB is maximum size specified by +// resource rating tier documentation. +const size_t MAX_FUZZ_SAMPLE_SIZE = 5 * MB; extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // Redirect printf and log statements from oemcrypto functions to a file to // reduce noise RedirectStdoutToFile(); - size_t samples_length; // Split data using separator. - auto inputs = SplitInput(data, size); - if (inputs.size() < 2) { + const std::vector inputs = SplitFuzzedData(data, size); + if (inputs.size() < 3) { return 0; } + // Read cipher mode and pattern from fuzzed data. OEMCrypto_Decrypt_Cenc_Fuzz fuzzed_structure; - if (inputs[0].size() < sizeof(fuzzed_structure)) { + if (inputs[0].size < sizeof(fuzzed_structure)) { return 0; } - // Copy OEMCrypto_Decrypt_Cenc_Fuzz from input data. - memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure)); + FuzzedDataProvider fuzzed_data(inputs[0].data, inputs[0].size); + fuzzed_data.ConsumeData(&fuzzed_structure, sizeof(fuzzed_structure)); ConvertDataToValidEnum(OEMCrypto_CipherMode_MaxValue, &fuzzed_structure.cipher_mode); - size_t remaining_size_for_samples = - inputs[0].size() - sizeof(fuzzed_structure); - // Initialize FDP structures to read data using inbuilt functions. - FuzzedDataProvider fuzzed_sample_data(data + sizeof(fuzzed_structure), - remaining_size_for_samples); - FuzzedDataProvider fuzzed_subsample_data(inputs[1].data(), inputs[1].size()); + // Allocate sample descriptions. + std::vector sample_descriptions( + fuzzed_data.remaining_bytes() / sizeof(OEMCrypto_SampleDescription_Fuzz)); - // Read subsamples from fuzzed data. - vector subsamples; - while (fuzzed_subsample_data.remaining_bytes() >= - sizeof(OEMCrypto_SubSampleDescription)) { - OEMCrypto_SubSampleDescription subsample; - fuzzed_subsample_data.ConsumeData(&subsample, - sizeof(OEMCrypto_SubSampleDescription)); - subsamples.push_back(subsample); - } - if (subsamples.size() == 0) { - return 0; - } + // Allocate input buffers for each sample description. + std::vector> input_buffers( + sample_descriptions.size()); - // Infer samples_length from fuzzed data. - size_t sample_description_size = sizeof(OEMCrypto_SampleDescription); - samples_length = - fuzzed_sample_data.remaining_bytes() / sample_description_size; - if (samples_length == 0) { - return 0; - } + // Allocate secure_fd values for secure buffers. + std::vector secure_fd_array(sample_descriptions.size()); - // Initialize sample_descriptions array. - vector sample_descriptions(samples_length); - // Create array to maintain secure_fd buffer values for secure buffers. - vector secure_fd_array(samples_length); + // Allocate subsamples for each sample description. + std::vector> subsamples( + sample_descriptions.size()); OEMCryptoLicenseAPIFuzz license_api_fuzz; - Session* session = license_api_fuzz.session(); - // Copy samples from fuzzed data. - size_t input_subsample_index = 0; - size_t total_input_data_length = 0; - for (size_t i = 0; i < samples_length; i++) { - fuzzed_sample_data.ConsumeData(&sample_descriptions[i], - sample_description_size); + const uint32_t session_id = license_api_fuzz.session()->session_id(); + + // Free first given number of output buffers. + const auto FreeOutputBuffers = [&sample_descriptions, session_id, + &secure_fd_array](size_t num_buffers) { + for (size_t i = 0; i < num_buffers; i++) { + OEMCrypto_DestBufferDesc& output_descriptor = + sample_descriptions[i].buffers.output_descriptor; + switch (output_descriptor.type) { + case OEMCrypto_BufferType_Clear: + delete[] output_descriptor.buffer.clear.clear_buffer; + break; + + case OEMCrypto_BufferType_Secure: + OEMCrypto_FreeSecureBuffer(session_id, &output_descriptor, + secure_fd_array[i]); + break; + + case OEMCrypto_BufferType_Direct: + break; + } + } + }; + + // Prepare each sample description. + FuzzedDataProvider& sample_description_data = fuzzed_data; + FuzzedDataProvider input_buffer_data(inputs[1].data, inputs[1].size); + FuzzedDataProvider subsample_data(inputs[2].data, inputs[2].size); + for (size_t i = 0; i < sample_descriptions.size(); i++) { + // Read and normalize sample description fuzzed properties. + OEMCrypto_SampleDescription_Fuzz fuzzed_sample_description; + sample_description_data.ConsumeData(&fuzzed_sample_description, + sizeof(fuzzed_sample_description)); + fuzzed_sample_description.buffers.input_data_length %= + MAX_FUZZ_SAMPLE_SIZE + 1; ConvertDataToValidEnum( OEMCrypto_BufferType_MaxValue, - &sample_descriptions[i].buffers.output_descriptor.type); + &fuzzed_sample_description.buffers.output_descriptor.type); + fuzzed_sample_description.buffers.output_descriptor.buffer_config %= + MAX_FUZZ_SAMPLE_SIZE + 1; - // Copy random data into input sample data. Cap input data length at 5 MB, - // 1 MB higher than that described by resource rating tier. - total_input_data_length += std::min( - MAX_FUZZ_SAMPLE_SIZE, sample_descriptions[i].buffers.input_data_length); - - // Copy sub sample data. - sample_descriptions[i].subsamples = &subsamples[input_subsample_index]; - if (OPK_AddOverflowUX(input_subsample_index, - sample_descriptions[i].subsamples_length, - &input_subsample_index)) { + // Read input data. + if (fuzzed_sample_description.buffers.input_data_length > + input_buffer_data.remaining_bytes()) { + FreeOutputBuffers(i); return 0; } - if (input_subsample_index > subsamples.size()) return 0; - } // Sample loop. + input_buffers[i] = input_buffer_data.ConsumeBytes( + fuzzed_sample_description.buffers.input_data_length); + sample_descriptions[i].buffers.input_data = input_buffers[i].data(); + sample_descriptions[i].buffers.input_data_length = input_buffers[i].size(); - // Allocate input/output buffers for each sample description. - vector input_buffer(total_input_data_length); - size_t input_buffer_index = 0; - for (size_t i = 0; i < samples_length; i++) { - sample_descriptions[i].buffers.input_data = - &input_buffer[input_buffer_index]; - input_buffer_index += std::min( - MAX_FUZZ_SAMPLE_SIZE, sample_descriptions[i].buffers.input_data_length); + // Set subsample data. + if (fuzzed_sample_description.subsamples_length > + subsample_data.remaining_bytes() / + sizeof(OEMCrypto_SubSampleDescription)) { + FreeOutputBuffers(i); + return 0; + } + if (fuzzed_sample_description.subsamples_length > 0) { + subsamples[i].resize(fuzzed_sample_description.subsamples_length); + subsample_data.ConsumeData( + subsamples[i].data(), + subsamples[i].size() * sizeof(OEMCrypto_SubSampleDescription)); + } + sample_descriptions[i].subsamples = subsamples[i].data(); + sample_descriptions[i].subsamples_length = subsamples[i].size(); - // Create output buffer pointers. If secure buffer is not supported, we - // explicitly convert to clear buffer and fuzz. - if (!InitializeOutputBuffers( - session->session_id(), - sample_descriptions[i].buffers.output_descriptor, i, - secure_fd_array)) { - LOGI( - "[OEMCrypto decrypt CENC fuzz] Secure buffers are not supported. Use " - "clear buffer instead."); - sample_descriptions[i].buffers.output_descriptor.type = - OEMCrypto_BufferType_Clear; - InitializeOutputBuffers(session->session_id(), - sample_descriptions[i].buffers.output_descriptor, - i, secure_fd_array); + // Set IV data. + memcpy(sample_descriptions[i].iv, fuzzed_sample_description.iv, + sizeof(sample_descriptions[i].iv)); + + // Initialize output buffer. + OEMCrypto_DestBufferDesc& output_descriptor = + sample_descriptions[i].buffers.output_descriptor; + const OEMCrypto_DestBufferDesc_Fuzz& fuzzed_output_descriptor = + fuzzed_sample_description.buffers.output_descriptor; + output_descriptor.type = fuzzed_output_descriptor.type; + switch (output_descriptor.type) { + case OEMCrypto_BufferType_Clear: + output_descriptor.buffer.clear.clear_buffer = + new OEMCrypto_SharedMemory[fuzzed_output_descriptor.buffer_config]; + output_descriptor.buffer.clear.clear_buffer_length = + fuzzed_output_descriptor.buffer_config; + break; + + case OEMCrypto_BufferType_Secure: + if (OEMCrypto_AllocateSecureBuffer( + session_id, fuzzed_output_descriptor.buffer_config, + &output_descriptor, &secure_fd_array[i]) != OEMCrypto_SUCCESS) { + FreeOutputBuffers(i); + return 0; + } + break; + + case OEMCrypto_BufferType_Direct: + output_descriptor.buffer.direct.is_video = + fuzzed_output_descriptor.buffer_config & 1; + break; } } // Load license and call decrypt_cenc API. license_api_fuzz.LoadLicense(); - OEMCrypto_SelectKey(session->session_id(), session->license().keys[0].key_id, - session->license().keys[0].key_id_length, + const MessageKeyData& key = license_api_fuzz.session()->license().keys[0]; + OEMCrypto_SelectKey(session_id, key.key_id, key.key_id_length, fuzzed_structure.cipher_mode); - OEMCrypto_DecryptCENC(session->session_id(), sample_descriptions.data(), - samples_length, &fuzzed_structure.pattern); - FreeOutputBuffers(session->session_id(), sample_descriptions.data(), - samples_length, secure_fd_array.data()); + OEMCrypto_DecryptCENC(session_id, sample_descriptions.data(), + sample_descriptions.size(), &fuzzed_structure.pattern); + + // Free all output buffers. + FreeOutputBuffers(sample_descriptions.size()); + return 0; } + } // namespace wvoec diff --git a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.cc b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.cc index f76fafae..eb6a351e 100644 --- a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.cc +++ b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.cc @@ -6,19 +6,18 @@ namespace wvoec { void RedirectStdoutToFile() { freopen("log.txt", "a", stdout); } -std::vector> SplitInput(const uint8_t* data, size_t size) { - std::vector> result; - auto current_pos = data; - auto end = data + size; - // Using memmem to find separator - while (const uint8_t* pos = reinterpret_cast( - memmem(current_pos, end - current_pos, kFuzzDataSeparator, - sizeof(kFuzzDataSeparator)))) { - result.push_back({current_pos, pos}); - current_pos = pos + sizeof(kFuzzDataSeparator); +std::vector SplitFuzzedData(const uint8_t* data, size_t size) { + std::vector result; + const uint8_t* const end = data + size; + // Using memmem to find separator. + while ( + const uint8_t* const separator = reinterpret_cast(memmem( + data, end - data, kFuzzDataSeparator, sizeof(kFuzzDataSeparator)))) { + result.push_back({data, static_cast(separator - data)}); + data = separator + sizeof(kFuzzDataSeparator); } - if (current_pos < end) { - result.push_back({current_pos, end}); + if (data < end) { + result.push_back({data, static_cast(end - data)}); } return result; } diff --git a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.h b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.h index 8c12316c..d7be2208 100644 --- a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.h +++ b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.h @@ -24,6 +24,12 @@ const size_t KB = 1024; // Default maximum length of fuzzing output parameters. const size_t MAX_FUZZ_OUTPUT_LENGTH = 5 * KB; +// Fuzzed data region. +struct FuzzedData { + const uint8_t* data; + size_t size; +}; + // Initial setup to create a valid OEMCrypto state such as initializing crypto // firmware/hardware, installing golden key box etc. in order to fuzz // OEMCrypto APIs. @@ -124,8 +130,9 @@ void ConvertDataToValidEnum(T max_enum_value, T* t) { // reduce noise void RedirectStdoutToFile(); -// Function to split fuzzer input using delimiter "-_^_". -std::vector> SplitInput(const uint8_t* data, size_t size); +// Split fuzzed data using delimiter "-_^_". +std::vector SplitFuzzedData(const uint8_t* data, size_t size); + // Check the status and exit fuzzer if arguments do not match. This is usually // called to check status of APIs which are called to setup state for fuzzers. void CheckStatusAndExitFuzzerOnFailure(OEMCryptoResult result, diff --git a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_structs.h b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_structs.h index 37b3daf7..42d077c1 100644 --- a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_structs.h +++ b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_structs.h @@ -8,6 +8,26 @@ #include "odk.h" namespace wvoec { + +// OEMCrypto_DestBufferDesc fuzzed properties. +struct OEMCrypto_DestBufferDesc_Fuzz { + OEMCryptoBufferType type; + size_t buffer_config; +}; + +// OEMCrypto_InputOutputPair fuzzed properties. +struct OEMCrypto_InputOutputPair_Fuzz { + size_t input_data_length; + OEMCrypto_DestBufferDesc_Fuzz output_descriptor; +}; + +// OEMCrypto_SampleDescription fuzzed properties. +struct OEMCrypto_SampleDescription_Fuzz { + OEMCrypto_InputOutputPair_Fuzz buffers; + uint8_t iv[16]; + size_t subsamples_length; +}; + struct OEMCrypto_Renewal_Response_Fuzz { // Timer limits in core license response needs to be fuzzed as load renewal // depends on timer limits loaded from license response. @@ -50,16 +70,6 @@ struct OEMCrypto_Generic_Api_Fuzz { // this structure. }; -struct OEMCrypto_Generic_Verify_Fuzz { - // Corpus format is as belowr. - // cipher_mode + algorithm + signature_length + buffer with actual data - OEMCryptoCipherMode cipher_mode; - OEMCrypto_Algorithm algorithm; - size_t signature_length; - // Buffer data is of variable length and not included in - // this structure. -}; - struct OEMCrypto_Generate_RSA_Signature_Fuzz { // Corpus format is as below, let | be separator. // padding_scheme + signature_length + input buffer @@ -72,10 +82,11 @@ struct OEMCrypto_Generate_RSA_Signature_Fuzz { struct OEMCrypto_Copy_Buffer_Fuzz { // Corpus format is as below. // dest_buffer_desc + subsample_flags + input buffer - OEMCrypto_DestBufferDesc dest_buffer_desc; + OEMCrypto_DestBufferDesc_Fuzz dest_buffer_desc; uint8_t subsample_flags; // Input buffer of variable length is not included in this structure. }; + } // namespace wvoec -#endif // OEMCRYPTO_FUZZ_STRUCTS_H_ \ No newline at end of file +#endif // OEMCRYPTO_FUZZ_STRUCTS_H_ diff --git a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_generate_rsa_signature_fuzz.cc b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_generate_rsa_signature_fuzz.cc index 44ca1d0a..39aa72c1 100644 --- a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_generate_rsa_signature_fuzz.cc +++ b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_generate_rsa_signature_fuzz.cc @@ -2,6 +2,7 @@ // source code may only be used and distributed under the Widevine // License Agreement. +#include "FuzzedDataProvider.h" #include "OEMCryptoCENC.h" #include "oemcrypto_fuzz_helper.h" @@ -11,23 +12,25 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // Redirect printf and log statements from oemcrypto functions to a file to // reduce noise RedirectStdoutToFile(); + OEMCrypto_Generate_RSA_Signature_Fuzz fuzzed_structure; - if (size <= sizeof(OEMCrypto_Generate_RSA_Signature_Fuzz)) { + if (size < sizeof(fuzzed_structure)) { return 0; } + FuzzedDataProvider fuzzed_data(data, size); + fuzzed_data.ConsumeData(&fuzzed_structure, sizeof(fuzzed_structure)); + const std::vector message = + fuzzed_data.ConsumeRemainingBytes(); - // Copy data to fuzzed structure. - memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure)); // Creates wrapped rsa key and calls load drm private key. static OEMCryptoLicenseAPIFuzz license_api_fuzz; // We cannot allocate buffers of random huge lengths in memory. // This also slows down the fuzzer. - size_t signature_length = - std::min(MAX_FUZZ_OUTPUT_LENGTH, fuzzed_structure.signature_length); - vector signature(signature_length); + fuzzed_structure.signature_length %= MAX_FUZZ_OUTPUT_LENGTH + 1; + std::vector signature(fuzzed_structure.signature_length); OEMCrypto_GenerateRSASignature( - license_api_fuzz.session()->session_id(), data + sizeof(fuzzed_structure), - size - sizeof(fuzzed_structure), signature.data(), &signature_length, + license_api_fuzz.session()->session_id(), message.data(), message.size(), + signature.data(), &fuzzed_structure.signature_length, fuzzed_structure.padding_scheme); return 0; } diff --git a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_generic_decrypt_fuzz.cc b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_generic_decrypt_fuzz.cc index e36d5508..c583165f 100644 --- a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_generic_decrypt_fuzz.cc +++ b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_generic_decrypt_fuzz.cc @@ -16,34 +16,29 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { RedirectStdoutToFile(); // Split data using separator. - auto inputs = SplitInput(data, size); + const std::vector inputs = SplitFuzzedData(data, size); if (inputs.size() < 2) { return 0; } OEMCrypto_Generic_Api_Fuzz fuzzed_structure; - if (inputs[0].size() < sizeof(fuzzed_structure)) { + if (inputs[0].size < sizeof(fuzzed_structure)) { return 0; } // Copy OEMCrypto_Generic_Api_Fuzz from input data. - memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure)); + FuzzedDataProvider fuzzed_data(inputs[0].data, inputs[0].size); + fuzzed_data.ConsumeData(&fuzzed_structure, sizeof(fuzzed_structure)); ConvertDataToValidEnum(OEMCrypto_CipherMode_MaxValue, &fuzzed_structure.cipher_mode); ConvertDataToValidEnum(OEMCrypto_Algorithm_MaxValue, &fuzzed_structure.algorithm); - // Copy iv from input data. - size_t iv_size = inputs[0].size() - sizeof(fuzzed_structure); - if (iv_size == 0) { - return 0; - } - vector iv(iv_size); - memcpy(iv.data(), data + sizeof(fuzzed_structure), iv_size); + const std::vector iv = fuzzed_data.ConsumeRemainingBytes(); - // Copy clear buffer from input data. - vector encrypted_buffer(inputs[1].size()); - vector clear_buffer(inputs[1].size()); - memcpy(encrypted_buffer.data(), inputs[1].data(), inputs[1].size()); + // Initialize encrypted and clear buffers. + const std::vector encrypted_buffer(inputs[1].data, + inputs[1].data + inputs[1].size); + std::vector clear_buffer(encrypted_buffer.size()); OEMCryptoLicenseAPIFuzz license_api_fuzz; Session* session = license_api_fuzz.session(); diff --git a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_generic_encrypt_fuzz.cc b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_generic_encrypt_fuzz.cc index df0a35e9..acd97f60 100644 --- a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_generic_encrypt_fuzz.cc +++ b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_generic_encrypt_fuzz.cc @@ -16,34 +16,29 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { RedirectStdoutToFile(); // Split data using separator. - auto inputs = SplitInput(data, size); + const std::vector inputs = SplitFuzzedData(data, size); if (inputs.size() < 2) { return 0; } OEMCrypto_Generic_Api_Fuzz fuzzed_structure; - if (inputs[0].size() < sizeof(fuzzed_structure)) { + if (inputs[0].size < sizeof(fuzzed_structure)) { return 0; } // Copy OEMCrypto_Generic_Api_Fuzz from input data. - memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure)); + FuzzedDataProvider fuzzed_data(inputs[0].data, inputs[0].size); + fuzzed_data.ConsumeData(&fuzzed_structure, sizeof(fuzzed_structure)); ConvertDataToValidEnum(OEMCrypto_CipherMode_MaxValue, &fuzzed_structure.cipher_mode); ConvertDataToValidEnum(OEMCrypto_Algorithm_MaxValue, &fuzzed_structure.algorithm); - // Copy iv from input data. - size_t iv_size = inputs[0].size() - sizeof(fuzzed_structure); - if (iv_size == 0) { - return 0; - } - vector iv(iv_size); - memcpy(iv.data(), data + sizeof(fuzzed_structure), iv_size); + const std::vector iv = fuzzed_data.ConsumeRemainingBytes(); - // Copy clear buffer from input data. - vector clear_buffer(inputs[1].size()); - vector encrypted_buffer(inputs[1].size()); - memcpy(clear_buffer.data(), inputs[1].data(), inputs[1].size()); + // Initialize clear and encrypted buffers. + const std::vector clear_buffer(inputs[1].data, + inputs[1].data + inputs[1].size); + std::vector encrypted_buffer(clear_buffer.size()); OEMCryptoLicenseAPIFuzz license_api_fuzz; Session* session = license_api_fuzz.session(); diff --git a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_generic_sign_fuzz.cc b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_generic_sign_fuzz.cc index d27415d1..93ff89c1 100644 --- a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_generic_sign_fuzz.cc +++ b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_generic_sign_fuzz.cc @@ -2,6 +2,7 @@ // source code may only be used and distributed under the Widevine // License Agreement. +#include "FuzzedDataProvider.h" #include "OEMCryptoCENC.h" #include "log.h" #include "oemcrypto_fuzz_helper.h" @@ -19,20 +20,15 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { return 0; } // Copy OEMCrypto_Generic_Api_Fuzz from input data. - memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure)); + FuzzedDataProvider fuzzed_data(data, size); + fuzzed_data.ConsumeData(&fuzzed_structure, sizeof(fuzzed_structure)); ConvertDataToValidEnum(OEMCrypto_CipherMode_MaxValue, &fuzzed_structure.cipher_mode); ConvertDataToValidEnum(OEMCrypto_Algorithm_MaxValue, &fuzzed_structure.algorithm); - - size_t clear_buffer_size = size - sizeof(fuzzed_structure); - if (clear_buffer_size == 0) { - return 0; - } // Copy clear buffer from input data. - vector clear_buffer(clear_buffer_size); - memcpy(clear_buffer.data(), data + sizeof(fuzzed_structure), - clear_buffer_size); + const std::vector clear_buffer = + fuzzed_data.ConsumeRemainingBytes(); OEMCryptoLicenseAPIFuzz license_api_fuzz; Session* session = license_api_fuzz.session(); @@ -46,7 +42,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { OEMCrypto_Generic_Sign(session->session_id(), clear_buffer.data(), clear_buffer.size(), fuzzed_structure.algorithm, nullptr, &signature_length); - vector signature(signature_length); + std::vector signature(signature_length); OEMCrypto_Generic_Sign(session->session_id(), clear_buffer.data(), clear_buffer.size(), fuzzed_structure.algorithm, signature.data(), &signature_length); diff --git a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_generic_verify_fuzz.cc b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_generic_verify_fuzz.cc index db858f55..6432eb86 100644 --- a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_generic_verify_fuzz.cc +++ b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_generic_verify_fuzz.cc @@ -2,66 +2,124 @@ // source code may only be used and distributed under the Widevine // License Agreement. -#include -#include - +#include "FuzzedDataProvider.h" #include "OEMCryptoCENC.h" -#include "log.h" #include "oemcrypto_fuzz_helper.h" #include "oemcrypto_fuzz_structs.h" #include "oemcrypto_types.h" namespace wvoec { -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - // Redirect printf and log statements from oemcrypto functions to a file to - // reduce noise - RedirectStdoutToFile(); - OEMCrypto_Generic_Verify_Fuzz fuzzed_structure; - if (size < sizeof(fuzzed_structure)) { - return 0; +// Properties deserialized from fuzzed data. +struct FuzzedProperties { + OEMCrypto_Generic_Api_Fuzz structure; + std::vector buffer; + std::vector signature; +}; + +// Contains value only if has_value is true. +struct OptionalFuzzedProperties { + FuzzedProperties value; + bool has_value; +}; + +OEMCryptoLicenseAPIFuzz license_api_fuzz; + +OptionalFuzzedProperties DeserializeFuzzedData(const uint8_t* data, + size_t size) { + OptionalFuzzedProperties fuzzed_properties; + const std::vector inputs = SplitFuzzedData(data, size); + if (inputs.size() < 2 || + inputs[0].size < sizeof(fuzzed_properties.value.structure)) { + fuzzed_properties.has_value = false; + return fuzzed_properties; } - // Copy OEMCrypto_Generic_Verify_Fuzz from input data. - memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure)); + FuzzedDataProvider fuzzed_data(inputs[0].data, inputs[0].size); + fuzzed_data.ConsumeData(&fuzzed_properties.value.structure, + sizeof(fuzzed_properties.value.structure)); ConvertDataToValidEnum(OEMCrypto_CipherMode_MaxValue, - &fuzzed_structure.cipher_mode); + &fuzzed_properties.value.structure.cipher_mode); ConvertDataToValidEnum(OEMCrypto_Algorithm_MaxValue, - &fuzzed_structure.algorithm); + &fuzzed_properties.value.structure.algorithm); + fuzzed_properties.value.buffer = fuzzed_data.ConsumeRemainingBytes(); + fuzzed_properties.value.signature.assign(inputs[1].data, + inputs[1].data + inputs[1].size); + fuzzed_properties.has_value = true; + return fuzzed_properties; +} - size_t in_buffer_size = size - sizeof(fuzzed_structure); - if (in_buffer_size == 0) { - return 0; - } - // Copy clear buffer from input data. - vector in_buffer(in_buffer_size); - memcpy(in_buffer.data(), data + sizeof(fuzzed_structure), in_buffer_size); - - OEMCryptoLicenseAPIFuzz license_api_fuzz; - Session* session = license_api_fuzz.session(); - // Load license and call generic_verify API. +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { + RedirectStdoutToFile(); license_api_fuzz.LoadLicense(); - OEMCrypto_SelectKey(session->session_id(), session->license().keys[0].key_id, - session->license().keys[0].key_id_length, - OEMCrypto_CipherMode_CENC); - // Calculate signature for in buffer. - size_t signature_length = 0; - OEMCrypto_Generic_Sign(session->session_id(), in_buffer.data(), - in_buffer.size(), fuzzed_structure.algorithm, nullptr, - &signature_length); - vector signature(signature_length); - OEMCrypto_Generic_Sign(session->session_id(), in_buffer.data(), - in_buffer.size(), fuzzed_structure.algorithm, - signature.data(), &signature_length); - - OEMCrypto_SelectKey(session->session_id(), session->license().keys[0].key_id, - session->license().keys[0].key_id_length, - fuzzed_structure.cipher_mode); - signature_length = - std::min(MAX_FUZZ_OUTPUT_LENGTH, fuzzed_structure.signature_length); - signature.resize(signature_length); - OEMCrypto_Generic_Verify(session->session_id(), in_buffer.data(), - in_buffer.size(), fuzzed_structure.algorithm, - signature.data(), signature_length); return 0; } + +extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size, + size_t max_size, unsigned int seed) { + // Deserialize fuzzed data. + OptionalFuzzedProperties fuzzed_properties = + DeserializeFuzzedData(data, size); + if (!fuzzed_properties.has_value) { + return 0; + } + + // Select key and perform verification. + Session* const session = license_api_fuzz.session(); + OEMCrypto_SelectKey(session->session_id(), session->license().keys[0].key_id, + session->license().keys[0].key_id_length, + fuzzed_properties.value.structure.cipher_mode); + if (OEMCrypto_Generic_Verify( + session->session_id(), fuzzed_properties.value.buffer.data(), + fuzzed_properties.value.buffer.size(), + fuzzed_properties.value.structure.algorithm, + fuzzed_properties.value.signature.data(), + fuzzed_properties.value.signature.size()) != OEMCrypto_SUCCESS) { + // Generate a new signature. + size_t signature_length = 0; + OEMCrypto_Generic_Sign(session->session_id(), + fuzzed_properties.value.buffer.data(), + fuzzed_properties.value.buffer.size(), + fuzzed_properties.value.structure.algorithm, nullptr, + &signature_length); + fuzzed_properties.value.signature.resize(signature_length); + OEMCrypto_Generic_Sign( + session->session_id(), fuzzed_properties.value.buffer.data(), + fuzzed_properties.value.buffer.size(), + fuzzed_properties.value.structure.algorithm, + fuzzed_properties.value.signature.data(), &signature_length); + const size_t signature_offset = sizeof(fuzzed_properties.value.structure) + + fuzzed_properties.value.buffer.size() + + sizeof(kFuzzDataSeparator); + size = signature_offset + signature_length; + if (size > max_size) { + return 0; + } + memcpy(data + signature_offset, fuzzed_properties.value.signature.data(), + signature_length); + } + return LLVMFuzzerMutate(data, size, max_size); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + // Deserialize fuzzed data. + const OptionalFuzzedProperties fuzzed_properties = + DeserializeFuzzedData(data, size); + if (!fuzzed_properties.has_value) { + return 0; + } + + // Select key and perform verification. + Session* const session = license_api_fuzz.session(); + OEMCrypto_SelectKey(session->session_id(), session->license().keys[0].key_id, + session->license().keys[0].key_id_length, + fuzzed_properties.value.structure.cipher_mode); + OEMCrypto_Generic_Verify(session->session_id(), + fuzzed_properties.value.buffer.data(), + fuzzed_properties.value.buffer.size(), + fuzzed_properties.value.structure.algorithm, + fuzzed_properties.value.signature.data(), + fuzzed_properties.value.signature.size()); + return 0; +} + } // namespace wvoec diff --git a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_load_entitled_content_keys_fuzz.cc b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_load_entitled_content_keys_fuzz.cc index fbb33e67..fcc53a0a 100644 --- a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_load_entitled_content_keys_fuzz.cc +++ b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_load_entitled_content_keys_fuzz.cc @@ -2,9 +2,7 @@ // source code may only be used and distributed under the Widevine // License Agreement. -#include "FuzzedDataProvider.h" #include "oemcrypto_fuzz_helper.h" -#include "oemcrypto_fuzz_structs.h" namespace wvoec { @@ -17,34 +15,18 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // message buffer with key data | entitled content key object array with // offsets and lengths to read key data from message buffer. // Split data using separator. - auto inputs = SplitInput(data, size); + const std::vector inputs = SplitFuzzedData(data, size); if (inputs.size() < 2) { return 0; } - FuzzedDataProvider fuzzed_entitled_content_key_array(inputs[1].data(), - inputs[1].size()); - - // Message to be verified. Return 0 if key data buffer is empty. - if (inputs[0].size() == 0) { - return 0; - } - // Copy data to OEMCrypto_EntitledContentKeyObject array. - size_t entitled_content_key_object_size = - sizeof(OEMCrypto_EntitledContentKeyObject); - size_t entitled_content_key_array_length = - fuzzed_entitled_content_key_array.remaining_bytes() / - entitled_content_key_object_size; - if (entitled_content_key_array_length == 0) { - return 0; - } - OEMCrypto_EntitledContentKeyObject* entitled_content_key_array = - new OEMCrypto_EntitledContentKeyObject[entitled_content_key_array_length]; - - for (size_t i = 0; i < entitled_content_key_array_length; i++) { - fuzzed_entitled_content_key_array.ConsumeData( - &entitled_content_key_array[i], entitled_content_key_object_size); + std::vector entitled_content_keys( + inputs[1].size / sizeof(OEMCrypto_EntitledContentKeyObject)); + if (!entitled_content_keys.empty()) { + memcpy(entitled_content_keys.data(), inputs[1].data, + entitled_content_keys.size() * + sizeof(OEMCrypto_EntitledContentKeyObject)); } OEMCryptoLicenseAPIFuzz license_api_fuzz; @@ -54,13 +36,12 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { OEMCrypto_EntitlementLicense); license_api_fuzz.LoadLicense(); // Call OEMCrypto_LoadEntitledContentKeys with fuzzed buffers. - Session* session = license_api_fuzz.session(); - uint8_t* fuzzed_key_data = inputs[0].data(); - size_t fuzzed_key_data_size = inputs[0].size(); + const std::vector message(inputs[0].data, + inputs[0].data + inputs[0].size); OEMCrypto_LoadEntitledContentKeys( - session->session_id(), fuzzed_key_data, fuzzed_key_data_size, - entitled_content_key_array_length, entitled_content_key_array); - delete[] entitled_content_key_array; + license_api_fuzz.session()->session_id(), message.data(), message.size(), + entitled_content_keys.size(), entitled_content_keys.data()); return 0; } + } // namespace wvoec diff --git a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_entry_fuzz.cc b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_entry_fuzz.cc index ed47b0b2..d95c7ad7 100644 --- a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_entry_fuzz.cc +++ b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_entry_fuzz.cc @@ -2,33 +2,50 @@ // source code may only be used and distributed under the Widevine Master // License Agreement. +#include "FuzzedDataProvider.h" #include "OEMCryptoCENC.h" #include "oemcrypto_fuzz_helper.h" namespace wvoec { -LicenseWithUsageEntryFuzz entry; + +OEMCryptoResult LoadUsageEntryWithFuzzedData(OEMCrypto_SESSION session, + const uint8_t* data, size_t size) { + if (size < sizeof(uint32_t)) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + FuzzedDataProvider fuzzed_data(data, size); + const uint32_t usage_entry_number = fuzzed_data.ConsumeIntegral(); + const std::vector buffer = + fuzzed_data.ConsumeRemainingBytes(); + return OEMCrypto_LoadUsageEntry(session, usage_entry_number, buffer.data(), + buffer.size()); +} + // The custom mutator to mutate created encrypted usage entry. extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size, size_t max_size, unsigned int seed) { + LicenseWithUsageEntryFuzz entry; entry.CreateUsageTableHeader(); Session* s = entry.license_messages().session(); s->open(); entry.InstallTestRSAKey(s); - uint32_t usage_entry_number = 0; - memcpy(&usage_entry_number, data, sizeof(uint32_t)); - if (OEMCrypto_LoadUsageEntry(s->session_id(), usage_entry_number, - data + sizeof(uint32_t), - size - sizeof(uint32_t)) != OEMCrypto_SUCCESS) { + if (LoadUsageEntryWithFuzzedData(s->session_id(), data, size) != + OEMCrypto_SUCCESS) { s->CreateNewUsageEntry(); - vector encrypted_usage_header; + std::vector encrypted_usage_header; s->UpdateUsageEntry(&encrypted_usage_header); - vector encrypted_usage_entry = s->encrypted_usage_entry(); - usage_entry_number = s->usage_entry_number(); + const uint32_t usage_entry_number = s->usage_entry_number(); + const std::vector& encrypted_usage_entry = + s->encrypted_usage_entry(); + size = sizeof(usage_entry_number) + encrypted_usage_entry.size(); + if (size > max_size) { + return 0; + } // Copy created usage entry number and usage entry to data and mutate it. - memcpy(data, &usage_entry_number, sizeof(uint32_t)); - memcpy(data + sizeof(uint32_t), encrypted_usage_entry.data(), + memcpy(data, &usage_entry_number, sizeof(usage_entry_number)); + memcpy(data + sizeof(usage_entry_number), encrypted_usage_entry.data(), encrypted_usage_entry.size()); - size = sizeof(uint32_t) + encrypted_usage_entry.size(); } s->close(); return LLVMFuzzerMutate(data, size, max_size); @@ -39,23 +56,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // reduce noise RedirectStdoutToFile(); - uint32_t usage_entry_number = 0; - if (size < sizeof(usage_entry_number)) { - return 0; - } - - memcpy(&usage_entry_number, data, sizeof(usage_entry_number)); - const uint8_t* extra_data = data + sizeof(usage_entry_number); - size_t extra_data_size = size - sizeof(usage_entry_number); - if (extra_data_size == 0) { - return 0; - } - Session s; s.open(); - OEMCrypto_LoadUsageEntry(s.session_id(), usage_entry_number, extra_data, - extra_data_size); + LoadUsageEntryWithFuzzedData(s.session_id(), data, size); s.close(); return 0; } + } // namespace wvoec diff --git a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_table_header_fuzz.cc b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_table_header_fuzz.cc index 8d3000af..19c699a3 100644 --- a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_table_header_fuzz.cc +++ b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_table_header_fuzz.cc @@ -13,13 +13,13 @@ extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size, LicenseWithUsageEntryFuzz entry; if (OEMCrypto_LoadUsageTableHeader(data, size) != OEMCrypto_SUCCESS) { entry.CreateUsageTableHeader(); - if (size < entry.encrypted_usage_header().size()) { + size = entry.encrypted_usage_header().size(); + if (size > max_size) { return 0; } // Copy created usage table header to data and mutate it. memcpy(data, entry.encrypted_usage_header().data(), entry.encrypted_usage_header().size()); - size = entry.encrypted_usage_header().size(); } return LLVMFuzzerMutate(data, size, max_size); } @@ -33,4 +33,5 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { OEMCrypto_LoadUsageTableHeader(data, size); return 0; } + } // namespace wvoec diff --git a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_opk_dispatcher_fuzz.cc b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_opk_dispatcher_fuzz.cc index 3fae8e6c..537e90ec 100644 --- a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_opk_dispatcher_fuzz.cc +++ b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_opk_dispatcher_fuzz.cc @@ -1,40 +1,38 @@ -#include -#include +#include #include "opk_dispatcher.h" #include "opk_init.h" -#include "tos_transport_interface.h" namespace wvoec { void OpenOEMCryptoTASession() { - ODK_Message request; - ODK_Message response; - uint8_t response_buffer[0x1000]; uint8_t request_body[] = { - 0x06, // TAG_UINT32 - 0x09, 0x00, 0x00, 0x00, // API value (0x09) - 0x01, // TAG_BOOL - 0x00, // value (false) - 0x0a // TAG_EOM + 0x06, // TAG_UINT32 + 0x09, 0x00, 0x00, 0x00, // API value (0x09) + 0x07, // TAG_UINT64 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Timestamp + 0x01, // TAG_BOOL + 0x00, // value (false) + 0x0a // TAG_EOM }; - request = ODK_Message_Create(request_body, sizeof(request_body)); + ODK_Message request = ODK_Message_Create(request_body, sizeof(request_body)); + ODK_Message_SetSize(&request, sizeof(request_body)); + ODK_Message response; OPK_DispatchMessage(&request, &response); } void InitializeOEMCryptoTA() { - ODK_Message init_request; - ODK_Message init_response; - uint8_t response_buffer[0x1000]; - uint8_t init_request_body[] = { - 0x06, // TAG_UINT32 - 0x01, 0x00, 0x00, 0x00, // API value(0x01) - 0x0a // TAG_EOM + uint8_t request_body[] = { + 0x06, // TAG_UINT32 + 0x01, 0x00, 0x00, 0x00, // API value (0x01) + 0x07, // TAG_UINT64 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Timestamp + 0x0a // TAG_EOM }; - - init_request = - ODK_Message_Create(init_request_body, sizeof(init_request_body)); - OPK_DispatchMessage(&init_request, &init_response); + ODK_Message request = ODK_Message_Create(request_body, sizeof(request_body)); + ODK_Message_SetSize(&request, sizeof(request_body)); + ODK_Message response; + OPK_DispatchMessage(&request, &response); } extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { @@ -45,17 +43,12 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { } extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - ODK_Message request; + std::vector request_body(data, data + size); + ODK_Message request = + ODK_Message_Create(request_body.data(), request_body.size()); + ODK_Message_SetSize(&request, request_body.size()); ODK_Message response; - unsigned char response_buffer[0x1000]; - - uint8_t* input = new uint8_t[size]; - memcpy(input, data, size); - - request = ODK_Message_Create(input, size); OPK_DispatchMessage(&request, &response); - - delete[] input; return 0; } diff --git a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_report_usage_fuzz.cc b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_report_usage_fuzz.cc index 03fcffda..077a7df1 100644 --- a/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_report_usage_fuzz.cc +++ b/libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_report_usage_fuzz.cc @@ -2,6 +2,7 @@ // source code may only be used and distributed under the Widevine Master // License Agreement. +#include "FuzzedDataProvider.h" #include "oemcrypto_fuzz_helper.h" namespace wvoec { @@ -11,8 +12,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // reduce noise RedirectStdoutToFile(); - size_t pst_buffer_length = 0; - if (size <= sizeof(pst_buffer_length)) { + if (size < sizeof(size_t)) { return 0; } @@ -29,17 +29,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // Sets pst for usage entry. entry.LoadLicense(); - memcpy(&pst_buffer_length, data, sizeof(pst_buffer_length)); - const uint8_t* extra_data = data + sizeof(pst_buffer_length); - size_t extra_data_size = size - sizeof(pst_buffer_length); - // We cannot allocate a huge buffer, hence limiting buffer size to - // MAX_FUZZ_PST_REPORT_BUFFER_LENGTH. - pst_buffer_length = - std::min(MAX_FUZZ_PST_REPORT_BUFFER_LENGTH, pst_buffer_length); - vector pst_report_buffer(pst_buffer_length); + FuzzedDataProvider fuzzed_data(data, size); + size_t pst_report_buffer_length = fuzzed_data.ConsumeIntegralInRange( + 0, MAX_FUZZ_PST_REPORT_BUFFER_LENGTH); + const std::vector pst = fuzzed_data.ConsumeRemainingBytes(); + std::vector pst_report_buffer(pst_report_buffer_length); // Call API with fuzzed pst_buffer_length, pst. - OEMCrypto_ReportUsage(session->session_id(), extra_data, extra_data_size, - pst_report_buffer.data(), &pst_buffer_length); + OEMCrypto_ReportUsage(session->session_id(), pst.data(), pst.size(), + pst_report_buffer.data(), &pst_report_buffer_length); session->close(); return 0; } diff --git a/libwvdrmengine/oemcrypto/test/oec_decrypt_fallback_chain.cpp b/libwvdrmengine/oemcrypto/test/oec_decrypt_fallback_chain.cpp index 8eebf9bc..cbf552bf 100644 --- a/libwvdrmengine/oemcrypto/test/oec_decrypt_fallback_chain.cpp +++ b/libwvdrmengine/oemcrypto/test/oec_decrypt_fallback_chain.cpp @@ -198,26 +198,64 @@ OEMCryptoResult DecryptFallbackChain::DecryptSubsampleHalf( // Used for OEMCrypto Fuzzing: Corpus format is as below, let | be separator. // cipher_mode + pattern + sample_data for all samples | -// subsample_data for all samples +// input_data for all samples | subsample_data for all samples void WriteDecryptCencCorpus( OEMCryptoCipherMode cipher_mode, const OEMCrypto_SampleDescription* samples_description, const OEMCrypto_CENCEncryptPatternDesc* pattern, size_t samples_length) { const std::string file_name = GetFileName("oemcrypto_decrypt_cenc_fuzz_seed_corpus"); + + // Cipher mode and Pattern. OEMCrypto_Decrypt_Cenc_Fuzz decrypt_cenc_fuzz_struct; decrypt_cenc_fuzz_struct.cipher_mode = cipher_mode; decrypt_cenc_fuzz_struct.pattern = *pattern; - // Cipher mode and Pattern. AppendToFile(file_name, reinterpret_cast(&decrypt_cenc_fuzz_struct), sizeof(OEMCrypto_Decrypt_Cenc_Fuzz)); // Sample data for all samples. for (size_t i = 0; i < samples_length; i++) { + OEMCrypto_SampleDescription_Fuzz sample_description_data; + sample_description_data.buffers.input_data_length = + samples_description[i].buffers.input_data_length; + sample_description_data.buffers.output_descriptor.type = + samples_description[i].buffers.output_descriptor.type; + switch (sample_description_data.buffers.output_descriptor.type) { + case OEMCrypto_BufferType_Clear: + sample_description_data.buffers.output_descriptor.buffer_config = + samples_description[i] + .buffers.output_descriptor.buffer.clear.clear_buffer_length; + break; + + case OEMCrypto_BufferType_Secure: + sample_description_data.buffers.output_descriptor.buffer_config = + samples_description[i] + .buffers.output_descriptor.buffer.secure.secure_buffer_length; + break; + + case OEMCrypto_BufferType_Direct: + sample_description_data.buffers.output_descriptor.buffer_config = + samples_description[i] + .buffers.output_descriptor.buffer.direct.is_video; + break; + } + memcpy(sample_description_data.iv, samples_description[i].iv, + sizeof(sample_description_data.iv)); + sample_description_data.subsamples_length = + samples_description[i].subsamples_length; AppendToFile(file_name, - reinterpret_cast(&samples_description[i]), - sizeof(OEMCrypto_SampleDescription)); + reinterpret_cast(&sample_description_data), + sizeof(OEMCrypto_SampleDescription_Fuzz)); + } + AppendSeparator(file_name); + + // Input data for all samples. + for (size_t i = 0; i < samples_length; i++) { + AppendToFile(file_name, + reinterpret_cast( + samples_description[i].buffers.input_data), + samples_description[i].buffers.input_data_length); } AppendSeparator(file_name); diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp index 985484a7..c8312733 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp @@ -228,11 +228,29 @@ class OEMCryptoClientTest : public ::testing::Test, public SessionUtil { uint8_t subsample_flags) { if (ShouldGenerateCorpus() && input_buffer != nullptr && dest_buffer_descriptor != nullptr) { - OEMCrypto_Copy_Buffer_Fuzz fuzzed_structure; - fuzzed_structure.dest_buffer_desc = *dest_buffer_descriptor; - fuzzed_structure.subsample_flags = subsample_flags; const std::string file_name = GetFileName("oemcrypto_copy_buffer_fuzz_seed_corpus"); + + OEMCrypto_Copy_Buffer_Fuzz fuzzed_structure; + fuzzed_structure.dest_buffer_desc.type = dest_buffer_descriptor->type; + switch (fuzzed_structure.dest_buffer_desc.type) { + case OEMCrypto_BufferType_Clear: + fuzzed_structure.dest_buffer_desc.buffer_config = + dest_buffer_descriptor->buffer.clear.clear_buffer_length; + break; + + case OEMCrypto_BufferType_Secure: + fuzzed_structure.dest_buffer_desc.buffer_config = + dest_buffer_descriptor->buffer.secure.secure_buffer_length; + break; + + case OEMCrypto_BufferType_Direct: + fuzzed_structure.dest_buffer_desc.buffer_config = + dest_buffer_descriptor->buffer.direct.is_video; + break; + } + fuzzed_structure.subsample_flags = subsample_flags; + // Corpus for copy buffer fuzzer should be in the format: // (dest_buffer_descriptor | subsample_flags | input_buffer). AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), @@ -7513,15 +7531,17 @@ class OEMCryptoGenericCryptoTest : public OEMCryptoRefreshTest { if (ShouldGenerateCorpus()) { const std::string file_name = GetFileName("oemcrypto_generic_verify_fuzz_seed_corpus"); - OEMCrypto_Generic_Verify_Fuzz fuzzed_structure; + OEMCrypto_Generic_Api_Fuzz fuzzed_structure; fuzzed_structure.cipher_mode = OEMCrypto_CipherMode_CENC; fuzzed_structure.algorithm = algorithm; - fuzzed_structure.signature_length = signature_length; // Cipher mode and algorithm. AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), sizeof(fuzzed_structure)); AppendToFile(file_name, reinterpret_cast(clear_buffer), clear_buffer_length); + AppendSeparator(file_name); + AppendToFile(file_name, reinterpret_cast(signature), + signature_length); } return OEMCrypto_Generic_Verify(session, clear_buffer, clear_buffer_length, algorithm, signature, signature_length);