* This is a change required to migrate function parameters to absl::Span from const std::vector (2 times)
See go/vector2span for more information on why you've received this change and why it is important.
This CL looks good? Just LGTM and Approve it!
This CL doesn’t look good? This is what you can do:
* Revert this CL, by replying "REVERT: <provide reason>"
* File a bug under go/absl-span-params-bug for category AbslSpanParams if there's an issue with the CL content.
* File a bug under go/rosie-bug if there's an issue with how the CL was managed.
* For all other issues such as the formatting of the CL, please file a bug under
go/clrobot-bug.
* Revert this CL and not get a CL that cleans up these paths in the future by
replying "BLOCKLIST: <provide reason>". This is not reversible! We recommend to
opt out the respective paths in your CL Robot configuration instead:
go/clrobot-opt-out.
This CL was generated by CL Robot - a tool that cleans up code findings
(go/clrobot). The affected code paths have been enabled for CL Robot in //depot/google3/METADATA by
following go/clrobot#how-to-opt-in. Anything wrong with the signup? File a bug
at go/clrobot-bug.
#codehealth
Tested:
Local presubmit tests passed.
PiperOrigin-RevId: 601411040
Change-Id: I4235e711867fde7cf3c9f27bb0cae3453853394d
795 lines
29 KiB
C++
795 lines
29 KiB
C++
// Copyright 2019 Google LLC. This file and proprietary
|
|
// source code may only be used and distributed under the Widevine
|
|
// License Agreement.
|
|
|
|
#include "odk_test_helper.h"
|
|
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <fstream>
|
|
#include <iomanip>
|
|
#include <ios>
|
|
#include <iostream>
|
|
#include <ostream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "OEMCryptoCENCCommon.h"
|
|
#include "gtest/gtest.h"
|
|
#include "odk_endian.h"
|
|
#include "odk_structs.h"
|
|
#include "odk_structs_priv.h"
|
|
#include "third_party/absl/types/span.h"
|
|
|
|
namespace wvodk_test {
|
|
|
|
void ODK_SetDefaultCoreFields(ODK_CoreMessage* core_message,
|
|
ODK_MessageType message_type) {
|
|
ASSERT_TRUE(core_message != nullptr);
|
|
core_message->message_type = message_type;
|
|
core_message->message_length = 0;
|
|
core_message->nonce_values.api_minor_version = ODK_MINOR_VERSION;
|
|
core_message->nonce_values.api_major_version = ODK_MAJOR_VERSION;
|
|
core_message->nonce_values.nonce = 0xdeadbeef;
|
|
core_message->nonce_values.session_id = 0xcafebabe;
|
|
}
|
|
|
|
void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params,
|
|
uint32_t odk_major_version) {
|
|
ODK_SetDefaultCoreFields(&(params->core_message), ODK_License_Response_Type);
|
|
params->initial_license_load = true;
|
|
params->usage_entry_present = true;
|
|
params->parsed_license = {
|
|
.enc_mac_keys_iv = {.offset = 0, .length = 1},
|
|
.enc_mac_keys = {.offset = 2, .length = 3},
|
|
.pst = {.offset = 4, .length = 5},
|
|
.srm_restriction_data = {.offset = 6, .length = 7},
|
|
.license_type = OEMCrypto_EntitlementLicense,
|
|
.nonce_required = true,
|
|
.timer_limits =
|
|
{
|
|
.soft_enforce_rental_duration = true,
|
|
.soft_enforce_playback_duration = false,
|
|
.earliest_playback_start_seconds = 10,
|
|
.rental_duration_seconds = 11,
|
|
.total_playback_duration_seconds = 12,
|
|
.initial_renewal_duration_seconds = 13,
|
|
},
|
|
.watermarking = 0,
|
|
.dtcp2_required = {.dtcp2_required = 0,
|
|
.cmi_descriptor_0 =
|
|
{
|
|
.id = 0,
|
|
.extension = 0,
|
|
.length = 1,
|
|
.data = 0,
|
|
},
|
|
.cmi_descriptor_1 =
|
|
{
|
|
.id = 1,
|
|
.extension = 0,
|
|
.length = 3,
|
|
.data = {0, 0, 0},
|
|
},
|
|
.cmi_descriptor_2 =
|
|
{
|
|
.id = 2,
|
|
.extension = 0,
|
|
.length = 3,
|
|
.data = {0, 0, 0},
|
|
}},
|
|
.renewal_delay_base = OEMCrypto_License_Start,
|
|
.key_array_length = 3,
|
|
.key_array =
|
|
{
|
|
{
|
|
.key_id = {.offset = 15, .length = 16},
|
|
.key_data_iv = {.offset = 17, .length = 18},
|
|
.key_data = {.offset = 19, .length = 20},
|
|
.key_control_iv = {.offset = 21, .length = 22},
|
|
.key_control = {.offset = 23, .length = 24},
|
|
},
|
|
{
|
|
.key_id = {.offset = 25, .length = 26},
|
|
.key_data_iv = {.offset = 27, .length = 28},
|
|
.key_data = {.offset = 29, .length = 30},
|
|
.key_control_iv = {.offset = 31, .length = 32},
|
|
.key_control = {.offset = 33, .length = 34},
|
|
},
|
|
{
|
|
.key_id = {.offset = 35, .length = 36},
|
|
.key_data_iv = {.offset = 37, .length = 38},
|
|
.key_data = {.offset = 39, .length = 40},
|
|
.key_control_iv = {.offset = 41, .length = 42},
|
|
.key_control = {.offset = 43, .length = 44},
|
|
},
|
|
},
|
|
};
|
|
memset(params->request_hash, 0xaa, sizeof(params->request_hash));
|
|
params->extra_fields = {
|
|
{ODK_SUBSTRING, &(params->parsed_license.enc_mac_keys_iv),
|
|
".enc_mac_keys_iv"},
|
|
{ODK_SUBSTRING, &(params->parsed_license.enc_mac_keys), ".enc_mac_keys"},
|
|
{ODK_SUBSTRING, &(params->parsed_license.pst), ".pst"},
|
|
{ODK_SUBSTRING, &(params->parsed_license.srm_restriction_data),
|
|
".srm_restriction_data"},
|
|
{ODK_UINT32, &(params->parsed_license.license_type), ".license_type"},
|
|
{ODK_UINT32, &(params->parsed_license.nonce_required), ".nonce_required"},
|
|
{ODK_BOOL,
|
|
&(params->parsed_license.timer_limits.soft_enforce_rental_duration),
|
|
".soft_enforce_rental_duration"},
|
|
{ODK_BOOL,
|
|
&(params->parsed_license.timer_limits.soft_enforce_playback_duration),
|
|
".soft_enforce_playback_duration"},
|
|
{ODK_UINT64,
|
|
&(params->parsed_license.timer_limits.earliest_playback_start_seconds),
|
|
".earliest_playback_start_seconds"},
|
|
{ODK_UINT64,
|
|
&(params->parsed_license.timer_limits.rental_duration_seconds),
|
|
".rental_duration_seconds"},
|
|
{ODK_UINT64,
|
|
&(params->parsed_license.timer_limits.total_playback_duration_seconds),
|
|
".total_playback_duration_seconds"},
|
|
{ODK_UINT64,
|
|
&(params->parsed_license.timer_limits.initial_renewal_duration_seconds),
|
|
".initial_renewal_duration_seconds"},
|
|
};
|
|
if (odk_major_version >= 17) {
|
|
params->extra_fields.push_back(
|
|
{ODK_UINT32, &(params->parsed_license.watermarking), ".watermarking"});
|
|
params->extra_fields.push_back(
|
|
{ODK_UINT8, &(params->parsed_license.dtcp2_required.dtcp2_required),
|
|
".dtcp2_required"});
|
|
if (params->parsed_license.dtcp2_required.dtcp2_required) {
|
|
params->extra_fields.push_back(
|
|
{ODK_UINT8,
|
|
&(params->parsed_license.dtcp2_required.cmi_descriptor_0.id),
|
|
".cmi_descriptor_data"});
|
|
params->extra_fields.push_back(
|
|
{ODK_UINT8,
|
|
&(params->parsed_license.dtcp2_required.cmi_descriptor_0.extension),
|
|
".cmi_descriptor_data"});
|
|
params->extra_fields.push_back(
|
|
{ODK_UINT16,
|
|
&(params->parsed_license.dtcp2_required.cmi_descriptor_0.length),
|
|
".cmi_descriptor_data"});
|
|
params->extra_fields.push_back(
|
|
{ODK_UINT8,
|
|
&(params->parsed_license.dtcp2_required.cmi_descriptor_0.data),
|
|
".cmi_descriptor_data"});
|
|
params->extra_fields.push_back(
|
|
{ODK_UINT8,
|
|
&(params->parsed_license.dtcp2_required.cmi_descriptor_1.id),
|
|
".cmi_descriptor_data"});
|
|
params->extra_fields.push_back(
|
|
{ODK_UINT8,
|
|
&(params->parsed_license.dtcp2_required.cmi_descriptor_1.extension),
|
|
".cmi_descriptor_data"});
|
|
params->extra_fields.push_back(
|
|
{ODK_UINT16,
|
|
&(params->parsed_license.dtcp2_required.cmi_descriptor_1.length),
|
|
".cmi_descriptor_data"});
|
|
params->extra_fields.push_back(
|
|
{ODK_UINT8,
|
|
&(params->parsed_license.dtcp2_required.cmi_descriptor_1.data[0]),
|
|
".cmi_descriptor_data"});
|
|
params->extra_fields.push_back(
|
|
{ODK_UINT8,
|
|
&(params->parsed_license.dtcp2_required.cmi_descriptor_1.data[1]),
|
|
".cmi_descriptor_data"});
|
|
params->extra_fields.push_back(
|
|
{ODK_UINT8,
|
|
&(params->parsed_license.dtcp2_required.cmi_descriptor_1.data[2]),
|
|
".cmi_descriptor_data"});
|
|
params->extra_fields.push_back(
|
|
{ODK_UINT8,
|
|
&(params->parsed_license.dtcp2_required.cmi_descriptor_2.id),
|
|
".cmi_descriptor_data"});
|
|
params->extra_fields.push_back(
|
|
{ODK_UINT8,
|
|
&(params->parsed_license.dtcp2_required.cmi_descriptor_2.extension),
|
|
".cmi_descriptor_data"});
|
|
params->extra_fields.push_back(
|
|
{ODK_UINT16,
|
|
&(params->parsed_license.dtcp2_required.cmi_descriptor_2.length),
|
|
".cmi_descriptor_data"});
|
|
params->extra_fields.push_back(
|
|
{ODK_UINT8,
|
|
&(params->parsed_license.dtcp2_required.cmi_descriptor_2.data[0]),
|
|
".cmi_descriptor_data"});
|
|
params->extra_fields.push_back(
|
|
{ODK_UINT8,
|
|
&(params->parsed_license.dtcp2_required.cmi_descriptor_2.data[1]),
|
|
".cmi_descriptor_data"});
|
|
params->extra_fields.push_back(
|
|
{ODK_UINT8,
|
|
&(params->parsed_license.dtcp2_required.cmi_descriptor_2.data[2]),
|
|
".cmi_descriptor_data"});
|
|
}
|
|
}
|
|
if (odk_major_version >= 18) {
|
|
params->extra_fields.push_back(
|
|
{ODK_UINT32, &(params->parsed_license.renewal_delay_base),
|
|
".renewal_delay_base"});
|
|
}
|
|
params->extra_fields.push_back({ODK_UINT32,
|
|
&(params->parsed_license.key_array_length),
|
|
".key_array_length"});
|
|
params->extra_fields.push_back({ODK_SUBSTRING,
|
|
&(params->parsed_license.key_array[0].key_id),
|
|
".key_id"});
|
|
params->extra_fields.push_back(
|
|
{ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_data_iv),
|
|
".key_data_iv"});
|
|
params->extra_fields.push_back(
|
|
{ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_data),
|
|
".key_data"});
|
|
params->extra_fields.push_back(
|
|
{ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_control_iv),
|
|
".key_control_iv"});
|
|
params->extra_fields.push_back(
|
|
{ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_control),
|
|
".key_control"});
|
|
params->extra_fields.push_back({ODK_SUBSTRING,
|
|
&(params->parsed_license.key_array[1].key_id),
|
|
".key_id"});
|
|
params->extra_fields.push_back(
|
|
{ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_data_iv),
|
|
".key_data_iv"});
|
|
params->extra_fields.push_back(
|
|
{ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_data),
|
|
".key_data"});
|
|
params->extra_fields.push_back(
|
|
{ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_control_iv),
|
|
".key_control_iv"});
|
|
params->extra_fields.push_back(
|
|
{ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_control),
|
|
".key_control"});
|
|
params->extra_fields.push_back({ODK_SUBSTRING,
|
|
&(params->parsed_license.key_array[2].key_id),
|
|
".key_id"});
|
|
params->extra_fields.push_back(
|
|
{ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_data_iv),
|
|
".key_data_iv"});
|
|
params->extra_fields.push_back(
|
|
{ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_data),
|
|
".key_data"});
|
|
params->extra_fields.push_back(
|
|
{ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_control_iv),
|
|
".key_control_iv"});
|
|
params->extra_fields.push_back(
|
|
{ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_control),
|
|
".key_control"});
|
|
if (odk_major_version == 16) {
|
|
params->extra_fields.push_back(
|
|
{ODK_HASH, params->request_hash, ".request_hash"});
|
|
}
|
|
}
|
|
|
|
void ODK_SetDefaultReleaseResponseParams(ODK_ReleaseResponseParams* params) {
|
|
ODK_SetDefaultCoreFields(&(params->core_message), ODK_Release_Response_Type);
|
|
params->status = kActive;
|
|
params->clock_security_level = 0;
|
|
params->seconds_since_license_requested = 0;
|
|
params->seconds_since_first_decrypt = 0;
|
|
}
|
|
|
|
void ODK_SetDefaultRenewalResponseParams(ODK_RenewalResponseParams* params) {
|
|
ODK_SetDefaultCoreFields(&(params->core_message), ODK_Renewal_Response_Type);
|
|
params->system_time = 0xfaceb00c;
|
|
params->playback_clock = 10;
|
|
params->playback_timer = 20;
|
|
params->renewal_duration = 300;
|
|
params->extra_fields = {
|
|
{ODK_UINT64, &(params->playback_clock), "playback_clock"},
|
|
{ODK_UINT64, &(params->renewal_duration), "renewal_duration"},
|
|
};
|
|
params->timer_limits = {
|
|
.soft_enforce_rental_duration = false,
|
|
.soft_enforce_playback_duration = false,
|
|
.earliest_playback_start_seconds = 0,
|
|
.rental_duration_seconds = 1000,
|
|
.total_playback_duration_seconds = 2000,
|
|
.initial_renewal_duration_seconds = 300,
|
|
};
|
|
params->clock_values = {
|
|
.time_of_license_request_signed =
|
|
params->system_time - params->playback_clock - 42,
|
|
.time_of_first_decrypt = params->system_time - params->playback_clock,
|
|
.time_of_last_decrypt = params->system_time - params->playback_clock,
|
|
.time_of_renewal_request = params->playback_clock,
|
|
.time_when_timer_expires = params->system_time + params->playback_timer,
|
|
.timer_status = ODK_CLOCK_TIMER_STATUS_ACTIVE,
|
|
.status = kActive,
|
|
};
|
|
}
|
|
|
|
void ODK_SetDefaultProvisioningResponseParams(
|
|
ODK_ProvisioningResponseParams* params, uint32_t odk_major_version) {
|
|
ODK_SetDefaultCoreFields(&(params->core_message),
|
|
ODK_Provisioning_Response_Type);
|
|
params->device_id_length = ODK_DEVICE_ID_LEN_MAX / 2;
|
|
memset(params->device_id, 0xff, params->device_id_length);
|
|
memset(params->device_id + params->device_id_length, 0,
|
|
ODK_DEVICE_ID_LEN_MAX - params->device_id_length);
|
|
params->parsed_provisioning = {
|
|
.key_type = OEMCrypto_RSA_Private_Key,
|
|
.enc_private_key = {.offset = 0, .length = 1},
|
|
.enc_private_key_iv = {.offset = 2, .length = 3},
|
|
.encrypted_message_key = {.offset = 4, .length = 5},
|
|
};
|
|
|
|
params->extra_fields = {};
|
|
// V17 uses device_id
|
|
if (odk_major_version <= 17) {
|
|
params->extra_fields.push_back(
|
|
{ODK_UINT32, &(params->device_id_length), "device_id_length"});
|
|
params->extra_fields.push_back(
|
|
{ODK_DEVICEID, params->device_id, "device_id"});
|
|
}
|
|
|
|
params->extra_fields.push_back(
|
|
{ODK_UINT32, &(params->parsed_provisioning).key_type, "key_type"});
|
|
params->extra_fields.push_back(
|
|
{ODK_SUBSTRING, &(params->parsed_provisioning).enc_private_key,
|
|
"enc_private_key"});
|
|
params->extra_fields.push_back(
|
|
{ODK_SUBSTRING, &(params->parsed_provisioning).enc_private_key_iv,
|
|
"enc_private_key_iv"});
|
|
params->extra_fields.push_back(
|
|
{ODK_SUBSTRING, &(params->parsed_provisioning).encrypted_message_key,
|
|
"encrypted_message_key"});
|
|
}
|
|
|
|
void ODK_SetDefaultProvisioning40ResponseParams(
|
|
ODK_Provisioning40ResponseParams* params) {
|
|
ODK_SetDefaultCoreFields(&(params->core_message),
|
|
ODK_Provisioning_Response_Type);
|
|
params->extra_fields = {};
|
|
}
|
|
|
|
size_t ODK_FieldLength(ODK_FieldType type) {
|
|
switch (type) {
|
|
case ODK_UINT8:
|
|
return sizeof(uint8_t);
|
|
case ODK_UINT16:
|
|
return sizeof(uint16_t);
|
|
case ODK_UINT32:
|
|
return sizeof(uint32_t);
|
|
case ODK_UINT64:
|
|
return sizeof(uint64_t);
|
|
case ODK_INT64:
|
|
return sizeof(uint64_t);
|
|
case ODK_BOOL: // Booleans are stored in the message as 32 bit ints.
|
|
return sizeof(uint32_t);
|
|
case ODK_SUBSTRING:
|
|
return sizeof(uint32_t) + sizeof(uint32_t);
|
|
case ODK_DEVICEID:
|
|
return ODK_DEVICE_ID_LEN_MAX;
|
|
case ODK_MESSAGECOUNTER:
|
|
return ODK_MESSAGECOUNTERINFO_SIZE;
|
|
case ODK_DEVICEINFO:
|
|
return ODK_DEVICE_INFO_LEN_MAX;
|
|
case ODK_RENEWALDATA:
|
|
return ODK_KEYBOX_RENEWAL_DATA_SIZE;
|
|
case ODK_HASH:
|
|
return ODK_SHA256_HASH_SIZE;
|
|
default:
|
|
return SIZE_MAX;
|
|
}
|
|
}
|
|
|
|
size_t ODK_AllocSize(ODK_FieldType type) {
|
|
if (type == ODK_SUBSTRING) {
|
|
return sizeof(OEMCrypto_Substring);
|
|
}
|
|
if (type == ODK_MESSAGECOUNTER) {
|
|
return sizeof(ODK_MessageCounterInfo);
|
|
}
|
|
return ODK_FieldLength(type);
|
|
}
|
|
|
|
OEMCryptoResult ODK_WriteSingleField(uint8_t* buf, const ODK_Field* field) {
|
|
if (buf == nullptr || field == nullptr || field->value == nullptr) {
|
|
return ODK_ERROR_CORE_MESSAGE;
|
|
}
|
|
switch (field->type) {
|
|
case ODK_UINT8: {
|
|
memcpy(buf, field->value, sizeof(uint8_t));
|
|
break;
|
|
}
|
|
case ODK_UINT16: {
|
|
const uint16_t u16 =
|
|
oemcrypto_htobe16(*static_cast<uint16_t*>(field->value));
|
|
memcpy(buf, &u16, sizeof(u16));
|
|
break;
|
|
}
|
|
case ODK_UINT32: {
|
|
const uint32_t u32 =
|
|
oemcrypto_htobe32(*static_cast<uint32_t*>(field->value));
|
|
memcpy(buf, &u32, sizeof(u32));
|
|
break;
|
|
}
|
|
case ODK_UINT64: {
|
|
const uint64_t u64 =
|
|
oemcrypto_htobe64(*static_cast<uint64_t*>(field->value));
|
|
memcpy(buf, &u64, sizeof(u64));
|
|
break;
|
|
}
|
|
case ODK_INT64: {
|
|
const int64_t i64 =
|
|
oemcrypto_htobe64(*static_cast<int64_t*>(field->value));
|
|
memcpy(buf, &i64, sizeof(i64));
|
|
break;
|
|
}
|
|
case ODK_BOOL: {
|
|
const bool value = *static_cast<bool*>(field->value);
|
|
const uint32_t u32 = oemcrypto_htobe32(value ? 1 : 0);
|
|
memcpy(buf, &u32, sizeof(u32));
|
|
break;
|
|
}
|
|
case ODK_SUBSTRING: {
|
|
OEMCrypto_Substring* s = static_cast<OEMCrypto_Substring*>(field->value);
|
|
const uint32_t off = oemcrypto_htobe32(s->offset);
|
|
const uint32_t len = oemcrypto_htobe32(s->length);
|
|
memcpy(buf, &off, sizeof(off));
|
|
memcpy(buf + sizeof(off), &len, sizeof(len));
|
|
break;
|
|
}
|
|
case ODK_DEVICEID:
|
|
case ODK_DEVICEINFO:
|
|
case ODK_RENEWALDATA:
|
|
case ODK_HASH: {
|
|
const size_t field_len = ODK_FieldLength(field->type);
|
|
const uint8_t* const id = static_cast<uint8_t*>(field->value);
|
|
memcpy(buf, id, field_len);
|
|
|
|
break;
|
|
}
|
|
case ODK_MESSAGECOUNTER: {
|
|
// Size required in field->value, which may get padding from the compiler.
|
|
const size_t src_len = ODK_AllocSize(field->type);
|
|
// Size taken up in serialized message buffer, which is tightly packed.
|
|
const size_t dest_len = ODK_FieldLength(field->type);
|
|
const uint8_t* const write_src = static_cast<uint8_t*>(field->value);
|
|
|
|
// Copy data from field to buf, fixing endian-ness
|
|
ODK_MessageCounterInfo info;
|
|
memcpy(&info, write_src, src_len);
|
|
info.master_generation_number =
|
|
oemcrypto_htobe64(info.master_generation_number);
|
|
info.provisioning_count = oemcrypto_htobe32(info.provisioning_count);
|
|
info.license_count = oemcrypto_htobe32(info.license_count);
|
|
info.decrypt_count = oemcrypto_htobe32(info.decrypt_count);
|
|
info.major_version = oemcrypto_htobe16(info.major_version);
|
|
info.minor_version = oemcrypto_htobe16(info.minor_version);
|
|
info.patch_version = oemcrypto_htobe16(info.patch_version);
|
|
memcpy(buf, &info, dest_len);
|
|
break;
|
|
}
|
|
default:
|
|
return ODK_ERROR_CORE_MESSAGE;
|
|
}
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
OEMCryptoResult ODK_ReadSingleField(const uint8_t* buf,
|
|
const ODK_Field* field) {
|
|
if (buf == nullptr || field == nullptr || field->value == nullptr) {
|
|
return ODK_ERROR_CORE_MESSAGE;
|
|
}
|
|
switch (field->type) {
|
|
case ODK_UINT8: {
|
|
memcpy(field->value, buf, sizeof(uint8_t));
|
|
break;
|
|
}
|
|
case ODK_UINT16: {
|
|
memcpy(field->value, buf, sizeof(uint16_t));
|
|
uint16_t* u16p = static_cast<uint16_t*>(field->value);
|
|
*u16p = oemcrypto_be16toh(*u16p);
|
|
break;
|
|
}
|
|
case ODK_UINT32: {
|
|
memcpy(field->value, buf, sizeof(uint32_t));
|
|
uint32_t* u32p = static_cast<uint32_t*>(field->value);
|
|
*u32p = oemcrypto_be32toh(*u32p);
|
|
break;
|
|
}
|
|
case ODK_UINT64: {
|
|
memcpy(field->value, buf, sizeof(uint64_t));
|
|
uint64_t* u64p = static_cast<uint64_t*>(field->value);
|
|
*u64p = oemcrypto_be64toh(*u64p);
|
|
break;
|
|
}
|
|
case ODK_INT64: {
|
|
memcpy(field->value, buf, sizeof(int64_t));
|
|
int64_t* i64p = static_cast<int64_t*>(field->value);
|
|
*i64p = oemcrypto_be64toh(*i64p);
|
|
break;
|
|
}
|
|
case ODK_BOOL: {
|
|
uint32_t value;
|
|
memcpy(&value, buf, sizeof(uint32_t));
|
|
value = oemcrypto_be32toh(value);
|
|
*static_cast<bool*>(field->value) = (value != 0);
|
|
break;
|
|
}
|
|
case ODK_SUBSTRING: {
|
|
OEMCrypto_Substring* s = static_cast<OEMCrypto_Substring*>(field->value);
|
|
uint32_t off = 0;
|
|
uint32_t len = 0;
|
|
memcpy(&off, buf, sizeof(off));
|
|
memcpy(&len, buf + sizeof(off), sizeof(len));
|
|
s->offset = oemcrypto_be32toh(off);
|
|
s->length = oemcrypto_be32toh(len);
|
|
break;
|
|
}
|
|
case ODK_DEVICEID:
|
|
case ODK_DEVICEINFO:
|
|
case ODK_RENEWALDATA:
|
|
case ODK_HASH: {
|
|
const size_t field_len = ODK_FieldLength(field->type);
|
|
uint8_t* const id = static_cast<uint8_t*>(field->value);
|
|
memcpy(id, buf, field_len);
|
|
break;
|
|
}
|
|
case ODK_MESSAGECOUNTER: {
|
|
// Size required in field->value, which may get padding from the compiler.
|
|
const size_t dest_len = ODK_AllocSize(field->type);
|
|
// Size taken up in serialized message buffer, which is tightly packed.
|
|
const size_t src_len = ODK_FieldLength(field->type);
|
|
uint8_t* const read_dest = static_cast<uint8_t*>(field->value);
|
|
|
|
// Copy data from buf to field, fixing endian-ness
|
|
uint8_t temp_buf[sizeof(ODK_MessageCounterInfo)] = {0};
|
|
memcpy(temp_buf, buf, src_len);
|
|
|
|
size_t index = 0;
|
|
ODK_MessageCounterInfo info;
|
|
uint64_t* u64 = reinterpret_cast<uint64_t*>(&temp_buf[index]);
|
|
info.master_generation_number = oemcrypto_be64toh(*u64);
|
|
index += sizeof(uint64_t);
|
|
|
|
uint32_t* u32 = reinterpret_cast<uint32_t*>(&temp_buf[index]);
|
|
info.provisioning_count = oemcrypto_be32toh(*u32);
|
|
index += sizeof(uint32_t);
|
|
|
|
u32 = reinterpret_cast<uint32_t*>(&temp_buf[index]);
|
|
info.license_count = oemcrypto_be32toh(*u32);
|
|
index += sizeof(uint32_t);
|
|
|
|
u32 = reinterpret_cast<uint32_t*>(&temp_buf[index]);
|
|
info.decrypt_count = oemcrypto_be32toh(*u32);
|
|
index += sizeof(uint32_t);
|
|
|
|
uint16_t* u16 = reinterpret_cast<uint16_t*>(&temp_buf[index]);
|
|
info.major_version = oemcrypto_be16toh(*u16);
|
|
index += sizeof(uint16_t);
|
|
|
|
u16 = reinterpret_cast<uint16_t*>(&temp_buf[index]);
|
|
info.minor_version = oemcrypto_be16toh(*u16);
|
|
index += sizeof(uint16_t);
|
|
|
|
u16 = reinterpret_cast<uint16_t*>(&temp_buf[index]);
|
|
info.patch_version = oemcrypto_be16toh(*u16);
|
|
index += sizeof(uint16_t);
|
|
|
|
memcpy(info.soc_vendor, &temp_buf[index], sizeof(info.soc_vendor));
|
|
index += sizeof(info.soc_vendor);
|
|
memcpy(info.chipset_model, &temp_buf[index], sizeof(info.chipset_model));
|
|
index += sizeof(info.chipset_model);
|
|
memcpy(info.extra, &temp_buf[index], sizeof(info.extra));
|
|
memcpy(read_dest, &info, dest_len);
|
|
break;
|
|
}
|
|
default:
|
|
return ODK_ERROR_CORE_MESSAGE;
|
|
}
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
OEMCryptoResult ODK_DumpSingleField(const uint8_t* buf,
|
|
const ODK_Field* field) {
|
|
if (buf == nullptr || field == nullptr || field->value == nullptr) {
|
|
return ODK_ERROR_CORE_MESSAGE;
|
|
}
|
|
switch (field->type) {
|
|
case ODK_UINT8: {
|
|
uint8_t val;
|
|
memcpy(&val, buf, sizeof(uint8_t));
|
|
std::cerr << field->name << ": " << val << " = 0x" << std::hex << val
|
|
<< "\n";
|
|
break;
|
|
}
|
|
case ODK_UINT16: {
|
|
uint16_t val;
|
|
memcpy(&val, buf, sizeof(uint16_t));
|
|
val = oemcrypto_be16toh(val);
|
|
std::cerr << field->name << ": " << val << " = 0x" << std::hex << val
|
|
<< "\n";
|
|
break;
|
|
}
|
|
case ODK_BOOL:
|
|
case ODK_UINT32: {
|
|
uint32_t val;
|
|
memcpy(&val, buf, sizeof(uint32_t));
|
|
val = oemcrypto_be32toh(val);
|
|
std::cerr << field->name << ": " << val << " = 0x" << std::hex << val
|
|
<< "\n";
|
|
break;
|
|
}
|
|
case ODK_UINT64: {
|
|
uint64_t val;
|
|
memcpy(&val, buf, sizeof(uint64_t));
|
|
val = oemcrypto_be64toh(val);
|
|
std::cerr << field->name << ": " << val << " = 0x" << std::hex << val
|
|
<< "\n";
|
|
break;
|
|
}
|
|
case ODK_INT64: {
|
|
int64_t val;
|
|
memcpy(&val, buf, sizeof(int64_t));
|
|
val = oemcrypto_be64toh(val);
|
|
std::cerr << field->name << ": " << val << " = 0x" << std::hex << val
|
|
<< "\n";
|
|
break;
|
|
}
|
|
case ODK_SUBSTRING: {
|
|
uint32_t off = 0;
|
|
uint32_t len = 0;
|
|
memcpy(&off, buf, sizeof(off));
|
|
memcpy(&len, buf + sizeof(off), sizeof(len));
|
|
std::cerr << field->name << ": (off=" << off << ", len=" << len << ")\n";
|
|
break;
|
|
}
|
|
case ODK_DEVICEID:
|
|
case ODK_MESSAGECOUNTER:
|
|
case ODK_DEVICEINFO:
|
|
case ODK_RENEWALDATA:
|
|
case ODK_HASH: {
|
|
const size_t field_len = ODK_FieldLength(field->type);
|
|
std::cerr << field->name << ": ";
|
|
for (size_t i = 0; i < field_len; i++) {
|
|
std::cerr << std::hex << std::setfill('0') << std::setw(2)
|
|
<< static_cast<unsigned int>(buf[i]);
|
|
}
|
|
std::cerr << "\n";
|
|
break;
|
|
}
|
|
default:
|
|
return ODK_ERROR_CORE_MESSAGE;
|
|
}
|
|
std::cerr << std::dec; // Return to normal.
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Parameters:
|
|
* [in] size_in: buffer size
|
|
* [out] size_out: bytes processed
|
|
*/
|
|
OEMCryptoResult ODK_IterFields(ODK_FieldMode mode, uint8_t* buf,
|
|
const size_t size_in, size_t* size_out,
|
|
absl::Span<const ODK_Field> fields) {
|
|
if (buf == nullptr || size_out == nullptr) {
|
|
return ODK_ERROR_CORE_MESSAGE;
|
|
}
|
|
size_t off = 0, off2 = 0;
|
|
for (size_t i = 0; i < fields.size(); i++) {
|
|
if (__builtin_add_overflow(off, ODK_FieldLength(fields[i].type), &off2) ||
|
|
off2 > size_in) {
|
|
return ODK_ERROR_CORE_MESSAGE;
|
|
}
|
|
uintptr_t base = reinterpret_cast<uintptr_t>(buf);
|
|
if (__builtin_add_overflow(base, off, &base)) {
|
|
return ODK_ERROR_CORE_MESSAGE;
|
|
}
|
|
uint8_t* const buf_off = buf + off;
|
|
switch (mode) {
|
|
case ODK_WRITE:
|
|
ODK_WriteSingleField(buf_off, &fields[i]);
|
|
break;
|
|
case ODK_READ:
|
|
ODK_ReadSingleField(buf_off, &fields[i]);
|
|
break;
|
|
case ODK_DUMP:
|
|
ODK_DumpSingleField(buf_off, &fields[i]);
|
|
break;
|
|
default:
|
|
return ODK_ERROR_CORE_MESSAGE;
|
|
}
|
|
off = off2;
|
|
}
|
|
*size_out = off;
|
|
if (*size_out > size_in) {
|
|
return ODK_ERROR_CORE_MESSAGE;
|
|
}
|
|
return OEMCrypto_SUCCESS;
|
|
}
|
|
|
|
std::vector<ODK_Field> ODK_MakeTotalFields(
|
|
absl::Span<const ODK_Field> extra_fields, ODK_CoreMessage* core_message) {
|
|
std::vector<ODK_Field> total_fields = {
|
|
{ODK_UINT32, &(core_message->message_type), "message_type"},
|
|
{ODK_UINT32, &(core_message->message_length), "message_size"},
|
|
{ODK_UINT16, &(core_message->nonce_values.api_minor_version),
|
|
"api_minor_version"},
|
|
{ODK_UINT16, &(core_message->nonce_values.api_major_version),
|
|
"api_major_version"},
|
|
{ODK_UINT32, &(core_message->nonce_values.nonce), "nonce"},
|
|
{ODK_UINT32, &(core_message->nonce_values.session_id), "session_id"},
|
|
};
|
|
total_fields.insert(total_fields.end(), extra_fields.begin(),
|
|
extra_fields.end());
|
|
return total_fields;
|
|
}
|
|
|
|
// Expect the two buffers of size n to be equal. If not, dump the messages.
|
|
void ODK_ExpectEqualBuf(const void* s1, const void* s2, size_t n,
|
|
const std::vector<ODK_Field>& fields) {
|
|
if (memcmp(s1, s2, n) != 0) {
|
|
ODK_CoreMessage core_message;
|
|
std::vector<ODK_Field> total_fields =
|
|
ODK_MakeTotalFields(fields, &core_message);
|
|
const void* buffers[] = {s1, s2};
|
|
for (int i = 0; i < 2; i++) {
|
|
char _tmp[] = "/tmp/fileXXXXXX";
|
|
const int temp_fd = mkstemp(_tmp);
|
|
if (temp_fd >= 0) {
|
|
close(temp_fd);
|
|
} else {
|
|
std::cerr << "Failed to open temp file." << '\n';
|
|
break;
|
|
}
|
|
std::string tmp(_tmp);
|
|
std::fstream out(tmp, std::ios::out | std::ios::binary);
|
|
out.write(static_cast<const char*>(buffers[i]), n);
|
|
out.close();
|
|
std::cerr << '\n'
|
|
<< "Message buffer " << i << " dumped to " << tmp << '\n';
|
|
size_t bytes_written;
|
|
uint8_t* buf =
|
|
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(buffers[i]));
|
|
ODK_IterFields(ODK_DUMP, buf, n, &bytes_written, total_fields);
|
|
}
|
|
FAIL();
|
|
}
|
|
}
|
|
|
|
void ODK_ResetOdkFields(std::vector<ODK_Field>* fields) {
|
|
if (fields == nullptr) {
|
|
return;
|
|
}
|
|
for (auto& field : *fields) {
|
|
if (field.value != nullptr) {
|
|
const size_t size = ODK_AllocSize(field.type);
|
|
memset(field.value, 0, size);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ODK_BuildMessageBuffer(ODK_CoreMessage* core_message,
|
|
const std::vector<ODK_Field>& extra_fields,
|
|
uint8_t** buf, uint32_t* buf_size) {
|
|
ASSERT_TRUE(core_message != nullptr);
|
|
ASSERT_TRUE(buf_size != nullptr);
|
|
std::vector<ODK_Field> total_fields =
|
|
ODK_MakeTotalFields(extra_fields, core_message);
|
|
|
|
for (auto& field : total_fields) {
|
|
*buf_size += ODK_FieldLength(field.type);
|
|
}
|
|
// update message_size
|
|
*(reinterpret_cast<uint32_t*>(total_fields[1].value)) = *buf_size;
|
|
|
|
*buf = new uint8_t[*buf_size]{};
|
|
size_t bytes_written = 0;
|
|
// serialize ODK fields to message buffer
|
|
EXPECT_EQ(OEMCrypto_SUCCESS, ODK_IterFields(ODK_WRITE, *buf, SIZE_MAX,
|
|
&bytes_written, total_fields));
|
|
EXPECT_EQ(bytes_written, *buf_size);
|
|
}
|
|
|
|
} // namespace wvodk_test
|