Files
android/libwvdrmengine/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp
Vicky Min 152f2144f9 Fix ODK warning errors for WV DRM
PiperOrigin-RevId: 525266553
Merged from https://widevine-internal-review.googlesource.com/169640

Change-Id: Id92dac068a2b2f767287641170f7b522f54588e4
2024-01-29 11:51:41 -08:00

179 lines
7.7 KiB
C++

// Copyright 2020 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
#include "fuzzing/odk_fuzz_helper.h"
#include <string>
#include "core_message_types.h"
#include "odk.h"
#include "odk_attributes.h"
#include "odk_structs.h"
namespace oemcrypto_core_message {
using features::CoreMessageFeatures;
bool convert_byte_to_valid_boolean(const bool* in) {
const char* buf = reinterpret_cast<const char*>(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) {
// TODO(mattfedd): hook up counters to fuzzer
const ODK_MessageCounterInfo counter_info = {0, 0, 0, 0, 0,
0, 0, {0}, {0}, {0}};
return ODK_PrepareCoreLicenseRequest(out, SIZE_MAX, size, nonce_values,
&counter_info);
}
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 UNUSED,
const ODK_NonceValues* nonce_values) {
// TODO(mattfedd): hook up counters to fuzzer
const ODK_MessageCounterInfo counter_info = {0, 0, 0, 0, 0,
0, 0, {0}, {0}, {0}};
return ODK_PrepareCoreProvisioningRequest(out, SIZE_MAX, size, nonce_values,
&counter_info);
}
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), 0,
&a->timer_limits, &a->clock_values, nonce_values,
parsed_lic, nullptr);
}
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<uint8_t*>(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;
const ODK_MessageCounter counter_info = {0, 0, 0, 0, 0, 0, 0, {0}, {0}, {0}};
ODK_LicenseRequest core_request{
nonce_values.api_minor_version, nonce_values.api_major_version,
nonce_values.nonce, nonce_values.session_id, counter_info};
std::string core_request_sha_256(
reinterpret_cast<const char*>(args->request_hash), ODK_SHA256_HASH_SIZE);
return serialize::CreateCoreLicenseResponse(
CoreMessageFeatures::kDefaultFeatures, 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(
CoreMessageFeatures::kDefaultFeatures, 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;
}
const ODK_MessageCounter counter_info = {0, 0, 0, 0, 0, 0, 0, {0}, {0}, {0}};
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),
0,
"",
counter_info};
return serialize::CreateCoreProvisioningResponse(
CoreMessageFeatures::kDefaultFeatures, parsed_prov, core_request,
oemcrypto_core_message);
}
} // namespace oemcrypto_core_message