// 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 #include #include "OEMCryptoCENCCommon.h" #include "core_message_deserialize.h" #include "core_message_features.h" #include "core_message_serialize.h" #include "core_message_types.h" #include "gtest/gtest.h" #include "odk_structs_priv.h" #include "odk_test_helper.h" namespace wvodk_test { namespace { using oemcrypto_core_message::ODK_LicenseRequest; using oemcrypto_core_message::ODK_ProvisioningRequest; using oemcrypto_core_message::ODK_RenewalRequest; using oemcrypto_core_message::deserialize::CoreLicenseRequestFromMessage; using oemcrypto_core_message::deserialize::CoreProvisioningRequestFromMessage; using oemcrypto_core_message::deserialize::CoreRenewalRequestFromMessage; using oemcrypto_core_message::features::CoreMessageFeatures; using oemcrypto_core_message::serialize::CreateCoreLicenseResponse; using oemcrypto_core_message::serialize::CreateCoreProvisioningResponse; using oemcrypto_core_message::serialize::CreateCoreRenewalResponse; constexpr uint32_t kExtraPayloadSize = 128u; /* Used to parameterize tests by version number. The request is given one * version number, and we will expect the response to have another version * number. */ struct VersionParameters { uint32_t maximum_major_version; uint16_t request_major_version; uint16_t request_minor_version; uint16_t response_major_version; uint16_t response_minor_version; }; // This function is called by GTest when a parameterized test fails in order // to log the parameter used for the failing test. void PrintTo(const VersionParameters& p, std::ostream* os) { *os << "max=v" << p.maximum_major_version << ", request = v" << p.request_major_version << "." << p.request_minor_version << ", response = v" << p.response_major_version << "." << p.response_minor_version; } template void ValidateRequest(uint32_t message_type, const std::vector& 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 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(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 void ValidateResponse(const VersionParameters& versions, ODK_CoreMessage* core_message, const std::vector& 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 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 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 fields(n); std::srand(0); size_t total_size = 0; for (int i = 0; i < n; i++) { fields[i].type = static_cast( std::rand() % static_cast(ODK_LAST_STRESSABLE_TYPE)); fields[i].value = malloc(ODK_AllocSize(fields[i].type)); fields[i].name = "stress"; total_size += ODK_FieldLength(fields[i].type); } uint8_t* buf = new uint8_t[total_size]{}; for (size_t i = 0; i < total_size; i++) { buf[i] = std::rand() & 0xff; } size_t bytes_read = 0, bytes_written = 0; uint8_t* buf2 = new uint8_t[total_size]{}; ODK_IterFields(ODK_READ, buf, total_size, &bytes_read, fields); EXPECT_EQ(bytes_read, total_size); ODK_IterFields(ODK_WRITE, buf2, total_size, &bytes_written, fields); EXPECT_EQ(bytes_written, total_size); EXPECT_NO_FATAL_FAILURE(ODK_ExpectEqualBuf(buf, buf2, total_size, fields)); // cleanup for (int i = 0; i < n; i++) { free(fields[i].value); } delete[] buf; delete[] buf2; } TEST(OdkTest, NullRequestTest) { size_t core_message_length = 0; ODK_NonceValues nonce_values; memset(&nonce_values, 0, sizeof(nonce_values)); ODK_ClockValues clock_values; memset(&clock_values, 0, sizeof(clock_values)); // Assert that nullptr does not cause a core dump. EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreLicenseRequest( nullptr, 0uL, nullptr, &nonce_values)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreLicenseRequest(nullptr, 0uL, &core_message_length, nullptr)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreRenewalRequest(nullptr, 0uL, nullptr, &nonce_values, &clock_values, 0uL)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreRenewalRequest(nullptr, 0uL, &core_message_length, nullptr, &clock_values, 0uL)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreRenewalRequest(nullptr, 0uL, &core_message_length, &nonce_values, nullptr, 0uL)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreProvisioningRequest( nullptr, 0uL, &core_message_length, nullptr, nullptr, 0uL)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreProvisioningRequest(nullptr, 0uL, nullptr, &nonce_values, nullptr, 0uL)); // Null device id in provisioning request is ok uint8_t message[ODK_PROVISIONING_REQUEST_SIZE] = {0}; core_message_length = ODK_PROVISIONING_REQUEST_SIZE; EXPECT_EQ(OEMCrypto_SUCCESS, ODK_PrepareCoreProvisioningRequest( message, ODK_PROVISIONING_REQUEST_SIZE, &core_message_length, &nonce_values, nullptr, 0uL)); } TEST(OdkTest, NullResponseTest) { constexpr size_t message_size = 64; uint8_t message[message_size] = {0}; size_t core_message_length = message_size; ODK_TimerLimits timer_limits; ODK_ParsedLicense parsed_license; ODK_NonceValues nonce_values; memset(&nonce_values, 0, sizeof(nonce_values)); ODK_ClockValues clock_values; memset(&clock_values, 0, sizeof(clock_values)); // Assert that nullptr does not cause a core dump. EXPECT_EQ( ODK_ERROR_CORE_MESSAGE, ODK_ParseLicense(message, message_size, core_message_length, true, true, &timer_limits, &clock_values, &nonce_values, nullptr)); EXPECT_EQ( ODK_ERROR_CORE_MESSAGE, ODK_ParseLicense(message, message_size, core_message_length, true, true, &timer_limits, &clock_values, nullptr, &parsed_license)); EXPECT_EQ( ODK_ERROR_CORE_MESSAGE, ODK_ParseLicense(message, message_size, core_message_length, true, true, &timer_limits, nullptr, &nonce_values, &parsed_license)); EXPECT_EQ( ODK_ERROR_CORE_MESSAGE, ODK_ParseLicense(message, message_size, core_message_length, true, true, nullptr, &clock_values, &nonce_values, &parsed_license)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_ParseLicense(nullptr, message_size, core_message_length, true, true, &timer_limits, &clock_values, &nonce_values, &parsed_license)); constexpr uint64_t system_time = 0; uint64_t timer_value = 0; EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_ParseRenewal(message, message_size, core_message_length, &nonce_values, system_time, &timer_limits, nullptr, &timer_value)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_ParseRenewal(message, message_size, core_message_length, &nonce_values, system_time, nullptr, &clock_values, &timer_value)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_ParseRenewal(message, message_size, core_message_length, nullptr, system_time, &timer_limits, &clock_values, &timer_value)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_ParseRenewal(nullptr, message_size, core_message_length, &nonce_values, system_time, &timer_limits, &clock_values, &timer_value)); uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0}; ODK_ParsedProvisioning parsed_response; EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_ParseProvisioning(message, message_size, core_message_length, &nonce_values, device_id, ODK_DEVICE_ID_LEN_MAX, nullptr)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_ParseProvisioning(message, message_size, core_message_length, &nonce_values, nullptr, 0, &parsed_response)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_ParseProvisioning(message, message_size, core_message_length, nullptr, device_id, ODK_DEVICE_ID_LEN_MAX, &parsed_response)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_ParseProvisioning(nullptr, message_size, core_message_length, &nonce_values, device_id, ODK_DEVICE_ID_LEN_MAX, &parsed_response)); } TEST(OdkTest, PrepareCoreLicenseRequest) { uint8_t license_message[ODK_LICENSE_REQUEST_SIZE] = {0}; size_t core_message_length = sizeof(license_message); ODK_NonceValues nonce_values; memset(&nonce_values, 0, sizeof(nonce_values)); EXPECT_EQ(OEMCrypto_SUCCESS, ODK_PrepareCoreLicenseRequest( license_message, sizeof(license_message), &core_message_length, &nonce_values)); } TEST(OdkTest, PrepareCoreLicenseRequestSize) { uint8_t license_message[ODK_LICENSE_REQUEST_SIZE] = {0}; size_t core_message_length = sizeof(license_message); ODK_NonceValues nonce_values; memset(&nonce_values, 0, sizeof(nonce_values)); // message length smaller than core message length size_t core_message_length_invalid = core_message_length + 1; EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreLicenseRequest( license_message, sizeof(license_message), &core_message_length_invalid, &nonce_values)); // message length larger than core message length uint8_t license_message_large[ODK_LICENSE_REQUEST_SIZE * 2] = {0}; EXPECT_EQ(OEMCrypto_SUCCESS, ODK_PrepareCoreLicenseRequest(license_message_large, sizeof(license_message_large), &core_message_length, &nonce_values)); } TEST(OdkTest, PrepareCoreRenewalRequest) { uint8_t renewal_message[ODK_RENEWAL_REQUEST_SIZE] = {0}; size_t core_message_length = sizeof(renewal_message); ODK_NonceValues nonce_values; memset(&nonce_values, 0, sizeof(nonce_values)); ODK_ClockValues clock_values; memset(&clock_values, 0, sizeof(clock_values)); constexpr uint64_t system_time_seconds = 10; EXPECT_EQ(OEMCrypto_SUCCESS, ODK_PrepareCoreRenewalRequest( renewal_message, sizeof(renewal_message), &core_message_length, &nonce_values, &clock_values, system_time_seconds)); } TEST(OdkTest, PrepareCoreRenewalRequestTimer) { uint8_t renewal_message[ODK_RENEWAL_REQUEST_SIZE] = {0}; size_t core_message_length = sizeof(renewal_message); ODK_NonceValues nonce_values{2, 16, 0, 0}; constexpr uint64_t system_time_seconds = 10; ODK_ClockValues clock_values_updated; memset(&clock_values_updated, 0, sizeof(clock_values_updated)); // system time smaller than first decrypt time clock_values_updated.time_of_first_decrypt = system_time_seconds + 1; EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreRenewalRequest( renewal_message, sizeof(renewal_message), &core_message_length, &nonce_values, &clock_values_updated, system_time_seconds)); clock_values_updated.time_of_first_decrypt = system_time_seconds - 1; EXPECT_EQ(OEMCrypto_SUCCESS, ODK_PrepareCoreRenewalRequest( renewal_message, sizeof(renewal_message), &core_message_length, &nonce_values, &clock_values_updated, system_time_seconds)); // clock_values.time_of_renewal_request should get updated EXPECT_EQ(system_time_seconds - clock_values_updated.time_of_first_decrypt, clock_values_updated.time_of_renewal_request); } TEST(OdkTest, PrepareCoreProvisioningRequest) { uint8_t provisioning_message[ODK_PROVISIONING_REQUEST_SIZE] = {0}; size_t core_message_length = sizeof(provisioning_message); ODK_NonceValues nonce_values; memset(&nonce_values, 0, sizeof(nonce_values)); uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0}; EXPECT_EQ( OEMCrypto_SUCCESS, ODK_PrepareCoreProvisioningRequest( provisioning_message, sizeof(provisioning_message), &core_message_length, &nonce_values, device_id, sizeof(device_id))); } TEST(OdkTest, PrepareCoreProvisioningRequestDeviceId) { uint8_t provisioning_message[ODK_PROVISIONING_REQUEST_SIZE] = {0}; size_t core_message_length = sizeof(provisioning_message); ODK_NonceValues nonce_values; memset(&nonce_values, 0, sizeof(nonce_values)); uint8_t device_id_invalid[ODK_DEVICE_ID_LEN_MAX + 1] = {0}; EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreProvisioningRequest( provisioning_message, sizeof(provisioning_message), &core_message_length, &nonce_values, device_id_invalid, sizeof(device_id_invalid))); } // Serialize and de-serialize license request TEST(OdkTest, LicenseRequestRoundtrip) { std::vector empty; auto odk_prepare_func = [&](uint8_t* const buf, size_t* size, ODK_NonceValues* nonce_values) { return ODK_PrepareCoreLicenseRequest(buf, SIZE_MAX, size, nonce_values); }; auto kdo_parse_func = CoreLicenseRequestFromMessage; ValidateRequest(ODK_License_Request_Type, empty, odk_prepare_func, kdo_parse_func); } TEST(OdkTest, RenewalRequestRoundtrip) { constexpr uint64_t system_time_seconds = 0xBADDCAFE000FF1CE; uint64_t playback_time = 0xCAFE00000000; const uint64_t playback_start = system_time_seconds - playback_time; const std::vector 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_Renewal_Request_Type, extra_fields, odk_prepare_func, kdo_parse_func); } TEST(OdkTest, ProvisionRequestRoundtrip) { uint32_t device_id_length = ODK_DEVICE_ID_LEN_MAX / 2; uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0}; memset(device_id, 0xff, device_id_length); std::vector extra_fields = { {ODK_UINT32, &device_id_length, "device_id_length"}, {ODK_DEVICEID, device_id, "device_id"}, }; auto odk_prepare_func = [&](uint8_t* const buf, size_t* size, const ODK_NonceValues* nonce_values) { return ODK_PrepareCoreProvisioningRequest(buf, SIZE_MAX, size, nonce_values, device_id, device_id_length); }; auto kdo_parse_func = [&](const std::string& oemcrypto_core_message, ODK_ProvisioningRequest* core_provisioning_request) { bool ok = CoreProvisioningRequestFromMessage(oemcrypto_core_message, core_provisioning_request); return ok; }; ValidateRequest(ODK_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, &(params.timer_limits), &(params.clock_values), &(params.core_message.nonce_values), &(params.parsed_license)); EXPECT_EQ(OEMCrypto_ERROR_INVALID_NONCE, err); delete[] buf; } TEST(OdkTest, ParseLicenseErrorUsageEntry) { ODK_LicenseResponseParams params; ODK_SetDefaultLicenseResponseParams(¶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, &(params.timer_limits), &(params.clock_values), &(params.core_message.nonce_values), &(params.parsed_license)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err); delete[] buf; } TEST(OdkTest, ParseLicenseNullSubstring) { ODK_LicenseResponseParams params; ODK_SetDefaultLicenseResponseParams(¶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, &(params.timer_limits), &(params.clock_values), &(params.core_message.nonce_values), &(params.parsed_license)); EXPECT_EQ(OEMCrypto_SUCCESS, result); delete[] buf; } TEST(OdkTest, ParseLicenseErrorSubstringOffset) { // offset out of range ODK_LicenseResponseParams params; ODK_SetDefaultLicenseResponseParams(¶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, &(params.timer_limits), &(params.clock_values), &(params.core_message.nonce_values), &(params.parsed_license)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err); delete[] buf; // offset + length out of range err = OEMCrypto_SUCCESS; ODK_SetDefaultLicenseResponseParams(¶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, &(params.timer_limits), &(params.clock_values), &(params.core_message.nonce_values), &(params.parsed_license)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err); delete[] buf; } TEST(OdkTest, ParseRenewalErrorTimer) { ODK_RenewalResponseParams params; ODK_SetDefaultRenewalResponseParams(¶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, ParsePrivisioningErrorDeviceId) { ODK_ProvisioningResponseParams params; ODK_SetDefaultProvisioningResponseParams(¶ms); uint8_t* buf = nullptr; uint32_t buf_size = 0; ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf, &buf_size); // temporarily mess up with device_id params.device_id[0] = 0; OEMCryptoResult err = ODK_ParseProvisioning( buf, buf_size + 16, buf_size, &(params.core_message.nonce_values), params.device_id, params.device_id_length, &(params.parsed_provisioning)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err); delete[] buf; } class OdkVersionTest : public ::testing::Test, public ::testing::WithParamInterface { protected: template void SetRequestVersion(P* params) { params->core_message.nonce_values.api_major_version = GetParam().response_major_version; params->core_message.nonce_values.api_minor_version = GetParam().response_minor_version; features_ = CoreMessageFeatures::DefaultFeatures(GetParam().maximum_major_version); } CoreMessageFeatures features_; }; // Serialize and de-serialize license response TEST_P(OdkVersionTest, LicenseResponseRoundtrip) { ODK_LicenseResponseParams params; ODK_SetDefaultLicenseResponseParams(¶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, &(params.timer_limits), &(params.clock_values), &(params.core_message.nonce_values), &(params.parsed_license)); }; const std::string request_hash_string( reinterpret_cast(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(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(GetParam(), &(params.core_message), params.extra_fields, odk_parse_func, kdo_prepare_func); } TEST_P(OdkVersionTest, ProvisionResponseRoundtrip) { ODK_ProvisioningResponseParams params; ODK_SetDefaultProvisioningResponseParams(¶ms); 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) { core_request.device_id.assign(reinterpret_cast(device_id), device_id_length); return CreateCoreProvisioningResponse(features_, params.parsed_provisioning, core_request, oemcrypto_core_message); }; ValidateResponse(GetParam(), &(params.core_message), params.extra_fields, odk_parse_func, kdo_prepare_func); } // If the minor version is positive, we can test an older minor version. const uint16_t kOldMinor = ODK_MINOR_VERSION > 0 ? ODK_MINOR_VERSION - 1 : 0; // Similarly, if this isn't the first major version, we can test an older major // version. // TODO(b/163416999): Remove it in the future. This will be unecessarily // complicated after we upgrade to version 17. const uint16_t kOldMajor = ODK_MAJOR_VERSION > ODK_FIRST_VERSION ? ODK_MAJOR_VERSION - 1 : ODK_FIRST_VERSION; // If there is an older major, then we should accept any minor version. // Otherwise, this test won't make sense and we should just use a minor of 0. const uint16_t kOldMajorMinor = ODK_MAJOR_VERSION > ODK_FIRST_VERSION ? 42 : 0; // List of major and minor versions to test. std::vector TestCases() { std::vector test_cases{ // Fields: maximum major version, // request major, request minor, response major, response minor, {ODK_MAJOR_VERSION, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, ODK_MAJOR_VERSION, ODK_MINOR_VERSION}, {ODK_MAJOR_VERSION, ODK_MAJOR_VERSION, ODK_MINOR_VERSION + 1, ODK_MAJOR_VERSION, ODK_MINOR_VERSION}, {ODK_MAJOR_VERSION, ODK_MAJOR_VERSION, kOldMinor, ODK_MAJOR_VERSION, kOldMinor}, {ODK_MAJOR_VERSION, ODK_MAJOR_VERSION, 0, ODK_MAJOR_VERSION, 0}, {ODK_MAJOR_VERSION, ODK_MAJOR_VERSION + 1, 42, ODK_MAJOR_VERSION, ODK_MINOR_VERSION}, {ODK_MAJOR_VERSION, kOldMajor, 0, kOldMajor, 0}, {ODK_MAJOR_VERSION, kOldMajor, kOldMajorMinor, kOldMajor, kOldMajorMinor}, // If the server is restricted to v16, then the response can be at // most 16.5 {16, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 16, 5}, // Here are some known good versions. Make extra sure they work. {16, 16, 3, 16, 3}, {16, 16, 4, 16, 4}, {16, 16, 5, 16, 5}, {17, 16, 3, 16, 3}, {17, 16, 4, 16, 4}, {17, 16, 5, 16, 5}, {17, 17, 0, 17, 0}, }; return test_cases; } INSTANTIATE_TEST_SUITE_P(OdkVersionTests, OdkVersionTest, ::testing::ValuesIn(TestCases())); TEST(OdkSizeTest, LicenseRequest) { uint8_t* message = nullptr; size_t message_length = 0; size_t core_message_length = 0; uint16_t api_minor_version = ODK_MINOR_VERSION; uint16_t api_major_version = 0; uint32_t nonce = 0; uint32_t session_id = 0; ODK_NonceValues nonce_values{api_minor_version, api_major_version, nonce, session_id}; EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, ODK_PrepareCoreLicenseRequest(message, message_length, &core_message_length, &nonce_values)); // the core_message_length should be appropriately set EXPECT_EQ(ODK_LICENSE_REQUEST_SIZE, core_message_length); } TEST(OdkSizeTest, RenewalRequest) { uint8_t* message = nullptr; size_t message_length = 0; size_t core_message_length = 0; uint16_t api_minor_version = ODK_MINOR_VERSION; uint16_t api_major_version = ODK_MAJOR_VERSION; uint32_t nonce = 0; uint32_t session_id = 0; ODK_ClockValues clock_values = {}; clock_values.time_of_first_decrypt = 10; clock_values.timer_status = ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED; uint64_t system_time_seconds = 15; ODK_NonceValues nonce_values{api_minor_version, api_major_version, nonce, session_id}; EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, ODK_PrepareCoreRenewalRequest(message, message_length, &core_message_length, &nonce_values, &clock_values, system_time_seconds)); // the core_message_length should be appropriately set EXPECT_EQ(ODK_RENEWAL_REQUEST_SIZE, core_message_length); } TEST(OdkSizeTest, ReleaseRequest) { uint8_t* message = nullptr; size_t message_length = 0; size_t core_message_length = 0; uint16_t api_minor_version = ODK_MINOR_VERSION; uint16_t api_major_version = 0; uint32_t nonce = 0; uint32_t session_id = 0; ODK_ClockValues clock_values = {}; clock_values.time_of_first_decrypt = 10; clock_values.timer_status = ODK_CLOCK_TIMER_STATUS_LICENSE_INACTIVE; uint64_t system_time_seconds = 15; ODK_NonceValues nonce_values{api_minor_version, api_major_version, nonce, session_id}; EXPECT_EQ(OEMCrypto_SUCCESS, ODK_PrepareCoreRenewalRequest(message, message_length, &core_message_length, &nonce_values, &clock_values, system_time_seconds)); // Release requests do not have a core message. EXPECT_GE(core_message_length, 0u); } TEST(OdkSizeTest, ProvisioningRequest) { uint8_t* message = nullptr; size_t message_length = 0; size_t core_message_length = 0; uint16_t api_minor_version = ODK_MINOR_VERSION; uint16_t api_major_version = 0; uint32_t nonce = 0; uint32_t session_id = 0; uint32_t device_id_length = 0; ODK_NonceValues nonce_values{api_minor_version, api_major_version, nonce, session_id}; EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, ODK_PrepareCoreProvisioningRequest( message, message_length, &core_message_length, &nonce_values, nullptr, device_id_length)); // the core_message_length should be appropriately set EXPECT_EQ(ODK_PROVISIONING_REQUEST_SIZE, core_message_length); } // Verify the version string contains the right version numbers. TEST(OdkTest, CheckReleaseVersion) { // Here are the version numbers. std::string expected_version = std::to_string(ODK_MAJOR_VERSION) + "." + std::to_string(ODK_MINOR_VERSION); // Here is the version string. EXPECT_NE(std::string(ODK_RELEASE_DATE).find(expected_version), std::string::npos) << "Version mismatch in odk_structs.h"; } } // namespace } // namespace wvodk_test