No-Typo-Check: From a third party header file Bug: 260918793 Test: unit tests Test: atp v2/widevine-eng/drm_compliance Change-Id: I36effd6a10a99bdb2399ab1f4a0fad026d607c70
231 lines
6.9 KiB
C
231 lines
6.9 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.
|
|
|
|
#include "serialization_base.h"
|
|
|
|
#include <assert.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#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);
|
|
}
|