// 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 "serialization_base.h" #include #include #include #include #include "OEMCryptoCENCCommon.h" #include "odk_message.h" #include "odk_message_priv.h" #include "odk_overflow.h" /* * An ODK_Message_Impl pointer must only be obtained by calling GetMessageImpl. * This forces any message to pass the validity check before being operated on, * which means that no function can modify or access the internals of a message * without having it be validated first. */ static ODK_Message_Impl* GetMessageImpl(ODK_Message* message) { if (!ODK_Message_IsValid(message)) return NULL; return (ODK_Message_Impl*)message; } static void PackBytes(ODK_Message* message, const uint8_t* ptr, size_t count) { ODK_Message_Impl* message_impl = GetMessageImpl(message); if (!message_impl) return; if (count <= message_impl->capacity - message_impl->size) { memcpy((void*)(message_impl->base + message_impl->size), (const void*)ptr, count); message_impl->size += count; } else { message_impl->status = MESSAGE_STATUS_OVERFLOW_ERROR; } } void Pack_enum(ODK_Message* message, int value) { uint32_t v32 = (uint32_t)value; Pack_uint32_t(message, &v32); } void Pack_bool(ODK_Message* message, const bool* value) { assert(value); uint8_t data[4] = {0}; data[3] = *value ? 1 : 0; PackBytes(message, data, sizeof(data)); } void Pack_uint8_t(ODK_Message* message, const uint8_t* value) { assert(value); uint8_t data[1] = {0}; data[0] = (uint8_t)(*value >> 0); PackBytes(message, data, sizeof(data)); } void Pack_uint16_t(ODK_Message* message, const uint16_t* value) { assert(value); uint8_t data[2] = {0}; data[0] = (uint8_t)(*value >> 8); data[1] = (uint8_t)(*value >> 0); PackBytes(message, data, sizeof(data)); } void Pack_uint32_t(ODK_Message* message, const uint32_t* value) { assert(value); uint8_t data[4] = {0}; data[0] = (uint8_t)(*value >> 24); data[1] = (uint8_t)(*value >> 16); data[2] = (uint8_t)(*value >> 8); data[3] = (uint8_t)(*value >> 0); PackBytes(message, data, sizeof(data)); } void Pack_uint64_t(ODK_Message* message, const uint64_t* value) { assert(value); uint32_t hi = (uint32_t)(*value >> 32); uint32_t lo = (uint32_t)(*value); Pack_uint32_t(message, &hi); Pack_uint32_t(message, &lo); } void PackArray(ODK_Message* message, const uint8_t* base, size_t size) { PackBytes(message, base, size); } void Pack_OEMCrypto_Substring(ODK_Message* message, const OEMCrypto_Substring* obj) { assert(obj); uint32_t offset = (uint32_t)obj->offset; uint32_t length = (uint32_t)obj->length; Pack_uint32_t(message, &offset); Pack_uint32_t(message, &length); } static void UnpackBytes(ODK_Message* message, uint8_t* ptr, size_t count) { assert(ptr); ODK_Message_Impl* message_impl = GetMessageImpl(message); if (!message_impl) return; if (count <= message_impl->size - message_impl->read_offset) { memcpy((void*)ptr, (void*)(message_impl->base + message_impl->read_offset), count); message_impl->read_offset += count; } else { message_impl->status = MESSAGE_STATUS_UNDERFLOW_ERROR; } } void Unpack_OEMCrypto_LicenseType(ODK_Message* message, OEMCrypto_LicenseType* value) { assert(value); uint32_t v32 = 0; Unpack_uint32_t(message, &v32); if (v32 <= OEMCrypto_LicenseType_MaxValue) { *value = (OEMCrypto_LicenseType)v32; } else { ODK_Message_SetStatus(message, MESSAGE_STATUS_PARSE_ERROR); } } void Unpack_OEMCrypto_PrivateKeyType(ODK_Message* message, OEMCrypto_PrivateKeyType* value) { assert(value); uint32_t v32 = 0; Unpack_uint32_t(message, &v32); if (v32 <= OEMCrypto_PrivateKeyType_MaxValue) { *value = (OEMCrypto_PrivateKeyType)v32; } else { ODK_Message_SetStatus(message, MESSAGE_STATUS_PARSE_ERROR); } } void Unpack_OEMCrypto_TimerDelayBase(ODK_Message* message, OEMCrypto_TimerDelayBase* value) { assert(value); uint32_t v32 = 0; Unpack_uint32_t(message, &v32); if (v32 <= OEMCrypto_TimerDelayBase_MaxValue) { *value = (OEMCrypto_TimerDelayBase)v32; } else { ODK_Message_SetStatus(message, MESSAGE_STATUS_PARSE_ERROR); } } void Unpack_bool(ODK_Message* message, bool* value) { uint8_t data[4] = {0}; UnpackBytes(message, data, sizeof(data)); assert(value); *value = (0 != data[3]); } void Unpack_uint8_t(ODK_Message* message, uint8_t* value) { assert(value); uint8_t data[1] = {0}; UnpackBytes(message, data, sizeof(data)); *value = data[0]; } void Unpack_uint16_t(ODK_Message* message, uint16_t* value) { assert(value); uint8_t data[2] = {0}; UnpackBytes(message, data, sizeof(data)); *value = data[0]; *value = *value << 8 | data[1]; } void Unpack_uint32_t(ODK_Message* message, uint32_t* value) { ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; if (!message_impl) return; uint8_t data[4] = {0}; UnpackBytes(message, data, sizeof(data)); assert(value); *value = data[0]; *value = *value << 8 | data[1]; *value = *value << 8 | data[2]; *value = *value << 8 | data[3]; } void Unpack_uint64_t(ODK_Message* message, uint64_t* value) { uint32_t hi = 0; uint32_t lo = 0; Unpack_uint32_t(message, &hi); Unpack_uint32_t(message, &lo); assert(value); *value = hi; *value = *value << 32 | lo; } void Unpack_OEMCrypto_Substring(ODK_Message* message, OEMCrypto_Substring* obj) { uint32_t offset = 0, length = 0; Unpack_uint32_t(message, &offset); Unpack_uint32_t(message, &length); ODK_Message_Impl* message_impl = GetMessageImpl(message); if (!message_impl) return; /* Each substring should be contained within the message body, which is in the * total message, just after the core message. The offset of a substring is * relative to the message body. So we need to verify: * * For non-empty substring: * offset + length < message_impl->capacity - message_impl->size or * offset + length + message_impl->size < message_impl->capacity * * For empty substring (length is 0): * offset must be 0 */ if (length == 0 && offset != 0) { message_impl->status = MESSAGE_STATUS_UNKNOWN_ERROR; return; } size_t substring_end = 0; /* = offset + length; */ size_t end = 0; /* = substring_end + message_impl->size; */ if (odk_add_overflow_ux(offset, length, &substring_end) || odk_add_overflow_ux(substring_end, message_impl->size, &end) || end > message_impl->capacity) { message_impl->status = MESSAGE_STATUS_OVERFLOW_ERROR; return; } assert(obj); obj->offset = offset; obj->length = length; } /* copy out */ void UnpackArray(ODK_Message* message, uint8_t* address, size_t size) { UnpackBytes(message, address, size); }