// Copyright 2019 Google LLC. All rights reserved. This file and proprietary // source code may only be used and distributed under the Widevine Master // License Agreement. #include "odk.h" #include // TODO(b/147944591): use this one? Or odk_endian.h? #include #include #include #include #include #include #include #include #include #include "OEMCryptoCENCCommon.h" #include "core_message_deserialize.h" #include "core_message_serialize.h" #include "core_message_types.h" #include "gtest/gtest.h" #include "odk_structs.h" #include "odk_structs_priv.h" 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::serialize::CreateCoreLicenseResponse; using oemcrypto_core_message::serialize::CreateCoreProvisioningResponse; using oemcrypto_core_message::serialize::CreateCoreRenewalResponse; enum ODK_FieldType { ODK_UINT16, ODK_UINT32, ODK_UINT64, ODK_SUBSTRING, ODK_DEVICEID, ODK_HASH, ODK_NUMTYPES, }; enum ODK_FieldMode { ODK_READ, ODK_WRITE, ODK_DUMP, }; struct ODK_Field { ODK_FieldType type; void* value; std::string name; }; size_t ODK_FieldLength(ODK_FieldType type) { switch (type) { case ODK_UINT16: return sizeof(uint16_t); case ODK_UINT32: return sizeof(uint32_t); case ODK_UINT64: return sizeof(uint64_t); case ODK_SUBSTRING: return sizeof(uint32_t) + sizeof(uint32_t); case ODK_DEVICEID: return ODK_DEVICE_ID_LEN_MAX; case ODK_HASH: return ODK_SHA256_HASH_SIZE; default: return SIZE_MAX; } } size_t ODK_AllocSize(ODK_FieldType type) { if (type == ODK_SUBSTRING) { return sizeof(OEMCrypto_Substring); } return ODK_FieldLength(type); } OEMCryptoResult ODK_WriteSingleField(uint8_t* const buf, const ODK_Field* const field) { if (!buf || !field || !field->value) { return ODK_ERROR_CORE_MESSAGE; } switch (field->type) { case ODK_UINT16: { uint16_t u16 = htobe16(*static_cast(field->value)); memcpy(buf, &u16, sizeof(u16)); break; } case ODK_UINT32: { uint32_t u32 = htobe32(*static_cast(field->value)); memcpy(buf, &u32, sizeof(u32)); break; } case ODK_UINT64: { uint64_t u64 = htobe64(*static_cast(field->value)); memcpy(buf, &u64, sizeof(u64)); break; } case ODK_SUBSTRING: { OEMCrypto_Substring* s = static_cast(field->value); uint32_t off = htobe32(s->offset); uint32_t len = htobe32(s->length); memcpy(buf, &off, sizeof(off)); memcpy(buf + sizeof(off), &len, sizeof(len)); break; } case ODK_DEVICEID: case ODK_HASH: { const size_t field_len = ODK_FieldLength(field->type); const uint8_t* const id = static_cast(field->value); memcpy(buf, id, field_len); break; } default: return ODK_ERROR_CORE_MESSAGE; } return OEMCrypto_SUCCESS; } OEMCryptoResult ODK_ReadSingleField(const uint8_t* const buf, const ODK_Field* const field) { if (!field || !field->value) { return ODK_ERROR_CORE_MESSAGE; } switch (field->type) { case ODK_UINT16: { memcpy(field->value, buf, sizeof(uint16_t)); uint16_t* u16p = static_cast(field->value); *u16p = be16toh(*u16p); break; } case ODK_UINT32: { memcpy(field->value, buf, sizeof(uint32_t)); uint32_t* u32p = static_cast(field->value); *u32p = be32toh(*u32p); break; } case ODK_UINT64: { memcpy(field->value, buf, sizeof(uint64_t)); uint64_t* u64p = static_cast(field->value); *u64p = be64toh(*u64p); break; } case ODK_SUBSTRING: { OEMCrypto_Substring* s = static_cast(field->value); uint32_t off = 0; uint32_t len = 0; memcpy(&off, buf, sizeof(off)); memcpy(&len, buf + sizeof(off), sizeof(len)); s->offset = be32toh(off); s->length = be32toh(len); break; } case ODK_DEVICEID: case ODK_HASH: { const size_t field_len = ODK_FieldLength(field->type); uint8_t* const id = static_cast(field->value); memcpy(id, buf, field_len); break; } default: return ODK_ERROR_CORE_MESSAGE; } return OEMCrypto_SUCCESS; } OEMCryptoResult ODK_DumpSingleField(const uint8_t* const buf, const ODK_Field* const field) { if (!field || !field->value) { return ODK_ERROR_CORE_MESSAGE; } switch (field->type) { case ODK_UINT16: { uint16_t val; memcpy(&val, buf, sizeof(uint16_t)); val = be16toh(val); std::cerr << field->name << ": " << val << " = 0x" << std::hex << val << "\n"; break; } case ODK_UINT32: { uint32_t val; memcpy(&val, buf, sizeof(uint32_t)); val = be32toh(val); std::cerr << field->name << ": " << val << " = 0x" << std::hex << val << "\n"; break; } case ODK_UINT64: { uint64_t val; memcpy(&val, buf, sizeof(uint64_t)); val = be64toh(val); std::cerr << field->name << ": " << val << " = 0x" << std::hex << val << "\n"; break; } case ODK_SUBSTRING: { uint32_t off = 0; uint32_t len = 0; memcpy(&off, buf, sizeof(off)); memcpy(&len, buf + sizeof(off), sizeof(len)); std::cerr << field->name << ": (off=" << off << ", len=" << len << ")\n"; break; } case ODK_DEVICEID: case ODK_HASH: { const size_t field_len = ODK_FieldLength(field->type); std::cerr << field->name << ": "; for (size_t i = 0; i < field_len; i++) { std::cerr << std::hex << std::setfill('0') << std::setw(2) << buf[i] << "\n"; } std::cerr << "\n"; break; } default: return ODK_ERROR_CORE_MESSAGE; } std::cerr << std::dec; // Return to normal. return OEMCrypto_SUCCESS; } /* * Parameters: * [in] size_in: buffer size * [out] size_out: bytes processed */ OEMCryptoResult ODK_IterFields(ODK_FieldMode mode, uint8_t* const buf, const size_t size_in, size_t* size_out, const std::vector& fields) { if (!buf || !size_out) { return ODK_ERROR_CORE_MESSAGE; } size_t off = 0, off2 = 0; for (size_t i = 0; i < fields.size(); i++) { if (__builtin_add_overflow(off, ODK_FieldLength(fields[i].type), &off2) || off2 > size_in) { return ODK_ERROR_CORE_MESSAGE; } uintptr_t base = reinterpret_cast(buf); if (__builtin_add_overflow(base, off, &base)) { return ODK_ERROR_CORE_MESSAGE; } uint8_t* const buf_off = buf + off; switch (mode) { case ODK_WRITE: ODK_WriteSingleField(buf_off, &fields[i]); break; case ODK_READ: ODK_ReadSingleField(buf_off, &fields[i]); break; case ODK_DUMP: ODK_DumpSingleField(buf_off, &fields[i]); break; default: return ODK_ERROR_CORE_MESSAGE; } off = off2; } *size_out = off; if (*size_out > size_in) { return ODK_ERROR_CORE_MESSAGE; } return OEMCrypto_SUCCESS; } void expect_eq_buf(const void* s1, const void* s2, size_t n, const std::vector& fields) { if (memcmp(s1, s2, n)) { const void* buffers[] = {s1, s2}; for (int i = 0; i < 2; i++) { char _tmp[] = "/tmp/fileXXXXXX"; const int temp_fd = mkstemp(_tmp); if (temp_fd >= 0) { close(temp_fd); } else { std::cerr << "Failed to open temp file." << std::endl; break; } std::string tmp(_tmp); std::fstream out(tmp, std::ios::out | std::ios::binary); out.write(static_cast(buffers[i]), n); out.close(); std::cerr << "buffer " << i << " dumped to " << tmp << std::endl; size_t bytes_written; uint8_t* buf = const_cast(reinterpret_cast(buffers[i])); ODK_IterFields(ODK_DUMP, buf, n, &bytes_written, fields); } FAIL(); } } 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); } uint8_t* buf = new uint8_t[message_size](); uint8_t* buf2 = new uint8_t[message_size](); size_t bytes_written = message_size; EXPECT_EQ(OEMCrypto_SUCCESS, odk_prepare_func(buf, &bytes_written, &nonce_values)); EXPECT_EQ(bytes_written, message_size); EXPECT_EQ(OEMCrypto_SUCCESS, ODK_IterFields(ODK_WRITE, buf2, SIZE_MAX, &bytes_written, total_fields)); EXPECT_EQ(bytes_written, message_size); EXPECT_NO_FATAL_FAILURE(expect_eq_buf(buf, buf2, message_size, total_fields)); // odk kdo roundtrip 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; EXPECT_EQ(OEMCrypto_SUCCESS, odk_prepare_func(buf2, &bytes_written, &nonce_values)); EXPECT_EQ(bytes_written, message_size); EXPECT_NO_FATAL_FAILURE(expect_eq_buf(buf, buf2, message_size, total_fields)); delete[] buf; delete[] buf2; } /** * Template arguments: * T: kdo input struct * F: odk deserializer * G: kdo serializer */ template void ValidateResponse(uint32_t message_type, const std::vector& extra_fields, const F& odk_parse_func, const G& kdo_prepare_func) { uint32_t message_size = 0; uint16_t api_minor_version = ODK_MINOR_VERSION; uint16_t api_major_version = ODK_MAJOR_VERSION; uint32_t nonce = 0xdeadbeef; uint32_t session_id = 0xcafebabe; 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"}, }; uint32_t header_size = 0; for (auto& field : total_fields) { header_size += ODK_FieldLength(field.type); } total_fields.insert(total_fields.end(), extra_fields.begin(), extra_fields.end()); for (auto& field : total_fields) { message_size += ODK_FieldLength(field.type); } uint8_t* buf = new uint8_t[message_size](); uint8_t* zero = new uint8_t[message_size](); size_t bytes_read = 0, bytes_written = 0; T t = {}; t.api_minor_version = api_minor_version; t.api_major_version = api_major_version; t.nonce = nonce; t.session_id = session_id; // serialize input to buf EXPECT_EQ(OEMCrypto_SUCCESS, ODK_IterFields(ODK_WRITE, buf, SIZE_MAX, &bytes_written, total_fields)); EXPECT_EQ(bytes_written, message_size); // zero-out input EXPECT_EQ(OEMCrypto_SUCCESS, ODK_IterFields(ODK_READ, zero, bytes_written, &bytes_read, extra_fields)); EXPECT_TRUE(bytes_written > bytes_read && bytes_written - bytes_read == header_size); // parse buf with odk ODK_NonceValues nonce_values{ODK_MINOR_VERSION, api_major_version, nonce, session_id}; EXPECT_EQ(OEMCrypto_SUCCESS, odk_parse_func(buf, bytes_written, &nonce_values)); // serialize odk output to oemcrypto_core_message std::string oemcrypto_core_message; EXPECT_TRUE(kdo_prepare_func(t, &oemcrypto_core_message)); EXPECT_EQ(bytes_written, message_size); EXPECT_NO_FATAL_FAILURE(expect_eq_buf(buf, oemcrypto_core_message.data(), message_size, total_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); ODK_IterFields(ODK_READ, buf, bytes_read, &bytes_written, fields); ODK_IterFields(ODK_WRITE, buf2, SIZE_MAX, &bytes_read, fields); EXPECT_NO_FATAL_FAILURE(expect_eq_buf(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_NUMTYPES)); 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 (int 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(expect_eq_buf(buf, buf2, total_size, fields)); // cleanup for (int i = 0; i < n; i++) { free(fields[i].value); } delete[] buf; delete[] buf2; } TEST(OdkTest, LicenseRequest) { 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, RenewalRequest) { 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 = {0}; 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); if (ok) { playback_time = core_renewal_request->playback_time_seconds; } return ok; }; ValidateRequest(ODK_Renewal_Request_Type, extra_fields, odk_prepare_func, kdo_parse_func); } TEST(OdkTest, ProvisionRequest) { 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); if (ok) { const std::string& device_id_str = core_provisioning_request->device_id; device_id_length = device_id_str.size(); memcpy(device_id, device_id_str.data(), device_id_length); } return ok; }; ValidateRequest(ODK_Provisioning_Request_Type, extra_fields, odk_prepare_func, kdo_parse_func); } TEST(OdkTest, LicenseResponse) { ODK_ParsedLicense parsed_license = { .enc_mac_keys_iv = {.offset = 0, .length = 1}, .enc_mac_keys = {.offset = 2, .length = 3}, .pst = {.offset = 4, .length = 5}, .srm_restriction_data = {.offset = 6, .length = 7}, .license_type = OEMCrypto_EntitlementLicense, .nonce_required = true, .timer_limits = { .soft_enforce_rental_duration = true, .soft_enforce_playback_duration = false, .earliest_playback_start_seconds = 10, .rental_duration_seconds = 11, .total_playback_duration_seconds = 12, .initial_renewal_duration_seconds = 13, }, .key_array_length = 3, .key_array = { { .key_id = {.offset = 15, .length = 16}, .key_data_iv = {.offset = 17, .length = 18}, .key_data = {.offset = 19, .length = 20}, .key_control_iv = {.offset = 21, .length = 22}, .key_control = {.offset = 23, .length = 24}, }, { .key_id = {.offset = 25, .length = 26}, .key_data_iv = {.offset = 27, .length = 28}, .key_data = {.offset = 29, .length = 30}, .key_control_iv = {.offset = 31, .length = 32}, .key_control = {.offset = 33, .length = 34}, }, { .key_id = {.offset = 35, .length = 36}, .key_data_iv = {.offset = 37, .length = 38}, .key_data = {.offset = 39, .length = 40}, .key_control_iv = {.offset = 41, .length = 42}, .key_control = {.offset = 43, .length = 44}, }, }, }; const uint8_t request_hash[ODK_SHA256_HASH_SIZE] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; uint8_t request_hash_read[ODK_SHA256_HASH_SIZE]; memcpy(request_hash_read, request_hash, sizeof(request_hash)); std::vector extra_fields = { {ODK_SUBSTRING, &parsed_license.enc_mac_keys_iv, ".enc_mac_keys_iv"}, {ODK_SUBSTRING, &parsed_license.enc_mac_keys, ".enc_mac_keys"}, {ODK_SUBSTRING, &parsed_license.pst, ".pst"}, {ODK_SUBSTRING, &parsed_license.srm_restriction_data, ".srm_restriction_data"}, {ODK_UINT32, &parsed_license.license_type, ".license_type"}, {ODK_UINT32, &parsed_license.nonce_required, ".nonce_required"}, {ODK_UINT32, &parsed_license.timer_limits.soft_enforce_rental_duration, ".soft_enforce_rental_duration"}, {ODK_UINT32, &parsed_license.timer_limits.soft_enforce_playback_duration, ".soft_enforce_playback_duration"}, {ODK_UINT64, &parsed_license.timer_limits.earliest_playback_start_seconds, ".earliest_playback_start_seconds"}, {ODK_UINT64, &parsed_license.timer_limits.rental_duration_seconds, ".rental_duration_seconds"}, {ODK_UINT64, &parsed_license.timer_limits.total_playback_duration_seconds, ".total_playback_duration_seconds"}, {ODK_UINT64, &parsed_license.timer_limits.initial_renewal_duration_seconds, ".initial_renewal_duration_seconds"}, {ODK_UINT32, &parsed_license.key_array_length, ".key_array_length"}, {ODK_SUBSTRING, &parsed_license.key_array[0].key_id, ".key_id"}, {ODK_SUBSTRING, &parsed_license.key_array[0].key_data_iv, ".key_data_iv"}, {ODK_SUBSTRING, &parsed_license.key_array[0].key_data, ".key_data"}, {ODK_SUBSTRING, &parsed_license.key_array[0].key_control_iv, ".key_control_iv"}, {ODK_SUBSTRING, &parsed_license.key_array[0].key_control, ".key_control"}, {ODK_SUBSTRING, &parsed_license.key_array[1].key_id, ".key_id"}, {ODK_SUBSTRING, &parsed_license.key_array[1].key_data_iv, ".key_data_iv"}, {ODK_SUBSTRING, &parsed_license.key_array[1].key_data, ".key_data"}, {ODK_SUBSTRING, &parsed_license.key_array[1].key_control_iv, ".key_control_iv"}, {ODK_SUBSTRING, &parsed_license.key_array[1].key_control, ".key_control"}, {ODK_SUBSTRING, &parsed_license.key_array[2].key_id, ".key_id"}, {ODK_SUBSTRING, &parsed_license.key_array[2].key_data_iv, ".key_data_iv"}, {ODK_SUBSTRING, &parsed_license.key_array[2].key_data, ".key_data"}, {ODK_SUBSTRING, &parsed_license.key_array[2].key_control_iv, ".key_control_iv"}, {ODK_SUBSTRING, &parsed_license.key_array[2].key_control, ".key_control"}, {ODK_HASH, request_hash_read, ".request_hash"}, }; const std::string request_hash_string( reinterpret_cast(request_hash), sizeof(request_hash)); auto odk_parse_func = [&](const uint8_t* buf, size_t size, ODK_NonceValues* nonce_values) { ODK_TimerLimits timer_limits; ODK_ClockValues clock_values; constexpr bool initial_license_load = true; constexpr bool usage_entry_present = true; return ODK_ParseLicense(buf, size + 128, size, initial_license_load, usage_entry_present, request_hash, &timer_limits, &clock_values, nonce_values, &parsed_license); }; auto kdo_prepare_func = [&](const ODK_LicenseRequest& core_request, std::string* oemcrypto_core_message) { return CreateCoreLicenseResponse(parsed_license, core_request, request_hash_string, oemcrypto_core_message); }; ValidateResponse(ODK_License_Response_Type, extra_fields, odk_parse_func, kdo_prepare_func); } TEST(OdkTest, RenewalResponse) { uint64_t system_time = 0xfaceb00c; uint64_t playback_clock = 11; uint64_t playback_timer = 12; uint64_t message_playback_clock = 10; constexpr uint64_t renewal_duration = 130; uint64_t var_renewal_duration = renewal_duration; std::vector extra_fields = { {ODK_UINT64, &message_playback_clock, "message_playback_clock"}, {ODK_UINT64, &var_renewal_duration, "renewal_duration"}, }; ODK_TimerLimits timer_limits = { .soft_enforce_rental_duration = false, .soft_enforce_playback_duration = false, .earliest_playback_start_seconds = 0, .rental_duration_seconds = 1000, .total_playback_duration_seconds = 2000, .initial_renewal_duration_seconds = 30, }; ODK_ClockValues clock_values = { .time_of_license_signed = system_time - playback_clock - 42, .time_of_first_decrypt = system_time - playback_clock, .time_of_last_decrypt = 0, .time_of_renewal_request = message_playback_clock, .time_when_timer_expires = system_time + playback_timer, .timer_status = ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED, .status = kUnused, }; auto odk_parse_func = [&](const uint8_t* buf, size_t size, ODK_NonceValues* nonce_values) { OEMCryptoResult err = ODK_ParseRenewal(buf, size, size, nonce_values, system_time, &timer_limits, &clock_values, &playback_timer); EXPECT_EQ(ODK_SET_TIMER, err); EXPECT_EQ(renewal_duration, playback_timer); EXPECT_EQ(clock_values.time_when_timer_expires, system_time + playback_timer); // manually restore message_playback_clock since ODK_ParseRenewal doesn't // generate output message_playback_clock = 10; return OEMCrypto_SUCCESS; }; auto kdo_prepare_func = [&](ODK_RenewalRequest& core_request, std::string* oemcrypto_core_message) { core_request.playback_time_seconds = message_playback_clock; return CreateCoreRenewalResponse(core_request, renewal_duration, oemcrypto_core_message); }; ValidateResponse(ODK_Renewal_Response_Type, extra_fields, odk_parse_func, kdo_prepare_func); } TEST(OdkTest, ProvisionResponse) { 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); ODK_ParsedProvisioning parsed_response = { .enc_private_key = {.offset = 0, .length = 1}, .enc_private_key_iv = {.offset = 2, .length = 3}, .encrypted_message_key = {.offset = 4, .length = 5}, }; std::vector extra_fields = { {ODK_UINT32, &device_id_length, "device_id_length"}, {ODK_DEVICEID, device_id, "device_id"}, {ODK_UINT32, &parsed_response.key_type, "key_type"}, {ODK_SUBSTRING, &parsed_response.enc_private_key, "enc_private_key"}, {ODK_SUBSTRING, &parsed_response.enc_private_key_iv, "enc_private_key_iv"}, {ODK_SUBSTRING, &parsed_response.encrypted_message_key, "encrypted_message_key"}, }; auto odk_parse_func = [&](const uint8_t* buf, size_t size, ODK_NonceValues* nonce_values) { // restore device id because it is not part of parsed_response device_id_length = ODK_DEVICE_ID_LEN_MAX / 2; memset(device_id, 0xff, device_id_length); OEMCryptoResult err = ODK_ParseProvisioning(buf, size + 16, size, nonce_values, device_id, device_id_length, &parsed_response); 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(parsed_response, core_request, oemcrypto_core_message); }; ValidateResponse(ODK_Provisioning_Response_Type, extra_fields, odk_parse_func, kdo_prepare_func); } 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)); // All messages have at least a five 4-byte fields. size_t minimum_message_size = 5 * 4; EXPECT_GE(core_message_length, minimum_message_size); } 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 = 0; uint32_t nonce = 0; uint32_t session_id = 0; ODK_ClockValues clock_values = {}; clock_values.time_of_first_decrypt = 10; 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)); // All messages have at least a five 4-byte fields. size_t minimum_message_size = 5 * 4; EXPECT_GE(core_message_length, minimum_message_size); } 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)); // All messages have at least a five 4-byte fields. size_t minimum_message_size = 5 * 4; EXPECT_GE(core_message_length, minimum_message_size); } } // namespace