// Copyright 2019 Google LLC. All rights reserved. This file and proprietary // source code may only be used and distributed under the Widevine // License Agreement. #ifndef WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_H_ #define WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_H_ #ifdef __cplusplus extern "C" { #endif #include #include #include /* * ODK_Message is the structure that defines the serialized messages passed * between the REE and TEE. ODK_Message is an abstract data type that represents * the concept of a message without disclosing the implementation details. By * hiding the internal structure, modification of the message fields by code * that is not privy to the message definition can be prevented. If the message * definition was exposed, there could be serious yet subtle errors in message * manipulation anywhere in the code base. By restricting message modification * it is possible to enforce validity and integrity with a small set of * primitives that can be carefully reviewed. Checks can be added to verify that * a message's fields are internally consistent before every operation. As an * example, it can be guaranteed that the message status will be checked prior * to accessing any field so parsing will be stopped when the message status is * set after any parse error is detected. This also makes development easier * since any access to the message structure can be tracked through a single * point so, for example, it becomes possible to add trace statements globally * to all message operations by only changing the field accessors. Finally it * simplifies maintenance by localizing changes to the message structure to a * few files. */ #if defined(__GNUC__) || defined(__clang__) #define ALIGNED __attribute__((aligned)) #else #define ALIGNED #error ODK_Message must be aligned to the maximum useful alignment of the \ machine you are compiling for. Define the ALIGNED macro accordingly. #endif typedef struct { #define SIZE_OF_ODK_MESSAGE_IMPL 64 uint8_t opaque_data[SIZE_OF_ODK_MESSAGE_IMPL]; } ALIGNED ODK_Message; typedef enum { MESSAGE_STATUS_OK = 0xe937fcf7, MESSAGE_STATUS_UNKNOWN_ERROR = 0xe06c1190, MESSAGE_STATUS_OVERFLOW_ERROR = 0xc43ae4bc, MESSAGE_STATUS_UNDERFLOW_ERROR = 0x7123cd0b, MESSAGE_STATUS_PARSE_ERROR = 0x0b9f6189, MESSAGE_STATUS_NULL_POINTER_ERROR = 0x2d66837a, MESSAGE_STATUS_API_VALUE_ERROR = 0x6ba34f47, MESSAGE_STATUS_END_OF_MESSAGE_ERROR = 0x998db72a, MESSAGE_STATUS_INVALID_ENUM_VALUE = 0xedb88197, MESSAGE_STATUS_INVALID_TAG_ERROR = 0x14dce06a, MESSAGE_STATUS_NOT_INITIALIZED = 0x2990b6c6, MESSAGE_STATUS_OUT_OF_MEMORY = 0xfc5c64cc, MESSAGE_STATUS_MAP_SHARED_MEMORY_FAILED = 0xfafecacf, MESSAGE_STATUS_SECURE_BUFFER_ERROR = 0x78f0e873 } ODK_MessageStatus; /* * Create a message structure that references a separate data buffer. An * initialized message is returned. The caller is responsible for ensuring that * the buffer remains allocated for the lifetime of the message. If |buffer| * is NULL or |capacity| is zero, the message is invalid and the status * will be set to MESSAGE_STATUS_NOT_INITIALIZED. */ ODK_Message ODK_Message_Create(uint8_t* buffer, size_t capacity); /* * Erase the contents of the message, set it to an empty state by setting the * message size and read offset to 0, effectively erasing the contents of the * message. The message data buffer pointer remains unchanged, i.e. the message * retains ownership of the buffer. The message status is reset to * MESSAGE_STATUS_OK. */ void ODK_Message_Clear(ODK_Message* message); /* * Reset read pointer to the beginning of the message and clear status * so that parsing of the message will restart at the beginning of the * message. The message status is reset to MESSAGE_STATUS_OK. */ void ODK_Message_Reset(ODK_Message* message); /* * Return a pointer to the message data buffer, i.e. the message payload. * This is the buffer address that was passed into ODK_Message_Create. */ uint8_t* ODK_Message_GetBase(ODK_Message* message); /* * Get the maximum number of bytes the message can hold. */ size_t ODK_Message_GetCapacity(ODK_Message* message); /* * Get the number of bytes currently in the message */ size_t ODK_Message_GetSize(ODK_Message* message); /* * Get the offset of where the next bytes will be read from the message data * buffer. */ size_t ODK_Message_GetOffset(ODK_Message* message); /* * Return the status of the message */ ODK_MessageStatus ODK_Message_GetStatus(ODK_Message* message); /* * Set the message status to a specific value */ void ODK_Message_SetStatus(ODK_Message* message, ODK_MessageStatus status); /* * Set the size of the message to a value. This may be needed after writing data * into the message data buffer. */ void ODK_Message_SetSize(ODK_Message* message, size_t size); /* * Test if the integrity of a message. This means that the status must be * MESSAGE_STATUS_OK and that the internal fields of the message are * within the range of valid values. */ bool ODK_Message_IsValid(ODK_Message* message); #ifdef __cplusplus } // extern "C" #endif #endif // WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_H_