/* * 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 "oec_util.h" #include #include #include #include #include #include #include "odk_overflow.h" #include "odk_serialize.h" #include "odk_structs.h" #include "odk_structs_priv.h" #include "oemcrypto_types.h" #include "serialization_base.h" using namespace oec_util; namespace oec_util { namespace { /* @ private functions */ const int CURRENT_OEC_VERSION = 16; /** * Template for parsing requests * * Template arguments: * S: kdo output struct * T: struct serialized by odk * U: auto-generated deserializing function for |T| */ template bool ParseRequest(uint32_t message_type, const string& oemcrypto_core_message, S* core_request, T* prepared, const U unpacker) { if (!core_request) { return false; } const uint8_t* buf = reinterpret_cast(oemcrypto_core_message.c_str()); size_t buf_length = oemcrypto_core_message.size(); Message* msg = NULL; AllocateMessage(&msg, message_block); InitMessage(msg, const_cast(buf), buf_length); SetSize(msg, buf_length); unpacker(msg, prepared); if (!ValidMessage(msg)) { return false; } const auto& core_message = prepared->core_message; core_request->api_version = core_message.nonce_values.api_version; core_request->nonce = core_message.nonce_values.nonce; core_request->session_id = core_message.nonce_values.session_id; return core_message.message_type == message_type && core_message.message_length == GetOffset(msg) && core_request->api_version == CURRENT_OEC_VERSION; } /** * Template for parsing requests * * Template arguments: * T: struct to be deserialized by odk * S: kdo input struct * P: auto-generated serializing function for |T| */ template bool CreateResponse(uint32_t message_type, const S& core_request, string* oemcrypto_core_message, T& response, const P& packer) { if (!oemcrypto_core_message) { return false; } auto* header = reinterpret_cast(&response); header->message_type = message_type; header->nonce_values.api_version = core_request.api_version; header->nonce_values.nonce = core_request.nonce; header->nonce_values.session_id = core_request.session_id; uint8_t buf[2048] = {0}; Message* msg = NULL; AllocateMessage(&msg, message_block); InitMessage(msg, buf, sizeof(buf)); packer(msg, &response); if (!ValidMessage(msg)) { return false; } uint32_t message_length = GetSize(msg); InitMessage(msg, buf + sizeof(header->message_type), sizeof(header->message_length)); Pack_uint32_t(msg, &message_length); oemcrypto_core_message->assign(reinterpret_cast(buf), message_length); return true; } bool CopyDeviceId(ODK_ProvisioningResponse& dest, const ODK_ProvisioningRequest& src) { auto& core_provisioning = dest.core_provisioning; const string& device_id = src.device_id; core_provisioning.device_id_length = device_id.size(); if (core_provisioning.device_id_length > sizeof(core_provisioning.device_id)) { return false; } memset(core_provisioning.device_id, 0, sizeof(core_provisioning.device_id)); memcpy(core_provisioning.device_id, device_id.data(), core_provisioning.device_id_length); return true; } } // namespace // @ public parse request (deserializer) functions bool ParseLicenseRequest(const string& oemcrypto_core_message, ODK_LicenseRequest* core_license_request) { const auto unpacker = Unpack_ODK_PreparedLicense; ODK_PreparedLicense prepared_license = {}; return ParseRequest(ODK_License_Request_Type, oemcrypto_core_message, core_license_request, &prepared_license, unpacker); } bool ParseRenewalRequest(const string& oemcrypto_core_message, ODK_RenewalRequest* core_renewal_request) { const auto unpacker = Unpack_ODK_RenewalMessage; ODK_RenewalMessage prepared_renewal = {}; if (!ParseRequest(ODK_Renewal_Request_Type, oemcrypto_core_message, core_renewal_request, &prepared_renewal, unpacker)) { return false; } core_renewal_request->playback_time = prepared_renewal.playback_time; return true; } bool ParseProvisioningRequest( const string& oemcrypto_core_message, ODK_ProvisioningRequest* core_provisioning_request) { const auto unpacker = Unpack_ODK_ProvisioningMessage; ODK_ProvisioningMessage prepared_provision = {}; if (!ParseRequest(ODK_Provisioning_Request_Type, oemcrypto_core_message, core_provisioning_request, &prepared_provision, unpacker)) { return false; } const uint8_t* device_id = prepared_provision.device_id; const uint32_t device_id_length = prepared_provision.device_id_length; if (device_id_length > ODK_DEVICE_ID_LEN_MAX) { return false; } uint8_t zero[ODK_DEVICE_ID_LEN_MAX] = {}; if (memcmp(zero, device_id + device_id_length, ODK_DEVICE_ID_LEN_MAX - device_id_length)) { return false; } core_provisioning_request->device_id.assign( reinterpret_cast(device_id), device_id_length); return true; } // @ public create response functions bool CreateCoreLicenseResponse(const ODK_ParsedLicense& parsed_lic, const ODK_LicenseRequest& core_request, string* oemcrypto_core_message) { ODK_LicenseResponse license_response{ {}, const_cast(&parsed_lic)}; return CreateResponse(ODK_License_Response_Type, core_request, oemcrypto_core_message, license_response, Pack_ODK_LicenseResponse); } bool CreateCoreRenewalResponse(const ODK_RenewalRequest& core_request, string* oemcrypto_core_message) { ODK_RenewalMessage renewal{{}, core_request.playback_time}; renewal.playback_time = core_request.playback_time; return CreateResponse(ODK_Renewal_Response_Type, core_request, oemcrypto_core_message, renewal, Pack_ODK_RenewalMessage); } bool CreateCoreProvisioningResponse(const ODK_ParsedProvisioning& parsed_prov, const ODK_ProvisioningRequest& core_request, string* oemcrypto_core_message) { ODK_ProvisioningResponse prov_response{ {}, const_cast(&parsed_prov)}; if (!CopyDeviceId(prov_response, core_request)) { return false; } return CreateResponse(ODK_Provisioning_Response_Type, core_request, oemcrypto_core_message, prov_response, Pack_ODK_ProvisioningResponse); } } // namespace oec_util