/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include "odk.h" #include "odk_test.h" #include "oec_util.h" using namespace oec_util; size_t ODK_FieldLength(ODK_FieldType type) { switch (type) { 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_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_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; } /* * 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, 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; if (mode == ODK_WRITE) { ODK_WriteSingleField(buf_off, &fields[i]); } else if (mode == ODK_READ) { ODK_ReadSingleField(buf_off, &fields[i]); } else { return ODK_ERROR_CORE_MESSAGE; } off = off2; } *size_out = off; if (*size_out > size_in) { return ODK_ERROR_CORE_MESSAGE; } return OEMCrypto_SUCCESS; } OEMCryptoResult ODK_ReadFields(const uint8_t* const buf, const size_t size_in, size_t* size_out, std::vector& fields) { return ODK_IterFields(ODK_READ, const_cast(buf), size_in, size_out, fields); } OEMCryptoResult ODK_WriteFields(uint8_t* const buf, const size_t size_in, size_t* size_out, std::vector& fields) { return ODK_IterFields(ODK_WRITE, buf, size_in, size_out, fields); } void expect_eq_buf(const void* s1, const void* s2, size_t n) { if (memcmp(s1, s2, n)) { const void* buffers[] = {s1, s2}; for (int i = 0; i < 2; i++) { char _tmp[] = "/tmp/fileXXXXXX"; mkstemp(_tmp); std::string tmp(_tmp); std::fstream out(tmp, std::ios::out | std::ios::binary); out.write((char*)buffers[i], n); out.close(); std: std::cerr << "buffer " << i << " dumped to " << tmp << std::endl; } FAIL(); } } template void ValidateRequest(uint32_t message_type, std::vector& extra_fields, const F& odk_prepare_func, const G& kdo_parse_func) { uint32_t message_size = 0; uint32_t api_version = 16; uint32_t nonce = 0xdeadbeef; uint32_t session_id = 0xcafebabe; ODK_NonceValues nonce_values{api_version, nonce, session_id}; std::vector total_fields = { {ODK_UINT32, &message_type}, {ODK_UINT32, &message_size}, {ODK_UINT32, &api_version}, {ODK_UINT32, &nonce}, {ODK_UINT32, &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_eq_buf(buf, buf2, message_size); // 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_version = t.api_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_eq_buf(buf, buf2, message_size); delete[] buf; delete[] buf2; } /** * Template arguments: * T: kdo input struct * F: odk deserializer * G: kdo serializer */ template void ValidateResponse(uint32_t message_type, std::vector& extra_fields, const F& odk_parse_func, const G& kdo_prepare_func) { uint32_t message_size = 0; uint32_t api_version = 16; uint32_t nonce = 0xdeadbeef; uint32_t session_id = 0xcafebabe; std::vector total_fields = { {ODK_UINT32, &message_type}, {ODK_UINT32, &message_size}, {ODK_UINT32, &api_version}, {ODK_UINT32, &nonce}, {ODK_UINT32, &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_version = api_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{api_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_eq_buf(buf, oemcrypto_core_message.data(), message_size); 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]}, {ODK_UINT32, &x[1]}, {ODK_UINT32, &x[2]}, {ODK_UINT64, &y[0]}, {ODK_UINT64, &y[1]}, {ODK_UINT64, &y[2]}, {ODK_SUBSTRING, &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_eq_buf(buf, buf2, bytes_read); } 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)); size_t field_size = ODK_AllocSize(fields[i].type); fields[i].value = malloc(ODK_AllocSize(fields[i].type)); 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_eq_buf(buf, buf2, total_size); // 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 = ParseLicenseRequest; ValidateRequest(ODK_License_Request_Type, empty, odk_prepare_func, kdo_parse_func); } TEST(OdkTest, RenewalRequest) { uint64_t system_time_seconds = 0xBADDCAFE000FF1CE; std::vector extra_fields = { {ODK_UINT64, &system_time_seconds}, }; ODK_ClockValues clock_values = {0}; auto odk_prepare_func = [&](uint8_t* const buf, size_t* size, const 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 = ParseRenewalRequest(oemcrypto_core_message, core_renewal_request); if (ok) { system_time_seconds = core_renewal_request->playback_time; } return ok; }; ValidateRequest(ODK_Renewal_Request_Type, extra_fields, odk_prepare_func, kdo_parse_func); } TEST(OdkTest, ProvisionRequest) { uint32_t device_id_length = DEVICE_ID_MAX / 2; uint8_t device_id[DEVICE_ID_MAX] = {0}; memset(device_id, 0xff, device_id_length); std::vector extra_fields = { {ODK_UINT32, &device_id_length}, {ODK_DEVICEID, 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 = ParseProvisioningRequest(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 = 8, .nonce_required = 0xDEADC0DE, .timer_limits = { .soft_expiry = 9, .earliest_playback_start_seconds = 10, .latest_playback_start_seconds = 11, .initial_playback_duration_seconds = 12, .renewal_playback_duration_seconds = 13, .license_duration_seconds = 14, }, .request_hash = {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}, .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}, }, }, }; uint32_t message_type = ODK_License_Response_Type; std::vector extra_fields = { {ODK_SUBSTRING, &parsed_license.enc_mac_keys_iv}, {ODK_SUBSTRING, &parsed_license.enc_mac_keys}, {ODK_SUBSTRING, &parsed_license.pst}, {ODK_SUBSTRING, &parsed_license.srm_restriction_data}, {ODK_UINT32, &parsed_license.license_type}, {ODK_UINT32, &parsed_license.nonce_required}, {ODK_UINT32, &parsed_license.timer_limits.soft_expiry}, {ODK_UINT64, &parsed_license.timer_limits.earliest_playback_start_seconds}, {ODK_UINT64, &parsed_license.timer_limits.latest_playback_start_seconds}, {ODK_UINT64, &parsed_license.timer_limits.initial_playback_duration_seconds}, {ODK_UINT64, &parsed_license.timer_limits.renewal_playback_duration_seconds}, {ODK_UINT64, &parsed_license.timer_limits.license_duration_seconds}, {ODK_HASH, &parsed_license.request_hash}, {ODK_UINT32, &parsed_license.key_array_length}, {ODK_SUBSTRING, &parsed_license.key_array[0].key_id}, {ODK_SUBSTRING, &parsed_license.key_array[0].key_data_iv}, {ODK_SUBSTRING, &parsed_license.key_array[0].key_data}, {ODK_SUBSTRING, &parsed_license.key_array[0].key_control_iv}, {ODK_SUBSTRING, &parsed_license.key_array[0].key_control}, {ODK_SUBSTRING, &parsed_license.key_array[1].key_id}, {ODK_SUBSTRING, &parsed_license.key_array[1].key_data_iv}, {ODK_SUBSTRING, &parsed_license.key_array[1].key_data}, {ODK_SUBSTRING, &parsed_license.key_array[1].key_control_iv}, {ODK_SUBSTRING, &parsed_license.key_array[1].key_control}, {ODK_SUBSTRING, &parsed_license.key_array[2].key_id}, {ODK_SUBSTRING, &parsed_license.key_array[2].key_data_iv}, {ODK_SUBSTRING, &parsed_license.key_array[2].key_data}, {ODK_SUBSTRING, &parsed_license.key_array[2].key_control_iv}, {ODK_SUBSTRING, &parsed_license.key_array[2].key_control}, }; uint8_t request_hash[ODK_SHA256_HASH_SIZE] = {}; memcpy(request_hash, parsed_license.request_hash, ODK_SHA256_HASH_SIZE); auto odk_parse_func = [&](const uint8_t* buf, size_t size, ODK_NonceValues* nonce_values) { return ODK_ParseLicense(buf, size + 128, size, 1, 0, request_hash, nullptr, nullptr, nonce_values, &parsed_license); }; auto kdo_prepare_func = [&](const ODK_LicenseRequest& core_request, std::string* oemcrypto_core_message) { return CreateCoreLicenseResponse(parsed_license, core_request, 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; std::vector extra_fields = { {ODK_UINT64, &message_playback_clock}, }; ODK_TimerLimits timer_limits = { .soft_expiry = 0, .earliest_playback_start_seconds = 0, .latest_playback_start_seconds = 100, .initial_playback_duration_seconds = 10, .renewal_playback_duration_seconds = 20, .license_duration_seconds = 100, }; ODK_ClockValues clock_values = { .time_of_license_signed = 0, .time_of_first_decrypt = system_time - playback_clock, .time_of_last_decrypt = 0, .time_when_timer_expires = system_time + playback_timer, .timer_status = 0, .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(timer_limits.renewal_playback_duration_seconds, 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 = message_playback_clock; return CreateCoreRenewalResponse(core_request, oemcrypto_core_message); }; ValidateResponse(ODK_Renewal_Response_Type, extra_fields, odk_parse_func, kdo_prepare_func); } TEST(OdkTest, ProvisionResponse) { uint32_t device_id_length = DEVICE_ID_MAX / 2; uint8_t device_id[DEVICE_ID_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}, {ODK_DEVICEID, device_id}, {ODK_UINT32, &parsed_response.key_type}, {ODK_SUBSTRING, &parsed_response.enc_private_key}, {ODK_SUBSTRING, &parsed_response.enc_private_key_iv}, {ODK_SUBSTRING, &parsed_response.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 = DEVICE_ID_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; uint32_t api_version = 0; uint32_t nonce = 0; uint32_t session_id = 0; ODK_NonceValues nonce_values{api_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; uint32_t api_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_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; uint32_t api_version = 0; uint32_t nonce = 0; uint32_t session_id = 0; uint8_t* device_id = nullptr; uint32_t device_id_length = 0; ODK_NonceValues nonce_values{api_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); }