Merge from Widevine repo of two CLs. Merge from Widevine repo of http://go/wvgerrit/94743 A license release should not have a core message. This CL adjusts the existing unit tests to verify this. There is also a new unit test called SecureStop that explicitly tests sending a secure stop in a new session without first loading the license. Merge from Widevine repo of http://go/wvgerrit/94865 This CL has the following changes copied from google3: http://cr/298871728 Remove odk_static_assert for Message size temporarily http://cr/298755935 Fix a compiling error during macro expansion http://cr/298481745 Add missing header for android http://cr/298448142 Fix odk_test gyp file http://cr/298419641 Remove header from Android.bp http://cr/298402053 Separate sizeOf(args) bytes in fuzz tests http://cr/297730316 No core messages for license release http://cr/297714346 Add copybara_test and piper_sot_to_gerrit http://cr/297636713 Adding some comments around boolean conversion code http://cr/297420679 Autofuzzer when ran with address sanitizer ... http://cr/296513584 Minor fix with fuzzing odk clock values http://cr/296322024 Fixing errors in code with how request ... http://cr/296313159 Fuzzing ODK clock values by setting aside ... http://cr/295763207 Add more odk tests and move helper functions to test helper http://cr/294524098 Adding a Build Rule for ODK_KDO_Fuzzer and updating http://cr/294492213 Address a few review comments of ODK http://cr/293674368 odk_fuzz: add TODOs & comments http://cr/293492806 Fix spelling Bug: 150243585 Bug: 150020278 Bug: 150095506 Bug: 147297226 Bug: 148290294 Bug: 148907684 Bug: 150608451 Test: unit tests Change-Id: I25fd406f29f4eba40f5cb27e9a1317dce4ffc2f5
260 lines
7.0 KiB
C
260 lines
7.0 KiB
C
/* 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 <stddef.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#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); }
|