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:
Fred Gylys-Colwell
2020-09-11 13:30:58 -07:00
parent 28b13ef65e
commit 20bb84ffee
75 changed files with 5717 additions and 4488 deletions

View File

@@ -62,6 +62,9 @@ library and need to preload that before OEMCrypto unit tests run
* Preload the shared library before running OEMCrypto unit tests
```shell
$ cd oemcrypto/odk/test/fuzzing/corpus
$ mkdir license_request_corpus license_response_corpus renewal_request_corpus renewal_response_corpus provisioning_request_corpus provisioning_response_corpus
$ cd /path/to/cdm/repo
$ LD_PRELOAD=out/Default/lib/libodk_corpus_generator.so ./out/Default/oemcrypto_unittests
```

View File

@@ -1,8 +1,8 @@
/* 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. */
// 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 <dlfcn.h> */
// We must define this macro to get RTLD_NEXT definition from <dlfcn.h>
#define _GNU_SOURCE
#include <dlfcn.h>
@@ -21,7 +21,7 @@ OEMCryptoResult ODK_PrepareCoreLicenseRequest(
message, message_length, core_message_length, nonce_values);
char* file_name = GetFileName("license_request_corpus");
/* License Request format expected by fuzzer - [Core License Request] */
// 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;
@@ -50,9 +50,8 @@ OEMCryptoResult ODK_ParseLicense(
nonce_values, parsed_license);
char* file_name = GetFileName("license_response_corpus");
/* License Response format expected by fuzzer - [ODK_ParseLicense_Args][Core
*/
/* License Response] */
// 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);
@@ -74,8 +73,8 @@ OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message,
nonce_values, clock_values, system_time_seconds);
char* file_name = GetFileName("renewal_request_corpus");
/* License Request format expected by fuzzer - [ODK_ClockValues][Core */
/* License Request] */
// 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);
@@ -103,9 +102,8 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
timer_limits, clock_values, timer_value);
char* file_name = GetFileName("renewal_response_corpus");
/* Renewal Response format expected by fuzzer - [ODK_ParseRenewal_Args][Core
*/
/* Renewal Response] */
// 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);
@@ -126,8 +124,8 @@ OEMCryptoResult ODK_PrepareCoreProvisioningRequest(
nonce_values, device_id, device_id_length);
char* file_name = GetFileName("provisioning_request_corpus");
/* Provisioning Request format expected by fuzzer - [Core Provisioning */
/* Request] */
// 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;
@@ -150,8 +148,8 @@ OEMCryptoResult ODK_ParseProvisioning(
device_id_length, parsed_response);
char* file_name = GetFileName("provisioning_response_corpus");
/* Provisioning Response format expected by fuzzer - */
/* [ODK_ParseProvisioning_Args][Core Provisioning Response] */
// 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);

View File

@@ -1,6 +1,6 @@
/* 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. */
// 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,

View File

