Pick widevine oemcrypto-v18 change

No-Typo-Check: From a third party header file
Bug: 260918793
Test: unit tests
Test: atp v2/widevine-eng/drm_compliance
Change-Id: I36effd6a10a99bdb2399ab1f4a0fad026d607c70
This commit is contained in:
Kyle Zhang
2022-12-16 03:21:08 +00:00
parent 4586522c07
commit 11255b7426
105 changed files with 324641 additions and 299787 deletions

View File

@@ -23,7 +23,7 @@ OEMCrypto implementations on linux.
The options to select are `Job type: libfuzzer_asan_oemcrypto` and `Fuzzer:
fuzzer name you are looking for`
Example: [load_license_fuzz](https://clusterfuzz.corp.google.com/fuzzer-stats?group_by=by-day&date_start=2020-07-11&date_end=2020-07-17&fuzzer=libFuzzer_oemcrypto_load_license_fuzz&job=libfuzzer_asan_oemcrypto)
Example: [load_license_fuzz](https://clusterfuzz.corp.google.com/fuzzer-stats?group_by=by-day&date_start=2022-07-11&date_end=2022-07-17&fuzzer=libFuzzer_oemcrypto_load_license_fuzz&job=libfuzzer_asan_oemcrypto)
### Issues filed by clusterfuzz - Fixing those issues
@@ -127,8 +127,7 @@ OEMCrypto implementations on linux.
information locally.
* Build and test fuzz scripts locally using following commands. The build
script builds fuzz binaries for both oemcrypto reference implementation
as well as opk implementation.
script builds fuzz binaries for opk implementation.
```shell
$ cd PATH_TO_CDM_DIR

View File

@@ -6,18 +6,21 @@
set -ex
# CDM_DIR is used by several script, especially when there is some confusion
if [ -z "$CDM_DIR" ]; then
export CDM_DIR="$(readlink -e $(dirname $0)/../../..)"
fi
cd $CDM_DIR
export CXX=clang++
export CC=clang
export GYP_DEFINES="$GYP_DEFINES clang=1"
export PATH_TO_CDM_DIR=.
export PYTHONPATH="$PYTHONPATH:$PATH_TO_CDM_DIR/third_party"
echo "CDM_DIR = $CDM_DIR"
export PYTHONPATH="$PYTHONPATH:$CDM_DIR/third_party"
python3 $PATH_TO_CDM_DIR/third_party/gyp/__init__.py --format=ninja \
--depth=$(pwd) oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp
ninja -C out/Default
# oemcrypto_opk_fuzztests.gypi has flags to instrument all the gyp targets
# with fuzzer flags.
python3 $PATH_TO_CDM_DIR/third_party/gyp/__init__.py --format=ninja \
python3 $CDM_DIR/third_party/gyp/__init__.py --format=ninja \
--depth=$(pwd) \
--include=oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gypi \
oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gyp

View File

@@ -2,93 +2,82 @@
// 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
// reduce noise
RedirectStdoutToFile();
uint8_t subsample_flags;
// 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)
if (size <= sizeof(OEMCrypto_Copy_Buffer_Fuzz)) {
OEMCrypto_Copy_Buffer_Fuzz fuzzed_structure;
if (size < sizeof(fuzzed_structure)) {
return 0;
}
OEMCrypto_Copy_Buffer_Fuzz fuzzed_structure;
// Fuzz dest_buffer_desc.
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<OEMCrypto_SharedMemory> input_buffer =
fuzzed_data.ConsumeRemainingBytes<OEMCrypto_SharedMemory>();
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,
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
} // namespace wvoec

View File

@@ -15,7 +15,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Open a session, create a usage entry.
Session* session = entry.license_messages().session();
session->open();
entry.InstallTestRSAKey(session);
entry.InstallTestDrmKey(session);
session->CreateNewUsageEntry();
session->GenerateNonce();
vector<uint8_t> encrypted_usage_header;

View File

@@ -4,187 +4,169 @@
#include "FuzzedDataProvider.h"
#include "OEMCryptoCENC.h"
#include "log.h"
#include "oec_session_util.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<int>& 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<FuzzedData> 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<OEMCrypto_SampleDescription> sample_descriptions(
fuzzed_data.remaining_bytes() / sizeof(OEMCrypto_SampleDescription_Fuzz));
// Read subsamples from fuzzed data.
vector<OEMCrypto_SubSampleDescription> 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<std::vector<OEMCrypto_SharedMemory>> 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<int> secure_fd_array(sample_descriptions.size());
// Initialize sample_descriptions array.
vector<OEMCrypto_SampleDescription> sample_descriptions(samples_length);
// Create array to maintain secure_fd buffer values for secure buffers.
vector<int> secure_fd_array(samples_length);
// Allocate subsamples for each sample description.
std::vector<std::vector<OEMCrypto_SubSampleDescription>> 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<uint8_t>(
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<OEMCrypto_SharedMemory> input_buffer(total_input_data_length);
size_t input_buffer_index = 0;
for (size_t i = 0; i < samples_length; i++) {
if (total_input_data_length > 0) {
sample_descriptions[i].buffers.input_data =
&input_buffer[input_buffer_index];
// Set subsample data.
if (fuzzed_sample_description.subsamples_length >
subsample_data.remaining_bytes() /
sizeof(OEMCrypto_SubSampleDescription)) {
FreeOutputBuffers(i);
return 0;
}
input_buffer_index += std::min(
MAX_FUZZ_SAMPLE_SIZE, sample_descriptions[i].buffers.input_data_length);
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,
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());
const MessageKeyData& key = license_api_fuzz.session()->license().keys[0];
vector<uint8_t> key_handle;
GetKeyHandleIntoVector(session_id, key.key_id, key.key_id_length,
fuzzed_structure.cipher_mode, key_handle);
OEMCrypto_DecryptCENC(key_handle.data(), key_handle.size(),
sample_descriptions.data(), sample_descriptions.size(),
&fuzzed_structure.pattern);
// Free all output buffers.
FreeOutputBuffers(sample_descriptions.size());
return 0;
}
} // namespace wvoec

View File

@@ -6,19 +6,18 @@
namespace wvoec {
void RedirectStdoutToFile() { freopen("log.txt", "a", stdout); }
std::vector<std::vector<uint8_t>> SplitInput(const uint8_t* data, size_t size) {
std::vector<std::vector<uint8_t>> result;
auto current_pos = data;
auto end = data + size;
// Using memmem to find separator
while (const uint8_t* pos = reinterpret_cast<const uint8_t*>(
memmem(current_pos, end - current_pos, kFuzzDataSeparator,
sizeof(kFuzzDataSeparator)))) {
result.push_back({current_pos, pos});
current_pos = pos + sizeof(kFuzzDataSeparator);
std::vector<FuzzedData> SplitFuzzedData(const uint8_t* data, size_t size) {
std::vector<FuzzedData> result;
const uint8_t* const end = data + size;
// Using memmem to find separator.
while (
const uint8_t* const separator = reinterpret_cast<const uint8_t*>(memmem(
data, end - data, kFuzzDataSeparator, sizeof(kFuzzDataSeparator)))) {
result.push_back({data, static_cast<size_t>(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<size_t>(end - data)});
}
return result;
}

View File

@@ -20,9 +20,16 @@ extern "C" size_t LLVMFuzzerMutate(uint8_t* Data, size_t Size, size_t MaxSize)
__attribute__((weak));
const size_t KB = 1024;
// Maximum signature length. If fuzzed signature length is greater that this,
// this value will be used for signature length.
const size_t MAX_FUZZ_SIGNATURE_LENGTH = 5 * KB;
// 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.
@@ -32,7 +39,8 @@ class InitializeFuzz : public SessionUtil {
wvoec::global_features.Initialize();
OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox));
OEMCrypto_Initialize();
EnsureTestKeys();
OEMCrypto_EnterTestMode();
EnsureTestROT();
}
~InitializeFuzz() { OEMCrypto_Terminate(); }
@@ -42,7 +50,7 @@ class OEMCryptoLicenseAPIFuzz : public InitializeFuzz {
public:
OEMCryptoLicenseAPIFuzz() : license_messages_(&session_) {
session_.open();
InstallTestRSAKey(&session_);
InstallTestDrmKey(&session_);
session_.GenerateNonce();
}
@@ -113,20 +121,27 @@ class LicenseWithUsageEntryFuzz : public InitializeFuzz {
Session session_;
};
// Convert data to valid enum value.
// Convert data from FuzzedDataProvider to valid enum value.
template <typename T>
T ConvertDataToValidEnum(FuzzedDataProvider& fuzzed_data, T max_enum_value) {
return static_cast<T>(fuzzed_data.ConsumeIntegralInRange<uint32_t>(
0, static_cast<uint32_t>(max_enum_value)));
}
// Convert data to valid enum value in place.
template <typename T>
void ConvertDataToValidEnum(T max_enum_value, T* t) {
FuzzedDataProvider fuzzed_enum_data(reinterpret_cast<uint8_t*>(t), sizeof(T));
*t = static_cast<T>(fuzzed_enum_data.ConsumeIntegralInRange<uint32_t>(
0, static_cast<uint32_t>(max_enum_value)));
*t = ConvertDataToValidEnum(fuzzed_enum_data, max_enum_value);
}
// Redirect printf and log statements from oemcrypto functions to a file to
// reduce noise
void RedirectStdoutToFile();
// Function to split fuzzer input using delimiter "-_^_".
std::vector<std::vector<uint8_t>> SplitInput(const uint8_t* data, size_t size);
// Split fuzzed data using delimiter "-_^_".
std::vector<FuzzedData> 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,

View File

@@ -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_
#endif // OEMCRYPTO_FUZZ_STRUCTS_H_

View File

@@ -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<uint8_t> message =
fuzzed_data.ConsumeRemainingBytes<uint8_t>();
// 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_SIGNATURE_LENGTH, fuzzed_structure.signature_length);
vector<uint8_t> signature(signature_length);
fuzzed_structure.signature_length %= MAX_FUZZ_OUTPUT_LENGTH + 1;
std::vector<uint8_t> 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;
}

View File

@@ -15,7 +15,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
}
OEMCrypto_Initialize();
session_helper.EnsureTestKeys();
OEMCrypto_EnterTestMode();
session_helper.EnsureTestROT();
Session s;
s.open();

View File

@@ -5,6 +5,7 @@
#include "FuzzedDataProvider.h"
#include "OEMCryptoCENC.h"
#include "log.h"
#include "oec_session_util.h"
#include "oemcrypto_fuzz_helper.h"
#include "oemcrypto_fuzz_structs.h"
#include "oemcrypto_types.h"
@@ -16,45 +17,43 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
RedirectStdoutToFile();
// Split data using separator.
auto inputs = SplitInput(data, size);
const std::vector<FuzzedData> 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<uint8_t> iv(iv_size);
memcpy(iv.data(), data + sizeof(fuzzed_structure), iv_size);
const std::vector<uint8_t> iv = fuzzed_data.ConsumeRemainingBytes<uint8_t>();
// Copy clear buffer from input data.
vector<uint8_t> encrypted_buffer(inputs[1].size());
vector<uint8_t> clear_buffer(inputs[1].size());
memcpy(encrypted_buffer.data(), inputs[1].data(), inputs[1].size());
// Initialize encrypted and clear buffers.
const std::vector<uint8_t> encrypted_buffer(inputs[1].data,
inputs[1].data + inputs[1].size);
std::vector<uint8_t> clear_buffer(encrypted_buffer.size());
OEMCryptoLicenseAPIFuzz license_api_fuzz;
Session* session = license_api_fuzz.session();
// Load license and call generic_decrypt API.
license_api_fuzz.LoadLicense();
OEMCrypto_SelectKey(session->session_id(), session->license().keys[0].key_id,
session->license().keys[0].key_id_length,
fuzzed_structure.cipher_mode);
OEMCrypto_Generic_Decrypt(session->session_id(), encrypted_buffer.data(),
encrypted_buffer.size(), iv.data(),
fuzzed_structure.algorithm, clear_buffer.data());
vector<uint8_t> key_handle;
GetKeyHandleIntoVector(session->session_id(),
session->license().keys[0].key_id,
session->license().keys[0].key_id_length,
fuzzed_structure.cipher_mode, key_handle);
OEMCrypto_Generic_Decrypt(key_handle.data(), key_handle.size(),
encrypted_buffer.data(), encrypted_buffer.size(),
iv.data(), fuzzed_structure.algorithm,
clear_buffer.data());
return 0;
}
} // namespace wvoec

View File

@@ -5,6 +5,7 @@
#include "FuzzedDataProvider.h"
#include "OEMCryptoCENC.h"
#include "log.h"
#include "oec_session_util.h"
#include "oemcrypto_fuzz_helper.h"
#include "oemcrypto_fuzz_structs.h"
#include "oemcrypto_types.h"
@@ -16,45 +17,43 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
RedirectStdoutToFile();
// Split data using separator.
auto inputs = SplitInput(data, size);
const std::vector<FuzzedData> 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<uint8_t> iv(iv_size);
memcpy(iv.data(), data + sizeof(fuzzed_structure), iv_size);
const std::vector<uint8_t> iv = fuzzed_data.ConsumeRemainingBytes<uint8_t>();
// Copy clear buffer from input data.
vector<uint8_t> clear_buffer(inputs[1].size());
vector<uint8_t> encrypted_buffer(inputs[1].size());
memcpy(clear_buffer.data(), inputs[1].data(), inputs[1].size());
// Initialize clear and encrypted buffers.
const std::vector<uint8_t> clear_buffer(inputs[1].data,
inputs[1].data + inputs[1].size);
std::vector<uint8_t> encrypted_buffer(clear_buffer.size());
OEMCryptoLicenseAPIFuzz license_api_fuzz;
Session* session = license_api_fuzz.session();
// Load license and call generic_encrypt API.
license_api_fuzz.LoadLicense();
OEMCrypto_SelectKey(session->session_id(), session->license().keys[0].key_id,
session->license().keys[0].key_id_length,
fuzzed_structure.cipher_mode);
OEMCrypto_Generic_Encrypt(
session->session_id(), clear_buffer.data(), clear_buffer.size(),
iv.data(), fuzzed_structure.algorithm, encrypted_buffer.data());
vector<uint8_t> key_handle;
GetKeyHandleIntoVector(session->session_id(),
session->license().keys[0].key_id,
session->license().keys[0].key_id_length,
fuzzed_structure.cipher_mode, key_handle);
OEMCrypto_Generic_Encrypt(key_handle.data(), key_handle.size(),
clear_buffer.data(), clear_buffer.size(), iv.data(),
fuzzed_structure.algorithm,
encrypted_buffer.data());
return 0;
}
} // namespace wvoec

View File

@@ -2,8 +2,10 @@
// source code may only be used and distributed under the Widevine
// License Agreement.
#include "FuzzedDataProvider.h"
#include "OEMCryptoCENC.h"
#include "log.h"
#include "oec_session_util.h"
#include "oemcrypto_fuzz_helper.h"
#include "oemcrypto_fuzz_structs.h"
#include "oemcrypto_types.h"
@@ -19,36 +21,35 @@ 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<uint8_t> clear_buffer(clear_buffer_size);
memcpy(clear_buffer.data(), data + sizeof(fuzzed_structure),
clear_buffer_size);
const std::vector<uint8_t> clear_buffer =
fuzzed_data.ConsumeRemainingBytes<uint8_t>();
OEMCryptoLicenseAPIFuzz license_api_fuzz;
Session* session = license_api_fuzz.session();
// Load license and call generic_sign API.
license_api_fuzz.LoadLicense();
OEMCrypto_SelectKey(session->session_id(), session->license().keys[0].key_id,
session->license().keys[0].key_id_length,
fuzzed_structure.cipher_mode);
vector<uint8_t> key_handle;
GetKeyHandleIntoVector(session->session_id(),
session->license().keys[0].key_id,
session->license().keys[0].key_id_length,
fuzzed_structure.cipher_mode, key_handle);
size_t signature_length = 0;
OEMCrypto_Generic_Sign(session->session_id(), clear_buffer.data(),
clear_buffer.size(), fuzzed_structure.algorithm,
nullptr, &signature_length);
vector<uint8_t> signature(signature_length);
OEMCrypto_Generic_Sign(session->session_id(), clear_buffer.data(),
clear_buffer.size(), fuzzed_structure.algorithm,
signature.data(), &signature_length);
OEMCrypto_Generic_Sign(key_handle.data(), key_handle.size(),
clear_buffer.data(), clear_buffer.size(),
fuzzed_structure.algorithm, nullptr,
&signature_length);
std::vector<uint8_t> signature(signature_length);
OEMCrypto_Generic_Sign(key_handle.data(), key_handle.size(),
clear_buffer.data(), clear_buffer.size(),
fuzzed_structure.algorithm, signature.data(),
&signature_length);
return 0;
}
} // namespace wvoec

View File

@@ -2,66 +2,130 @@
// source code may only be used and distributed under the Widevine
// License Agreement.
#include <openssl/hmac.h>
#include <openssl/sha.h>
#include "FuzzedDataProvider.h"
#include "OEMCryptoCENC.h"
#include "log.h"
#include "oec_session_util.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<uint8_t> buffer;
std::vector<uint8_t> 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<FuzzedData> 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<uint8_t>();
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<uint8_t> 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<uint8_t> 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_SIGNATURE_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();
vector<uint8_t> key_handle;
GetKeyHandleIntoVector(
session->session_id(), session->license().keys[0].key_id,
session->license().keys[0].key_id_length,
fuzzed_properties.value.structure.cipher_mode, key_handle);
if (OEMCrypto_Generic_Verify(key_handle.data(), key_handle.size(),
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(key_handle.data(), key_handle.size(),
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(key_handle.data(), key_handle.size(),
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();
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();
vector<uint8_t> key_handle;
GetKeyHandleIntoVector(
session->session_id(), session->license().keys[0].key_id,
session->license().keys[0].key_id_length,
fuzzed_properties.value.structure.cipher_mode, key_handle);
OEMCrypto_Generic_Verify(key_handle.data(), key_handle.size(),
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

View File

@@ -1,3 +1,8 @@
// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
#include "FuzzedDataProvider.h"
#include "OEMCryptoCENC.h"
#include "oemcrypto_fuzz_helper.h"
@@ -7,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(OEMCrypto_PrivateKeyType)) {
return 0;
}
@@ -17,17 +21,21 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Open a session, create a usage entry.
Session* session = entry.license_messages().session();
session->open();
entry.InstallTestRSAKey(session);
entry.InstallTestDrmKey(session);
session->GenerateNonce();
session->CreateNewUsageEntry();
vector<uint8_t> encrypted_usage_header;
std::vector<uint8_t> encrypted_usage_header;
session->UpdateUsageEntry(&encrypted_usage_header);
std::vector<uint8_t> wrapped_private_key(size);
memcpy(wrapped_private_key.data(), data, size);
OEMCrypto_PrivateKeyType key_type = OEMCrypto_RSA_Private_Key;
OEMCrypto_InstallOemPrivateKey(session->session_id(), key_type, wrapped_private_key.data(), size);
FuzzedDataProvider fuzzed_data(data, size);
const OEMCrypto_PrivateKeyType key_type =
ConvertDataToValidEnum(fuzzed_data, OEMCrypto_PrivateKeyType_MaxValue);
const std::vector<uint8_t> wrapped_private_key =
fuzzed_data.ConsumeRemainingBytes<uint8_t>();
OEMCrypto_InstallOemPrivateKey(session->session_id(), key_type,
wrapped_private_key.data(),
wrapped_private_key.size());
session->close();
return 0;
}
}
} // namespace wvoec

View File

@@ -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<FuzzedData> 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<OEMCrypto_EntitledContentKeyObject> 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<uint8_t> 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

View File

@@ -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<uint32_t>();
const std::vector<uint8_t> buffer =
fuzzed_data.ConsumeRemainingBytes<uint8_t>();
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) {
entry.InstallTestDrmKey(s);
if (LoadUsageEntryWithFuzzedData(s->session_id(), data, size) !=
OEMCrypto_SUCCESS) {
s->CreateNewUsageEntry();
vector<uint8_t> encrypted_usage_header;
std::vector<uint8_t> encrypted_usage_header;
s->UpdateUsageEntry(&encrypted_usage_header);
vector<uint8_t> 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<uint8_t>& 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

View File

@@ -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

View File

@@ -20,14 +20,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
entry.CreateUsageTableHeader();
Session* s = entry.license_messages().session();
s->open();
entry.InstallTestRSAKey(s);
entry.InstallTestDrmKey(s);
memcpy(&usage_entry_number, data, sizeof(uint32_t));
s->CreateNewUsageEntry();
vector<uint8_t> encrypted_usage_header;
s->UpdateUsageEntry(&encrypted_usage_header);
OEMCrypto_MoveEntry(s->session_id(), usage_entry_number);
s ->close();
return 0;
}
} // namespace wvoec

View File

@@ -1,40 +1,38 @@
#include <stdio.h>
#include <string.h>
#include <vector>
#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<uint8_t> 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;
}

View File

@@ -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;
}
@@ -21,7 +21,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Open a session, create a usage entry.
Session* session = entry.license_messages().session();
session->open();
entry.InstallTestRSAKey(session);
entry.InstallTestDrmKey(session);
session->CreateNewUsageEntry();
session->GenerateNonce();
vector<uint8_t> encrypted_usage_header;
@@ -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<uint8_t> pst_report_buffer(pst_buffer_length);
FuzzedDataProvider fuzzed_data(data, size);
size_t pst_report_buffer_length = fuzzed_data.ConsumeIntegralInRange<size_t>(
0, MAX_FUZZ_PST_REPORT_BUFFER_LENGTH);
const std::vector<uint8_t> pst = fuzzed_data.ConsumeRemainingBytes<uint8_t>();
std::vector<uint8_t> 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;
}

View File

@@ -20,7 +20,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
entry.CreateUsageTableHeader();
Session* s = entry.license_messages().session();
s->open();
entry.InstallTestRSAKey(s);
entry.InstallTestDrmKey(s);
s->CreateNewUsageEntry();
s->close();
s->open();

View File

@@ -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,15 +12,17 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// reduce noise
RedirectStdoutToFile();
if (size < sizeof(uint32_t)) {
if (size < sizeof(uint32_t) + sizeof(size_t)) {
return 0;
}
LicenseWithUsageEntryFuzz entry;
uint32_t new_entry_count = 0;
memcpy(&new_entry_count, data, sizeof(uint32_t));
std::vector<uint8_t> header_buffer(size - sizeof(uint32_t));
size_t header_buffer_length = header_buffer.size();
entry.CreateUsageTableHeader();
FuzzedDataProvider fuzzed_data(data, size);
const uint32_t new_entry_count = fuzzed_data.ConsumeIntegral<uint32_t>();
size_t header_buffer_length =
fuzzed_data.ConsumeIntegralInRange<size_t>(0, MAX_FUZZ_OUTPUT_LENGTH);
std::vector<uint8_t> header_buffer(header_buffer_length);
OEMCrypto_ShrinkUsageTableHeader(new_entry_count, header_buffer.data(),
&header_buffer_length);