/* 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 #include #include #include #include #include #include #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 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(device_id.data()), device_id.size()); } template 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(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(a->initial_license_load), static_cast(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_PreparedRenewalRequest& 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(buf), len); SetSize(msg, len); Unpack_ODK_PreparedRenewalRequest(msg, &renewal_msg); assert(ValidMessage(msg)); } return err; } static bool kdo_fun_RenewalResponse( const ODK_ParseRenewal_Args* args, const ODK_PreparedRenewalRequest& 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(args->device_id), args->device_id_length)}; return CreateCoreProvisioningResponse(parsed_prov, core_request, oemcrypto_core_message); } template 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 _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 _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(ParseLicenseRequest, odk_fun_LicenseRequest)); verify_roundtrip( data, size, kdo_odk(ParseRenewalRequest, odk_fun_RenewalRequest)); verify_roundtrip(data, size, kdo_odk( ParseProvisioningRequest, odk_fun_ProvisioningRequest)); verify_roundtrip(data, size, odk_kdo( odk_fun_LicenseResponse, kdo_fun_LicenseResponse)); verify_roundtrip(data, size, odk_kdo( odk_fun_RenewalResponse, kdo_fun_RenewalResponse)); verify_roundtrip( data, size, odk_kdo( odk_fun_ProvisioningResponse, kdo_fun_ProvisioningResponse)); return 0; }