1577 lines
69 KiB
C++
1577 lines
69 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.h"
|
|
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <ostream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "OEMCryptoCENCCommon.h"
|
|
#include "core_message_deserialize.h"
|
|
#include "core_message_features.h"
|
|
#include "core_message_serialize.h"
|
|
#include "core_message_serialize_proto.h"
|
|
#include "core_message_types.h"
|
|
#include "gtest/gtest.h"
|
|
#include "license_protocol.pb.h"
|
|
#include "odk_overflow.h"
|
|
#include "odk_structs.h"
|
|
#include "odk_structs_priv.h"
|
|
#include "odk_target.h"
|
|
#include "odk_test_helper.h"
|
|
|
|
namespace wvodk_test {
|
|
|
|
namespace {
|
|
|
|
using oemcrypto_core_message::ODK_CommonRequest;
|
|
using oemcrypto_core_message::ODK_LicenseRequest;
|
|
using oemcrypto_core_message::ODK_MessageCounter;
|
|
using oemcrypto_core_message::ODK_Provisioning40Request;
|
|
using oemcrypto_core_message::ODK_ProvisioningRequest;
|
|
using oemcrypto_core_message::ODK_ReleaseRequest;
|
|
using oemcrypto_core_message::ODK_RenewalRequest;
|
|
|
|
using oemcrypto_core_message::deserialize::CoreCommonRequestFromMessage;
|
|
using oemcrypto_core_message::deserialize::CoreLicenseRequestFromMessage;
|
|
using oemcrypto_core_message::deserialize::CoreProvisioning40RequestFromMessage;
|
|
using oemcrypto_core_message::deserialize::CoreProvisioningRequestFromMessage;
|
|
using oemcrypto_core_message::deserialize::CoreReleaseRequestFromMessage;
|
|
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::CreateCoreProvisioning40Response;
|
|
using oemcrypto_core_message::serialize::CreateCoreProvisioningResponse;
|
|
using oemcrypto_core_message::serialize::
|
|
CreateCoreProvisioningResponseFromProto;
|
|
using oemcrypto_core_message::serialize::CreateCoreReleaseResponse;
|
|
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;
|
|
}
|
|
|
|
void SetDefaultSerializedProvisioningResponse(std::string* serialized_message) {
|
|
// Create a dummy provisioning response
|
|
video_widevine::ProvisioningResponse provisioning_response;
|
|
provisioning_response.set_device_certificate("device_certificate");
|
|
provisioning_response.set_device_rsa_key("device_rsa_key");
|
|
provisioning_response.set_device_rsa_key_iv("device_rsa_key_iv");
|
|
if (!provisioning_response.SerializeToString(serialized_message)) {
|
|
FAIL();
|
|
}
|
|
}
|
|
|
|
bool CheckCounterInfoIsEqual(ODK_MessageCounterInfo* a, ODK_MessageCounter* b) {
|
|
if (!a || !b) return false;
|
|
|
|
EXPECT_EQ(a->master_generation_number, b->master_generation_number);
|
|
EXPECT_EQ(a->provisioning_count, b->provisioning_count);
|
|
EXPECT_EQ(a->license_count, b->license_count);
|
|
EXPECT_EQ(a->decrypt_count, b->decrypt_count);
|
|
EXPECT_EQ(a->major_version, b->major_version);
|
|
EXPECT_EQ(a->minor_version, b->minor_version);
|
|
EXPECT_EQ(a->patch_version, b->patch_version);
|
|
for (size_t i = 0; i < sizeof(a->soc_vendor); i++) {
|
|
EXPECT_EQ(a->soc_vendor[i], b->soc_vendor[i]);
|
|
}
|
|
for (size_t i = 0; i < sizeof(a->chipset_model); i++) {
|
|
EXPECT_EQ(a->chipset_model[i], b->chipset_model[i]);
|
|
}
|
|
for (size_t i = 0; i < sizeof(a->extra); i++) {
|
|
EXPECT_EQ(a->extra[i], b->extra[i]);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
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) + 1));
|
|
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));
|
|
ODK_MessageCounterInfo counter_info;
|
|
memset(&counter_info, 0, sizeof(counter_info));
|
|
|
|
// Assert that nullptr does not cause a core dump.
|
|
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
|
|
ODK_PrepareCoreLicenseRequest(nullptr, 0uL, nullptr, &nonce_values,
|
|
&counter_info));
|
|
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
|
|
ODK_PrepareCoreLicenseRequest(nullptr, 0uL, &core_message_length,
|
|
nullptr, &counter_info));
|
|
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
|
|
ODK_PrepareCoreLicenseRequest(nullptr, 0uL, &core_message_length,
|
|
&nonce_values, 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, &counter_info));
|
|
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
|
|
ODK_PrepareCoreProvisioningRequest(nullptr, 0uL, nullptr,
|
|
&nonce_values, &counter_info));
|
|
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
|
|
ODK_PrepareCoreProvisioningRequest(
|
|
nullptr, 0uL, &core_message_length, &nonce_values, nullptr));
|
|
|
|
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreProvisioning40Request(
|
|
nullptr, 0uL, &core_message_length,
|
|
nullptr, nullptr, 0uL, &counter_info));
|
|
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreProvisioning40Request(
|
|
nullptr, 0uL, nullptr, &nonce_values,
|
|
nullptr, 0uL, &counter_info));
|
|
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreProvisioning40Request(
|
|
nullptr, 0uL, &core_message_length,
|
|
&nonce_values, nullptr, 0uL, nullptr));
|
|
|
|
// Null device id in provisioning request is ok
|
|
if (nonce_values.api_major_version > 17) {
|
|
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, &counter_info));
|
|
} else {
|
|
uint8_t message[ODK_PROVISIONING_REQUEST_SIZE_V17] = {0};
|
|
core_message_length = ODK_PROVISIONING_REQUEST_SIZE_V17;
|
|
EXPECT_EQ(OEMCrypto_SUCCESS,
|
|
ODK_PrepareCoreProvisioningRequest(
|
|
message, ODK_PROVISIONING_REQUEST_SIZE_V17,
|
|
&core_message_length, &nonce_values, &counter_info));
|
|
}
|
|
|
|
// Null device info in provisioning 4.0 request is ok
|
|
uint8_t message_prov4[ODK_PROVISIONING40_REQUEST_SIZE] = {0};
|
|
core_message_length = ODK_PROVISIONING40_REQUEST_SIZE;
|
|
EXPECT_EQ(
|
|
OEMCrypto_SUCCESS,
|
|
ODK_PrepareCoreProvisioning40Request(
|
|
message_prov4, ODK_PROVISIONING40_REQUEST_SIZE, &core_message_length,
|
|
&nonce_values, nullptr, 0uL, &counter_info));
|
|
|
|
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, 0, &timer_limits, &clock_values,
|
|
&nonce_values, nullptr, nullptr));
|
|
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
|
|
ODK_ParseLicense(message, message_size, core_message_length, true,
|
|
true, 0, &timer_limits, &clock_values, nullptr,
|
|
&parsed_license, nullptr));
|
|
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
|
|
ODK_ParseLicense(message, message_size, core_message_length, true,
|
|
true, 0, &timer_limits, nullptr, &nonce_values,
|
|
&parsed_license, nullptr));
|
|
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
|
|
ODK_ParseLicense(message, message_size, core_message_length, true,
|
|
true, 0, nullptr, &clock_values, &nonce_values,
|
|
&parsed_license, nullptr));
|
|
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
|
|
ODK_ParseLicense(nullptr, message_size, core_message_length, true,
|
|
true, 0, &timer_limits, &clock_values,
|
|
&nonce_values, &parsed_license, nullptr));
|
|
|
|
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));
|
|
|
|
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
|
|
ODK_ParseProvisioning40(message, message_size, core_message_length,
|
|
nullptr));
|
|
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
|
|
ODK_ParseProvisioning40(nullptr, message_size, core_message_length,
|
|
&nonce_values));
|
|
}
|
|
|
|
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));
|
|
ODK_MessageCounterInfo counter_info;
|
|
memset(&counter_info, 0, sizeof(counter_info));
|
|
EXPECT_EQ(OEMCrypto_SUCCESS,
|
|
ODK_PrepareCoreLicenseRequest(
|
|
license_message, sizeof(license_message), &core_message_length,
|
|
&nonce_values, &counter_info));
|
|
}
|
|
|
|
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));
|
|
ODK_MessageCounterInfo counter_info;
|
|
memset(&counter_info, 0, sizeof(counter_info));
|
|
// 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, &counter_info));
|
|
// 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, &counter_info));
|
|
}
|
|
|
|
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));
|
|
ODK_MessageCounterInfo counter_info;
|
|
memset(&counter_info, 0, sizeof(counter_info));
|
|
EXPECT_EQ(OEMCrypto_SUCCESS,
|
|
ODK_PrepareCoreProvisioningRequest(
|
|
provisioning_message, sizeof(provisioning_message),
|
|
&core_message_length, &nonce_values, &counter_info));
|
|
}
|
|
|
|
TEST(OdkTest, PrepareCoreProvisioning40Request) {
|
|
uint8_t provisioning_message[ODK_PROVISIONING40_REQUEST_SIZE] = {0};
|
|
size_t core_message_length = sizeof(provisioning_message);
|
|
ODK_NonceValues nonce_values;
|
|
memset(&nonce_values, 0, sizeof(nonce_values));
|
|
ODK_MessageCounterInfo counter_info;
|
|
memset(&counter_info, 0, sizeof(counter_info));
|
|
uint8_t device_info[ODK_DEVICE_INFO_LEN_MAX] = {0};
|
|
EXPECT_EQ(OEMCrypto_SUCCESS,
|
|
ODK_PrepareCoreProvisioning40Request(
|
|
provisioning_message, sizeof(provisioning_message),
|
|
&core_message_length, &nonce_values, device_info,
|
|
sizeof(device_info), &counter_info));
|
|
}
|
|
|
|
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, PrepareCoreProvisioning40RequestDeviceInfo) {
|
|
uint8_t provisioning_message[ODK_PROVISIONING40_REQUEST_SIZE] = {0};
|
|
size_t core_message_length = sizeof(provisioning_message);
|
|
ODK_NonceValues nonce_values;
|
|
memset(&nonce_values, 0, sizeof(nonce_values));
|
|
ODK_MessageCounterInfo counter_info;
|
|
memset(&counter_info, 0, sizeof(counter_info));
|
|
uint8_t device_info_invalid[ODK_DEVICE_INFO_LEN_MAX + 1] = {0};
|
|
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
|
|
ODK_PrepareCoreProvisioning40Request(
|
|
provisioning_message, sizeof(provisioning_message),
|
|
&core_message_length, &nonce_values, device_info_invalid,
|
|
sizeof(device_info_invalid), &counter_info));
|
|
}
|
|
|
|
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) {
|
|
ODK_MessageCounterInfo counter_info;
|
|
counter_info.master_generation_number = 0x12345678abcdffff;
|
|
counter_info.provisioning_count = 12;
|
|
counter_info.license_count = 50;
|
|
counter_info.decrypt_count = 340;
|
|
counter_info.major_version = ODK_MAJOR_VERSION;
|
|
counter_info.minor_version = ODK_MINOR_VERSION;
|
|
counter_info.patch_version = 4;
|
|
memset(counter_info.soc_vendor, 0xff, sizeof(counter_info.soc_vendor));
|
|
memset(counter_info.chipset_model, 0xdd, sizeof(counter_info.chipset_model));
|
|
memset(counter_info.extra, 0xee, sizeof(counter_info.extra));
|
|
std::vector<ODK_Field> extra_fields = {
|
|
{ODK_MESSAGECOUNTER, &counter_info, "counter_info"},
|
|
};
|
|
auto odk_prepare_func = [&](uint8_t* const buf, size_t* size,
|
|
ODK_NonceValues* nonce_values) {
|
|
return ODK_PrepareCoreLicenseRequest(buf, SIZE_MAX, size, nonce_values,
|
|
&counter_info);
|
|
};
|
|
auto kdo_parse_func = [&](const std::string& oemcrypto_core_message,
|
|
ODK_LicenseRequest* core_license_request) {
|
|
bool ok = CoreLicenseRequestFromMessage(oemcrypto_core_message,
|
|
core_license_request);
|
|
if (!ok) return false;
|
|
|
|
ok = CheckCounterInfoIsEqual(&counter_info,
|
|
&core_license_request->counter_info);
|
|
return ok;
|
|
};
|
|
ValidateRequest<ODK_LicenseRequest>(ODK_License_Request_Type, extra_fields,
|
|
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, ReleaseRequestRoundTrip) {
|
|
const uint32_t clock_security_level = 1;
|
|
const uint32_t status = 1;
|
|
constexpr uint64_t system_time_seconds = 0xBADDCAFE000FF1CE;
|
|
uint64_t playback_time = 0xCAFE00000000;
|
|
const int64_t seconds_since_license_requested = 1;
|
|
const int64_t seconds_since_first_decrypt =
|
|
static_cast<int64_t>(system_time_seconds - playback_time);
|
|
ODK_ClockValues clock_values;
|
|
memset(&clock_values, 0, sizeof(clock_values));
|
|
clock_values.time_of_first_decrypt = seconds_since_first_decrypt;
|
|
std::vector<ODK_Field> extra_fields = {};
|
|
auto odk_prepare_func = [&](uint8_t* const buf, size_t* size,
|
|
ODK_NonceValues* nonce_values) {
|
|
return ODK_PrepareCoreReleaseRequest(
|
|
buf, SIZE_MAX, size, nonce_values, status, clock_security_level,
|
|
seconds_since_license_requested, seconds_since_first_decrypt,
|
|
&clock_values, system_time_seconds);
|
|
};
|
|
auto kdo_parse_func = [&](const std::string& oemcrypto_core_message,
|
|
ODK_ReleaseRequest* core_release_request) {
|
|
bool ok = CoreReleaseRequestFromMessage(oemcrypto_core_message,
|
|
core_release_request);
|
|
return ok;
|
|
};
|
|
ValidateRequest<ODK_ReleaseRequest>(ODK_Release_Request_Type, extra_fields,
|
|
odk_prepare_func, kdo_parse_func);
|
|
}
|
|
|
|
TEST(OdkTest, ProvisionRequestRoundtrip) {
|
|
ODK_MessageCounterInfo counter_info;
|
|
counter_info.master_generation_number = 0x12345678abcdffff;
|
|
counter_info.provisioning_count = 12;
|
|
counter_info.license_count = 50;
|
|
counter_info.decrypt_count = 340;
|
|
counter_info.major_version = ODK_MAJOR_VERSION;
|
|
counter_info.minor_version = ODK_MINOR_VERSION;
|
|
counter_info.patch_version = 4;
|
|
memset(counter_info.soc_vendor, 0xff, sizeof(counter_info.soc_vendor));
|
|
memset(counter_info.chipset_model, 0xdd, sizeof(counter_info.chipset_model));
|
|
memset(counter_info.extra, 0xee, sizeof(counter_info.extra));
|
|
// Fake device_id_length for older servers, since we removed device id from
|
|
// the v18 request
|
|
uint32_t fake_device_id_length = 64;
|
|
std::vector<ODK_Field> extra_fields = {
|
|
{ODK_UINT32, &(fake_device_id_length), "fake_device_id_length"},
|
|
{ODK_MESSAGECOUNTER, &counter_info, "counter_info"},
|
|
};
|
|
|
|
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,
|
|
&counter_info);
|
|
};
|
|
auto kdo_parse_func =
|
|
[&](const std::string& oemcrypto_core_message,
|
|
ODK_ProvisioningRequest* core_provisioning_request) {
|
|
bool ok = CoreProvisioningRequestFromMessage(oemcrypto_core_message,
|
|
core_provisioning_request);
|
|
if (!ok) return false;
|
|
ok = CheckCounterInfoIsEqual(&counter_info,
|
|
&core_provisioning_request->counter_info);
|
|
return ok;
|
|
};
|
|
ValidateRequest<ODK_ProvisioningRequest>(ODK_Provisioning_Request_Type,
|
|
extra_fields, odk_prepare_func,
|
|
kdo_parse_func);
|
|
}
|
|
|
|
TEST(OdkTest, ProvisionRequest40Roundtrip) {
|
|
uint32_t device_info_length = ODK_DEVICE_INFO_LEN_MAX / 2;
|
|
uint8_t device_info[ODK_DEVICE_INFO_LEN_MAX] = {0};
|
|
memset(device_info, 0xaa, device_info_length);
|
|
ODK_MessageCounterInfo counter_info;
|
|
counter_info.master_generation_number = 0x12345678abcdffff;
|
|
counter_info.provisioning_count = 12;
|
|
counter_info.license_count = 50;
|
|
counter_info.decrypt_count = 340;
|
|
counter_info.major_version = ODK_MAJOR_VERSION;
|
|
counter_info.minor_version = ODK_MINOR_VERSION;
|
|
counter_info.patch_version = 4;
|
|
memset(counter_info.soc_vendor, 0xff, sizeof(counter_info.soc_vendor));
|
|
memset(counter_info.chipset_model, 0xdd, sizeof(counter_info.chipset_model));
|
|
memset(counter_info.extra, 0xee, sizeof(counter_info.extra));
|
|
std::vector<ODK_Field> extra_fields = {
|
|
{ODK_UINT32, &device_info_length, "device_info_length"},
|
|
{ODK_DEVICEINFO, device_info, "device_info"},
|
|
{ODK_MESSAGECOUNTER, &counter_info, "counter_info"},
|
|
};
|
|
auto odk_prepare_func = [&](uint8_t* const buf, size_t* size,
|
|
const ODK_NonceValues* nonce_values) {
|
|
return ODK_PrepareCoreProvisioning40Request(
|
|
buf, SIZE_MAX, size, nonce_values, device_info, device_info_length,
|
|
&counter_info);
|
|
};
|
|
auto kdo_parse_func =
|
|
[&](const std::string& oemcrypto_core_message,
|
|
ODK_Provisioning40Request* core_provisioning_request) {
|
|
bool ok = CoreProvisioning40RequestFromMessage(
|
|
oemcrypto_core_message, core_provisioning_request);
|
|
if (!ok) return false;
|
|
ok = CheckCounterInfoIsEqual(&counter_info,
|
|
&core_provisioning_request->counter_info);
|
|
return ok;
|
|
};
|
|
ValidateRequest<ODK_Provisioning40Request>(ODK_Provisioning40_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(¶ms, 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, 0, &(params.timer_limits),
|
|
&(params.clock_values), &(params.core_message.nonce_values),
|
|
&(params.parsed_license), nullptr);
|
|
EXPECT_EQ(OEMCrypto_ERROR_INVALID_NONCE, err);
|
|
delete[] buf;
|
|
}
|
|
|
|
TEST(OdkTest, ParseLicenseErrorUsageEntry) {
|
|
ODK_LicenseResponseParams params;
|
|
ODK_SetDefaultLicenseResponseParams(¶ms, 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, 0, &(params.timer_limits),
|
|
&(params.clock_values), &(params.core_message.nonce_values),
|
|
&(params.parsed_license), nullptr);
|
|
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err);
|
|
delete[] buf;
|
|
}
|
|
|
|
TEST(OdkTest, ParseLicenseNullSubstring) {
|
|
ODK_LicenseResponseParams params;
|
|
ODK_SetDefaultLicenseResponseParams(¶ms, 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, 0, &(params.timer_limits),
|
|
&(params.clock_values), &(params.core_message.nonce_values),
|
|
&(params.parsed_license), nullptr);
|
|
EXPECT_EQ(OEMCrypto_SUCCESS, result);
|
|
delete[] buf;
|
|
}
|
|
|
|
TEST(OdkTest, ParseLicenseErrorSubstringOffset) {
|
|
// offset out of range
|
|
ODK_LicenseResponseParams params;
|
|
ODK_SetDefaultLicenseResponseParams(¶ms, 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, 0, &(params.timer_limits),
|
|
&(params.clock_values), &(params.core_message.nonce_values),
|
|
&(params.parsed_license), nullptr);
|
|
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err);
|
|
delete[] buf;
|
|
|
|
// offset + length out of range
|
|
err = OEMCrypto_SUCCESS;
|
|
ODK_SetDefaultLicenseResponseParams(¶ms, 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, 0, &(params.timer_limits),
|
|
&(params.clock_values), &(params.core_message.nonce_values),
|
|
&(params.parsed_license), nullptr);
|
|
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err);
|
|
delete[] buf;
|
|
}
|
|
|
|
TEST(OdkTest, ParseRenewalErrorTimer) {
|
|
ODK_RenewalResponseParams params;
|
|
ODK_SetDefaultRenewalResponseParams(¶ms);
|
|
uint8_t* buf = nullptr;
|
|
uint32_t buf_size = 0;
|
|
ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf,
|
|
&buf_size);
|
|
// Set the time for the last renewal request, as seen in clock_values, to be
|
|
// after the time in the request.
|
|
// TODO: b/290249855 - This is reversed. It should be +5.
|
|
params.clock_values.time_of_renewal_request = params.playback_clock - 5;
|
|
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, ProvisionResponseFromProto) {
|
|
std::string serialized_provisioning_resp;
|
|
EXPECT_NO_FATAL_FAILURE(
|
|
SetDefaultSerializedProvisioningResponse(&serialized_provisioning_resp));
|
|
ODK_ProvisioningRequest core_request = {
|
|
.api_minor_version = ODK_MINOR_VERSION,
|
|
.api_major_version = ODK_MAJOR_VERSION,
|
|
.nonce = 0xdeadbeef,
|
|
.session_id = 0xcafebabe,
|
|
};
|
|
const CoreMessageFeatures features =
|
|
CoreMessageFeatures::DefaultFeatures(ODK_MAJOR_VERSION);
|
|
std::string oemcrypto_core_message;
|
|
EXPECT_TRUE(CreateCoreProvisioningResponseFromProto(
|
|
features, serialized_provisioning_resp, core_request,
|
|
OEMCrypto_RSA_Private_Key, &oemcrypto_core_message));
|
|
}
|
|
|
|
// Verify de-serialize common request.
|
|
TEST(OdkTest, ParseCoreCommonRequestFromMessage) {
|
|
std::string serialized_provisioning_resp;
|
|
EXPECT_NO_FATAL_FAILURE(
|
|
SetDefaultSerializedProvisioningResponse(&serialized_provisioning_resp));
|
|
ODK_ProvisioningRequest core_request = {
|
|
.api_minor_version = ODK_MINOR_VERSION,
|
|
.api_major_version = ODK_MAJOR_VERSION,
|
|
.nonce = 0xdeadbeef,
|
|
.session_id = 0xcafebabe,
|
|
};
|
|
const CoreMessageFeatures features =
|
|
CoreMessageFeatures::DefaultFeatures(ODK_MAJOR_VERSION);
|
|
std::string oemcrypto_core_message;
|
|
EXPECT_TRUE(CreateCoreProvisioningResponseFromProto(
|
|
features, serialized_provisioning_resp, core_request,
|
|
OEMCrypto_RSA_Private_Key, &oemcrypto_core_message));
|
|
ODK_CommonRequest odk_common_request;
|
|
ASSERT_TRUE(CoreCommonRequestFromMessage(oemcrypto_core_message,
|
|
&odk_common_request));
|
|
EXPECT_EQ(odk_common_request.message_type, 6u);
|
|
EXPECT_EQ(odk_common_request.message_length, 48u);
|
|
EXPECT_EQ(odk_common_request.api_minor_version, ODK_MINOR_VERSION);
|
|
EXPECT_EQ(odk_common_request.api_major_version, ODK_MAJOR_VERSION);
|
|
EXPECT_EQ(odk_common_request.nonce, 0xdeadbeef);
|
|
EXPECT_EQ(odk_common_request.session_id, 0xcafebabe);
|
|
}
|
|
|
|
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;
|
|
if (GetParam().maximum_major_version > 0) {
|
|
features_ = CoreMessageFeatures::DefaultFeatures(
|
|
GetParam().maximum_major_version);
|
|
} else {
|
|
features_ = CoreMessageFeatures::kDefaultFeatures;
|
|
}
|
|
}
|
|
CoreMessageFeatures features_;
|
|
};
|
|
|
|
// Serialize and de-serialize license response
|
|
TEST_P(OdkVersionTest, LicenseResponseRoundtrip) {
|
|
ODK_LicenseResponseParams params;
|
|
ODK_SetDefaultLicenseResponseParams(¶ms,
|
|
GetParam().response_major_version);
|
|
SetRequestVersion(¶ms);
|
|
// 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, 0, &(params.timer_limits),
|
|
&(params.clock_values), &(params.core_message.nonce_values),
|
|
&(params.parsed_license), nullptr);
|
|
};
|
|
|
|
ODK_Packing_ParsedLicense parsed_license;
|
|
parsed_license.enc_mac_keys_iv = params.parsed_license.enc_mac_keys_iv;
|
|
parsed_license.enc_mac_keys = params.parsed_license.enc_mac_keys;
|
|
parsed_license.pst = params.parsed_license.pst;
|
|
parsed_license.srm_restriction_data =
|
|
params.parsed_license.srm_restriction_data;
|
|
parsed_license.license_type = params.parsed_license.license_type;
|
|
parsed_license.nonce_required = params.parsed_license.nonce_required;
|
|
parsed_license.timer_limits = params.parsed_license.timer_limits;
|
|
parsed_license.watermarking = params.parsed_license.watermarking;
|
|
parsed_license.dtcp2_required = params.parsed_license.dtcp2_required;
|
|
parsed_license.renewal_delay_base = params.parsed_license.renewal_delay_base;
|
|
parsed_license.key_array_length = params.parsed_license.key_array_length;
|
|
std::vector<OEMCrypto_KeyObject> key_array;
|
|
for (size_t i = 0; i < params.parsed_license.key_array_length; i++) {
|
|
key_array.push_back(params.parsed_license.key_array[i]);
|
|
}
|
|
parsed_license.key_array = key_array.data();
|
|
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_, 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);
|
|
}
|
|
|
|
// Serialize and de-serialize license response with more keys than
|
|
// ODK_MAX_NUM_KEYS.
|
|
TEST_P(OdkVersionTest, LicenseResponseRoundtripMoreThanMaxKeys) {
|
|
ODK_LicenseResponseParams params;
|
|
ODK_SetDefaultLicenseResponseParams(¶ms,
|
|
GetParam().response_major_version);
|
|
SetRequestVersion(¶ms);
|
|
// 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));
|
|
uint8_t* buf = nullptr;
|
|
uint32_t buf_size = 0;
|
|
ODK_BuildMessageBuffer(&(params.core_message), params.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,
|
|
params.extra_fields));
|
|
|
|
// Parse buf with odk
|
|
const OEMCryptoResult parse_result = ODK_ParseLicense(
|
|
buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load,
|
|
params.usage_entry_present, 0, &(params.timer_limits),
|
|
&(params.clock_values), &(params.core_message.nonce_values),
|
|
&(params.parsed_license), nullptr);
|
|
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,
|
|
params.extra_fields);
|
|
}
|
|
|
|
ODK_Packing_ParsedLicense parsed_license;
|
|
parsed_license.enc_mac_keys_iv = params.parsed_license.enc_mac_keys_iv;
|
|
parsed_license.enc_mac_keys = params.parsed_license.enc_mac_keys;
|
|
parsed_license.pst = params.parsed_license.pst;
|
|
parsed_license.srm_restriction_data =
|
|
params.parsed_license.srm_restriction_data;
|
|
parsed_license.license_type = params.parsed_license.license_type;
|
|
parsed_license.nonce_required = params.parsed_license.nonce_required;
|
|
parsed_license.timer_limits = params.parsed_license.timer_limits;
|
|
parsed_license.watermarking = params.parsed_license.watermarking;
|
|
parsed_license.dtcp2_required = params.parsed_license.dtcp2_required;
|
|
parsed_license.renewal_delay_base = params.parsed_license.renewal_delay_base;
|
|
parsed_license.key_array_length = ODK_MAX_NUM_KEYS + 1;
|
|
std::vector<OEMCrypto_KeyObject> key_array;
|
|
for (size_t i = 0; i < ODK_MAX_NUM_KEYS + 1; i++) {
|
|
OEMCrypto_KeyObject key = {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}};
|
|
key_array.push_back(key);
|
|
}
|
|
parsed_license.key_array = key_array.data();
|
|
const std::string request_hash_string(
|
|
reinterpret_cast<const char*>(request_hash_read),
|
|
sizeof(request_hash_read));
|
|
|
|
// serialize odk output to oemcrypto_core_message
|
|
std::string oemcrypto_core_message;
|
|
ODK_LicenseRequest core_request = {};
|
|
core_request.api_major_version = GetParam().request_major_version;
|
|
core_request.api_minor_version = GetParam().request_minor_version;
|
|
core_request.nonce = params.core_message.nonce_values.nonce;
|
|
core_request.session_id = params.core_message.nonce_values.session_id;
|
|
bool result =
|
|
CreateCoreLicenseResponse(features_, parsed_license, core_request,
|
|
request_hash_string, &oemcrypto_core_message);
|
|
EXPECT_TRUE(result);
|
|
|
|
delete[] buf;
|
|
delete[] zero;
|
|
}
|
|
|
|
TEST_P(OdkVersionTest, RenewalResponseRoundtrip) {
|
|
ODK_RenewalResponseParams params;
|
|
ODK_SetDefaultRenewalResponseParams(¶ms);
|
|
SetRequestVersion(¶ms);
|
|
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, ReleaseResponseRoundtrip) {
|
|
ODK_ReleaseResponseParams params;
|
|
ODK_SetDefaultReleaseResponseParams(¶ms);
|
|
SetRequestVersion(¶ms);
|
|
const int64_t seconds_since_license_requested =
|
|
params.seconds_since_license_requested;
|
|
const int64_t seconds_since_first_decrypt =
|
|
params.seconds_since_first_decrypt;
|
|
auto odk_parse_func = [&](const uint8_t* buf, size_t size) {
|
|
OEMCryptoResult err =
|
|
ODK_ParseRelease(buf, size, size, &(params.core_message.nonce_values));
|
|
return err;
|
|
};
|
|
auto kdo_prepare_func = [&](ODK_ReleaseRequest& core_request,
|
|
std::string* oemcrypto_core_message) {
|
|
return CreateCoreReleaseResponse(
|
|
features_, core_request, seconds_since_license_requested,
|
|
seconds_since_first_decrypt, oemcrypto_core_message);
|
|
};
|
|
ValidateResponse<ODK_ReleaseRequest>(GetParam(), &(params.core_message),
|
|
params.extra_fields, odk_parse_func,
|
|
kdo_prepare_func);
|
|
}
|
|
|
|
TEST_P(OdkVersionTest, ProvisionResponseRoundtrip) {
|
|
ODK_ProvisioningResponseParams params;
|
|
ODK_SetDefaultProvisioningResponseParams(¶ms,
|
|
GetParam().response_major_version);
|
|
SetRequestVersion(¶ms);
|
|
// 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) {
|
|
// use device_id for V17 and V16
|
|
core_request.device_id.assign(reinterpret_cast<char*>(device_id),
|
|
device_id_length);
|
|
// use counter info for V18
|
|
memcpy(&core_request.counter_info, ¶ms.counter_info,
|
|
sizeof(params.counter_info));
|
|
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);
|
|
}
|
|
|
|
TEST_P(OdkVersionTest, Provision40ResponseRoundtrip) {
|
|
ODK_Provisioning40ResponseParams params;
|
|
ODK_SetDefaultProvisioning40ResponseParams(¶ms);
|
|
SetRequestVersion(¶ms);
|
|
|
|
auto odk_parse_func = [&](const uint8_t* buf, size_t size) {
|
|
OEMCryptoResult err = ODK_ParseProvisioning40(
|
|
buf, size + 16, size, &(params.core_message.nonce_values));
|
|
return err;
|
|
};
|
|
auto kdo_prepare_func = [&](ODK_Provisioning40Request& core_request,
|
|
std::string* oemcrypto_core_message) {
|
|
return CreateCoreProvisioning40Response(features_, core_request,
|
|
oemcrypto_core_message);
|
|
};
|
|
ValidateResponse<ODK_Provisioning40Request>(
|
|
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.
|
|
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
|
|
// These tests cases must be updated whenever we roll the minor version
|
|
// number.
|
|
{16, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 16, 5},
|
|
{17, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 17, 2},
|
|
{18, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 18, 4},
|
|
{19, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 19, 6},
|
|
// Here are some known good versions. Make extra sure they work.
|
|
{ODK_MAJOR_VERSION, 16, 3, 16, 3},
|
|
{ODK_MAJOR_VERSION, 16, 4, 16, 4},
|
|
{ODK_MAJOR_VERSION, 16, 5, 16, 5},
|
|
{ODK_MAJOR_VERSION, 17, 1, 17, 1},
|
|
{ODK_MAJOR_VERSION, 17, 2, 17, 2},
|
|
{ODK_MAJOR_VERSION, 18, 1, 18, 1},
|
|
{ODK_MAJOR_VERSION, 18, 2, 18, 2},
|
|
{ODK_MAJOR_VERSION, 18, 3, 18, 3},
|
|
{ODK_MAJOR_VERSION, 19, 0, 19, 0},
|
|
{ODK_MAJOR_VERSION, 19, 1, 19, 1},
|
|
{ODK_MAJOR_VERSION, 19, 2, 19, 2},
|
|
{ODK_MAJOR_VERSION, 19, 3, 19, 3},
|
|
{ODK_MAJOR_VERSION, 19, 4, 19, 4},
|
|
{ODK_MAJOR_VERSION, 19, 5, 19, 5},
|
|
{ODK_MAJOR_VERSION, 19, 6, 19, 6},
|
|
{0, 16, 3, 16, 3},
|
|
{0, 16, 4, 16, 4},
|
|
{0, 16, 5, 16, 5},
|
|
{0, 17, 1, 17, 1},
|
|
{0, 17, 2, 17, 2},
|
|
{0, 18, 3, 18, 3},
|
|
{0, 18, 4, 18, 4},
|
|
{0, 19, 0, 19, 0},
|
|
{0, 19, 1, 19, 1},
|
|
{0, 19, 2, 19, 2},
|
|
{0, 19, 3, 19, 3},
|
|
{0, 19, 4, 19, 4},
|
|
{0, 19, 5, 19, 5},
|
|
{0, 19, 6, 19, 6},
|
|
};
|
|
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_MessageCounterInfo counter_info;
|
|
memset(&counter_info, 0, sizeof(counter_info));
|
|
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,
|
|
&counter_info));
|
|
// the core_message_length should be appropriately set
|
|
if (nonce_values.api_major_version > 17) {
|
|
EXPECT_EQ(ODK_LICENSE_REQUEST_SIZE, core_message_length);
|
|
} else {
|
|
EXPECT_EQ(ODK_LICENSE_REQUEST_SIZE_V17, 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;
|
|
ODK_MessageCounterInfo counter_info;
|
|
memset(&counter_info, 0, sizeof(counter_info));
|
|
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, &counter_info));
|
|
// the core_message_length should be appropriately set
|
|
if (nonce_values.api_major_version > 17) {
|
|
EXPECT_EQ(ODK_PROVISIONING_REQUEST_SIZE, core_message_length);
|
|
} else {
|
|
EXPECT_EQ(ODK_PROVISIONING_REQUEST_SIZE_V17, 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";
|
|
}
|
|
|
|
TEST(OdkOverflowTest, SubtractU64) {
|
|
uint64_t result = 0;
|
|
EXPECT_FALSE(odk_sub_overflow_u64(10, 5, &result));
|
|
EXPECT_EQ(result, static_cast<uint64_t>(10 - 5));
|
|
EXPECT_TRUE(odk_sub_overflow_u64(5, 10, &result));
|
|
}
|
|
|
|
TEST(OdkOverflowTest, AddU64) {
|
|
uint64_t result = 0;
|
|
EXPECT_FALSE(odk_add_overflow_u64(2, 2, &result));
|
|
EXPECT_EQ(result, static_cast<uint64_t>(2 + 2));
|
|
EXPECT_TRUE(odk_add_overflow_u64(0xffffffffffffffff, 1, &result));
|
|
EXPECT_TRUE(odk_add_overflow_u64(1, 0xffffffffffffffff, &result));
|
|
}
|
|
|
|
TEST(OdkOverflowTest, AddUX) {
|
|
size_t result = 0;
|
|
EXPECT_FALSE(odk_add_overflow_ux(2, 2, &result));
|
|
EXPECT_EQ(result, static_cast<uint64_t>(2 + 2));
|
|
EXPECT_TRUE(odk_add_overflow_ux(SIZE_MAX, 1, &result));
|
|
EXPECT_TRUE(odk_add_overflow_ux(1, SIZE_MAX, &result));
|
|
}
|
|
|
|
TEST(OdkOverflowTest, MultiplyUX) {
|
|
size_t result = 0;
|
|
EXPECT_FALSE(odk_mul_overflow_ux(2, 7, &result));
|
|
EXPECT_EQ(result, static_cast<uint64_t>(2 * 7));
|
|
EXPECT_TRUE(odk_mul_overflow_ux(SIZE_MAX >> 1, 4, &result));
|
|
EXPECT_TRUE(odk_mul_overflow_ux(4, SIZE_MAX >> 1, &result));
|
|
}
|
|
|
|
TEST(OdkTest, GenerateKeyContexts_Success) {
|
|
const uint8_t kContext[] = {
|
|
0x0a, 0x4c, 0x08, 0x00, 0x12, 0x48, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
|
|
0x10, 0x19, 0x07, 0xd9, 0xff, 0xde, 0x13, 0xaa, 0x95, 0xc1, 0x22, 0x67,
|
|
0x80, 0x53, 0x36, 0x21, 0x36, 0xbd, 0xf8, 0x40, 0x8f, 0x82, 0x76, 0xe4,
|
|
0xc2, 0xd8, 0x7e, 0xc5, 0x2b, 0x61, 0xaa, 0x1b, 0x9f, 0x64, 0x6e, 0x58,
|
|
0x73, 0x49, 0x30, 0xac, 0xeb, 0xe8, 0x99, 0xb3, 0xe4, 0x64, 0x18, 0x9a,
|
|
0x14, 0xa8, 0x72, 0x02, 0xfb, 0x02, 0x57, 0x4e, 0x70, 0x64, 0x0b, 0xd2,
|
|
0x2e, 0xf4, 0x4b, 0x2d, 0x7e, 0x39, 0x12, 0x25, 0x0a, 0x23, 0x0a, 0x14,
|
|
0x08, 0x01, 0x12, 0x10, 0x09, 0x15, 0x00, 0x7c, 0xaa, 0x9b, 0x59, 0x31,
|
|
0xb7, 0x6a, 0x3a, 0x85, 0xf0, 0x46, 0x52, 0x3e, 0x10, 0x01, 0x1a, 0x09,
|
|
0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x18, 0x01, 0x20,
|
|
0x00, 0x2a, 0x0c, 0x31, 0x38, 0x38, 0x36, 0x37, 0x38, 0x37, 0x34, 0x30,
|
|
0x35, 0x00, 0x00,
|
|
};
|
|
const uint8_t kMacKey[] = {
|
|
0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x49,
|
|
0x4f, 0x4e, 0x00, 0x0a, 0x4c, 0x08, 0x00, 0x12, 0x48, 0x00, 0x00, 0x00,
|
|
0x02, 0x00, 0x00, 0x10, 0x19, 0x07, 0xd9, 0xff, 0xde, 0x13, 0xaa, 0x95,
|
|
0xc1, 0x22, 0x67, 0x80, 0x53, 0x36, 0x21, 0x36, 0xbd, 0xf8, 0x40, 0x8f,
|
|
0x82, 0x76, 0xe4, 0xc2, 0xd8, 0x7e, 0xc5, 0x2b, 0x61, 0xaa, 0x1b, 0x9f,
|
|
0x64, 0x6e, 0x58, 0x73, 0x49, 0x30, 0xac, 0xeb, 0xe8, 0x99, 0xb3, 0xe4,
|
|
0x64, 0x18, 0x9a, 0x14, 0xa8, 0x72, 0x02, 0xfb, 0x02, 0x57, 0x4e, 0x70,
|
|
0x64, 0x0b, 0xd2, 0x2e, 0xf4, 0x4b, 0x2d, 0x7e, 0x39, 0x12, 0x25, 0x0a,
|
|
0x23, 0x0a, 0x14, 0x08, 0x01, 0x12, 0x10, 0x09, 0x15, 0x00, 0x7c, 0xaa,
|
|
0x9b, 0x59, 0x31, 0xb7, 0x6a, 0x3a, 0x85, 0xf0, 0x46, 0x52, 0x3e, 0x10,
|
|
0x01, 0x1a, 0x09, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31,
|
|
0x18, 0x01, 0x20, 0x00, 0x2a, 0x0c, 0x31, 0x38, 0x38, 0x36, 0x37, 0x38,
|
|
0x37, 0x34, 0x30, 0x35, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
|
|
};
|
|
const uint8_t kEncKey[] = {
|
|
0x45, 0x4e, 0x43, 0x52, 0x59, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x0a,
|
|
0x4c, 0x08, 0x00, 0x12, 0x48, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10,
|
|
0x19, 0x07, 0xd9, 0xff, 0xde, 0x13, 0xaa, 0x95, 0xc1, 0x22, 0x67, 0x80,
|
|
0x53, 0x36, 0x21, 0x36, 0xbd, 0xf8, 0x40, 0x8f, 0x82, 0x76, 0xe4, 0xc2,
|
|
0xd8, 0x7e, 0xc5, 0x2b, 0x61, 0xaa, 0x1b, 0x9f, 0x64, 0x6e, 0x58, 0x73,
|
|
0x49, 0x30, 0xac, 0xeb, 0xe8, 0x99, 0xb3, 0xe4, 0x64, 0x18, 0x9a, 0x14,
|
|
0xa8, 0x72, 0x02, 0xfb, 0x02, 0x57, 0x4e, 0x70, 0x64, 0x0b, 0xd2, 0x2e,
|
|
0xf4, 0x4b, 0x2d, 0x7e, 0x39, 0x12, 0x25, 0x0a, 0x23, 0x0a, 0x14, 0x08,
|
|
0x01, 0x12, 0x10, 0x09, 0x15, 0x00, 0x7c, 0xaa, 0x9b, 0x59, 0x31, 0xb7,
|
|
0x6a, 0x3a, 0x85, 0xf0, 0x46, 0x52, 0x3e, 0x10, 0x01, 0x1a, 0x09, 0x39,
|
|
0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x18, 0x01, 0x20, 0x00,
|
|
0x2a, 0x0c, 0x31, 0x38, 0x38, 0x36, 0x37, 0x38, 0x37, 0x34, 0x30, 0x35,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
|
|
};
|
|
|
|
std::vector<uint8_t> mac_key(sizeof(kMacKey) + 24);
|
|
std::vector<uint8_t> enc_key(sizeof(kEncKey) + 24);
|
|
size_t mac_key_size = mac_key.size();
|
|
size_t enc_key_size = enc_key.size();
|
|
ASSERT_EQ(OEMCrypto_SUCCESS,
|
|
ODK_GenerateKeyContexts(kContext, sizeof(kContext), &mac_key[0],
|
|
&mac_key_size, &enc_key[0], &enc_key_size));
|
|
ASSERT_EQ(mac_key_size, sizeof(kMacKey));
|
|
ASSERT_EQ(enc_key_size, sizeof(kEncKey));
|
|
mac_key.resize(mac_key_size);
|
|
enc_key.resize(enc_key_size);
|
|
|
|
EXPECT_EQ(std::vector<uint8_t>(kMacKey, kMacKey + sizeof(kMacKey)), mac_key);
|
|
EXPECT_EQ(std::vector<uint8_t>(kEncKey, kEncKey + sizeof(kEncKey)), enc_key);
|
|
}
|
|
|
|
TEST(OdkTest, GenerateKeyContexts_ShortBuffer) {
|
|
const uint8_t kContext[] = {1, 2, 3};
|
|
size_t mac_key_size = 0;
|
|
size_t enc_key_size = 0;
|
|
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
|
|
ODK_GenerateKeyContexts(kContext, sizeof(kContext), nullptr,
|
|
&mac_key_size, nullptr, &enc_key_size));
|
|
EXPECT_EQ(mac_key_size, sizeof(kContext) + 19);
|
|
EXPECT_EQ(enc_key_size, sizeof(kContext) + 15);
|
|
}
|
|
|
|
TEST(OdkTest, GenerateKeyContexts_ShortBufferMacOnly) {
|
|
const uint8_t kContext[] = {1, 2, 3};
|
|
uint8_t buffer[128];
|
|
size_t mac_key_size = 0;
|
|
size_t enc_key_size = sizeof(buffer);
|
|
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
|
|
ODK_GenerateKeyContexts(kContext, sizeof(kContext), nullptr,
|
|
&mac_key_size, buffer, &enc_key_size));
|
|
EXPECT_EQ(mac_key_size, sizeof(kContext) + 19);
|
|
EXPECT_EQ(enc_key_size, sizeof(kContext) + 15);
|
|
}
|
|
|
|
TEST(OdkTest, GenerateKeyContexts_ShortBufferEncOnly) {
|
|
const uint8_t kContext[] = {1, 2, 3};
|
|
uint8_t buffer[128];
|
|
size_t mac_key_size = sizeof(buffer);
|
|
size_t enc_key_size = 0;
|
|
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
|
|
ODK_GenerateKeyContexts(kContext, sizeof(kContext), buffer,
|
|
&mac_key_size, buffer, &enc_key_size));
|
|
EXPECT_EQ(mac_key_size, sizeof(kContext) + 19);
|
|
EXPECT_EQ(enc_key_size, sizeof(kContext) + 15);
|
|
}
|
|
|
|
TEST(OdkTest, GenerateKeyContexts_NullArgs) {
|
|
const uint8_t kContext[] = {1, 2, 3};
|
|
uint8_t buffer[24];
|
|
size_t buffer_size = sizeof(buffer);
|
|
size_t buffer_size2 = sizeof(buffer);
|
|
|
|
EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
|
|
ODK_GenerateKeyContexts(nullptr, sizeof(kContext), buffer,
|
|
&buffer_size, buffer, &buffer_size2));
|
|
buffer_size = buffer_size2 = sizeof(buffer); // Update to avoid short buffer.
|
|
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
|
|
ODK_GenerateKeyContexts(kContext, sizeof(kContext), nullptr,
|
|
&buffer_size, buffer, &buffer_size2));
|
|
buffer_size = buffer_size2 = sizeof(buffer); // Update to avoid short buffer.
|
|
EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
|
|
ODK_GenerateKeyContexts(kContext, sizeof(kContext), buffer, nullptr,
|
|
buffer, &buffer_size2));
|
|
buffer_size = buffer_size2 = sizeof(buffer); // Update to avoid short buffer.
|
|
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
|
|
ODK_GenerateKeyContexts(kContext, sizeof(kContext), buffer,
|
|
&buffer_size, nullptr, &buffer_size2));
|
|
buffer_size = buffer_size2 = sizeof(buffer); // Update to avoid short buffer.
|
|
EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT,
|
|
ODK_GenerateKeyContexts(kContext, sizeof(kContext), buffer,
|
|
&buffer_size, buffer, nullptr));
|
|
}
|
|
|
|
} // namespace
|
|
|
|
} // namespace wvodk_test
|