142 lines
5.1 KiB
C
142 lines
5.1 KiB
C
// 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 <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
/*
|
|
* 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 = 0x7937fcf7,
|
|
MESSAGE_STATUS_UNKNOWN_ERROR = 0x706c1190,
|
|
MESSAGE_STATUS_OVERFLOW_ERROR = 0x543ae4bc,
|
|
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 = 0x798db72a,
|
|
MESSAGE_STATUS_INVALID_ENUM_VALUE = 0x7db88197,
|
|
MESSAGE_STATUS_INVALID_TAG_ERROR = 0x14dce06a,
|
|
MESSAGE_STATUS_NOT_INITIALIZED = 0x2990b6c6,
|
|
MESSAGE_STATUS_OUT_OF_MEMORY = 0x7c5c64cc,
|
|
MESSAGE_STATUS_MAP_SHARED_MEMORY_FAILED = 0x7afecacf,
|
|
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_
|