@@ -1,6 +1,6 @@
/* 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. */
// 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_
@@ -15,5 +15,4 @@ void AppendToFile(const char* file_name, const char* message,
char* GetFileName(const char* directory);
#endif /* WIDEVINE_ODK_TEST_FUZZING_CORPUS_GENERATOR_ODK_CORPUS_GENERATOR_HELPER_H_ \
*/
#endif // WIDEVINE_ODK_TEST_FUZZING_CORPUS_GENERATOR_ODK_CORPUS_GENERATOR_HELPER_H_

View File

@@ -28,13 +28,13 @@ void ConvertDataToValidBools(ODK_ParsedLicense* t) {
&t->timer_limits.soft_enforce_rental_duration);
}
void ConvertDataToValidBools(ODK_PreparedRenewalRequest* t) {}
void ConvertDataToValidBools(ODK_PreparedRenewalRequest* t UNUSED) {}
void ConvertDataToValidBools(ODK_ParsedProvisioning* t) {}
void ConvertDataToValidBools(ODK_ParsedProvisioning* t UNUSED) {}
OEMCryptoResult odk_serialize_LicenseRequest(
const void* in, uint8_t* out, size_t* size,
const ODK_LicenseRequest& core_license_request,
const void* in UNUSED, uint8_t* out, size_t* size,
const ODK_LicenseRequest& core_license_request UNUSED,
const ODK_NonceValues* nonce_values) {
return ODK_PrepareCoreLicenseRequest(out, SIZE_MAX, size, nonce_values);
}
@@ -50,7 +50,7 @@ OEMCryptoResult odk_serialize_RenewalRequest(
}
OEMCryptoResult odk_serialize_ProvisioningRequest(
const void* in, uint8_t* out, size_t* size,
const void* in UNUSED, 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;
@@ -99,8 +99,8 @@ OEMCryptoResult odk_deserialize_RenewalResponse(
// odk_kdo method, we call Unpack_ODK_PreparedRenewalRequest private method.
// playback_time cannot be captured from publicly exposed API
// ODK_ParseRenewal.
Message* msg = nullptr;
AllocateMessage(&msg, message_block);
uint8_t blk[SIZE_OF_MESSAGE_STRUCT];
Message* msg = reinterpret_cast<Message*>(blk);
InitMessage(msg, const_cast<uint8_t*>(buf), len);
SetSize(msg, len);
Unpack_ODK_PreparedRenewalRequest(msg, renewal_msg);

View File

@@ -1,6 +1,6 @@
/* 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. */
// 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_
@@ -9,6 +9,7 @@
#include "core_message_serialize.h"
#include "fuzzing/odk_fuzz_structs.h"
#include "odk_attributes.h"
#include "odk_serialize.h"
namespace oemcrypto_core_message {
@@ -56,24 +57,23 @@ bool kdo_serialize_ProvisioningResponse(
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. */
// 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). */
// 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));
@@ -85,8 +85,8 @@ size_t FuzzerMutateResponse(uint8_t* data, size_t size, size_t max_size,
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]. */
// Deserializing data in order to make sure it deserializes properly.
// Input byte array format: [function arguments][data to parse].
std::shared_ptr<A> _args(new A());
A* args = _args.get();
memcpy(args, data, kArgsSize);
@@ -97,17 +97,16 @@ size_t FuzzerMutateResponse(uint8_t* data, size_t size, size_t max_size,
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 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. */
// Initialize remaining bytes needed in data to zero.
if (size < kTotalResponseSize) {
memset(data + size, 0, kTotalResponseSize - size);
}
@@ -115,24 +114,24 @@ size_t FuzzerMutateResponse(uint8_t* data, size_t size, size_t max_size,
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 */
// 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. */
// 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. */
// 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. */
// 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();
@@ -149,9 +148,9 @@ size_t FuzzerMutateResponse(uint8_t* data, size_t size, size_t max_size,
*/
template <typename A, typename T, typename F, typename G>
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) {
const size_t size, const size_t args_size, uint8_t* out UNUSED) {
T t = {};
/* Input byte array format: [function arguments][data to parse] */
// Input byte array format: [function arguments][data to parse]
if (size < args_size) {
return;
}
@@ -187,8 +186,8 @@ static void kdo_odk(const F& kdo_fun, const G& odk_fun, const uint8_t* in,
if (size <= clock_value_size) {
return;
}
/* Input byte array format: [Clock Values][data to parse]. */
/* Only Renewal Request expects clock values to be present. */
// Input byte array format: [Clock Values][data to parse].
// Only Renewal Request expects clock values to be present.
std::string input(reinterpret_cast<const char*>(in) + clock_value_size,
size - clock_value_size);
T t = {};
@@ -202,5 +201,5 @@ static void kdo_odk(const F& kdo_fun, const G& odk_fun, const uint8_t* in,
return;
}
}
} /* namespace oemcrypto_core_message */
#endif /* WIDEVINE_ODK_TEST_FUZZING_ODK_FUZZ_HELPER_H_ */
} // namespace oemcrypto_core_message
#endif // WIDEVINE_ODK_TEST_FUZZING_ODK_FUZZ_HELPER_H_

View File

@@ -1,6 +1,6 @@
/* 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. */
// 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_
@@ -25,4 +25,4 @@ struct ODK_ParseProvisioning_Args {
size_t device_id_length;
uint8_t device_id[64];
};
#endif /* WIDEVINE_ODK_TEST_FUZZING_ODK_FUZZ_STRUCTS_H_ */
#endif // WIDEVINE_ODK_TEST_FUZZING_ODK_FUZZ_STRUCTS_H_

View File

@@ -12,7 +12,8 @@ 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) {
size_t max_size,
unsigned int seed UNUSED) {
const size_t kLicenseResponseArgsSize = sizeof(ODK_ParseLicense_Args);
if (size < kLicenseResponseArgsSize) {
return 0;

View File

@@ -6,13 +6,15 @@
#include <vector>
#include "fuzzing/odk_fuzz_helper.h"
#include "odk_attributes.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) {
size_t max_size,
unsigned int seed UNUSED) {
const size_t kProvisioningResponseArgsSize =
sizeof(ODK_ParseProvisioning_Args);
if (size < kProvisioningResponseArgsSize) {

View File

@@ -6,13 +6,15 @@
#include <vector>
#include "fuzzing/odk_fuzz_helper.h"
#include "odk_attributes.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) {
size_t max_size,
unsigned int seed UNUSED) {
const size_t kRenewalResponseArgsSize = sizeof(ODK_ParseRenewal_Args);
if (size < kRenewalResponseArgsSize) {
return 0;

View File

@@ -0,0 +1,37 @@
// 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 "OEMCryptoCENCCommon.h"
#include "gtest/gtest.h"
#include "odk.h"
#include "third_party/absl/strings/escaping.h"
namespace wvodk_test {
TEST(CoreMessageTest, RenwalRequest) {
std::string oem =
"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst"
"uvwxyzabcdefghijklmnopqrstuvwxyz";
const uint8_t* buf = reinterpret_cast<const uint8_t*>(oem.c_str());
uint8_t* message = const_cast<uint8_t*>(buf);
size_t message_length = 88;
size_t core_message_length = 88;
uint16_t api_minor_version = 16;
uint16_t api_major_version = 16;
uint32_t nonce = 0;
uint32_t timer_status = 2;
uint64_t time = 10;
enum OEMCrypto_Usage_Entry_Status status = kInactiveUsed;
ODK_NonceValues nonce_values{api_minor_version, api_major_version, nonce};
ODK_ClockValues clock_values{time, time, time, time,
time, timer_status, status};
uint64_t system_time_seconds = 100;
EXPECT_EQ(OEMCrypto_SUCCESS,
ODK_PrepareCoreRenewalRequest(message, message_length,
&core_message_length, &nonce_values,
&clock_values, system_time_seconds));
// All messages have at least a five 4-byte fields.
char* m = reinterpret_cast<char*>(message);
VLOG(0) << absl::BytesToHexString(std::string(m, core_message_length));
}
} // namespace wvodk_test

View File

@@ -1,326 +0,0 @@
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary
* source code may only be used and distributed under the Widevine Master
* License Agreement.
*/
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <functional>
#include <memory>
#include <vector>
#include "OEMCryptoCENCCommon.h"
#include "core_message_deserialize.h"
#include "core_message_serialize.h"
#include "core_message_types.h"
#include "odk.h"
#include "odk_serialize.h"
#include "odk_structs.h"
#include "odk_structs_priv.h"
typedef std::function<void(const uint8_t*, uint8_t*, size_t, size_t)>
roundtrip_fun;
using oemcrypto_core_message::ODK_LicenseRequest;
using oemcrypto_core_message::ODK_ProvisioningRequest;
using oemcrypto_core_message::ODK_RenewalRequest;
using oemcrypto_core_message::deserialize::CoreLicenseRequestFromMessage;
using oemcrypto_core_message::deserialize::CoreProvisioningRequestFromMessage;
using oemcrypto_core_message::deserialize::CoreRenewalRequestFromMessage;
using oemcrypto_core_message::serialize::CreateCoreLicenseResponse;
using oemcrypto_core_message::serialize::CreateCoreProvisioningResponse;
using oemcrypto_core_message::serialize::CreateCoreRenewalResponse;
// @ kdo deserialize; odk serialize
static 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);
}
static 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);
}
static 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<const uint8_t*>(device_id.data()), device_id.size());
}
/**
* 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 <typename T, typename F, typename G>
static roundtrip_fun kdo_odk(const F& kdo_fun, const G& odk_fun) {
auto roundtrip = [&](const uint8_t* in, uint8_t* out, size_t size,
size_t clock_value_size) -> void {
if (size <= clock_value_size) {
return;
}
// Input byte array format: [Clock Values][data to parse]
std::string input(reinterpret_cast<const char*>(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;
}
assert(0 == memcmp(in + clock_value_size, out, size));
};
return roundtrip;
}
// @ odk deserialize; kdo serialize
namespace {
struct ODK_ParseLicense_Args {
ODK_NonceValues nonce_values;
uint8_t initial_license_load;
uint8_t usage_entry_present;
uint8_t request_hash[32];
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];
};
} // namespace
bool convert_byte_to_valid_boolean(const bool* in) {
const int value = *reinterpret_cast<const int*>(in);
return value != 0;
}
static 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<bool>(a->initial_license_load),
static_cast<bool>(a->usage_entry_present),
a->request_hash, &a->timer_limits, &a->clock_values,
nonce_values, parsed_lic);
}
static 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<const char*>(args->request_hash), 32);
return CreateCoreLicenseResponse(
parsed_lic, core_request, core_request_sha_256, oemcrypto_core_message);
}
static 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<uint8_t*>(buf), len);
SetSize(msg, len);
Unpack_ODK_PreparedRenewalRequest(msg, renewal_msg);
assert(ValidMessage(msg));
}
return err;
}
static 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 CreateCoreRenewalResponse(
core_request, args->timer_limits.initial_renewal_duration_seconds,
oemcrypto_core_message);
}
static 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);
}
static 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<const char*>(args->device_id),
args->device_id_length)};
return CreateCoreProvisioningResponse(parsed_prov, core_request,
oemcrypto_core_message);
}
/**
* 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 <typename A, typename T, typename F, typename G>
static roundtrip_fun odk_kdo(const F& odk_fun, const G& kdo_fun) {
auto roundtrip = [&](const uint8_t* in, uint8_t* out, size_t size,
size_t args_size) -> void {
// Input byte array format: [function arguments][data to parse]
if (args_size > size) {
return;
}
T t = {};
const uint8_t* buf = in + args_size;
std::shared_ptr<A> _args(new A());
A* args = _args.get();
memcpy(args, in, args_size);
args->nonce_values.api_major_version = ODK_MAJOR_VERSION;
args->nonce_values.api_minor_version = ODK_MINOR_VERSION;
/*
* Input random bytes from autofuzz are interpreted by this script as
* [function args][data to parse]. Odk deserialize functions
* expect the nonce values in function args to match with those
* in data to parse which is not possible with random bytes.
* We follow two pass approach.
*
* 1st pass - We copy random bytes into struct t and call kdo serialize
* with function args which will create oemcrypto core message using nonce
* from function args. Now we have a valid oemcrypto core message which is
* formed using nonce_values from function args which acts as input bytes
* for 2nd pass
*
* 2nd pass - oemcrypto core message from 1st pass guarantees that
* nonce_values in [function args] and core message match. we call
* odk_deserialize using nonce from function args and oemcrypto core message
* from 1st pass. Then we call kdo function which generates oemcrypto core
* message2, which should be equal to oemcrypto_core_message which was input
* to 2nd pass
*/
// TODO(ellurubharath): Use structure aware fuzzing
// 1st pass
memcpy(&t, buf, sizeof(t));
std::string oemcrypto_core_message;
if (!kdo_fun(args, t, &oemcrypto_core_message)) {
return;
}
assert(oemcrypto_core_message.size() <= size);
// 2nd pass
ODK_NonceValues nonce_values = args->nonce_values;
OEMCryptoResult result =
odk_fun(reinterpret_cast<const uint8_t*>(oemcrypto_core_message.data()),
oemcrypto_core_message.size(), args, &nonce_values, &t);
if (result != OEMCrypto_SUCCESS) {
return;
}
std::string oemcrypto_core_message2;
if (!kdo_fun(args, t, &oemcrypto_core_message2)) {
return;
}
assert(oemcrypto_core_message == oemcrypto_core_message2);
};
return roundtrip;
}
// @ fuzz raw -> parsed -> raw
static void verify_roundtrip(const uint8_t* in, size_t size,
roundtrip_fun roundtrip, size_t args_size) {
std::vector<uint8_t> _out(size);
auto out = _out.data();
roundtrip(in, out, size, args_size);
}
// Entry point for fuzzer, data is random bytes program gets from autofuzzer
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
verify_roundtrip(data, size,
kdo_odk<ODK_LicenseRequest>(CoreLicenseRequestFromMessage,
odk_serialize_LicenseRequest),
0);
verify_roundtrip(data, size,
kdo_odk<ODK_RenewalRequest>(CoreRenewalRequestFromMessage,
odk_serialize_RenewalRequest),
sizeof(ODK_ClockValues));
verify_roundtrip(
data, size,
kdo_odk<ODK_ProvisioningRequest>(CoreProvisioningRequestFromMessage,
odk_serialize_ProvisioningRequest),
0);
verify_roundtrip(
data, size,
odk_kdo<ODK_ParseLicense_Args, ODK_ParsedLicense>(
odk_deserialize_LicenseResponse, kdo_serialize_LicenseResponse),
sizeof(ODK_ParseLicense_Args));
verify_roundtrip(
data, size,
odk_kdo<ODK_ParseRenewal_Args, ODK_PreparedRenewalRequest>(
odk_deserialize_RenewalResponse, kdo_serialize_RenewalResponse),
sizeof(ODK_ParseRenewal_Args));
verify_roundtrip(data, size,
odk_kdo<ODK_ParseProvisioning_Args, ODK_ParsedProvisioning>(
odk_deserialize_ProvisioningResponse,
kdo_serialize_ProvisioningResponse),
sizeof(ODK_ParseProvisioning_Args));
return 0;
}

