diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/Android.bp b/libwvdrmengine/oemcrypto/odk/test/fuzzing/Android.bp new file mode 100644 index 00000000..13d6048b --- /dev/null +++ b/libwvdrmengine/oemcrypto/odk/test/fuzzing/Android.bp @@ -0,0 +1,168 @@ +// 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. + +cc_defaults { + name: "odk_fuzz_library_defaults", + srcs: [ + "odk_fuzz_helper.cpp", + ], + include_dirs: [ + "vendor/widevine/libwvdrmengine/oemcrypto/odk/test", + "vendor/widevine/libwvdrmengine/oemcrypto/odk/include", + "vendor/widevine/libwvdrmengine/oemcrypto/odk/src", + ], +} + +cc_fuzz { + name: "odk_license_request_fuzz", + srcs: [ + "odk_license_request_fuzz.cpp", + ], + fuzz_config: { + componentid: 425099, + }, + corpus: ["corpus/arm64/license_request_corpus/*"], + static_libs: [ + "libwv_kdo", + "libwv_odk", + ], + defaults: ["odk_fuzz_library_defaults"], + proprietary: true, +} + +cc_fuzz { + name: "odk_renewal_request_fuzz", + srcs: [ + "odk_renewal_request_fuzz.cpp", + ], + fuzz_config: { + componentid: 425099, + }, + corpus: ["corpus/arm64/renewal_request_corpus/*"], + static_libs: [ + "libwv_kdo", + "libwv_odk", + ], + defaults: ["odk_fuzz_library_defaults"], + proprietary: true, +} + +cc_fuzz { + name: "odk_provisioning_request_fuzz", + srcs: [ + "odk_provisioning_request_fuzz.cpp", + ], + fuzz_config: { + componentid: 425099, + }, + corpus: ["corpus/arm64/provisioning_request_corpus/*"], + static_libs: [ + "libwv_kdo", + "libwv_odk", + ], + defaults: ["odk_fuzz_library_defaults"], + proprietary: true, +} + +cc_fuzz { + name: "odk_license_response_fuzz", + srcs: [ + "odk_license_response_fuzz.cpp", + ], + fuzz_config: { + componentid: 425099, + }, + corpus: ["corpus/arm64/license_response_corpus/*"], + static_libs: [ + "libwv_kdo", + "libwv_odk", + ], + defaults: ["odk_fuzz_library_defaults"], + proprietary: true, +} + +cc_fuzz { + name: "odk_renewal_response_fuzz", + srcs: [ + "odk_renewal_response_fuzz.cpp", + ], + fuzz_config: { + componentid: 425099, + }, + corpus: ["corpus/arm64/renewal_response_corpus/*"], + static_libs: [ + "libwv_kdo", + "libwv_odk", + ], + defaults: ["odk_fuzz_library_defaults"], + proprietary: true, +} + +cc_fuzz { + name: "odk_provisioning_response_fuzz", + srcs: [ + "odk_provisioning_response_fuzz.cpp", + ], + fuzz_config: { + componentid: 425099, + }, + corpus: ["corpus/arm64/provisioning_response_corpus/*"], + static_libs: [ + "libwv_kdo", + "libwv_odk", + ], + defaults: ["odk_fuzz_library_defaults"], + proprietary: true, +} + +cc_fuzz { + name: "odk_license_response_fuzz_with_mutator", + srcs: [ + "odk_license_response_fuzz_with_mutator.cpp", + ], + fuzz_config: { + componentid: 425099, + }, + corpus: ["corpus/arm64/license_response_corpus/*"], + static_libs: [ + "libwv_kdo", + "libwv_odk", + ], + defaults: ["odk_fuzz_library_defaults"], + proprietary: true, +} + +cc_fuzz { + name: "odk_renewal_response_fuzz_with_mutator", + srcs: [ + "odk_renewal_response_fuzz_with_mutator.cpp", + ], + fuzz_config: { + componentid: 425099, + }, + corpus: ["corpus/arm64/renewal_response_corpus/*"], + static_libs: [ + "libwv_kdo", + "libwv_odk", + ], + defaults: ["odk_fuzz_library_defaults"], + proprietary: true, +} + +cc_fuzz { + name: "odk_provisioning_response_fuzz_with_mutator", + srcs: [ + "odk_provisioning_response_fuzz_with_mutator.cpp", + ], + fuzz_config: { + componentid: 425099, + }, + corpus: ["corpus/arm64/provisioning_response_corpus/*"], + static_libs: [ + "libwv_kdo", + "libwv_odk", + ], + defaults: ["odk_fuzz_library_defaults"], + proprietary: true, +} \ No newline at end of file diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/README.md b/libwvdrmengine/oemcrypto/odk/test/fuzzing/README.md new file mode 100644 index 00000000..eb7da4fc --- /dev/null +++ b/libwvdrmengine/oemcrypto/odk/test/fuzzing/README.md @@ -0,0 +1,19 @@ +# ODK Fuzzing + +## Objective + +* Run fuzzing on ODK and KDO serialize and deserialize APIs using google + supported fuzzer engines to find security vulnerabilities. Any issues found + by clusterfuzz will be reported to + [odk fuzz buganizer](https://b.corp.google.com/issues?q=componentid:425099%20status:open%20reporter:cluster-fuzz-googleplex@google.com). + +## Run fuzz target on local machine + +* In order to run fuzz target locally and see code coverage, save binary input + to be tested against fuzz target into a temporary corpus directory and + execute following commands + + ```shell + $ blaze build --config=asan-fuzzer //your:target + $ blaze-bin/your/target FULL_CORPUS_DIR + ``` diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/license_request_corpus/602c63d2f3d13ca3206cdf204cde24e7d8f4266c b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/license_request_corpus/602c63d2f3d13ca3206cdf204cde24e7d8f4266c new file mode 100644 index 00000000..dc8cabcb Binary files /dev/null and b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/license_request_corpus/602c63d2f3d13ca3206cdf204cde24e7d8f4266c differ diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/license_request_corpus/8cebdcc0161125a10e19c45f055051712873de25 b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/license_request_corpus/8cebdcc0161125a10e19c45f055051712873de25 new file mode 100644 index 00000000..608e888d Binary files /dev/null and b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/license_request_corpus/8cebdcc0161125a10e19c45f055051712873de25 differ diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/license_response_corpus/4e578d6c9628e832c099623b44f56d95aa37f94b b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/license_response_corpus/4e578d6c9628e832c099623b44f56d95aa37f94b new file mode 100644 index 00000000..e3197476 Binary files /dev/null and b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/license_response_corpus/4e578d6c9628e832c099623b44f56d95aa37f94b differ diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/license_response_corpus/5b693511ef850e42c5ffded171794dbeb9460cc0 b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/license_response_corpus/5b693511ef850e42c5ffded171794dbeb9460cc0 new file mode 100644 index 00000000..0cf77b5d Binary files /dev/null and b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/license_response_corpus/5b693511ef850e42c5ffded171794dbeb9460cc0 differ diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/license_response_corpus/b6b865b095697164ad032c2f695ed828f5754749 b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/license_response_corpus/b6b865b095697164ad032c2f695ed828f5754749 new file mode 100644 index 00000000..225f87ae --- /dev/null +++ b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/license_response_corpus/b6b865b095697164ad032c2f695ed828f5754749 @@ -0,0 +1 @@ +{"componentid":425099} diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/license_response_corpus/dba39b6cf6524e996397ddc1e08b928b5c92bb5d b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/license_response_corpus/dba39b6cf6524e996397ddc1e08b928b5c92bb5d new file mode 100644 index 00000000..51f67eb6 Binary files /dev/null and b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/license_response_corpus/dba39b6cf6524e996397ddc1e08b928b5c92bb5d differ diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/license_response_corpus/dd1bc1827a331b7aed2a6fb6740da032123aa0a8 b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/license_response_corpus/dd1bc1827a331b7aed2a6fb6740da032123aa0a8 new file mode 100644 index 00000000..a3f3b269 Binary files /dev/null and b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/license_response_corpus/dd1bc1827a331b7aed2a6fb6740da032123aa0a8 differ diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/provisioning_request_corpus/53c26407b39c997143146a0dce8ff0ac11f565e1 b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/provisioning_request_corpus/53c26407b39c997143146a0dce8ff0ac11f565e1 new file mode 100644 index 00000000..a2d65a82 Binary files /dev/null and b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/provisioning_request_corpus/53c26407b39c997143146a0dce8ff0ac11f565e1 differ diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/provisioning_request_corpus/fab3c99d604bab7b7bf5c54c5bd995fc98d4d96f b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/provisioning_request_corpus/fab3c99d604bab7b7bf5c54c5bd995fc98d4d96f new file mode 100644 index 00000000..a4ded576 Binary files /dev/null and b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/provisioning_request_corpus/fab3c99d604bab7b7bf5c54c5bd995fc98d4d96f differ diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/provisioning_response_corpus/91e10d030fbdd3374e57a2720f09488f2b03ce69 b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/provisioning_response_corpus/91e10d030fbdd3374e57a2720f09488f2b03ce69 new file mode 100644 index 00000000..0616a29b Binary files /dev/null and b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/provisioning_response_corpus/91e10d030fbdd3374e57a2720f09488f2b03ce69 differ diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/renewal_request_corpus/12a72efb395e731ec4470b5f5b6768d6806e9131 b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/renewal_request_corpus/12a72efb395e731ec4470b5f5b6768d6806e9131 new file mode 100644 index 00000000..7371c1f9 Binary files /dev/null and b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/renewal_request_corpus/12a72efb395e731ec4470b5f5b6768d6806e9131 differ diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/renewal_request_corpus/21de033b9baf2a0e82ae3b4185b22aa0acf69bbc b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/renewal_request_corpus/21de033b9baf2a0e82ae3b4185b22aa0acf69bbc new file mode 100644 index 00000000..ef24b189 Binary files /dev/null and b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/renewal_request_corpus/21de033b9baf2a0e82ae3b4185b22aa0acf69bbc differ diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/renewal_request_corpus/97bf96be666434bfa93dbfb36b81baeefed14170 b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/renewal_request_corpus/97bf96be666434bfa93dbfb36b81baeefed14170 new file mode 100644 index 00000000..4e6f216d Binary files /dev/null and b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/renewal_request_corpus/97bf96be666434bfa93dbfb36b81baeefed14170 differ diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/renewal_request_corpus/a7b0e7dca597331d7f051204096c9d01ba6d468e b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/renewal_request_corpus/a7b0e7dca597331d7f051204096c9d01ba6d468e new file mode 100644 index 00000000..748c29cf Binary files /dev/null and b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/renewal_request_corpus/a7b0e7dca597331d7f051204096c9d01ba6d468e differ diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/renewal_response_corpus/38df40a320f60e955006aaa294b74d45a316e50f b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/renewal_response_corpus/38df40a320f60e955006aaa294b74d45a316e50f new file mode 100644 index 00000000..4abb16a8 Binary files /dev/null and b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/renewal_response_corpus/38df40a320f60e955006aaa294b74d45a316e50f differ diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/renewal_response_corpus/9962997b5ea87005276319cbfff67884846485cf b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/renewal_response_corpus/9962997b5ea87005276319cbfff67884846485cf new file mode 100644 index 00000000..892a4edb Binary files /dev/null and b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/renewal_response_corpus/9962997b5ea87005276319cbfff67884846485cf differ diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/renewal_response_corpus/c84663115c890873dd585987c1223193d29aef16 b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/renewal_response_corpus/c84663115c890873dd585987c1223193d29aef16 new file mode 100644 index 00000000..b1fc6da6 Binary files /dev/null and b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus/arm64/renewal_response_corpus/c84663115c890873dd585987c1223193d29aef16 differ diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus_generator/README.md b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus_generator/README.md new file mode 100644 index 00000000..0376aeda --- /dev/null +++ b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus_generator/README.md @@ -0,0 +1,76 @@ +# Objective + +The Idea behind the corpus generator code is to intercept OEMCrypto unit test +calls to odk APIs using LD_PRELOAD and read the data into corpus files which can +be fed as corpus to fuzzer scripts. + +LD_PRELOAD command needs to be run from cdm repository while running oemcrypto +unit tests. + +## Get OEMCrypto and Build OEMCrypto unit tests: + +* 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 + ``` + +* We need to run odk as a dynamic library in order to use LD_PRELOAD, apply + patch from go/wvgerrit/95090 to locally cloned repo which has changes to run + odk as dynamic library: + + ```shell + $ cd /path/to/cdm/repo + $ git fetch origin 209721cc901745999e08e35466e74f708321267e + $ git cherry-pick FETCH_HEAD + ``` + +* Build OEMCrypto unit tests: + + ```shell + $ cd /path/to/cdm/repo + $ export PATH_TO_CDM_DIR=.. + $ gyp --format=ninja --depth=$(pwd) oemcrypto/oemcrypto_unittests.gyp + $ ninja -C out/Default/ + ``` + +## Capture corpus for odk fuzzer by intercepting OEMCrypto unit tests: + +When we run LD_PRELOAD command odk_corpus_generator.so gets preloaded before +oemcrypto_unittests and odk_corpus_generator has functions to intercept calls to +ODK request and response APIs. Each call to odk API from oemcrypto_unittests +gets intercepted and input to ODK de serialize response APIs and output from ODK +serialize request APIs is captured in binary format and stored into corpus files + +In order to run LD_PRELOAD command, we need to compile corpus generator shared +library and need to preload that before OEMCrypto unit tests run + +* Compile shared library + + ```shell + $ cd /path/to/cdm/repo + $ gyp --format=ninja --depth=$(pwd) oemcrypto/odk/test/fuzzing/corpus_generator/odk_fuzz_corpus_generator.gyp + $ ninja -C out/Default/ + ``` + +* Preload the shared library before running OEMCrypto unit tests + + ```shell + $ LD_PRELOAD=out/Default/lib/libodk_corpus_generator.so ./out/Default/oemcrypto_unittests + ``` + +LD_PRELOAD command runs oemcrypto_unittests with odk_corpus_generator as +interceptor. We should see unit tests being executed. The corpus files in binary +format will be captured into `oemcrypto/odk/test/fuzzing/corpus` path. These +files can be used as input corpus for ODK request and response fuzzer scripts. + +The generated corpus files can be minimized using go/testcorpus#minimize and +uploaded into google3 repository under following directory under respective +corpus types +`fuzzing/corpus` diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator.c b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator.c new file mode 100644 index 00000000..bf33b710 --- /dev/null +++ b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator.c @@ -0,0 +1,173 @@ +/* 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. */ + +/* We must define this macro to get RTLD_NEXT definition from */ +#define _GNU_SOURCE + +#include + +#include "OEMCryptoCENCCommon.h" +#include "fuzzing/corpus_generator/odk_corpus_generator_helper.h" +#include "fuzzing/odk_fuzz_structs.h" +#include "odk_structs.h" + +OEMCryptoResult ODK_PrepareCoreLicenseRequest( + uint8_t* message, size_t message_length, size_t* core_message_length, + const ODK_NonceValues* nonce_values) { + OEMCryptoResult (*original_function)(uint8_t*, size_t, size_t*, + const ODK_NonceValues*); + original_function = dlsym(RTLD_NEXT, "ODK_PrepareCoreLicenseRequest"); + OEMCryptoResult oem_crypto_result = (*original_function)( + message, message_length, core_message_length, nonce_values); + if (OEMCrypto_SUCCESS == oem_crypto_result) { + char* file_name = GetFileName("license_request_corpus"); + + /* License Request format expected by fuzzer - [Core License Request] */ + AppendToFile(file_name, (const char*)message, *core_message_length); + free(file_name); + } + return oem_crypto_result; +} + +OEMCryptoResult ODK_ParseLicense( + const uint8_t* message, size_t message_length, size_t core_message_length, + bool initial_license_load, bool usage_entry_present, + const uint8_t* request_hash, ODK_TimerLimits* timer_limits, + ODK_ClockValues* clock_values, ODK_NonceValues* nonce_values, + ODK_ParsedLicense* parsed_license) { + struct ODK_ParseLicense_Args parse_license_args; + parse_license_args.nonce_values = *nonce_values; + memcpy(parse_license_args.request_hash, request_hash, ODK_SHA256_HASH_SIZE); + parse_license_args.timer_limits = *timer_limits; + parse_license_args.clock_values = *clock_values; + parse_license_args.usage_entry_present = usage_entry_present; + parse_license_args.initial_license_load = initial_license_load; + OEMCryptoResult (*original_function)( + const uint8_t*, size_t, size_t, bool, bool, const uint8_t*, + ODK_TimerLimits*, ODK_ClockValues*, ODK_NonceValues*, ODK_ParsedLicense*); + original_function = dlsym(RTLD_NEXT, "ODK_ParseLicense"); + OEMCryptoResult oem_crypto_result = (*original_function)( + message, message_length, core_message_length, initial_license_load, + usage_entry_present, request_hash, timer_limits, clock_values, + nonce_values, parsed_license); + if (OEMCrypto_SUCCESS == oem_crypto_result) { + char* file_name = GetFileName("license_response_corpus"); + + /* License Response format expected by fuzzer - [ODK_ParseLicense_Args][Core + */ + /* License Response] */ + AppendToFile(file_name, (const char*)&parse_license_args, + sizeof(struct ODK_ParseLicense_Args)); + AppendToFile(file_name, (const char*)message, core_message_length); + free(file_name); + } + return oem_crypto_result; +} + +OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message, + size_t message_length, + size_t* core_message_size, + ODK_NonceValues* nonce_values, + ODK_ClockValues* clock_values, + uint64_t system_time_seconds) { + OEMCryptoResult (*original_function)( + uint8_t*, size_t, size_t*, ODK_NonceValues*, ODK_ClockValues*, uint64_t); + original_function = dlsym(RTLD_NEXT, "ODK_PrepareCoreRenewalRequest"); + OEMCryptoResult oem_crypto_result = + (*original_function)(message, message_length, core_message_size, + nonce_values, clock_values, system_time_seconds); + if (OEMCrypto_SUCCESS == oem_crypto_result) { + char* file_name = GetFileName("renewal_request_corpus"); + + /* License Request format expected by fuzzer - [ODK_ClockValues][Core */ + /* License Request] */ + AppendToFile(file_name, (const char*)clock_values, sizeof(ODK_ClockValues)); + AppendToFile(file_name, (const char*)message, *core_message_size); + free(file_name); + } + return oem_crypto_result; +} + +OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length, + size_t core_message_length, + const ODK_NonceValues* nonce_values, + uint64_t system_time, + const ODK_TimerLimits* timer_limits, + ODK_ClockValues* clock_values, + uint64_t* timer_value) { + struct ODK_ParseRenewal_Args parse_renewal_args; + parse_renewal_args.nonce_values = *nonce_values; + parse_renewal_args.clock_values = *clock_values; + parse_renewal_args.timer_limits = *timer_limits; + parse_renewal_args.system_time = system_time; + OEMCryptoResult (*original_function)( + const uint8_t*, size_t, size_t, const ODK_NonceValues*, uint64_t, + const ODK_TimerLimits*, ODK_ClockValues*, uint64_t*); + original_function = dlsym(RTLD_NEXT, "ODK_ParseRenewal"); + OEMCryptoResult oem_crypto_result = (*original_function)( + message, message_length, core_message_length, nonce_values, system_time, + timer_limits, clock_values, timer_value); + if (OEMCrypto_SUCCESS == oem_crypto_result) { + char* file_name = GetFileName("renewal_response_corpus"); + + /* Renewal Response format expected by fuzzer - [ODK_ParseRenewal_Args][Core + */ + /* Renewal Response] */ + AppendToFile(file_name, (const char*)&parse_renewal_args, + sizeof(struct ODK_ParseRenewal_Args)); + AppendToFile(file_name, (const char*)message, core_message_length); + free(file_name); + } + return oem_crypto_result; +} + +OEMCryptoResult ODK_PrepareCoreProvisioningRequest( + uint8_t* message, size_t message_length, size_t* core_message_length, + const ODK_NonceValues* nonce_values, const uint8_t* device_id, + size_t device_id_length) { + OEMCryptoResult (*original_function)(uint8_t*, size_t, size_t*, + const ODK_NonceValues*, const uint8_t*, + size_t); + original_function = dlsym(RTLD_NEXT, "ODK_PrepareCoreProvisioningRequest"); + OEMCryptoResult oem_crypto_result = + (*original_function)(message, message_length, core_message_length, + nonce_values, device_id, device_id_length); + if (OEMCrypto_SUCCESS == oem_crypto_result) { + char* file_name = GetFileName("provisioning_request_corpus"); + + /* Provisioning Request format expected by fuzzer - [Core Provisioning */ + /* Request] */ + AppendToFile(file_name, (const char*)message, *core_message_length); + free(file_name); + } + return oem_crypto_result; +} + +OEMCryptoResult ODK_ParseProvisioning( + const uint8_t* message, size_t message_length, size_t core_message_length, + const ODK_NonceValues* nonce_values, const uint8_t* device_id, + size_t device_id_length, ODK_ParsedProvisioning* parsed_response) { + struct ODK_ParseProvisioning_Args parse_provisioning_args; + parse_provisioning_args.nonce_values = *nonce_values; + memcpy(parse_provisioning_args.device_id, device_id, device_id_length); + parse_provisioning_args.device_id_length = device_id_length; + OEMCryptoResult (*original_function)(const uint8_t*, size_t, size_t, + const ODK_NonceValues*, const uint8_t*, + size_t, ODK_ParsedProvisioning*); + original_function = dlsym(RTLD_NEXT, "ODK_ParseProvisioning"); + OEMCryptoResult oem_crypto_result = (*original_function)( + message, message_length, core_message_length, nonce_values, device_id, + device_id_length, parsed_response); + if (OEMCrypto_SUCCESS == oem_crypto_result) { + char* file_name = GetFileName("provisioning_response_corpus"); + + /* Provisioning Response format expected by fuzzer - */ + /* [ODK_ParseProvisioning_Args][Core Provisioning Response] */ + AppendToFile(file_name, (const char*)&parse_provisioning_args, + sizeof(struct ODK_ParseProvisioning_Args)); + AppendToFile(file_name, (const char*)message, core_message_length); + free(file_name); + } + return oem_crypto_result; +} diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator_helper.c b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator_helper.c new file mode 100644 index 00000000..fa35dca9 --- /dev/null +++ b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator_helper.c @@ -0,0 +1,22 @@ +/* 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 "fuzzing/corpus_generator/odk_corpus_generator_helper.h" + +void AppendToFile(const char* file_name, const char* message, + const size_t message_size) { + FILE* fptr; + if ((fptr = fopen(file_name, "ab")) == NULL) { + printf("Error! opening file %s", file_name); + return; + } + fwrite(message, message_size, 1, fptr); + fclose(fptr); +} + +char* GetFileName(const char* directory) { + char* file_name; + file_name = malloc(150); + sprintf(file_name, "%s%s/%d", PATH_TO_CORPUS, directory, rand()); + return file_name; +} diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator_helper.h b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator_helper.h new file mode 100644 index 00000000..2dc6d51b --- /dev/null +++ b/libwvdrmengine/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator_helper.h @@ -0,0 +1,19 @@ +/* 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 WIDEVINE_ODK_TEST_FUZZING_CORPUS_GENERATOR_ODK_CORPUS_GENERATOR_HELPER_H_ +#define WIDEVINE_ODK_TEST_FUZZING_CORPUS_GENERATOR_ODK_CORPUS_GENERATOR_HELPER_H_ + +#define PATH_TO_CORPUS "./oemcrypto/odk/test/fuzzing/corpus/" + +#include +#include +#include + +void AppendToFile(const char* file_name, const char* message, + const size_t message_size); + +char* GetFileName(const char* directory); + +#endif /* WIDEVINE_ODK_TEST_FUZZING_CORPUS_GENERATOR_ODK_CORPUS_GENERATOR_HELPER_H_ \ + */ diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp new file mode 100644 index 00000000..889b205e --- /dev/null +++ b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp @@ -0,0 +1,151 @@ +// 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 "fuzzing/odk_fuzz_helper.h" + +#include "odk.h" + +namespace oemcrypto_core_message { + +bool convert_byte_to_valid_boolean(const bool* in) { + const char* buf = reinterpret_cast(in); + for (int i = 0; i < sizeof(bool); i++) { + if (buf[i]) { + return true; + } + } + return false; +} + +void ConvertDataToValidBools(ODK_ParsedLicense* t) { + // Convert boolean flags in parsed_license to valid bytes to + // avoid errors from msan + t->nonce_required = convert_byte_to_valid_boolean(&t->nonce_required); + t->timer_limits.soft_enforce_playback_duration = + convert_byte_to_valid_boolean( + &t->timer_limits.soft_enforce_playback_duration); + t->timer_limits.soft_enforce_rental_duration = convert_byte_to_valid_boolean( + &t->timer_limits.soft_enforce_rental_duration); +} + +void ConvertDataToValidBools(ODK_PreparedRenewalRequest* t) {} + +void ConvertDataToValidBools(ODK_ParsedProvisioning* t) {} + +OEMCryptoResult odk_serialize_LicenseRequest( + const void* in, uint8_t* out, size_t* size, + const ODK_LicenseRequest& core_license_request, + const ODK_NonceValues* nonce_values) { + return ODK_PrepareCoreLicenseRequest(out, SIZE_MAX, size, nonce_values); +} + +OEMCryptoResult odk_serialize_RenewalRequest( + const void* in, uint8_t* out, size_t* size, + const ODK_RenewalRequest& core_renewal, ODK_NonceValues* nonce_values) { + ODK_ClockValues clock{}; + memcpy(&clock, in, sizeof(ODK_ClockValues)); + uint64_t system_time_seconds = core_renewal.playback_time_seconds; + return ODK_PrepareCoreRenewalRequest(out, SIZE_MAX, size, nonce_values, + &clock, system_time_seconds); +} + +OEMCryptoResult odk_serialize_ProvisioningRequest( + const void* in, uint8_t* out, size_t* size, + const ODK_ProvisioningRequest& core_provisioning, + const ODK_NonceValues* nonce_values) { + const std::string& device_id = core_provisioning.device_id; + return ODK_PrepareCoreProvisioningRequest( + out, SIZE_MAX, size, nonce_values, + reinterpret_cast(device_id.data()), device_id.size()); +} + +OEMCryptoResult odk_deserialize_LicenseResponse(const uint8_t* message, + size_t core_message_length, + ODK_ParseLicense_Args* a, + ODK_NonceValues* nonce_values, + ODK_ParsedLicense* parsed_lic) { + return ODK_ParseLicense(message, SIZE_MAX, core_message_length, + static_cast(a->initial_license_load), + static_cast(a->usage_entry_present), + a->request_hash, &a->timer_limits, &a->clock_values, + nonce_values, parsed_lic); +} + +OEMCryptoResult odk_deserialize_RenewalResponse( + const uint8_t* buf, size_t len, ODK_ParseRenewal_Args* a, + ODK_NonceValues* nonce_values, ODK_PreparedRenewalRequest* renewal_msg) { + /* Address Sanitizer doesn't like values other than 0 OR 1 for boolean + * variables. Input from fuzzer can be parsed and any random bytes can be + * assigned to boolean variables. Using the workaround to mitigate sanitizer + * errors in fuzzer code and converting random bytes to 0 OR 1. + * This has no negative security impact*/ + a->timer_limits.soft_enforce_playback_duration = + convert_byte_to_valid_boolean( + &a->timer_limits.soft_enforce_playback_duration); + a->timer_limits.soft_enforce_rental_duration = convert_byte_to_valid_boolean( + &a->timer_limits.soft_enforce_rental_duration); + uint64_t timer_value = 0; + OEMCryptoResult err = + ODK_ParseRenewal(buf, SIZE_MAX, len, nonce_values, a->system_time, + &a->timer_limits, &a->clock_values, &timer_value); + if (OEMCrypto_SUCCESS == err) { + Message* msg = nullptr; + AllocateMessage(&msg, message_block); + InitMessage(msg, const_cast(buf), len); + SetSize(msg, len); + Unpack_ODK_PreparedRenewalRequest(msg, renewal_msg); + assert(ValidMessage(msg)); + } + return err; +} + +OEMCryptoResult odk_deserialize_ProvisioningResponse( + const uint8_t* buf, size_t len, ODK_ParseProvisioning_Args* a, + ODK_NonceValues* nonce_values, ODK_ParsedProvisioning* parsed_prov) { + return ODK_ParseProvisioning(buf, SIZE_MAX, len, nonce_values, a->device_id, + a->device_id_length, parsed_prov); +} + +bool kdo_serialize_LicenseResponse(const ODK_ParseLicense_Args* args, + const ODK_ParsedLicense& parsed_lic, + std::string* oemcrypto_core_message) { + const auto& nonce_values = args->nonce_values; + ODK_LicenseRequest core_request{nonce_values.api_minor_version, + nonce_values.api_major_version, + nonce_values.nonce, nonce_values.session_id}; + std::string core_request_sha_256( + reinterpret_cast(args->request_hash), ODK_SHA256_HASH_SIZE); + return serialize::CreateCoreLicenseResponse( + parsed_lic, core_request, core_request_sha_256, oemcrypto_core_message); +} + +bool kdo_serialize_RenewalResponse( + const ODK_ParseRenewal_Args* args, + const ODK_PreparedRenewalRequest& renewal_msg, + std::string* oemcrypto_core_message) { + const auto& nonce_values = args->nonce_values; + ODK_RenewalRequest core_request{ + nonce_values.api_minor_version, nonce_values.api_major_version, + nonce_values.nonce, nonce_values.session_id, renewal_msg.playback_time}; + return serialize::CreateCoreRenewalResponse( + core_request, args->timer_limits.initial_renewal_duration_seconds, + oemcrypto_core_message); +} + +bool kdo_serialize_ProvisioningResponse( + const ODK_ParseProvisioning_Args* args, + const ODK_ParsedProvisioning& parsed_prov, + std::string* oemcrypto_core_message) { + const auto& nonce_values = args->nonce_values; + if (args->device_id_length > sizeof(args->device_id)) { + return false; + } + ODK_ProvisioningRequest core_request{ + nonce_values.api_minor_version, nonce_values.api_major_version, + nonce_values.nonce, nonce_values.session_id, + std::string(reinterpret_cast(args->device_id), + args->device_id_length)}; + return serialize::CreateCoreProvisioningResponse(parsed_prov, core_request, + oemcrypto_core_message); +} +} // namespace oemcrypto_core_message diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.h b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.h new file mode 100644 index 00000000..5672c005 --- /dev/null +++ b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.h @@ -0,0 +1,206 @@ +/* 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 WIDEVINE_ODK_TEST_FUZZING_ODK_FUZZ_HELPER_H_ +#define WIDEVINE_ODK_TEST_FUZZING_ODK_FUZZ_HELPER_H_ + +#include +#include + +#include "core_message_serialize.h" +#include "fuzzing/odk_fuzz_structs.h" +#include "odk_serialize.h" + +namespace oemcrypto_core_message { +bool convert_byte_to_valid_boolean(const bool* in); + +OEMCryptoResult odk_serialize_LicenseRequest( + const void* in, uint8_t* out, size_t* size, + const ODK_LicenseRequest& core_license_request, + const ODK_NonceValues* nonce_values); + +OEMCryptoResult odk_serialize_RenewalRequest( + const void* in, uint8_t* out, size_t* size, + const ODK_RenewalRequest& core_renewal, ODK_NonceValues* nonce_values); + +OEMCryptoResult odk_serialize_ProvisioningRequest( + const void* in, uint8_t* out, size_t* size, + const ODK_ProvisioningRequest& core_provisioning, + const ODK_NonceValues* nonce_values); + +OEMCryptoResult odk_deserialize_LicenseResponse(const uint8_t* message, + size_t core_message_length, + ODK_ParseLicense_Args* a, + ODK_NonceValues* nonce_values, + ODK_ParsedLicense* parsed_lic); + +OEMCryptoResult odk_deserialize_RenewalResponse( + const uint8_t* buf, size_t len, ODK_ParseRenewal_Args* a, + ODK_NonceValues* nonce_values, ODK_PreparedRenewalRequest* renewal_msg); + +OEMCryptoResult odk_deserialize_ProvisioningResponse( + const uint8_t* buf, size_t len, ODK_ParseProvisioning_Args* a, + ODK_NonceValues* nonce_values, ODK_ParsedProvisioning* parsed_prov); + +bool kdo_serialize_LicenseResponse(const ODK_ParseLicense_Args* args, + const ODK_ParsedLicense& parsed_lic, + std::string* oemcrypto_core_message); + +bool kdo_serialize_RenewalResponse( + const ODK_ParseRenewal_Args* args, + const ODK_PreparedRenewalRequest& renewal_msg, + std::string* oemcrypto_core_message); + +bool kdo_serialize_ProvisioningResponse( + const ODK_ParseProvisioning_Args* args, + const ODK_ParsedProvisioning& parsed_prov, + std::string* oemcrypto_core_message); + +/* Idea behind having three different functions is: */ +/* Only ODK_ParseLicense structure had fields which needed additional */ +/* procession. Having a single function with templated parameter T was */ +/* failing during compile time because other two structures doesn't have */ +/* fields that need additional processing. Hence to reduce code redundance and + */ +/* make us of common FuzzerMutateResponse across three response fuzzers, */ +/* three independent functions were defined and renewal and provisioning */ +/* functions would be empty as no additional processing is needed for them. */ +void ConvertDataToValidBools(ODK_ParsedLicense* t); + +void ConvertDataToValidBools(ODK_PreparedRenewalRequest* t); + +void ConvertDataToValidBools(ODK_ParsedProvisioning* t); + +/* Forward-declare the libFuzzer's mutator callback. Mark it weak so that */ +/* the program links successfully even outside of --config=asan-fuzzer */ +/* (apparently the only config in which LLVM uses our custom mutator). */ +extern "C" size_t LLVMFuzzerMutate(uint8_t* Data, size_t Size, size_t MaxSize) + __attribute__((weak)); + +template +size_t FuzzerMutateResponse(uint8_t* data, size_t size, size_t max_size, + const F& odk_deserialize_fun, + const G& kdo_serialize_fun) { + const size_t kArgsSize = sizeof(A); + const size_t kCoreResponseSize = sizeof(T); + const size_t kTotalResponseSize = kArgsSize + kCoreResponseSize; + + /* Deserializing data in order to make sure it deserializes properly. */ + /* Input byte array format: [function arguments][data to parse]. */ + std::shared_ptr _args(new A()); + A* args = _args.get(); + memcpy(args, data, kArgsSize); + ODK_NonceValues nonce_values = args->nonce_values; + args->nonce_values.api_major_version = ODK_MAJOR_VERSION; + const uint8_t* buf = data + kArgsSize; + T t = {}; + OEMCryptoResult result = + odk_deserialize_fun(buf, size - kArgsSize, args, &nonce_values, &t); + + /* If data doesn't deserialize successfully, We copy random bytes into */ + /* T and serialize using kdo function */ + /* which will create a valid oemcrypto core message using */ + /* nonce and request hash from function args. OEMCrypto core message acts as + */ + /* input to odk_kdo. */ + if (result != OEMCrypto_SUCCESS) { + if (max_size < kTotalResponseSize) { + return 0; + } + /* Initialize remaining bytes needed in data to zero. */ + if (size < kTotalResponseSize) { + memset(data + size, 0, kTotalResponseSize - size); + } + t = {}; + memcpy(&t, buf, kCoreResponseSize); + } + + /* Ask LLVM to run its usual mutations, hopefully giving us interesting */ + /* inputs. We copy deserialized data into pointer data, run mutations */ + /* and copy back the mutated data to args and t */ + memcpy(data + kArgsSize, &t, kCoreResponseSize); + LLVMFuzzerMutate(data, kTotalResponseSize, kTotalResponseSize); + memcpy(args, data, kArgsSize); + memcpy(&t, data + kArgsSize, kCoreResponseSize); + /* Convert boolean flags in parsed message to valid bytes to */ + /* avoid errors from msan. Only needed for parsed license. */ + ConvertDataToValidBools(&t); + /* Serialize the data after mutation. */ + std::string oemcrypto_core_message; + if (!kdo_serialize_fun(args, t, &oemcrypto_core_message)) { + return 0; + } + + /* Copy mutated and serialized oemcrypto_core_message to data */ + /* so that it acts as input to odk_kdo function. */ + memcpy(data + kArgsSize, oemcrypto_core_message.data(), + oemcrypto_core_message.size()); + return kArgsSize + oemcrypto_core_message.size(); +} + +/** + * Template arguments: + * A: struct holding function arguments + * T: odk deserialize output/kdo serialize input structure + * F: odk deserialize function + * G: kdo serialize function + * + * raw bytes -> F deserialize -> struct T -> G serialize -> raw bytes + */ +template +void odk_kdo(const F& odk_fun, const G& kdo_fun, const uint8_t* in, + const size_t size, const size_t args_size, uint8_t* out) { + T t = {}; + /* Input byte array format: [function arguments][data to parse] */ + if (size < args_size) { + return; + } + const uint8_t* buf = in + args_size; + std::shared_ptr _args(new A()); + A* args = _args.get(); + memcpy(args, in, args_size); + args->nonce_values.api_major_version = ODK_MAJOR_VERSION; + ODK_NonceValues nonce_values = args->nonce_values; + + OEMCryptoResult result = + odk_fun(buf, size - args_size, args, &nonce_values, &t); + if (result != OEMCrypto_SUCCESS) { + return; + } + std::string oemcrypto_core_message; + if (!kdo_fun(args, t, &oemcrypto_core_message)) { + return; + } +} + +/** + * Template arguments: + * T: kdo deserialize output/odk serialize input structure + * F: kdo deserialize function + * G: odk serialize function + * + * raw bytes -> F deserialize -> struct T -> G serialize -> raw bytes + */ +template +static void kdo_odk(const F& kdo_fun, const G& odk_fun, const uint8_t* in, + size_t size, const size_t clock_value_size, uint8_t* out) { + if (size <= clock_value_size) { + return; + } + /* Input byte array format: [Clock Values][data to parse]. */ + /* Only Renewal Request expects clock values to be present. */ + std::string input(reinterpret_cast(in) + clock_value_size, + size - clock_value_size); + T t = {}; + if (!kdo_fun(input, &t)) { + return; + } + ODK_NonceValues nonce_values = {t.api_minor_version, t.api_major_version, + t.nonce, t.session_id}; + OEMCryptoResult err = odk_fun(in, out, &size, t, &nonce_values); + if (OEMCrypto_SUCCESS != err) { + return; + } +} +} /* namespace oemcrypto_core_message */ +#endif /* WIDEVINE_ODK_TEST_FUZZING_ODK_FUZZ_HELPER_H_ */ diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_fuzz_structs.h b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_fuzz_structs.h new file mode 100644 index 00000000..c88de194 --- /dev/null +++ b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_fuzz_structs.h @@ -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. */ +#ifndef WIDEVINE_ODK_TEST_FUZZING_ODK_FUZZ_STRUCTS_H_ +#define WIDEVINE_ODK_TEST_FUZZING_ODK_FUZZ_STRUCTS_H_ + +#include "odk_structs.h" + +struct ODK_ParseLicense_Args { + ODK_NonceValues nonce_values; + uint8_t initial_license_load; + uint8_t usage_entry_present; + uint8_t request_hash[ODK_SHA256_HASH_SIZE]; + ODK_TimerLimits timer_limits; + ODK_ClockValues clock_values; +}; +struct ODK_ParseRenewal_Args { + ODK_NonceValues nonce_values; + uint64_t system_time; + ODK_TimerLimits timer_limits; + ODK_ClockValues clock_values; +}; +struct ODK_ParseProvisioning_Args { + ODK_NonceValues nonce_values; + size_t device_id_length; + uint8_t device_id[64]; +}; +#endif /* WIDEVINE_ODK_TEST_FUZZING_ODK_FUZZ_STRUCTS_H_ */ diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_license_request_fuzz.cpp b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_license_request_fuzz.cpp new file mode 100644 index 00000000..463c604a --- /dev/null +++ b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_license_request_fuzz.cpp @@ -0,0 +1,22 @@ +/* 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 + +#include "core_message_deserialize.h" +#include "fuzzing/odk_fuzz_helper.h" + +namespace oemcrypto_core_message { +using oemcrypto_core_message::deserialize::CoreLicenseRequestFromMessage; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + std::vector out(size); + const size_t kClockValueSize = 0; + kdo_odk(CoreLicenseRequestFromMessage, + odk_serialize_LicenseRequest, data, size, + kClockValueSize, out.data()); + return 0; +} +} // namespace oemcrypto_core_message diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_license_response_fuzz.cpp b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_license_response_fuzz.cpp new file mode 100644 index 00000000..12398fd1 --- /dev/null +++ b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_license_response_fuzz.cpp @@ -0,0 +1,20 @@ +/* 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 + +#include "fuzzing/odk_fuzz_helper.h" + +namespace oemcrypto_core_message { + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + const size_t kLicenseResponseArgsSize = sizeof(ODK_ParseLicense_Args); + std::vector out(size); + odk_kdo( + odk_deserialize_LicenseResponse, kdo_serialize_LicenseResponse, data, + size, kLicenseResponseArgsSize, out.data()); + return 0; +} +} // namespace oemcrypto_core_message diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_license_response_fuzz_with_mutator.cpp b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_license_response_fuzz_with_mutator.cpp new file mode 100644 index 00000000..80c8ff39 --- /dev/null +++ b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_license_response_fuzz_with_mutator.cpp @@ -0,0 +1,35 @@ +/* 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 + +#include "fuzzing/odk_fuzz_helper.h" + +namespace oemcrypto_core_message { + +// The custom mutator: Ensure that each input can be deserialized properly +// by ODK function after mutation. +extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size, + size_t max_size, unsigned int seed) { + const size_t kLicenseResponseArgsSize = sizeof(ODK_ParseLicense_Args); + if (size < kLicenseResponseArgsSize) { + return 0; + } + + // Mutate input data and return mutated input size. + return FuzzerMutateResponse( + data, size, max_size, odk_deserialize_LicenseResponse, + kdo_serialize_LicenseResponse); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + const size_t kLicenseResponseArgsSize = sizeof(ODK_ParseLicense_Args); + std::vector out(size); + odk_kdo( + odk_deserialize_LicenseResponse, kdo_serialize_LicenseResponse, data, + size, kLicenseResponseArgsSize, out.data()); + return 0; +} +} // namespace oemcrypto_core_message diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_provisioning_request_fuzz.cpp b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_provisioning_request_fuzz.cpp new file mode 100644 index 00000000..984534e6 --- /dev/null +++ b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_provisioning_request_fuzz.cpp @@ -0,0 +1,22 @@ +/* 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 + +#include "core_message_deserialize.h" +#include "fuzzing/odk_fuzz_helper.h" + +namespace oemcrypto_core_message { +using oemcrypto_core_message::deserialize::CoreProvisioningRequestFromMessage; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + std::vector out(size); + const size_t kClockValueSize = 0; + kdo_odk(CoreProvisioningRequestFromMessage, + odk_serialize_ProvisioningRequest, data, + size, kClockValueSize, out.data()); + return 0; +} +} // namespace oemcrypto_core_message diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz.cpp b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz.cpp new file mode 100644 index 00000000..90dc017c --- /dev/null +++ b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz.cpp @@ -0,0 +1,21 @@ +/* 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 + +#include "fuzzing/odk_fuzz_helper.h" + +namespace oemcrypto_core_message { + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + const size_t kProvisioningResponseArgsSize = + sizeof(ODK_ParseProvisioning_Args); + std::vector out(size); + odk_kdo( + odk_deserialize_ProvisioningResponse, kdo_serialize_ProvisioningResponse, + data, size, kProvisioningResponseArgsSize, out.data()); + return 0; +} +} // namespace oemcrypto_core_message diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz_with_mutator.cpp b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz_with_mutator.cpp new file mode 100644 index 00000000..17787a41 --- /dev/null +++ b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz_with_mutator.cpp @@ -0,0 +1,38 @@ +/* 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 + +#include "fuzzing/odk_fuzz_helper.h" + +namespace oemcrypto_core_message { + +// The custom mutator: Ensure that each input can be deserialized properly +// by ODK function after mutation. +extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size, + size_t max_size, unsigned int seed) { + const size_t kProvisioningResponseArgsSize = + sizeof(ODK_ParseProvisioning_Args); + if (size < kProvisioningResponseArgsSize) { + return 0; + } + + // Mutate input data and return mutated input size. + return FuzzerMutateResponse( + data, size, max_size, odk_deserialize_ProvisioningResponse, + kdo_serialize_ProvisioningResponse); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + const size_t kProvisioningResponseArgsSize = + sizeof(ODK_ParseProvisioning_Args); + std::vector out(size); + odk_kdo( + odk_deserialize_ProvisioningResponse, kdo_serialize_ProvisioningResponse, + data, size, kProvisioningResponseArgsSize, out.data()); + return 0; +} +} // namespace oemcrypto_core_message diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_renewal_request_fuzz.cpp b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_renewal_request_fuzz.cpp new file mode 100644 index 00000000..602b37af --- /dev/null +++ b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_renewal_request_fuzz.cpp @@ -0,0 +1,22 @@ +/* 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 + +#include "core_message_deserialize.h" +#include "fuzzing/odk_fuzz_helper.h" + +namespace oemcrypto_core_message { +using oemcrypto_core_message::deserialize::CoreRenewalRequestFromMessage; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + std::vector out(size); + const size_t kClockValueSize = sizeof(ODK_ClockValues); + kdo_odk(CoreRenewalRequestFromMessage, + odk_serialize_RenewalRequest, data, size, + kClockValueSize, out.data()); + return 0; +} +} // namespace oemcrypto_core_message diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz.cpp b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz.cpp new file mode 100644 index 00000000..8d669089 --- /dev/null +++ b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz.cpp @@ -0,0 +1,20 @@ +/* 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 + +#include "fuzzing/odk_fuzz_helper.h" + +namespace oemcrypto_core_message { + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + const size_t kRenewalResponseArgsSize = sizeof(ODK_ParseRenewal_Args); + std::vector out(size); + odk_kdo( + odk_deserialize_RenewalResponse, kdo_serialize_RenewalResponse, data, + size, kRenewalResponseArgsSize, out.data()); + return 0; +} +} // namespace oemcrypto_core_message diff --git a/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz_with_mutator.cpp b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz_with_mutator.cpp new file mode 100644 index 00000000..0073c4ee --- /dev/null +++ b/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz_with_mutator.cpp @@ -0,0 +1,36 @@ +/* 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 + +#include "fuzzing/odk_fuzz_helper.h" + +namespace oemcrypto_core_message { + +// The custom mutator: Ensure that each input can be deserialized properly +// by ODK function after mutation. +extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size, + size_t max_size, unsigned int seed) { + const size_t kRenewalResponseArgsSize = sizeof(ODK_ParseRenewal_Args); + if (size < kRenewalResponseArgsSize) { + return 0; + } + + // Mutate input data and return mutated input size. + return FuzzerMutateResponse( + data, size, max_size, odk_deserialize_RenewalResponse, + kdo_serialize_RenewalResponse); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + const size_t kRenewalResponseArgsSize = sizeof(ODK_ParseRenewal_Args); + std::vector out(size); + odk_kdo( + odk_deserialize_RenewalResponse, kdo_serialize_RenewalResponse, data, + size, kRenewalResponseArgsSize, out.data()); + return 0; +} +} // namespace oemcrypto_core_message