/* 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 "serialization_base.h" #include #include #include #include "OEMCryptoCENCCommon.h" #include "odk_assert.h" #include "odk_overflow.h" struct _Message { uint8_t* base; size_t capacity; size_t size; /* bytes written */ size_t read_offset; /* bytes read */ MessageStatus status; }; /* TODO(b/150776214): this can be removed once AllocateMessage gets cleaned up */ /* * odk_static_assert(SIZE_OF_MESSAGE_STRUCT >= sizeof(struct _Message), * "SIZE_OF_MESSAGE_STRUCT too small"); */ bool ValidMessage(Message* message) { if (message == NULL) { return false; } if (message->status != MESSAGE_STATUS_OK) { return false; } if (message->base == NULL) { message->status = MESSAGE_STATUS_NULL_POINTER_ERROR; return false; } if (message->size > message->capacity || message->read_offset > message->size) { message->status = MESSAGE_STATUS_OVERFLOW_ERROR; return false; } return true; } static void PackBytes(Message* message, const uint8_t* ptr, size_t count) { if (count <= message->capacity - message->size) { memcpy((void*)(message->base + message->size), (void*)ptr, count); message->size += count; } else { message->status = MESSAGE_STATUS_OVERFLOW_ERROR; } } void Pack_enum(Message* message, int value) { uint32_t v32 = value; Pack_uint32_t(message, &v32); } void Pack_bool(Message* message, const bool* value) { if (!ValidMessage(message)) return; uint8_t data[4] = {0}; data[3] = *value ? 1 : 0; PackBytes(message, data, sizeof(data)); } void Pack_uint16_t(Message* message, const uint16_t* value) { if (!ValidMessage(message)) return; uint8_t data[2] = {0}; data[0] = *value >> 8; data[1] = *value >> 0; PackBytes(message, data, sizeof(data)); } void Pack_uint32_t(Message* message, const uint32_t* value) { if (!ValidMessage(message)) return; uint8_t data[4] = {0}; data[0] = *value >> 24; data[1] = *value >> 16; data[2] = *value >> 8; data[3] = *value >> 0; PackBytes(message, data, sizeof(data)); } void Pack_uint64_t(Message* message, const uint64_t* value) { if (!ValidMessage(message)) return; uint32_t hi = *value >> 32; uint32_t lo = *value; Pack_uint32_t(message, &hi); Pack_uint32_t(message, &lo); } void PackArray(Message* message, const uint8_t* base, size_t size) { if (!ValidMessage(message)) return; PackBytes(message, base, size); } void Pack_OEMCrypto_Substring(Message* msg, const OEMCrypto_Substring* obj) { uint32_t offset = obj->offset; uint32_t length = obj->length; Pack_uint32_t(msg, &offset); Pack_uint32_t(msg, &length); } static void UnpackBytes(Message* message, uint8_t* ptr, size_t count) { if (count <= message->size - message->read_offset) { memcpy((void*)ptr, (void*)(message->base + message->read_offset), count); message->read_offset += count; } else { message->status = MESSAGE_STATUS_UNDERFLOW_ERROR; } } int Unpack_enum(Message* message) { uint32_t v32; Unpack_uint32_t(message, &v32); return v32; } void Unpack_bool(Message* message, bool* value) { if (!ValidMessage(message)) return; uint8_t data[4] = {0}; UnpackBytes(message, data, sizeof(data)); *value = (0 != data[3]); } void Unpack_uint16_t(Message* message, uint16_t* value) { if (!ValidMessage(message)) return; uint8_t data[2] = {0}; UnpackBytes(message, data, sizeof(data)); *value = data[0]; *value = *value << 8 | data[1]; } void Unpack_uint32_t(Message* message, uint32_t* value) { if (!ValidMessage(message)) return; uint8_t data[4] = {0}; UnpackBytes(message, data, sizeof(data)); *value = data[0]; *value = *value << 8 | data[1]; *value = *value << 8 | data[2]; *value = *value << 8 | data[3]; } void Unpack_uint64_t(Message* message, uint64_t* value) { if (!ValidMessage(message)) return; uint32_t hi = 0; uint32_t lo = 0; Unpack_uint32_t(message, &hi); Unpack_uint32_t(message, &lo); *value = hi; *value = *value << 32 | lo; } void Unpack_OEMCrypto_Substring(Message* msg, OEMCrypto_Substring* obj) { uint32_t offset = 0, length = 0; Unpack_uint32_t(msg, &offset); Unpack_uint32_t(msg, &length); if (!ValidMessage(msg)) 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: * 0 < offset and offset + length < message->capacity - message->size * or offset + length + message->size < message->capacity */ size_t substring_end = 0; /* = offset + length; */ size_t end = 0; /* = substring_end + message->size; */ if (odk_add_overflow_ux(offset, length, &substring_end) || odk_add_overflow_ux(substring_end, msg->size, &end) || end > msg->capacity) { msg->status = MESSAGE_STATUS_OVERFLOW_ERROR; return; } obj->offset = offset; obj->length = length; } /* copy out */ void UnpackArray(Message* message, uint8_t* address, size_t size) { if (!ValidMessage(message)) return; UnpackBytes(message, address, size); } /* * The message structure, which is separate from the buffer, * is initialized to reference the buffer */ void InitMessage(Message* message, uint8_t* buffer, size_t capacity) { if (message == NULL) return; memset(message, 0, sizeof(Message)); message->base = buffer; message->capacity = capacity; message->size = 0; message->read_offset = 0; message->status = MESSAGE_STATUS_OK; } /* * The message structure is in the first sizeof(Memory) bytes * of the buffer */ Message* CreateMessage(uint8_t* buffer, size_t buffer_size) { if (buffer == NULL || buffer_size < sizeof(Message)) return NULL; Message* message = (Message*)buffer; message->base = buffer + sizeof(Message); message->capacity = buffer_size - sizeof(Message); message->size = 0; message->read_offset = 0; message->status = MESSAGE_STATUS_OK; return message; } /* * Set the message to an empty state */ void ResetMessage(Message* message) { message->size = 0; message->read_offset = 0; message->status = MESSAGE_STATUS_OK; } uint8_t* GetBase(Message* message) { if (message == NULL) return NULL; return message->base; } size_t GetCapacity(Message* message) { if (message == NULL) return 0; return message->capacity; } size_t GetSize(Message* message) { if (message == NULL) return 0; return message->size; } void SetSize(Message* message, size_t size) { if (message == NULL) return; if (size > message->capacity) message->status = MESSAGE_STATUS_OVERFLOW_ERROR; else message->size = size; } MessageStatus GetStatus(Message* message) { return message->status; } void SetStatus(Message* message, MessageStatus status) { message->status = status; } size_t GetOffset(Message* message) { if (message == NULL) return 0; return message->read_offset; } size_t SizeOfMessageStruct() { return sizeof(Message); }