Files
oemcrypto/oemcrypto/odk/test/odk_fuzz.cpp
Fred Gylys-Colwell 9fa2cbdb67 OEMCrypto v16.1 -- update ODK
This CL updates the ODK library to address review comments.
2020-02-01 11:56:34 -08:00

229 lines
8.3 KiB
C++

/* 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 <string>
#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"
// TODO(b/147297226): remove this: using namespace std;
// TODO(b/147297226): remove this: using namespace oec_util;
typedef std::function<size_t(const uint8_t*, uint8_t*, size_t)> roundtrip_fun;
// @ kdo deserialize; odk derialize
static OEMCryptoResult odk_fun_LicenseRequest(
uint8_t* out, size_t* size, uint32_t api_version, uint32_t nonce,
uint32_t session_id, const ODK_LicenseRequest& /*core_license_request*/) {
return ODK_PrepareCoreLicenseRequest(out, SIZE_MAX, size, api_version, nonce,
session_id);
}
static OEMCryptoResult odk_fun_RenewalRequest(
uint8_t* out, size_t* size, uint32_t api_version, uint32_t nonce,
uint32_t session_id, const ODK_RenewalRequest& core_renewal) {
// todo: fuzz ODK_ClockValues
ODK_ClockValues clock = {};
uint64_t system_time_seconds = core_renewal.playback_time;
return ODK_PrepareCoreRenewalRequest(out, SIZE_MAX, size, api_version, nonce,
session_id, &clock, system_time_seconds);
}
static OEMCryptoResult odk_fun_ProvisioningRequest(
uint8_t* out, size_t* size, uint32_t api_version, uint32_t nonce,
uint32_t session_id, const ODK_ProvisioningRequest& core_provisioning) {
const std::string& device_id = core_provisioning.device_id;
return ODK_PrepareCoreProvisioningRequest(
out, SIZE_MAX, size, api_version, nonce, session_id,
reinterpret_cast<const uint8_t*>(device_id.data()), device_id.size());
}
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 {
std::string input(reinterpret_cast<const char*>(in), size);
T t = {};
if (!kdo_fun(input, &t)) {
return 0;
}
OEMCryptoResult err =
odk_fun(out, &size, t.api_version, t.nonce, t.session_id, t);
return OEMCrypto_SUCCESS == err ? size : 0;
};
return roundtrip;
}
// @ odk deserialize; kdo serialize
namespace {
struct ODK_Common_Args {
uint32_t api_version;
uint32_t nonce;
uint32_t session_id;
};
struct ODK_ParseLicense_Args {
ODK_Common_Args common;
uint8_t initial_license_load;
uint8_t usage_entry_present;
};
struct ODK_ParseRenewal_Args {
ODK_Common_Args common;
uint64_t system_time;
ODK_TimerLimits timer_limits;
ODK_ClockValues clock_values;
};
struct ODK_ParseProvisioning_Args {
ODK_Common_Args common;
size_t device_id_length;
uint8_t device_id[64];
};
} // namespace
static OEMCryptoResult odk_fun_LicenseResponse(
const uint8_t* message, size_t message_length, uint32_t api_version,
uint32_t nonce, uint32_t session_id, const ODK_ParseLicense_Args* a,
ODK_ParsedLicense& parsed_lic) {
return ODK_ParseLicense(
message, message_length, api_version, nonce, session_id,
static_cast<bool>(a->initial_license_load),
static_cast<bool>(a->usage_entry_present), &parsed_lic);
}
static bool kdo_fun_LicenseResponse(const ODK_ParseLicense_Args* args,
const ODK_ParsedLicense& parsed_lic,
std::string* oemcrypto_core_message) {
const auto& common = args->common;
ODK_LicenseRequest core_request{common.api_version, common.nonce,
common.session_id};
return CreateCoreLicenseResponse(parsed_lic, core_request,
oemcrypto_core_message);
}
static OEMCryptoResult odk_fun_RenewalResponse(
const uint8_t* buf, size_t len, uint32_t api_version, uint32_t nonce,
uint32_t session_id, ODK_ParseRenewal_Args* a,
ODK_RenewalMessage& renewal_msg) {
uint64_t timer_value = 0;
OEMCryptoResult err =
ODK_ParseRenewal(buf, len, api_version, nonce, session_id, 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_RenewalMessage(msg, &renewal_msg);
assert(ValidMessage(msg));
}
return err;
}
static bool kdo_fun_RenewalResponse(const ODK_ParseRenewal_Args* args,
const ODK_RenewalMessage& renewal_msg,
std::string* oemcrypto_core_message) {
const auto& common = args->common;
ODK_RenewalRequest core_request{common.api_version, common.nonce,
common.session_id, renewal_msg.playback_time};
return CreateCoreRenewalResponse(core_request, oemcrypto_core_message);
}
static OEMCryptoResult odk_fun_ProvisioningResponse(
const uint8_t* buf, size_t len, uint32_t api_version, uint32_t nonce,
uint32_t session_id, ODK_ParseProvisioning_Args* a,
ODK_ParsedProvisioning& parsed_prov) {
return ODK_ParseProvisioning(buf, len, api_version, nonce, session_id,
a->device_id, a->device_id_length, &parsed_prov);
}
static bool kdo_fun_ProvisioningResponse(
const ODK_ParseProvisioning_Args* args,
const ODK_ParsedProvisioning& parsed_prov,
std::string* oemcrypto_core_message) {
const auto& common = args->common;
assert(args->device_id_length <= sizeof(args->device_id));
ODK_ProvisioningRequest core_request{
common.api_version, common.nonce, common.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 <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 {
if (sizeof(A) > size) {
return 0;
}
T t = {};
const uint8_t* buf = in + sizeof(A);
size_t len = size - sizeof(A);
std::shared_ptr<A> _args(new A());
A* args = _args.get();
memcpy(args, in, sizeof(A));
const auto& common = args->common;
OEMCryptoResult err = odk_fun(buf, len, common.api_version, common.nonce,
common.session_id, args, t);
if (err != OEMCrypto_SUCCESS) {
return 0;
}
std::string oemcrypto_core_message;
if (!kdo_fun(args, t, &oemcrypto_core_message)) {
return 0;
}
assert(oemcrypto_core_message.size() <= size);
memcpy(out, oemcrypto_core_message.data(), oemcrypto_core_message.size());
return oemcrypto_core_message.size();
};
return roundtrip;
}
// @ fuzz raw -> parsed -> raw
static void verify_roundtrip(const uint8_t* in, size_t size,
roundtrip_fun roundtrip) {
std::vector<uint8_t> _out(size);
auto out = _out.data();
size_t n = roundtrip(in, out, size);
assert(!n || (n <= size && 0 == memcmp(in, out, n)));
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
verify_roundtrip(
data, size,
kdo_odk<ODK_LicenseRequest>(ParseLicenseRequest, odk_fun_LicenseRequest));
verify_roundtrip(
data, size,
kdo_odk<ODK_RenewalRequest>(ParseRenewalRequest, odk_fun_RenewalRequest));
verify_roundtrip(data, size,
kdo_odk<ODK_ProvisioningRequest>(
ParseProvisioningRequest, odk_fun_ProvisioningRequest));
verify_roundtrip(data, size,
odk_kdo<ODK_ParseLicense_Args, ODK_ParsedLicense>(
odk_fun_LicenseResponse, kdo_fun_LicenseResponse));
verify_roundtrip(data, size,
odk_kdo<ODK_ParseRenewal_Args, ODK_RenewalMessage>(
odk_fun_RenewalResponse, kdo_fun_RenewalResponse));
verify_roundtrip(
data, size,
odk_kdo<ODK_ParseProvisioning_Args, ODK_ParsedProvisioning>(
odk_fun_ProvisioningResponse, kdo_fun_ProvisioningResponse));
return 0;
}