PiperOrigin-RevId: 525266553 Merged from https://widevine-internal-review.googlesource.com/169640 Change-Id: Id92dac068a2b2f767287641170f7b522f54588e4
179 lines
7.7 KiB
C++
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
|