Merge recent doc changes for OEMCrypto
This is a cherry pick of recent changes to OEMCrypto and ODK. Most of these are part of the document migration to doxygen. See http://go/wvgerrit/106005 and its parents for code reviews. Bug: 144715340 Bug: 148232693 Bug: 167580674 Change-Id: I658f99c8117b974faed97322d61fac0f382283af
This commit is contained in:
247
libwvdrmengine/oemcrypto/test/fuzz_tests/README.md
Normal file
247
libwvdrmengine/oemcrypto/test/fuzz_tests/README.md
Normal file
@@ -0,0 +1,247 @@
|
||||
# OEMCRYPTO Fuzzing
|
||||
|
||||
## Objective
|
||||
|
||||
* Run fuzzing on OEMCrypto public APIs on linux using google supported
|
||||
clusterfuzz infrastructure to find security vulnerabilities.
|
||||
|
||||
Design Document - https://docs.google.com/document/d/1mdSV2irJZz5Y9uYb5DmSIddBjrAIZU9q8G5Q_BGpA4I/edit?usp=sharing
|
||||
|
||||
Fuzzing at google -
|
||||
[go/fuzzing](https://g3doc.corp.google.com/security/fuzzing/g3doc/fuzzing_resources.md?cl=head)
|
||||
## Monitoring
|
||||
### Cluster fuzz statistics
|
||||
|
||||
* Performance of OEMCrypto fuzz binaries running continuously using cluster
|
||||
fuzz infrastructure can be monitored
|
||||
[here](https://clusterfuzz.corp.google.com/fuzzer-stats).
|
||||
|
||||
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)
|
||||
|
||||
### Issues filed by clusterfuzz - Fixing those issues
|
||||
|
||||
* Any issues found with the fuzz target under test are reported by clusterfuzz
|
||||
[here](https://b.corp.google.com/hotlists/2442954).
|
||||
|
||||
* The bug will have a link to the test case that generated the bug. Download
|
||||
the test case and follow the steps from
|
||||
[testing fuzzer locally](#testing-fuzzer-locally) section to run the fuzzer
|
||||
locally using the test case that caused the crash.
|
||||
|
||||
* Once the issue is fixed, consider adding the test case that caused the crash
|
||||
to the seed corpus zip file. Details about seed corpus and their location
|
||||
are mentioned in
|
||||
[this section](#build-oemcrypto-unit-tests-to-generate-corpus).
|
||||
|
||||
## Corpus
|
||||
|
||||
* Once the fuzzer scripts are ready and running continuously using clusterfuzz
|
||||
or android infrastructure, we can measure the efficiency of fuzzers by
|
||||
looking at code coverage and number of new features that have been
|
||||
discovered by fuzzer scripts here Fuzz script statistics.
|
||||
|
||||
A fuzzer which tries to start from random inputs and figure out intelligent
|
||||
inputs to crash the libraries can be time consuming and not effective. A way
|
||||
to make fuzzers more effective is by providing a set of valid and invalid
|
||||
inputs of the library so that fuzzer can use those as a starting point.
|
||||
These sets of valid and invalid inputs are called corpus.
|
||||
|
||||
The idea is to run OEMCrypto unit tests and read required data into binary
|
||||
corpus files before calling into respective OEMCrypto APIs under test.
|
||||
Writing corpus data to binary files is controlled by --generate_corpus flag.
|
||||
|
||||
### Build OEMCrypto unit tests to generate corpus
|
||||
|
||||
* Install Pre-requisites
|
||||
|
||||
```shell
|
||||
$ sudo apt-get install gyp ninja-build
|
||||
```
|
||||
|
||||
* download cdm source code (including ODK & OEMCrypto unit tests):
|
||||
|
||||
```shell
|
||||
$ git clone sso://widevine-internal/cdm
|
||||
```
|
||||
|
||||
* Build OEMCrypto unit tests and run with --generate_corpus flag to generate
|
||||
corpus files:
|
||||
|
||||
```shell
|
||||
$ cd /path/to/cdm/repo
|
||||
$ export CDM_DIR=/path/to/cdm/repo
|
||||
$ export PATH_TO_CDM_DIR=..
|
||||
$ gyp --format=ninja --depth=$(pwd) oemcrypto/oemcrypto_unittests.gyp
|
||||
$ ninja -C out/Default/
|
||||
$ ./out/Default/oemcrypto_unittests --generate_corpus
|
||||
```
|
||||
|
||||
* To avoid uploading huge binary files to git repository, the corpus files
|
||||
will be saved in fuzzername_seed_corpus.zip format in blockbuster project's
|
||||
oemcrypto_fuzzing_corpus GCS bucket using gsutil. If you need permissions
|
||||
for blockbuster project, contact widevine-engprod@google.com.
|
||||
|
||||
```shell
|
||||
$ gsutil cp gs://oemcrypto_fuzzing_corpus/<fuzzername_seed_corpus.zip> \
|
||||
<destination_path>
|
||||
```
|
||||
|
||||
## Testing fuzzer locally
|
||||
|
||||
* Corpus needed to run fuzz tests locally are available in blockbuster
|
||||
project's oemcrypto_fuzzing_corpus GCS bucket. If you need permissions for
|
||||
this project, contact widevine-engprod@google.com. Download corpus.
|
||||
|
||||
```shell
|
||||
$ gsutil cp gs://oemcrypto_fuzzing_corpus/<fuzzername_seed_corpus.zip> \
|
||||
<destination_path>
|
||||
```
|
||||
|
||||
* Add flags to generate additional debugging information. Add '-g3' flag to
|
||||
oemcrypto_fuzztests.gypi cflags_cc in order to generate additional debug
|
||||
information locally.
|
||||
|
||||
* Build and test fuzz scripts locally using:
|
||||
|
||||
```shell
|
||||
$ export CXX=clang++
|
||||
$ export CC=clang
|
||||
$ export GYP_DEFINES="clang=1"
|
||||
$ cd /path/to/cdm/repo
|
||||
$ export PATH_TO_CDM_DIR=.
|
||||
$ gyp --format=ninja --depth=$(pwd) \
|
||||
oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp
|
||||
$ ninja -C out/Default/
|
||||
$ mkdir /tmp/new_interesting_corpus
|
||||
$ ./out/Default/fuzzer_binary /tmp/new_interesting_corpus \
|
||||
/path/to/fuzz/seed/corpus/folder
|
||||
```
|
||||
|
||||
* In order to run fuzz script against a crash input, follow the above steps
|
||||
and run the fuzz binary against crash input rather than seed corpus.
|
||||
|
||||
```shell
|
||||
$ ./out/Default/fuzzer_binary crash_input_file
|
||||
```
|
||||
## Adding a new OEMCrypto fuzz script
|
||||
* In order to fuzz a new OEMCrypto API in future, a fuzz script can be added to
|
||||
oemcrypto/test/fuzz_tests folder which ends with _fuzz.cc.
|
||||
|
||||
* In the program, define the function LLVMFuzzerTestOneInput with the following signature:
|
||||
```
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
<your test code goes here>
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
*Note*: Make sure LLVMFuzzerTestOneInput calls the function you want to fuzz.
|
||||
|
||||
* Add a new target to oemcrypto_fuzztests.gyp file and follow instructions in
|
||||
[testing fuzzer locally](#testing-fuzzer-locally) to build and test locally.
|
||||
|
||||
## Building OEMCrypto fuzz scripts and uploading them to Google Cloud Storage:
|
||||
|
||||
* We are using Google Cloud Buid (GCB) in order to setup continuous
|
||||
integration which uploads OEMCrypto fuzz binaries to Google Cloud Storage.
|
||||
GCB expects build script in form of a docker image that is uploaded to
|
||||
Google Container Registry(GCR).
|
||||
|
||||
The cloud build scripts (docker images) for widevine projects are
|
||||
[here](https://widevine-internal.googlesource.com/cloud/+/refs/heads/master/docker/README.md)
|
||||
|
||||
Refer to README of the project to setup a new docker image and uploading
|
||||
the image to GCR.
|
||||
|
||||
* Git on borg repository needs to be integrated with GCB and a git trigger
|
||||
needs to be set up in order to achieve continuous integration. Git trigger
|
||||
will mention which docker image the GCB needs to use in order to build fuzz
|
||||
binaries. GCB searches for docker images from GCR.
|
||||
|
||||
Design document lists the steps to create a git trigger.
|
||||
|
||||
### Adding a new fuzz script to the build script:
|
||||
|
||||
* In order to update build script such as adding a new fuzzer to build script,
|
||||
we need to update the build script in docker image from cloud repository.
|
||||
[Build script.](https://widevine-internal.googlesource.com/cloud/+/refs/heads/master/docker
|
||||
/cloud_build/oemcrypto/release/ubuntu/fuzz/build.sh)
|
||||
|
||||
Add the new fuzz script name to fuzzers variable and follow steps in README
|
||||
to upload new docker image. Make sure you update the tag to be higher than
|
||||
latest version in GCR.
|
||||
|
||||
Run the following command from your machine to update the docker image tag
|
||||
in the git trigger.
|
||||
|
||||
```shell
|
||||
stubby call --rpc_creds_file=/tmp/mint.txt \
|
||||
blade:alphasource-ci-proctor-metadata-service-prod \
|
||||
ProctorMetadataService.UpdateTrigger --proto2 <<EOF
|
||||
trigger {
|
||||
cloud_project_number: 257246079067
|
||||
name: "cdm-git-trigger"
|
||||
id: "e8939c9a-d971-4c05-91b5-e0544abf872b"
|
||||
state: LIVE
|
||||
git_trigger {
|
||||
url: "https://widevine-internal.googlesource.com/cdm"
|
||||
branch_name: "master"
|
||||
}
|
||||
build_configs {
|
||||
build {
|
||||
steps {
|
||||
name: "gcr.io/google.com/blockbuster-1154/
|
||||
cloud-build-oemcrypto-release-ubuntu-fuzz:LATEST_TAG_VERSION"
|
||||
}
|
||||
}
|
||||
}
|
||||
result_config {
|
||||
email_config {
|
||||
notify_condition {
|
||||
condition: ON_FAILURE
|
||||
}
|
||||
to_address: "wideving-engprod@google.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
## Generate code coverage reports locally
|
||||
|
||||
* Code coverage is a means of measuring fuzzer performance. We want to make
|
||||
sure that our fuzzer covers all the paths in our code and make any tweeks to
|
||||
fuzzer logic so we can maximize coverage to get better results.
|
||||
|
||||
Coverage reports for git on borg project is not automated and needs to be
|
||||
generated manually. Future plan is to build a dashboard for git on borg
|
||||
coverage reports.
|
||||
|
||||
### Generate code coverage reports using script from Google cloud build
|
||||
* A docker image with script to generate code coverage reports for oemcrypto
|
||||
fuzz scripts is linked with a GCB trigger
|
||||
`oemcrypto-fuzzing-code-coverage-git-trigger`. More information about clang
|
||||
source based coverage can be found
|
||||
[here](https://clang.llvm.org/docs/SourceBasedCodeCoverage.html).
|
||||
|
||||
* This trigger when invoked compiles oemcrypto fuzz scripts with clang source
|
||||
based code coverage enabled, downloads latest corpus from cluster fuzz
|
||||
for the respective fuzzer, generates and uploads code coverage html reports
|
||||
to [GCS](https://pantheon.corp.google.com/storage/browser/oemcrypto_fuzzing_code_coverage_reports;tab=objects?forceOnBucketsSortingFiltering=false&project=google.com:blockbuster-1154&prefix=).
|
||||
|
||||
* The trigger can be invoked manually using cloud scheduler
|
||||
`oemcrypto_fuzzing_code_coverage_reports`.
|
||||
|
||||
* In order to generate latest code coverage reports from master branch,
|
||||
go to pantheon->cloud scheduler->oemcrypto_fuzzing_code_coverage_reports and
|
||||
click on `RUN NOW` button.
|
||||
|
||||
* The above step should invoke a google cloud build. Go to cloud build console
|
||||
and find latest build job with Trigger Name
|
||||
`oemcrypto-fuzzing-code-coverage-git-trigger`.
|
||||
|
||||
* Once the build job is successful, latest code coverage reports can be
|
||||
downloaded from [GCS](https://pantheon.corp.google.com/storage/browser/oemcrypto_fuzzing_code_coverage_reports;tab=objects?forceOnBucketsSortingFiltering=false&project=google.com:blockbuster-1154&prefix=).
|
||||
The coverage report folder uploaded to GCS is appended with timestamp.
|
||||
@@ -0,0 +1,182 @@
|
||||
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// 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 {
|
||||
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.address;
|
||||
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
|
||||
.address = new OEMCrypto_SharedMemory[std::min(
|
||||
MAX_FUZZ_SAMPLE_SIZE, output_descriptor.buffer.clear.address_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.handle_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
OEMCrypto_Decrypt_Cenc_Fuzz 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));
|
||||
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());
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
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);
|
||||
ConvertDataToValidEnum(
|
||||
OEMCrypto_BufferType_MaxValue,
|
||||
&sample_descriptions[i].buffers.output_descriptor.type);
|
||||
|
||||
// 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];
|
||||
input_subsample_index += sample_descriptions[i].subsamples_length;
|
||||
if (input_subsample_index > subsamples.size()) return 0;
|
||||
} // Sample loop.
|
||||
|
||||
// Allocate input/output buffers for each sample description.
|
||||
vector<OEMCrypto_SharedMemory> input_buffer(total_input_data_length);
|
||||
RAND_bytes(input_buffer.data(), 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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
// 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());
|
||||
return 0;
|
||||
}
|
||||
} // namespace wvoec
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine Master
|
||||
// License Agreement.
|
||||
#include "oemcrypto_fuzz_helper.h"
|
||||
|
||||
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);
|
||||
}
|
||||
if (current_pos < end) {
|
||||
result.push_back({current_pos, end});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} // namespace wvoec
|
||||
106
libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.h
Normal file
106
libwvdrmengine/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_helper.h
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine Master
|
||||
// License Agreement.
|
||||
#ifndef OEMCRYPTO_FUZZ_HELPER_H_
|
||||
#define OEMCRYPTO_FUZZ_HELPER_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "FuzzedDataProvider.h"
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "oec_device_features.h"
|
||||
#include "oemcrypto_corpus_generator_helper.h"
|
||||
#include "oemcrypto_session_tests_helper.h"
|
||||
|
||||
namespace wvoec {
|
||||
// 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.
|
||||
class InitializeFuzz : public SessionUtil {
|
||||
public:
|
||||
InitializeFuzz() {
|
||||
wvoec::global_features.Initialize();
|
||||
OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox));
|
||||
OEMCrypto_Initialize();
|
||||
EnsureTestKeys();
|
||||
}
|
||||
|
||||
~InitializeFuzz() { OEMCrypto_Terminate(); }
|
||||
};
|
||||
|
||||
class OEMCryptoLicenseAPIFuzz : public InitializeFuzz {
|
||||
public:
|
||||
OEMCryptoLicenseAPIFuzz() : license_messages_(&session_) {
|
||||
session_.open();
|
||||
InstallTestRSAKey(&session_);
|
||||
session_.GenerateNonce();
|
||||
}
|
||||
|
||||
~OEMCryptoLicenseAPIFuzz() {
|
||||
session_.close();
|
||||
}
|
||||
|
||||
LicenseRoundTrip& license_messages() { return license_messages_; }
|
||||
|
||||
Session* session() { return &session_; }
|
||||
|
||||
void LoadLicense() {
|
||||
license_messages_.SignAndVerifyRequest();
|
||||
license_messages_.CreateDefaultResponse();
|
||||
license_messages_.EncryptAndSignResponse();
|
||||
license_messages_.LoadResponse();
|
||||
}
|
||||
|
||||
private:
|
||||
Session session_;
|
||||
LicenseRoundTrip license_messages_;
|
||||
};
|
||||
|
||||
class OEMCryptoProvisioningAPIFuzz : public InitializeFuzz {
|
||||
public:
|
||||
OEMCryptoProvisioningAPIFuzz()
|
||||
: provisioning_messages_(&session_, encoded_rsa_key_) {
|
||||
// Opens a session and Generates Nonce.
|
||||
provisioning_messages_.PrepareSession(keybox_);
|
||||
}
|
||||
|
||||
~OEMCryptoProvisioningAPIFuzz() { session_.close(); }
|
||||
|
||||
ProvisioningRoundTrip& provisioning_messages() {
|
||||
return provisioning_messages_;
|
||||
}
|
||||
|
||||
private:
|
||||
Session session_;
|
||||
ProvisioningRoundTrip provisioning_messages_;
|
||||
};
|
||||
|
||||
// Initial setup to create a valid state such as creating session, installing
|
||||
// golden key box etc. in order to fuzz Load Renewal API.
|
||||
class OEMCryptoRenewalAPIFuzz : public OEMCryptoLicenseAPIFuzz {
|
||||
public:
|
||||
OEMCryptoRenewalAPIFuzz() : renewal_messages_(&license_messages()) {}
|
||||
|
||||
RenewalRoundTrip& renewal_messages() { return renewal_messages_; }
|
||||
|
||||
private:
|
||||
RenewalRoundTrip renewal_messages_;
|
||||
};
|
||||
|
||||
// Convert data to valid enum value.
|
||||
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)));
|
||||
}
|
||||
|
||||
// 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);
|
||||
} // namespace wvoec
|
||||
|
||||
#endif // OEMCRYPTO_FUZZ_HELPER_H_
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine Master
|
||||
// License Agreement.
|
||||
#ifndef OEMCRYPTO_FUZZ_STRUCTS_H_
|
||||
#define OEMCRYPTO_FUZZ_STRUCTS_H_
|
||||
|
||||
namespace wvoec {
|
||||
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.
|
||||
ODK_TimerLimits timer_limits;
|
||||
// message(core_response + license_renewal_response) which mimics
|
||||
// response from license renewal server needs to be fuzzed. core_request
|
||||
// will be used to generate serialized core response.
|
||||
oemcrypto_core_message::ODK_RenewalRequest core_request;
|
||||
// Renewal duration seconds needs to be fuzzed which is part of serialized
|
||||
// core message from license renewal server.
|
||||
uint64_t renewal_duration_seconds;
|
||||
// license_renewal_response is of variable length and not included in this
|
||||
// structure.
|
||||
};
|
||||
|
||||
struct OEMCrypto_Request_Fuzz {
|
||||
// We would like to fuzz computed signature_length, input core_message_length
|
||||
// that ODK parses and actual message buffer to the request APIs.
|
||||
size_t signature_length;
|
||||
size_t core_message_length;
|
||||
// Request message is of variable length and not included in this structure.
|
||||
};
|
||||
|
||||
struct OEMCrypto_Decrypt_Cenc_Fuzz {
|
||||
// Corpus format is as below, let | be separator.
|
||||
// cipher_mode + pattern + sample_data for all samples |
|
||||
// subsample_data for all samples
|
||||
OEMCryptoCipherMode cipher_mode;
|
||||
OEMCrypto_CENCEncryptPatternDesc pattern;
|
||||
// Sample data and subsample data are of variable length and not included in
|
||||
// this structure.
|
||||
};
|
||||
} // namespace wvoec
|
||||
|
||||
#endif // OEMCRYPTO_FUZZ_STRUCTS_H_
|
||||
@@ -0,0 +1,36 @@
|
||||
#include "properties.h"
|
||||
#include "oemcrypto_session_tests_helper.h"
|
||||
|
||||
using namespace wvoec;
|
||||
|
||||
static bool is_init = false;
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
SessionUtil session_helper;
|
||||
if (!is_init) {
|
||||
wvoec::global_features.Initialize();
|
||||
wvoec::global_features.RestrictFilter("*");
|
||||
wvcdm::Properties::Init();
|
||||
is_init = true;
|
||||
}
|
||||
|
||||
OEMCrypto_Initialize();
|
||||
session_helper.EnsureTestKeys();
|
||||
|
||||
Session s;
|
||||
s.open();
|
||||
s.GenerateDerivedKeysFromKeybox(session_helper.keybox_);
|
||||
|
||||
static const uint32_t SignatureBufferMaxLength = size;
|
||||
vector<uint8_t> signature(SignatureBufferMaxLength);
|
||||
size_t signature_length = signature.size();
|
||||
|
||||
OEMCryptoResult sts;
|
||||
sts = OEMCrypto_GenerateSignature(s.session_id(), data, size,
|
||||
&signature[0], &signature_length);
|
||||
|
||||
s.close();
|
||||
OEMCrypto_Terminate();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine Master
|
||||
// License Agreement.
|
||||
|
||||
#include "oemcrypto_fuzz_helper.h"
|
||||
#include "oemcrypto_fuzz_structs.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();
|
||||
// Reject the input if it is less than fuzz data structure size.
|
||||
if (size < sizeof(OEMCrypto_Request_Fuzz)) {
|
||||
return 0;
|
||||
}
|
||||
// Input for license request API will be modified by OEMCrypto, hence it
|
||||
// cannot be a const. Fuzzer complains if const identifier is removed of data,
|
||||
// hence copying data into a non const pointer.
|
||||
uint8_t* input = new uint8_t[size];
|
||||
memcpy(input, data, size);
|
||||
OEMCryptoLicenseAPIFuzz license_api_fuzz;
|
||||
license_api_fuzz.license_messages().InjectFuzzedRequestData(input, size);
|
||||
delete[] input;
|
||||
return 0;
|
||||
}
|
||||
} // namespace wvoec
|
||||
@@ -0,0 +1,66 @@
|
||||
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine Master
|
||||
// License Agreement.
|
||||
|
||||
#include "FuzzedDataProvider.h"
|
||||
#include "oemcrypto_fuzz_helper.h"
|
||||
#include "oemcrypto_fuzz_structs.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();
|
||||
|
||||
// Corpus format is as below, let | be separator.
|
||||
// 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);
|
||||
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);
|
||||
}
|
||||
|
||||
OEMCryptoLicenseAPIFuzz license_api_fuzz;
|
||||
// Setting up state. Load default entitlement license to load entitlement
|
||||
// keys into sessions key table.
|
||||
license_api_fuzz.license_messages().set_license_type(
|
||||
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();
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
} // namespace wvoec
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine Master
|
||||
// License Agreement.
|
||||
|
||||
#include "oemcrypto_fuzz_helper.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();
|
||||
if (size < sizeof(ODK_ParsedLicense) + sizeof(MessageData)) {
|
||||
return 0;
|
||||
}
|
||||
OEMCryptoLicenseAPIFuzz license_api_fuzz;
|
||||
license_api_fuzz.license_messages().SignAndVerifyRequest();
|
||||
// Interpreting input fuzz data as unencrypted (core_response + license
|
||||
// message data) from license server.
|
||||
license_api_fuzz.license_messages().InjectFuzzedResponseData(data, size);
|
||||
|
||||
// Convert OEMCrypto_LicenseType in core_response to a valid enum value.
|
||||
ConvertDataToValidEnum(
|
||||
OEMCrypto_LicenstType_MaxValue,
|
||||
&license_api_fuzz.license_messages().core_response().license_type);
|
||||
|
||||
license_api_fuzz.license_messages().EncryptAndSignResponse();
|
||||
license_api_fuzz.license_messages().LoadResponse();
|
||||
return 0;
|
||||
}
|
||||
} // namespace wvoec
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine Master
|
||||
// License Agreement.
|
||||
|
||||
#include "oemcrypto_fuzz_helper.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();
|
||||
if (size < sizeof(ODK_ParsedProvisioning) + sizeof(RSAPrivateKeyMessage)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
OEMCryptoProvisioningAPIFuzz provisioning_api_fuzz;
|
||||
provisioning_api_fuzz.provisioning_messages().SignAndVerifyRequest();
|
||||
// Interpreting input fuzz data as unencrypted(core_response + provisioning
|
||||
// message data) from provisioning server.
|
||||
provisioning_api_fuzz.provisioning_messages().InjectFuzzedResponseData(data,
|
||||
size);
|
||||
provisioning_api_fuzz.provisioning_messages().EncryptAndSignResponse();
|
||||
provisioning_api_fuzz.provisioning_messages().LoadResponse();
|
||||
return 0;
|
||||
}
|
||||
} // namespace wvoec
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine Master
|
||||
// License Agreement.
|
||||
|
||||
#include "oemcrypto_fuzz_helper.h"
|
||||
#include "oemcrypto_fuzz_structs.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();
|
||||
if (size < sizeof(OEMCrypto_Renewal_Response_Fuzz)) {
|
||||
return 0;
|
||||
}
|
||||
// Copy input data to OEMCrypto_Renewal_Response_Fuzz and rest of message
|
||||
// into encrypted license_renewal_response.
|
||||
OEMCrypto_Renewal_Response_Fuzz fuzzed_data;
|
||||
memcpy(&fuzzed_data, data, sizeof(fuzzed_data));
|
||||
const uint8_t* renewal_response =
|
||||
data + sizeof(OEMCrypto_Renewal_Response_Fuzz);
|
||||
const size_t renewal_response_size =
|
||||
size - sizeof(OEMCrypto_Renewal_Response_Fuzz);
|
||||
|
||||
OEMCryptoRenewalAPIFuzz renewal_response_fuzz;
|
||||
renewal_response_fuzz.license_messages().SignAndVerifyRequest();
|
||||
renewal_response_fuzz.license_messages().CreateDefaultResponse();
|
||||
// Inject timer limits from fuzzed input to timer_limits field from
|
||||
// core license response.
|
||||
renewal_response_fuzz.license_messages().InjectFuzzedTimerLimits(fuzzed_data);
|
||||
renewal_response_fuzz.license_messages().EncryptAndSignResponse();
|
||||
renewal_response_fuzz.license_messages().LoadResponse();
|
||||
|
||||
// Call renewal response API using fuzzed data.
|
||||
renewal_response_fuzz.renewal_messages().SignAndVerifyRequest();
|
||||
renewal_response_fuzz.renewal_messages().InjectFuzzedResponseData(
|
||||
fuzzed_data, renewal_response, renewal_response_size);
|
||||
renewal_response_fuzz.renewal_messages().LoadResponse();
|
||||
return 0;
|
||||
}
|
||||
} // namespace wvoec
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine Master
|
||||
// License Agreement.
|
||||
|
||||
#include "oemcrypto_fuzz_helper.h"
|
||||
#include "oemcrypto_fuzz_structs.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();
|
||||
// If input size is less than fuzz data structure size, reject the input.
|
||||
if (size < sizeof(OEMCrypto_Request_Fuzz)) {
|
||||
return 0;
|
||||
}
|
||||
// Input for provisioning request API will be modified by OEMCrypto, hence it
|
||||
// cannot be a const. Fuzzer complains if const identifier is removed of data,
|
||||
// hence copying data into a non const pointer.
|
||||
uint8_t* input = new uint8_t[size];
|
||||
memcpy(input, data, size);
|
||||
OEMCryptoProvisioningAPIFuzz provisioning_api_fuzz;
|
||||
provisioning_api_fuzz.provisioning_messages().InjectFuzzedRequestData(input,
|
||||
size);
|
||||
delete[] input;
|
||||
return 0;
|
||||
}
|
||||
} // namespace wvoec
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine Master
|
||||
// License Agreement.
|
||||
|
||||
#include "oemcrypto_fuzz_helper.h"
|
||||
#include "oemcrypto_fuzz_structs.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();
|
||||
// If input size is less than fuzz data structure, reject the input.
|
||||
if (size < sizeof(OEMCrypto_Request_Fuzz)) {
|
||||
return 0;
|
||||
}
|
||||
// Input for renewal request API will be modified by OEMCrypto, hence it
|
||||
// cannot be a const. Fuzzer complains if const identifier is removed of data,
|
||||
// hence copying data into a non const pointer.
|
||||
uint8_t* input = new uint8_t[size];
|
||||
memcpy(input, data, size);
|
||||
OEMCryptoRenewalAPIFuzz renewal_api_fuzz;
|
||||
renewal_api_fuzz.renewal_messages().InjectFuzzedRequestData(input, size);
|
||||
delete[] input;
|
||||
return 0;
|
||||
}
|
||||
} // namespace wvoec
|
||||
10
libwvdrmengine/oemcrypto/test/fuzz_tests/sample_test.cc
Normal file
10
libwvdrmengine/oemcrypto/test/fuzz_tests/sample_test.cc
Normal file
@@ -0,0 +1,10 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
if (size > 0 && data[0] == 'H')
|
||||
if (size > 1 && data[1] == 'I')
|
||||
if (size > 2 && data[2] == '!')
|
||||
__builtin_trap();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user