Files
ce_cdm/oemcrypto/odk/test/odk_test.cpp
John "Juce" Bruce f11df1e144 Source release 17.1.1
2022-11-29 12:54:04 -08:00

976 lines
42 KiB
C++

// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
#include "odk.h"
#include <cstdlib>
#include <cstring>
#include <string>
#include "OEMCryptoCENCCommon.h"
#include "core_message_deserialize.h"
#include "core_message_features.h"
#include "core_message_serialize.h"
#include "core_message_types.h"
#include "gtest/gtest.h"
#include "odk_structs_priv.h"
#include "odk_test_helper.h"
namespace wvodk_test {
namespace {
using oemcrypto_core_message::ODK_LicenseRequest;
using oemcrypto_core_message::ODK_ProvisioningRequest;
using oemcrypto_core_message::ODK_RenewalRequest;
using oemcrypto_core_message::deserialize::CoreLicenseRequestFromMessage;
using oemcrypto_core_message::deserialize::CoreProvisioningRequestFromMessage;
using oemcrypto_core_message::deserialize::CoreRenewalRequestFromMessage;
using oemcrypto_core_message::deserialize::
CoreRenewedProvisioningRequestFromMessage;
using oemcrypto_core_message::features::CoreMessageFeatures;
using oemcrypto_core_message::serialize::CreateCoreLicenseResponse;
using oemcrypto_core_message::serialize::CreateCoreProvisioningResponse;
using oemcrypto_core_message::serialize::CreateCoreRenewalResponse;
constexpr uint32_t kExtraPayloadSize = 128u;
/* Used to parameterize tests by version number. The request is given one
* version number, and we will expect the response to have another version
* number. */
struct VersionParameters {
uint32_t maximum_major_version;
uint16_t request_major_version;
uint16_t request_minor_version;
uint16_t response_major_version;
uint16_t response_minor_version;
};
// This function is called by GTest when a parameterized test fails in order
// to log the parameter used for the failing test.
void PrintTo(const VersionParameters& p, std::ostream* os) {
*os << "max=v" << p.maximum_major_version << ", request = v"
<< p.request_major_version << "." << p.request_minor_version
<< ", response = v" << p.response_major_version << "."
<< p.response_minor_version;
}
template <typename T, typename F, typename G>
void ValidateRequest(uint32_t message_type,
const std::vector<ODK_Field>& extra_fields,
const F& odk_prepare_func, const G& kdo_parse_func) {
uint32_t message_size = 0;
uint16_t api_major_version = ODK_MAJOR_VERSION;
uint16_t api_minor_version = ODK_MINOR_VERSION;
uint32_t nonce = 0xdeadbeef;
uint32_t session_id = 0xcafebabe;
ODK_NonceValues nonce_values{api_minor_version, api_major_version, nonce,
session_id};
std::vector<ODK_Field> total_fields = {
{ODK_UINT32, &message_type, "message_type"},
{ODK_UINT32, &message_size, "message_size"},
{ODK_UINT16, &api_minor_version, "api_minor_version"},
{ODK_UINT16, &api_major_version, "api_major_version"},
{ODK_UINT32, &nonce, "nonce"},
{ODK_UINT32, &session_id, "session_id"},
};
total_fields.insert(total_fields.end(), extra_fields.begin(),
extra_fields.end());
for (auto& field : total_fields) {
message_size += ODK_FieldLength(field.type);
}
// empty buf, expect core message length to be set correctly
size_t core_message_length = 0;
uint8_t* buf_empty = nullptr;
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
odk_prepare_func(buf_empty, &core_message_length, &nonce_values));
EXPECT_EQ(core_message_length, message_size);
// non-empty buf, expect core message length to be set correctly, and buf is
// filled with ODK_Field values appropriately
uint8_t* buf = new uint8_t[message_size]{};
EXPECT_EQ(OEMCrypto_SUCCESS,
odk_prepare_func(buf, &core_message_length, &nonce_values));
EXPECT_EQ(core_message_length, message_size);
uint8_t* buf_expected = new uint8_t[message_size]{};
size_t buf_len_expected = 0;
EXPECT_EQ(OEMCrypto_SUCCESS, ODK_IterFields(ODK_WRITE, buf_expected, SIZE_MAX,
&buf_len_expected, total_fields));
EXPECT_EQ(buf_len_expected, message_size);
EXPECT_NO_FATAL_FAILURE(
ODK_ExpectEqualBuf(buf_expected, buf, message_size, total_fields));
// odk kdo round-trip: deserialize from buf, then serialize it to buf2
// expect them to be identical
T t = {};
std::string oemcrypto_core_message(reinterpret_cast<char*>(buf),
message_size);
EXPECT_TRUE(kdo_parse_func(oemcrypto_core_message, &t));
nonce_values.api_minor_version = t.api_minor_version;
nonce_values.api_major_version = t.api_major_version;
nonce_values.nonce = t.nonce;
nonce_values.session_id = t.session_id;
uint8_t* buf2 = new uint8_t[message_size]{};
EXPECT_EQ(OEMCrypto_SUCCESS,
odk_prepare_func(buf2, &core_message_length, &nonce_values));
EXPECT_EQ(core_message_length, message_size);
EXPECT_NO_FATAL_FAILURE(
ODK_ExpectEqualBuf(buf, buf2, message_size, total_fields));
delete[] buf;
delete[] buf_expected;
delete[] buf2;
}
/**
* Template arguments:
* T: kdo input struct
* F: odk deserializer
* G: kdo serializer
*/
template <typename T, typename F, typename G>
void ValidateResponse(const VersionParameters& versions,
ODK_CoreMessage* core_message,
const std::vector<ODK_Field>& extra_fields,
const F& odk_parse_func, const G& kdo_prepare_func) {
T t = {};
t.api_major_version = versions.request_major_version;
t.api_minor_version = versions.request_minor_version;
t.nonce = core_message->nonce_values.nonce;
t.session_id = core_message->nonce_values.session_id;
uint8_t* buf = nullptr;
uint32_t buf_size = 0;
ODK_BuildMessageBuffer(core_message, extra_fields, &buf, &buf_size);
uint8_t* zero = new uint8_t[buf_size]{};
size_t bytes_read = 0;
// zero-out input
EXPECT_EQ(OEMCrypto_SUCCESS, ODK_IterFields(ODK_READ, zero, buf_size,
&bytes_read, extra_fields));
// Parse buf with odk
const OEMCryptoResult parse_result = odk_parse_func(buf, buf_size);
EXPECT_EQ(OEMCrypto_SUCCESS, parse_result);
size_t size_out = 0;
if (parse_result != OEMCrypto_SUCCESS) {
ODK_IterFields(ODK_FieldMode::ODK_DUMP, buf, buf_size, &size_out,
extra_fields);
}
// serialize odk output to oemcrypto_core_message
std::string oemcrypto_core_message;
EXPECT_TRUE(kdo_prepare_func(t, &oemcrypto_core_message));
// verify round-trip works
EXPECT_NO_FATAL_FAILURE(ODK_ExpectEqualBuf(buf, oemcrypto_core_message.data(),
buf_size, extra_fields));
delete[] buf;
delete[] zero;
}
TEST(OdkTest, SerializeFields) {
uint32_t x[] = {0, 1, 2};
uint64_t y[] = {3LL << 32, 4LL << 32, 5LL << 32};
OEMCrypto_Substring s = {.offset = 6, .length = 7};
std::vector<ODK_Field> fields = {
{ODK_UINT32, &x[0], "x[0]"}, {ODK_UINT32, &x[1], "x[1]"},
{ODK_UINT32, &x[2], "x[2]"}, {ODK_UINT64, &y[0], "y[0]"},
{ODK_UINT64, &y[1], "y[1]"}, {ODK_UINT64, &y[2], "y[2]"},
{ODK_SUBSTRING, &s, "s"},
};
uint8_t buf[1024] = {0};
uint8_t buf2[1024] = {0};
size_t bytes_read = 0, bytes_written = 0;
ODK_IterFields(ODK_WRITE, buf, SIZE_MAX, &bytes_read, fields);
std::vector<ODK_Field> fields2(fields.size());
ODK_ResetOdkFields(&fields);
ODK_IterFields(ODK_READ, buf, bytes_read, &bytes_written, fields);
ODK_IterFields(ODK_WRITE, buf2, SIZE_MAX, &bytes_read, fields);
EXPECT_NO_FATAL_FAILURE(ODK_ExpectEqualBuf(buf, buf2, bytes_read, fields));
}
TEST(OdkTest, SerializeFieldsStress) {
const int n = 1024;
std::vector<ODK_Field> fields(n);
std::srand(0);
size_t total_size = 0;
for (int i = 0; i < n; i++) {
fields[i].type = static_cast<ODK_FieldType>(
std::rand() % static_cast<int>(ODK_LAST_STRESSABLE_TYPE));
fields[i].value = malloc(ODK_AllocSize(fields[i].type));
fields[i].name = "stress";
total_size += ODK_FieldLength(fields[i].type);
}
uint8_t* buf = new uint8_t[total_size]{};
for (size_t i = 0; i < total_size; i++) {
buf[i] = std::rand() & 0xff;
}
size_t bytes_read = 0, bytes_written = 0;
uint8_t* buf2 = new uint8_t[total_size]{};
ODK_IterFields(ODK_READ, buf, total_size, &bytes_read, fields);
EXPECT_EQ(bytes_read, total_size);
ODK_IterFields(ODK_WRITE, buf2, total_size, &bytes_written, fields);
EXPECT_EQ(bytes_written, total_size);
EXPECT_NO_FATAL_FAILURE(ODK_ExpectEqualBuf(buf, buf2, total_size, fields));
// cleanup
for (int i = 0; i < n; i++) {
free(fields[i].value);
}
delete[] buf;
delete[] buf2;
}
TEST(OdkTest, NullRequestTest) {
size_t core_message_length = 0;
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
ODK_ClockValues clock_values;
memset(&clock_values, 0, sizeof(clock_values));
// Assert that nullptr does not cause a core dump.
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreLicenseRequest(
nullptr, 0uL, nullptr, &nonce_values));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreLicenseRequest(nullptr, 0uL, &core_message_length,
nullptr));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreRenewalRequest(nullptr, 0uL, nullptr, &nonce_values,
&clock_values, 0uL));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreRenewalRequest(nullptr, 0uL, &core_message_length,
nullptr, &clock_values, 0uL));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreRenewalRequest(nullptr, 0uL, &core_message_length,
&nonce_values, nullptr, 0uL));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreProvisioningRequest(
nullptr, 0uL, &core_message_length, nullptr, nullptr, 0uL));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreProvisioningRequest(nullptr, 0uL, nullptr,
&nonce_values, nullptr, 0uL));
// Null device id in provisioning request is ok
uint8_t message[ODK_PROVISIONING_REQUEST_SIZE] = {0};
core_message_length = ODK_PROVISIONING_REQUEST_SIZE;
EXPECT_EQ(OEMCrypto_SUCCESS,
ODK_PrepareCoreProvisioningRequest(
message, ODK_PROVISIONING_REQUEST_SIZE, &core_message_length,
&nonce_values, nullptr, 0uL));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreRenewedProvisioningRequest(
nullptr, 0uL, &core_message_length, nullptr, nullptr, 0uL,
OEMCrypto_RenewalACert, nullptr, 0uL));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreRenewedProvisioningRequest(
nullptr, 0uL, nullptr, &nonce_values, nullptr, 0uL,
OEMCrypto_RenewalACert, nullptr, 0uL));
// Null device id in renewed provisioning request is ok
uint8_t renewed_message[ODK_RENEWED_PROVISIONING_REQUEST_SIZE] = {0};
uint8_t renewal_data[ODK_KEYBOX_RENEWAL_DATA_SIZE] = {0};
uint32_t renewal_data_length = ODK_KEYBOX_RENEWAL_DATA_SIZE;
core_message_length = ODK_RENEWED_PROVISIONING_REQUEST_SIZE;
EXPECT_EQ(OEMCrypto_SUCCESS,
ODK_PrepareCoreRenewedProvisioningRequest(
renewed_message, ODK_RENEWED_PROVISIONING_REQUEST_SIZE,
&core_message_length, &nonce_values, nullptr, 0uL,
OEMCrypto_RenewalACert, renewal_data, renewal_data_length));
// Null renewal data in renewed provisioning request is ok
uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0};
uint32_t device_id_length = ODK_DEVICE_ID_LEN_MAX;
core_message_length = ODK_RENEWED_PROVISIONING_REQUEST_SIZE;
ODK_PrepareCoreRenewedProvisioningRequest(
renewed_message, ODK_RENEWED_PROVISIONING_REQUEST_SIZE,
&core_message_length, &nonce_values, device_id, device_id_length,
OEMCrypto_RenewalACert, nullptr, 0uL);
}
TEST(OdkTest, NullResponseTest) {
constexpr size_t message_size = 64;
uint8_t message[message_size] = {0};
size_t core_message_length = message_size;
ODK_TimerLimits timer_limits;
ODK_ParsedLicense parsed_license;
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
ODK_ClockValues clock_values;
memset(&clock_values, 0, sizeof(clock_values));
// Assert that nullptr does not cause a core dump.
EXPECT_EQ(
ODK_ERROR_CORE_MESSAGE,
ODK_ParseLicense(message, message_size, core_message_length, true, true,
&timer_limits, &clock_values, &nonce_values, nullptr));
EXPECT_EQ(
ODK_ERROR_CORE_MESSAGE,
ODK_ParseLicense(message, message_size, core_message_length, true, true,
&timer_limits, &clock_values, nullptr, &parsed_license));
EXPECT_EQ(
ODK_ERROR_CORE_MESSAGE,
ODK_ParseLicense(message, message_size, core_message_length, true, true,
&timer_limits, nullptr, &nonce_values, &parsed_license));
EXPECT_EQ(
ODK_ERROR_CORE_MESSAGE,
ODK_ParseLicense(message, message_size, core_message_length, true, true,
nullptr, &clock_values, &nonce_values, &parsed_license));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_ParseLicense(nullptr, message_size, core_message_length, true,
true, &timer_limits, &clock_values, &nonce_values,
&parsed_license));
constexpr uint64_t system_time = 0;
uint64_t timer_value = 0;
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_ParseRenewal(message, message_size, core_message_length,
&nonce_values, system_time, &timer_limits, nullptr,
&timer_value));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_ParseRenewal(message, message_size, core_message_length,
&nonce_values, system_time, nullptr, &clock_values,
&timer_value));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_ParseRenewal(message, message_size, core_message_length,
nullptr, system_time, &timer_limits, &clock_values,
&timer_value));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_ParseRenewal(nullptr, message_size, core_message_length,
&nonce_values, system_time, &timer_limits,
&clock_values, &timer_value));
uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0};
ODK_ParsedProvisioning parsed_response;
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_ParseProvisioning(message, message_size, core_message_length,
&nonce_values, device_id,
ODK_DEVICE_ID_LEN_MAX, nullptr));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_ParseProvisioning(message, message_size, core_message_length,
&nonce_values, nullptr, 0, &parsed_response));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_ParseProvisioning(message, message_size, core_message_length,
nullptr, device_id, ODK_DEVICE_ID_LEN_MAX,
&parsed_response));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_ParseProvisioning(nullptr, message_size, core_message_length,
&nonce_values, device_id,
ODK_DEVICE_ID_LEN_MAX, &parsed_response));
}
TEST(OdkTest, PrepareCoreLicenseRequest) {
uint8_t license_message[ODK_LICENSE_REQUEST_SIZE] = {0};
size_t core_message_length = sizeof(license_message);
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
EXPECT_EQ(OEMCrypto_SUCCESS, ODK_PrepareCoreLicenseRequest(
license_message, sizeof(license_message),
&core_message_length, &nonce_values));
}
TEST(OdkTest, PrepareCoreLicenseRequestSize) {
uint8_t license_message[ODK_LICENSE_REQUEST_SIZE] = {0};
size_t core_message_length = sizeof(license_message);
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
// message length smaller than core message length
size_t core_message_length_invalid = core_message_length + 1;
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreLicenseRequest(
license_message, sizeof(license_message),
&core_message_length_invalid, &nonce_values));
// message length larger than core message length
uint8_t license_message_large[ODK_LICENSE_REQUEST_SIZE * 2] = {0};
EXPECT_EQ(OEMCrypto_SUCCESS,
ODK_PrepareCoreLicenseRequest(license_message_large,
sizeof(license_message_large),
&core_message_length, &nonce_values));
}
TEST(OdkTest, PrepareCoreRenewalRequest) {
uint8_t renewal_message[ODK_RENEWAL_REQUEST_SIZE] = {0};
size_t core_message_length = sizeof(renewal_message);
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
ODK_ClockValues clock_values;
memset(&clock_values, 0, sizeof(clock_values));
constexpr uint64_t system_time_seconds = 10;
EXPECT_EQ(OEMCrypto_SUCCESS,
ODK_PrepareCoreRenewalRequest(
renewal_message, sizeof(renewal_message), &core_message_length,
&nonce_values, &clock_values, system_time_seconds));
}
TEST(OdkTest, PrepareCoreRenewalRequestTimer) {
uint8_t renewal_message[ODK_RENEWAL_REQUEST_SIZE] = {0};
size_t core_message_length = sizeof(renewal_message);
ODK_NonceValues nonce_values{2, 16, 0, 0};
constexpr uint64_t system_time_seconds = 10;
ODK_ClockValues clock_values_updated;
memset(&clock_values_updated, 0, sizeof(clock_values_updated));
// system time smaller than first decrypt time
clock_values_updated.time_of_first_decrypt = system_time_seconds + 1;
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreRenewalRequest(
renewal_message, sizeof(renewal_message), &core_message_length,
&nonce_values, &clock_values_updated, system_time_seconds));
clock_values_updated.time_of_first_decrypt = system_time_seconds - 1;
EXPECT_EQ(OEMCrypto_SUCCESS,
ODK_PrepareCoreRenewalRequest(
renewal_message, sizeof(renewal_message), &core_message_length,
&nonce_values, &clock_values_updated, system_time_seconds));
// clock_values.time_of_renewal_request should get updated
EXPECT_EQ(system_time_seconds - clock_values_updated.time_of_first_decrypt,
clock_values_updated.time_of_renewal_request);
}
TEST(OdkTest, PrepareCoreProvisioningRequest) {
uint8_t provisioning_message[ODK_PROVISIONING_REQUEST_SIZE] = {0};
size_t core_message_length = sizeof(provisioning_message);
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0};
EXPECT_EQ(
OEMCrypto_SUCCESS,
ODK_PrepareCoreProvisioningRequest(
provisioning_message, sizeof(provisioning_message),
&core_message_length, &nonce_values, device_id, sizeof(device_id)));
}
TEST(OdkTest, PrepareCoreRenewedProvisioningRequest) {
uint8_t provisioning_message[ODK_RENEWED_PROVISIONING_REQUEST_SIZE] = {0};
size_t core_message_length = sizeof(provisioning_message);
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0};
uint8_t renewal_data[ODK_KEYBOX_RENEWAL_DATA_SIZE] = {0};
EXPECT_EQ(
OEMCrypto_SUCCESS,
ODK_PrepareCoreRenewedProvisioningRequest(
provisioning_message, sizeof(provisioning_message),
&core_message_length, &nonce_values, device_id, sizeof(device_id),
OEMCrypto_RenewalACert, renewal_data, sizeof(renewal_data)));
}
TEST(OdkTest, PrepareCoreProvisioningRequestDeviceId) {
uint8_t provisioning_message[ODK_PROVISIONING_REQUEST_SIZE] = {0};
size_t core_message_length = sizeof(provisioning_message);
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
uint8_t device_id_invalid[ODK_DEVICE_ID_LEN_MAX + 1] = {0};
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreProvisioningRequest(
provisioning_message, sizeof(provisioning_message),
&core_message_length, &nonce_values, device_id_invalid,
sizeof(device_id_invalid)));
}
TEST(OdkTest, PrepareCoreRenewedProvisioningRequestDeviceId) {
uint8_t provisioning_message[ODK_PROVISIONING_REQUEST_SIZE] = {0};
size_t core_message_length = sizeof(provisioning_message);
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
uint8_t device_id_invalid[ODK_DEVICE_ID_LEN_MAX + 1] = {0};
uint8_t renewal_data[ODK_KEYBOX_RENEWAL_DATA_SIZE] = {0};
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreRenewedProvisioningRequest(
provisioning_message, sizeof(provisioning_message),
&core_message_length, &nonce_values, device_id_invalid,
sizeof(device_id_invalid), OEMCrypto_RenewalACert, renewal_data,
sizeof(renewal_data)));
}
TEST(OdkTest, PrepareCoreRenewedProvisioningRequestRenewalDataInvalid) {
uint8_t provisioning_message[ODK_PROVISIONING_REQUEST_SIZE] = {0};
size_t core_message_length = sizeof(provisioning_message);
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0};
uint8_t renewal_data_invalid[ODK_KEYBOX_RENEWAL_DATA_SIZE + 1] = {0};
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreRenewedProvisioningRequest(
provisioning_message, sizeof(provisioning_message),
&core_message_length, &nonce_values, device_id,
sizeof(device_id), OEMCrypto_RenewalACert, renewal_data_invalid,
sizeof(renewal_data_invalid)));
}
// Serialize and de-serialize license request
TEST(OdkTest, LicenseRequestRoundtrip) {
std::vector<ODK_Field> empty;
auto odk_prepare_func = [&](uint8_t* const buf, size_t* size,
ODK_NonceValues* nonce_values) {
return ODK_PrepareCoreLicenseRequest(buf, SIZE_MAX, size, nonce_values);
};
auto kdo_parse_func = CoreLicenseRequestFromMessage;
ValidateRequest<ODK_LicenseRequest>(ODK_License_Request_Type, empty,
odk_prepare_func, kdo_parse_func);
}
TEST(OdkTest, RenewalRequestRoundtrip) {
constexpr uint64_t system_time_seconds = 0xBADDCAFE000FF1CE;
uint64_t playback_time = 0xCAFE00000000;
const uint64_t playback_start = system_time_seconds - playback_time;
const std::vector<ODK_Field> extra_fields = {
{ODK_UINT64, &playback_time, "playback_time"},
};
ODK_ClockValues clock_values;
memset(&clock_values, 0, sizeof(clock_values));
clock_values.time_of_first_decrypt = playback_start;
auto odk_prepare_func = [&](uint8_t* const buf, size_t* size,
ODK_NonceValues* nonce_values) {
return ODK_PrepareCoreRenewalRequest(buf, SIZE_MAX, size, nonce_values,
&clock_values, system_time_seconds);
};
auto kdo_parse_func = [&](const std::string& oemcrypto_core_message,
ODK_RenewalRequest* core_renewal_request) {
bool ok = CoreRenewalRequestFromMessage(oemcrypto_core_message,
core_renewal_request);
return ok;
};
ValidateRequest<ODK_RenewalRequest>(ODK_Renewal_Request_Type, extra_fields,
odk_prepare_func, kdo_parse_func);
}
TEST(OdkTest, ProvisionRequestRoundtrip) {
uint32_t device_id_length = ODK_DEVICE_ID_LEN_MAX / 2;
uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0};
memset(device_id, 0xff, device_id_length);
std::vector<ODK_Field> extra_fields = {
{ODK_UINT32, &device_id_length, "device_id_length"},
{ODK_DEVICEID, device_id, "device_id"},
};
auto odk_prepare_func = [&](uint8_t* const buf, size_t* size,
const ODK_NonceValues* nonce_values) {
return ODK_PrepareCoreProvisioningRequest(buf, SIZE_MAX, size, nonce_values,
device_id, device_id_length);
};
auto kdo_parse_func =
[&](const std::string& oemcrypto_core_message,
ODK_ProvisioningRequest* core_provisioning_request) {
bool ok = CoreProvisioningRequestFromMessage(oemcrypto_core_message,
core_provisioning_request);
return ok;
};
ValidateRequest<ODK_ProvisioningRequest>(ODK_Provisioning_Request_Type,
extra_fields, odk_prepare_func,
kdo_parse_func);
}
TEST(OdkTest, RenewedProvisionRequestRoundtrip) {
uint32_t device_id_length = ODK_DEVICE_ID_LEN_MAX / 2;
uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0};
memset(device_id, 0xff, device_id_length);
uint16_t renewal_type = OEMCrypto_RenewalACert;
uint32_t renewal_data_length = ODK_KEYBOX_RENEWAL_DATA_SIZE / 2;
uint8_t renewal_data[ODK_KEYBOX_RENEWAL_DATA_SIZE] = {0};
memset(renewal_data, 0xff, renewal_data_length);
std::vector<ODK_Field> extra_fields = {
{ODK_UINT32, &device_id_length, "device_id_length"},
{ODK_DEVICEID, device_id, "device_id"},
{ODK_UINT16, &renewal_type, "renewal_type"},
{ODK_UINT32, &renewal_data_length, "renewal_data_length"},
{ODK_RENEWALDATA, renewal_data, "renewal_data"},
};
auto odk_prepare_func = [&](uint8_t* const buf, size_t* size,
const ODK_NonceValues* nonce_values) {
return ODK_PrepareCoreRenewedProvisioningRequest(
buf, SIZE_MAX, size, nonce_values, device_id, device_id_length,
renewal_type, renewal_data, renewal_data_length);
};
auto kdo_parse_func =
[&](const std::string& oemcrypto_core_message,
ODK_ProvisioningRequest* core_provisioning_request) {
bool ok = CoreRenewedProvisioningRequestFromMessage(
oemcrypto_core_message, core_provisioning_request);
return ok;
};
ValidateRequest<ODK_ProvisioningRequest>(
ODK_Renewed_Provisioning_Request_Type, extra_fields, odk_prepare_func,
kdo_parse_func);
}
TEST(OdkTest, ParseLicenseErrorNonce) {
ODK_LicenseResponseParams params;
ODK_SetDefaultLicenseResponseParams(&params, ODK_MAJOR_VERSION);
uint8_t* buf = nullptr;
uint32_t buf_size = 0;
ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf,
&buf_size);
// temporarily mess up with nonce
params.core_message.nonce_values.nonce = 0;
OEMCryptoResult err = ODK_ParseLicense(
buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load,
params.usage_entry_present, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license));
EXPECT_EQ(OEMCrypto_ERROR_INVALID_NONCE, err);
delete[] buf;
}
TEST(OdkTest, ParseLicenseErrorUsageEntry) {
ODK_LicenseResponseParams params;
ODK_SetDefaultLicenseResponseParams(&params, ODK_MAJOR_VERSION);
uint8_t* buf = nullptr;
uint32_t buf_size = 0;
ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf,
&buf_size);
params.usage_entry_present = false;
OEMCryptoResult err = ODK_ParseLicense(
buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load,
params.usage_entry_present, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err);
delete[] buf;
}
TEST(OdkTest, ParseLicenseNullSubstring) {
ODK_LicenseResponseParams params;
ODK_SetDefaultLicenseResponseParams(&params, ODK_MAJOR_VERSION);
params.parsed_license.srm_restriction_data.offset = 0;
params.parsed_license.srm_restriction_data.length = 0;
uint8_t* buf = nullptr;
uint32_t buf_size = 0;
ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf,
&buf_size);
OEMCryptoResult result = ODK_ParseLicense(
buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load,
params.usage_entry_present, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license));
EXPECT_EQ(OEMCrypto_SUCCESS, result);
delete[] buf;
}
TEST(OdkTest, ParseLicenseErrorSubstringOffset) {
// offset out of range
ODK_LicenseResponseParams params;
ODK_SetDefaultLicenseResponseParams(&params, ODK_MAJOR_VERSION);
params.parsed_license.enc_mac_keys_iv.offset = 1024;
uint8_t* buf = nullptr;
uint32_t buf_size = 0;
ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf,
&buf_size);
OEMCryptoResult err = ODK_ParseLicense(
buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load,
params.usage_entry_present, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err);
delete[] buf;
// offset + length out of range
err = OEMCrypto_SUCCESS;
ODK_SetDefaultLicenseResponseParams(&params, ODK_MAJOR_VERSION);
params.parsed_license.enc_mac_keys_iv.length = buf_size;
buf = nullptr;
buf_size = 0;
ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf,
&buf_size);
err = ODK_ParseLicense(
buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load,
params.usage_entry_present, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err);
delete[] buf;
}
TEST(OdkTest, ParseRenewalErrorTimer) {
ODK_RenewalResponseParams params;
ODK_SetDefaultRenewalResponseParams(&params);
uint8_t* buf = nullptr;
uint32_t buf_size = 0;
ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf,
&buf_size);
params.clock_values.time_of_renewal_request = 0;
OEMCryptoResult err = ODK_ParseRenewal(
buf, buf_size, buf_size, &(params.core_message.nonce_values),
params.system_time, &(params.timer_limits), &(params.clock_values),
&(params.playback_timer));
EXPECT_EQ(ODK_STALE_RENEWAL, err);
delete[] buf;
}
TEST(OdkTest, ParsePrivisioningErrorDeviceId) {
ODK_ProvisioningResponseParams params;
ODK_SetDefaultProvisioningResponseParams(&params);
uint8_t* buf = nullptr;
uint32_t buf_size = 0;
ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf,
&buf_size);
// temporarily mess up with device_id
params.device_id[0] = 0;
OEMCryptoResult err = ODK_ParseProvisioning(
buf, buf_size + 16, buf_size, &(params.core_message.nonce_values),
params.device_id, params.device_id_length, &(params.parsed_provisioning));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err);
delete[] buf;
}
class OdkVersionTest : public ::testing::Test,
public ::testing::WithParamInterface<VersionParameters> {
protected:
template <typename P>
void SetRequestVersion(P* params) {
params->core_message.nonce_values.api_major_version =
GetParam().response_major_version;
params->core_message.nonce_values.api_minor_version =
GetParam().response_minor_version;
features_ =
CoreMessageFeatures::DefaultFeatures(GetParam().maximum_major_version);
}
CoreMessageFeatures features_;
};
// Serialize and de-serialize license response
TEST_P(OdkVersionTest, LicenseResponseRoundtrip) {
ODK_LicenseResponseParams params;
ODK_SetDefaultLicenseResponseParams(&params,
GetParam().response_major_version);
SetRequestVersion(&params);
// For v17, we do not use the hash to verify the request. However, the server
// needs to be backwards compatible, so it still needs to pass the hash into
// CreateCoreLiceseseResponse below. Save a copy of params.request_hash as it
// will be zero out during the test
uint8_t request_hash_read[ODK_SHA256_HASH_SIZE];
memcpy(request_hash_read, params.request_hash, sizeof(request_hash_read));
auto odk_parse_func = [&](const uint8_t* buf, size_t size) {
return ODK_ParseLicense(
buf, size + kExtraPayloadSize, size, params.initial_license_load,
params.usage_entry_present, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license));
};
const std::string request_hash_string(
reinterpret_cast<const char*>(request_hash_read),
sizeof(request_hash_read));
auto kdo_prepare_func = [&](const ODK_LicenseRequest& core_request,
std::string* oemcrypto_core_message) {
return CreateCoreLicenseResponse(features_, params.parsed_license,
core_request, request_hash_string,
oemcrypto_core_message);
};
ValidateResponse<ODK_LicenseRequest>(GetParam(), &(params.core_message),
params.extra_fields, odk_parse_func,
kdo_prepare_func);
}
TEST_P(OdkVersionTest, RenewalResponseRoundtrip) {
ODK_RenewalResponseParams params;
ODK_SetDefaultRenewalResponseParams(&params);
SetRequestVersion(&params);
const uint64_t playback_clock = params.playback_clock;
const uint64_t renewal_duration = params.renewal_duration;
auto odk_parse_func = [&](const uint8_t* buf, size_t size) {
OEMCryptoResult err =
ODK_ParseRenewal(buf, size, size, &(params.core_message.nonce_values),
params.system_time, &(params.timer_limits),
&(params.clock_values), &(params.playback_timer));
EXPECT_EQ(ODK_SET_TIMER, err);
EXPECT_EQ(renewal_duration, params.playback_timer);
EXPECT_EQ(params.clock_values.time_when_timer_expires,
params.system_time + params.playback_timer);
return OEMCrypto_SUCCESS;
};
auto kdo_prepare_func = [&](ODK_RenewalRequest& core_request,
std::string* oemcrypto_core_message) {
core_request.playback_time_seconds = playback_clock;
return CreateCoreRenewalResponse(features_, core_request, renewal_duration,
oemcrypto_core_message);
};
ValidateResponse<ODK_RenewalRequest>(GetParam(), &(params.core_message),
params.extra_fields, odk_parse_func,
kdo_prepare_func);
}
TEST_P(OdkVersionTest, ProvisionResponseRoundtrip) {
ODK_ProvisioningResponseParams params;
ODK_SetDefaultProvisioningResponseParams(&params);
SetRequestVersion(&params);
// save a copy of params.device_id as it will be zero out during the test
const uint32_t device_id_length = params.device_id_length;
uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0};
memcpy(device_id, params.device_id, device_id_length);
auto odk_parse_func = [&](const uint8_t* buf, size_t size) {
OEMCryptoResult err = ODK_ParseProvisioning(
buf, size + 16, size, &(params.core_message.nonce_values), device_id,
device_id_length, &(params.parsed_provisioning));
return err;
};
auto kdo_prepare_func = [&](ODK_ProvisioningRequest& core_request,
std::string* oemcrypto_core_message) {
core_request.device_id.assign(reinterpret_cast<char*>(device_id),
device_id_length);
return CreateCoreProvisioningResponse(features_, params.parsed_provisioning,
core_request, oemcrypto_core_message);
};
ValidateResponse<ODK_ProvisioningRequest>(GetParam(), &(params.core_message),
params.extra_fields, odk_parse_func,
kdo_prepare_func);
}
// If the minor version is positive, we can test an older minor version.
const uint16_t kOldMinor = ODK_MINOR_VERSION > 0 ? ODK_MINOR_VERSION - 1 : 0;
// Similarly, if this isn't the first major version, we can test an older major
// version.
// TODO(b/163416999): Remove it in the future. This will be unecessarily
// complicated after we upgrade to version 17.
const uint16_t kOldMajor = ODK_MAJOR_VERSION > ODK_FIRST_VERSION
? ODK_MAJOR_VERSION - 1
: ODK_FIRST_VERSION;
// If there is an older major, then we should accept any minor version.
// Otherwise, this test won't make sense and we should just use a minor of 0.
const uint16_t kOldMajorMinor = ODK_MAJOR_VERSION > ODK_FIRST_VERSION ? 42 : 0;
// List of major and minor versions to test.
std::vector<VersionParameters> TestCases() {
std::vector<VersionParameters> test_cases{
// Fields: maximum major version,
// request major, request minor, response major, response minor,
{ODK_MAJOR_VERSION, ODK_MAJOR_VERSION, ODK_MINOR_VERSION,
ODK_MAJOR_VERSION, ODK_MINOR_VERSION},
{ODK_MAJOR_VERSION, ODK_MAJOR_VERSION, ODK_MINOR_VERSION + 1,
ODK_MAJOR_VERSION, ODK_MINOR_VERSION},
{ODK_MAJOR_VERSION, ODK_MAJOR_VERSION, kOldMinor, ODK_MAJOR_VERSION,
kOldMinor},
{ODK_MAJOR_VERSION, ODK_MAJOR_VERSION, 0, ODK_MAJOR_VERSION, 0},
{ODK_MAJOR_VERSION, ODK_MAJOR_VERSION + 1, 42, ODK_MAJOR_VERSION,
ODK_MINOR_VERSION},
{ODK_MAJOR_VERSION, kOldMajor, 0, kOldMajor, 0},
{ODK_MAJOR_VERSION, kOldMajor, kOldMajorMinor, kOldMajor, kOldMajorMinor},
// If the server is restricted to v16, then the response can be at
// most 16.5
{16, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 16, 5},
// Here are some known good versions. Make extra sure they work.
{16, 16, 3, 16, 3},
{16, 16, 4, 16, 4},
{16, 16, 5, 16, 5},
{17, 16, 3, 16, 3},
{17, 16, 4, 16, 4},
{17, 16, 5, 16, 5},
{17, 17, 0, 17, 0},
{17, 17, 1, 17, 1},
};
return test_cases;
}
INSTANTIATE_TEST_SUITE_P(OdkVersionTests, OdkVersionTest,
::testing::ValuesIn(TestCases()));
TEST(OdkSizeTest, LicenseRequest) {
uint8_t* message = nullptr;
size_t message_length = 0;
size_t core_message_length = 0;
uint16_t api_minor_version = ODK_MINOR_VERSION;
uint16_t api_major_version = 0;
uint32_t nonce = 0;
uint32_t session_id = 0;
ODK_NonceValues nonce_values{api_minor_version, api_major_version, nonce,
session_id};
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
ODK_PrepareCoreLicenseRequest(message, message_length,
&core_message_length, &nonce_values));
// the core_message_length should be appropriately set
EXPECT_EQ(ODK_LICENSE_REQUEST_SIZE, core_message_length);
}
TEST(OdkSizeTest, RenewalRequest) {
uint8_t* message = nullptr;
size_t message_length = 0;
size_t core_message_length = 0;
uint16_t api_minor_version = ODK_MINOR_VERSION;
uint16_t api_major_version = ODK_MAJOR_VERSION;
uint32_t nonce = 0;
uint32_t session_id = 0;
ODK_ClockValues clock_values = {};
clock_values.time_of_first_decrypt = 10;
clock_values.timer_status = ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED;
uint64_t system_time_seconds = 15;
ODK_NonceValues nonce_values{api_minor_version, api_major_version, nonce,
session_id};
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
ODK_PrepareCoreRenewalRequest(message, message_length,
&core_message_length, &nonce_values,
&clock_values, system_time_seconds));
// the core_message_length should be appropriately set
EXPECT_EQ(ODK_RENEWAL_REQUEST_SIZE, core_message_length);
}
TEST(OdkSizeTest, ReleaseRequest) {
uint8_t* message = nullptr;
size_t message_length = 0;
size_t core_message_length = 0;
uint16_t api_minor_version = ODK_MINOR_VERSION;
uint16_t api_major_version = 0;
uint32_t nonce = 0;
uint32_t session_id = 0;
ODK_ClockValues clock_values = {};
clock_values.time_of_first_decrypt = 10;
clock_values.timer_status = ODK_CLOCK_TIMER_STATUS_LICENSE_INACTIVE;
uint64_t system_time_seconds = 15;
ODK_NonceValues nonce_values{api_minor_version, api_major_version, nonce,
session_id};
EXPECT_EQ(OEMCrypto_SUCCESS,
ODK_PrepareCoreRenewalRequest(message, message_length,
&core_message_length, &nonce_values,
&clock_values, system_time_seconds));
// Release requests do not have a core message.
EXPECT_GE(core_message_length, 0u);
}
TEST(OdkSizeTest, ProvisioningRequest) {
uint8_t* message = nullptr;
size_t message_length = 0;
size_t core_message_length = 0;
uint16_t api_minor_version = ODK_MINOR_VERSION;
uint16_t api_major_version = 0;
uint32_t nonce = 0;
uint32_t session_id = 0;
uint32_t device_id_length = 0;
ODK_NonceValues nonce_values{api_minor_version, api_major_version, nonce,
session_id};
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
ODK_PrepareCoreProvisioningRequest(
message, message_length, &core_message_length, &nonce_values,
nullptr, device_id_length));
// the core_message_length should be appropriately set
EXPECT_EQ(ODK_PROVISIONING_REQUEST_SIZE, core_message_length);
}
// Verify the version string contains the right version numbers.
TEST(OdkTest, CheckReleaseVersion) {
// Here are the version numbers.
std::string expected_version = std::to_string(ODK_MAJOR_VERSION) + "." +
std::to_string(ODK_MINOR_VERSION);
// Here is the version string.
EXPECT_NE(std::string(ODK_RELEASE_DATE).find(expected_version),
std::string::npos)
<< "Version mismatch in odk_structs.h";
}
} // namespace
} // namespace wvodk_test