The core message had been throttled to only generate v17 messages because we wanted to stabilize the format before making the code live. PiperOrigin-RevId: 524309559 Merged from https://widevine-internal-review.googlesource.com/170311 Change-Id: I2d09c9f6c73f844fd509531e86285ad71d22690f
1228 lines
53 KiB
C++
1228 lines
53 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 <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 "odk_structs.h"
|
|
#include "odk_structs_priv.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_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::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::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));
|
|
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
|
|
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));
|
|
|
|
// 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, 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);
|
|
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, 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);
|
|
};
|
|
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(¶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, 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, 2},
|
|
// 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},
|
|
{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, 2, 18, 2}, // Change to 19 when the default version is updated.
|
|
};
|
|
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
|
|
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;
|
|
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
|
|
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
|