View File

@@ -209,8 +209,10 @@ TEST(OdkTest, SerializeFieldsStress) {
TEST(OdkTest, NullRequestTest) {
size_t core_message_length = 0;
ODK_NonceValues nonce_values{0};
ODK_ClockValues clock_values{0};
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
ODK_ClockValues clock_values;
memset(&clock_values, 0, sizeof(clock_values));
// Assert that nullptr does not cause a core dump.
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreLicenseRequest(
@@ -250,10 +252,12 @@ TEST(OdkTest, NullResponseTest) {
uint8_t message[message_size] = {0};
size_t core_message_length = message_size;
uint8_t request_hash[ODK_SHA256_HASH_SIZE] = {0};
ODK_TimerLimits timer_limits{0};
ODK_TimerLimits timer_limits;
ODK_ParsedLicense parsed_license;
ODK_NonceValues nonce_values{0};
ODK_ClockValues clock_values{0};
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
ODK_ClockValues clock_values;
memset(&clock_values, 0, sizeof(clock_values));
// Assert that nullptr does not cause a core dump.
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
@@ -322,7 +326,8 @@ TEST(OdkTest, NullResponseTest) {
TEST(OdkTest, PrepareCoreLicenseRequest) {
uint8_t license_message[ODK_LICENSE_REQUEST_SIZE] = {0};
size_t core_message_length = sizeof(license_message);
ODK_NonceValues nonce_values{0};
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
EXPECT_EQ(OEMCrypto_SUCCESS, ODK_PrepareCoreLicenseRequest(
license_message, sizeof(license_message),
&core_message_length, &nonce_values));
@@ -331,7 +336,8 @@ TEST(OdkTest, PrepareCoreLicenseRequest) {
TEST(OdkTest, PrepareCoreLicenseRequestSize) {
uint8_t license_message[ODK_LICENSE_REQUEST_SIZE] = {0};
size_t core_message_length = sizeof(license_message);
ODK_NonceValues nonce_values{0};
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
// message length smaller than core message length
size_t core_message_length_invalid = core_message_length + 1;
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
@@ -349,8 +355,10 @@ TEST(OdkTest, PrepareCoreLicenseRequestSize) {
TEST(OdkTest, PrepareCoreRenewalRequest) {
uint8_t renewal_message[ODK_RENEWAL_REQUEST_SIZE] = {0};
size_t core_message_length = sizeof(renewal_message);
ODK_NonceValues nonce_values{0};
ODK_ClockValues clock_values{0};
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
ODK_ClockValues clock_values;
memset(&clock_values, 0, sizeof(clock_values));
constexpr uint64_t system_time_seconds = 10;
EXPECT_EQ(OEMCrypto_SUCCESS,
ODK_PrepareCoreRenewalRequest(
@@ -363,7 +371,8 @@ TEST(OdkTest, PrepareCoreRenewalRequestTimer) {
size_t core_message_length = sizeof(renewal_message);
ODK_NonceValues nonce_values{2, 16, 0, 0};
constexpr uint64_t system_time_seconds = 10;
ODK_ClockValues clock_values_updated{0};
ODK_ClockValues clock_values_updated;
memset(&clock_values_updated, 0, sizeof(clock_values_updated));
// system time smaller than first decrypt time
clock_values_updated.time_of_first_decrypt = system_time_seconds + 1;
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
@@ -383,7 +392,8 @@ TEST(OdkTest, PrepareCoreRenewalRequestTimer) {
TEST(OdkTest, PrepareCoreProvisioningRequest) {
uint8_t provisioning_message[ODK_PROVISIONING_REQUEST_SIZE] = {0};
size_t core_message_length = sizeof(provisioning_message);
ODK_NonceValues nonce_values{0};
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0};
EXPECT_EQ(
OEMCrypto_SUCCESS,
@@ -395,7 +405,8 @@ TEST(OdkTest, PrepareCoreProvisioningRequest) {
TEST(OdkTest, PrepareCoreProvisioningRequestDeviceId) {
uint8_t provisioning_message[ODK_PROVISIONING_REQUEST_SIZE] = {0};
size_t core_message_length = sizeof(provisioning_message);
ODK_NonceValues nonce_values{0};
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
uint8_t device_id_invalid[ODK_DEVICE_ID_LEN_MAX + 1] = {0};
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreProvisioningRequest(
@@ -423,7 +434,8 @@ TEST(OdkTest, RenewalRequestRoundtrip) {
const std::vector<ODK_Field> extra_fields = {
{ODK_UINT64, &playback_time, "playback_time"},
};
ODK_ClockValues clock_values = {0};
ODK_ClockValues clock_values;
memset(&clock_values, 0, sizeof(clock_values));
clock_values.time_of_first_decrypt = playback_start;
auto odk_prepare_func = [&](uint8_t* const buf, size_t* size,
ODK_NonceValues* nonce_values) {
@@ -713,6 +725,17 @@ TEST(OdkSizeTest, ProvisioningRequest) {
EXPECT_EQ(ODK_PROVISIONING_REQUEST_SIZE, core_message_length);
}
// Verify the version string contains the right version numbers.
TEST(OdkTest, CheckReleaseVersion) {
// Here are the version numbers.
std::string expected_version = std::to_string(ODK_MAJOR_VERSION) + "." +
std::to_string(ODK_MINOR_VERSION);
// Here is the version string.
EXPECT_NE(std::string(ODK_RELEASE_DATE).find(expected_version),
std::string::npos)
<< "Version mismatch in odk_structs.h";
}
} // namespace
} // namespace wvodk_test

View File

@@ -1,6 +1,6 @@
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
// Copyright 2019 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_ODK_TEST_HELPER_H_
#define WIDEVINE_ODK_TEST_ODK_TEST_HELPER_H_
@@ -66,7 +66,7 @@ struct ODK_ProvisioningResponseParams {
std::vector<ODK_Field> extra_fields;
};
/* Default values in core_message for testing */
// Default values in core_message for testing
void ODK_SetDefaultCoreFields(ODK_CoreMessage* core_message,
uint32_t message_type);
void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params);
@@ -77,9 +77,9 @@ void ODK_SetDefaultProvisioningResponseParams(
size_t ODK_FieldLength(ODK_FieldType type);
size_t ODK_AllocSize(ODK_FieldType type);
/* Copy ODK_Field to buf */
// Copy ODK_Field to buf
OEMCryptoResult ODK_WriteSingleField(uint8_t* buf, const ODK_Field* field);
/* Load buf to ODK_Field */
// Load buf to ODK_Field
OEMCryptoResult ODK_ReadSingleField(const uint8_t* buf, const ODK_Field* field);
OEMCryptoResult ODK_DumpSingleField(const uint8_t* buf, const ODK_Field* field);
OEMCryptoResult ODK_IterFields(ODK_FieldMode mode, uint8_t* buf,
@@ -89,11 +89,11 @@ void ODK_ExpectEqualBuf(const void* s1, const void* s2, size_t n,
const std::vector<ODK_Field>& fields);
void ODK_ResetOdkFields(std::vector<ODK_Field>* fields);
/* Serialize core_message and extra_fields into buf */
// Serialize core_message and extra_fields into buf
void ODK_BuildMessageBuffer(ODK_CoreMessage* core_message,
const std::vector<ODK_Field>& extra_fields,
uint8_t** buf, uint32_t* buf_size);
} /* namespace wvodk_test */
} // namespace wvodk_test
#endif /* WIDEVINE_ODK_TEST_ODK_TEST_HELPER_H_ */
#endif // WIDEVINE_ODK_TEST_ODK_TEST_HELPER_H_

View File

@@ -35,6 +35,7 @@ TEST(OdkTimerBasicTest, NullTest) {
TEST(OdkTimerBasicTest, Init) {
// Verify that basic initialization sets all of the fields.
ODK_ClockValues clock_values;
memset(&clock_values, 0, sizeof(clock_values));
uint64_t time = 42;
ODK_InitializeClockValues(&clock_values, time);
EXPECT_EQ(clock_values.time_of_license_signed, time);
@@ -50,6 +51,7 @@ TEST(OdkTimerBasicTest, Reload) {
// Verify that reloading clock values uses the same values
// for fields that can be saved, and sets others to 0.
ODK_ClockValues clock_values;
memset(&clock_values, 0, sizeof(clock_values));
uint64_t time = 42u;
uint64_t lic_signed = 1u;
uint64_t first_decrypt = 2u;
@@ -1223,6 +1225,7 @@ TEST_F(ODKUseCase_LimitedDurationLicense, Case5) {
TEST_F(RenewalTest, V15Test) {
const uint32_t key_duration = 25;
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
const uint64_t license_loaded = GetSystemTime(10);
EXPECT_EQ(
ODK_InitializeV15Values(&timer_limits_, &clock_values_, &nonce_values,