// 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 UNUSED) {} void ConvertDataToValidBools(ODK_ParsedProvisioning* t UNUSED) {} OEMCryptoResult odk_serialize_LicenseRequest( 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); } 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 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; 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); const bool is_parse_renewal_response_successful = err == ODK_SET_TIMER || err == ODK_DISABLE_TIMER || err == ODK_TIMER_EXPIRED || err == ODK_STALE_RENEWAL; if (!is_parse_renewal_response_successful) { return err; } // In order to capture playback_time information which is part of // renewal_msg and will be later used in kdo_serialize_RenewalResponse in // odk_kdo method, we call Unpack_ODK_PreparedRenewalRequest private method. // playback_time cannot be captured from publicly exposed API // ODK_ParseRenewal. ODK_Message msg = ODK_Message_Create(const_cast(buf), len); ODK_Message_SetSize(&msg, len); Unpack_ODK_PreparedRenewalRequest(&msg, renewal_msg); return OEMCrypto_SUCCESS; } 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