* This is a change required to migrate function parameters to absl::Span from const std::vector
See go/vector2span for more information on why you've received this change and why it is important.
This CL looks good? Just LGTM and Approve it!
This CL doesn’t look good? This is what you can do:
* Revert this CL, by replying "REVERT: <provide reason>"
* File a bug under go/absl-span-params-bug for category AbslSpanParams if there's an issue with the CL content.
* File a bug under go/rosie-bug if there's an issue with how the CL was managed.
* For all other issues such as the formatting of the CL, please file a bug under
go/clrobot-bug.
* Revert this CL and not get a CL that cleans up these paths in the future by
replying "BLOCKLIST: <provide reason>". This is not reversible! We recommend to
opt out the respective paths in your CL Robot configuration instead:
go/clrobot-opt-out.
This CL was generated by CL Robot - a tool that cleans up code findings
(go/clrobot). The affected code paths have been enabled for CL Robot in //depot/google3/METADATA by
following go/clrobot#how-to-opt-in. Anything wrong with the signup? File a bug
at go/clrobot-bug.
#codehealth
Tested:
Local presubmit tests passed.
PiperOrigin-RevId: 601343954
Change-Id: I1d138aee430e96915a238464ee3b2277ce9b6772
1563 lines
69 KiB
C++
1563 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 "odk_overflow.h"
|
|
#include "odk_structs.h"
|
|
#include "odk_structs_priv.h"
|
|
#include "odk_test_helper.h"
|
|
#include "third_party/absl/types/span.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,
|
|
absl::Span<const 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
|
|
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, 0},
|
|
// 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, 18, 4, 18, 4},
|
|
{ODK_MAJOR_VERSION, 19, 0, 19, 0},
|
|
{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, 4, 18, 4}, // 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
|
|
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
|