Update ODK library for OPK compatibility

This is a merge from http://go/wvgerrit of several changes to the ODK
library that allow it to be used in the same compilation unit as the
OPK serialization/deserialization code.

Merge of:
http://go/wvgerrit/104403
http://go/wvgerrit/105663
http://go/wvgerrit/106004
http://go/wvgerrit/107903
http://go/wvgerrit/107985
http://go/wvgerrit/110167
http://go/wvgerrit/110403
http://go/wvgerrit/110423
http://go/wvgerrit/110663
http://go/wvgerrit/110703
http://go/wvgerrit/110985
http://go/wvgerrit/111703
http://go/wvgerrit/112563
http://go/wvgerrit/113243
http://go/wvgerrit/115204
http://go/wvgerrit/117803
http://go/wvgerrit/121949

bug: 174518179
bug: 175920940
bug: 175126254
Change-Id: I433459182043ca43a040cdbc16d04f2b8215067a
This commit is contained in:
Fred Gylys-Colwell
2021-04-09 14:43:02 -07:00
parent 985d0b5129
commit 6a59fee30a
22 changed files with 588 additions and 324 deletions

View File

@@ -39,13 +39,11 @@ bool ParseRequest(uint32_t message_type,
reinterpret_cast<const uint8_t*>(oemcrypto_core_message.c_str());
const size_t buf_length = oemcrypto_core_message.size();
uint8_t blk[SIZE_OF_MESSAGE_STRUCT];
Message* msg = reinterpret_cast<Message*>(blk);
InitMessage(msg, const_cast<uint8_t*>(buf), buf_length);
SetSize(msg, buf_length);
ODK_Message msg = ODK_Message_Create(const_cast<uint8_t*>(buf), buf_length);
ODK_Message_SetSize(&msg, buf_length);
unpacker(msg, prepared);
if (!ValidMessage(msg)) {
unpacker(&msg, prepared);
if (!ODK_Message_IsValid(&msg)) {
return false;
}
@@ -80,7 +78,7 @@ bool ParseRequest(uint32_t message_type,
// than the total message size. We allow the total message size to be larger
// for forward compatibility because future messages might have extra fields
// that we can ignore.
if (core_message.message_length < GetOffset(msg)) return false;
if (core_message.message_length < ODK_Message_GetOffset(&msg)) return false;
return true;
}

View File

@@ -50,18 +50,16 @@ bool CreateResponse(uint32_t message_type, const S& core_request,
static constexpr size_t BUF_CAPACITY = 2048;
std::vector<uint8_t> buf(BUF_CAPACITY, 0);
uint8_t blk[SIZE_OF_MESSAGE_STRUCT];
Message* msg = reinterpret_cast<Message*>(blk);
InitMessage(msg, buf.data(), buf.capacity());
packer(msg, &response);
if (!ValidMessage(msg)) {
ODK_Message msg = ODK_Message_Create(buf.data(), buf.capacity());
packer(&msg, &response);
if (!ODK_Message_IsValid(&msg)) {
return false;
}
uint32_t message_length = GetSize(msg);
InitMessage(msg, buf.data() + sizeof(header->message_type),
sizeof(header->message_length));
Pack_uint32_t(msg, &message_length);
uint32_t message_length = ODK_Message_GetSize(&msg);
msg = ODK_Message_Create(buf.data() + sizeof(header->message_type),
sizeof(header->message_length));
Pack_uint32_t(&msg, &message_length);
oemcrypto_core_message->assign(reinterpret_cast<const char*>(buf.data()),
message_length);
return true;

View File

@@ -27,9 +27,7 @@ static OEMCryptoResult ODK_PrepareRequest(
return ODK_ERROR_CORE_MESSAGE;
}
uint8_t blk[SIZE_OF_MESSAGE_STRUCT];
Message* msg = (Message*)blk;
InitMessage(msg, message, *core_message_length);
ODK_Message msg = ODK_Message_Create(message, *core_message_length);
/* The core message should be at the beginning of the buffer, and with a
* shorter length. */
@@ -52,7 +50,7 @@ static OEMCryptoResult ODK_PrepareRequest(
return ODK_ERROR_CORE_MESSAGE;
}
Pack_ODK_PreparedLicenseRequest(
msg, (ODK_PreparedLicenseRequest*)prepared_request_buffer);
&msg, (ODK_PreparedLicenseRequest*)prepared_request_buffer);
break;
}
case ODK_Renewal_Request_Type: {
@@ -61,7 +59,7 @@ static OEMCryptoResult ODK_PrepareRequest(
return ODK_ERROR_CORE_MESSAGE;
}
Pack_ODK_PreparedRenewalRequest(
msg, (ODK_PreparedRenewalRequest*)prepared_request_buffer);
&msg, (ODK_PreparedRenewalRequest*)prepared_request_buffer);
break;
}
case ODK_Provisioning_Request_Type: {
@@ -71,7 +69,7 @@ static OEMCryptoResult ODK_PrepareRequest(
return ODK_ERROR_CORE_MESSAGE;
}
Pack_ODK_PreparedProvisioningRequest(
msg, (ODK_PreparedProvisioningRequest*)prepared_request_buffer);
&msg, (ODK_PreparedProvisioningRequest*)prepared_request_buffer);
break;
}
default: {
@@ -80,13 +78,13 @@ static OEMCryptoResult ODK_PrepareRequest(
}
*core_message_length = core_message->message_length;
if (GetStatus(msg) != MESSAGE_STATUS_OK) {
if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK) {
/* This is to indicate the caller that the core_message_length has been
* appropriately set, but the message buffer is either empty or too small,
* which needs to be initialized and filled in the subsequent call. */
return OEMCrypto_ERROR_SHORT_BUFFER;
}
if (GetSize(msg) != *core_message_length) {
if (ODK_Message_GetSize(&msg) != *core_message_length) {
/* This should not happen. Something is wrong. */
return ODK_ERROR_CORE_MESSAGE;
}
@@ -102,20 +100,11 @@ static OEMCryptoResult ODK_ParseResponse(
return ODK_ERROR_CORE_MESSAGE;
}
uint8_t blk[SIZE_OF_MESSAGE_STRUCT];
Message* msg = (Message*)blk;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
/* We initialize the message buffer with a size of the entire message
* length. */
/* TODO(b/164486737): Fix the cast-qual warning */
InitMessage(msg, (uint8_t*)message, message_length);
#pragma GCC diagnostic pop
ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length);
/* The core message should be at the beginning of the buffer, and with a
* shorter length. The core message is the part we are parsing. */
SetSize(msg, core_message_length);
ODK_Message_SetSize(&msg, core_message_length);
/* Parse message and unpack it into response buffer. */
switch (message_type) {
@@ -123,14 +112,14 @@ static OEMCryptoResult ODK_ParseResponse(
if (sizeof(ODK_LicenseResponse) > response_buffer_length) {
return ODK_ERROR_CORE_MESSAGE;
}
Unpack_ODK_LicenseResponse(msg, (ODK_LicenseResponse*)response_buffer);
Unpack_ODK_LicenseResponse(&msg, (ODK_LicenseResponse*)response_buffer);
break;
}
case ODK_Renewal_Response_Type: {
if (sizeof(ODK_RenewalResponse) > response_buffer_length) {
return ODK_ERROR_CORE_MESSAGE;
}
Unpack_ODK_RenewalResponse(msg, (ODK_RenewalResponse*)response_buffer);
Unpack_ODK_RenewalResponse(&msg, (ODK_RenewalResponse*)response_buffer);
break;
}
case ODK_Provisioning_Response_Type: {
@@ -138,7 +127,7 @@ static OEMCryptoResult ODK_ParseResponse(
return ODK_ERROR_CORE_MESSAGE;
}
Unpack_ODK_ProvisioningResponse(
msg, (ODK_ProvisioningResponse*)response_buffer);
&msg, (ODK_ProvisioningResponse*)response_buffer);
break;
}
default: {
@@ -147,9 +136,9 @@ static OEMCryptoResult ODK_ParseResponse(
}
ODK_CoreMessage* core_message = (ODK_CoreMessage*)response_buffer;
if (GetStatus(msg) != MESSAGE_STATUS_OK ||
if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK ||
message_type != core_message->message_type ||
GetOffset(msg) != core_message->message_length) {
ODK_Message_GetOffset(&msg) != core_message->message_length) {
return ODK_ERROR_CORE_MESSAGE;
}
@@ -307,20 +296,24 @@ OEMCryptoResult ODK_ParseLicense(
return ODK_ERROR_CORE_MESSAGE;
}
if (parsed_license->nonce_required) {
if (initial_license_load) {
if (nonce_values->nonce !=
license_response.request.core_message.nonce_values.nonce ||
nonce_values->session_id !=
license_response.request.core_message.nonce_values.session_id) {
return OEMCrypto_ERROR_INVALID_NONCE;
}
} else { /* !initial_license_load */
nonce_values->nonce =
license_response.request.core_message.nonce_values.nonce;
nonce_values->session_id =
license_response.request.core_message.nonce_values.session_id;
/* If this is the first time we load this license, then we verify that the
* nonce values are the correct, otherwise we copy the nonce values. If the
* nonce values are not required to be correct, then we don't know if this is
* an initial load or not. In that case, we also copy the values so that we
* can use the nonce values later for a renewal.
*/
if (parsed_license->nonce_required && initial_license_load) {
if (nonce_values->nonce !=
license_response.request.core_message.nonce_values.nonce ||
nonce_values->session_id !=
license_response.request.core_message.nonce_values.session_id) {
return OEMCrypto_ERROR_INVALID_NONCE;
}
} else { /* !initial_license_load, or can't tell if initial. */
nonce_values->nonce =
license_response.request.core_message.nonce_values.nonce;
nonce_values->session_id =
license_response.request.core_message.nonce_values.session_id;
}
/* For v16, in order to be backwards compatible with a v15 license server,
* OEMCrypto stores a hash of the core license request and only signs the
@@ -367,9 +360,12 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
*/
/* If a renewal request is lost in transit, we should throw it out and create
* a new one. We use the timestamp to make sure we have the latest request.
* We only do this if playback has already started. This allows us to reload
* an offline license and also reload a renewal before starting playback.
*/
if (clock_values->time_of_renewal_request <
renewal_response.request.playback_time) {
if (clock_values->timer_status != ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED &&
clock_values->time_of_renewal_request <
renewal_response.request.playback_time) {
return ODK_STALE_RENEWAL;
}
return ODK_ComputeRenewalDuration(timer_limits, clock_values, system_time,

View File

@@ -11,11 +11,23 @@ extern "C" {
#if defined(__linux__) || defined(__ANDROID__)
#include <endian.h>
#define oemcrypto_htobe16 htobe16
#define oemcrypto_be16toh be16toh
#define oemcrypto_htobe32 htobe32
#define oemcrypto_be32toh be32toh
#define oemcrypto_htobe64 htobe64
#define oemcrypto_be64toh be64toh
#else /* defined(__linux__) || defined(__ANDROID__) */
#elif defined(__APPLE__)
#include <libkern/OSByteOrder.h>
#define oemcrypto_htobe16 OSSwapHostToBigInt16
#define oemcrypto_be16toh OSSwapBigToHostInt16
#define oemcrypto_htobe32 OSSwapHostToBigInt32
#define oemcrypto_be32toh OSSwapBigToHostInt32
#define oemcrypto_htobe64 OSSwapHostToBigInt64
#define oemcrypto_be64toh OSSwapBigToHostInt64
#else /* defined(__linux__) || defined(__ANDROID__) */
uint32_t oemcrypto_htobe16(uint16_t u16);
uint32_t oemcrypto_be16toh(uint16_t u16);
uint32_t oemcrypto_htobe32(uint32_t u32);
uint32_t oemcrypto_be32toh(uint32_t u32);
uint64_t oemcrypto_htobe64(uint64_t u64);

View File

@@ -0,0 +1,171 @@
/*
* 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 "odk_message.h"
#include "odk_message_priv.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
/*
* C11 defines static_assert in assert.h. If it is available, force a compile
* time error if the abstract ODK_Message struct size does not match its
* implementation. If static_assert is not available, the runtime assert in
* InitMessage will catch the mismatch at the time a message is initialized.
*/
#ifdef static_assert
static_assert(
sizeof(ODK_Message) >= sizeof(ODK_Message_Impl),
"sizeof(ODK_Message) is too small. You can increase "
"SIZE_OF_ODK_MESSAGE_IMPL in odk_message.h to make it large enough.");
#endif
/*
* 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. |buffer| may be
* NULL. Serialization into a message with a NULL buffer will cause the message
* size to be incremented, but no data will be written into the message
* buffer. This is useful for calculating the amount of space a message will
* need, prior to doing the actual serialization. The buffer contents are
* unchanged by this function.
*/
ODK_Message ODK_Message_Create(uint8_t* buffer, size_t capacity) {
assert(sizeof(ODK_Message) >= sizeof(ODK_Message_Impl));
ODK_Message message;
ODK_Message_Impl* message_impl = (ODK_Message_Impl*)&message;
message_impl->base = buffer;
message_impl->capacity = capacity;
message_impl->size = 0;
message_impl->read_offset = 0;
message_impl->status = MESSAGE_STATUS_OK;
return message;
}
/*
* 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 buffer is zero-filled. The
* message status is reset to MESSAGE_STATUS_OK.
*/
void ODK_Message_Clear(ODK_Message* message) {
ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
assert(message_impl != NULL);
message_impl->read_offset = 0;
message_impl->size = 0;
message_impl->status = MESSAGE_STATUS_OK;
if (message_impl->base) {
memset(message_impl->base, 0, message_impl->capacity);
}
}
/*
* 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) {
ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
assert(message_impl != NULL);
message_impl->read_offset = 0;
message_impl->status = MESSAGE_STATUS_OK;
}
/*
* 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) {
ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
assert(message_impl != NULL);
return message_impl->base;
}
/*
* Get the maximum number of bytes the message can hold.
*/
size_t ODK_Message_GetCapacity(ODK_Message* message) {
ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
assert(message_impl != NULL);
return message_impl->capacity;
}
/*
* Get the number of bytes currently in the message
*/
size_t ODK_Message_GetSize(ODK_Message* message) {
ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
assert(message_impl != NULL);
return message_impl->size;
}
/*
* Get the offset of where the next bytes will be read from the message data
* buffer.
*/
size_t ODK_Message_GetOffset(ODK_Message* message) {
ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
assert(message_impl != NULL);
return message_impl->read_offset;
}
/*
* Return the status of the message
*/
ODK_MessageStatus ODK_Message_GetStatus(ODK_Message* message) {
ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
assert(message_impl != NULL);
return message_impl->status;
}
/*
* Set the message status to a specific value
*/
void ODK_Message_SetStatus(ODK_Message* message, ODK_MessageStatus status) {
ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
assert(message_impl != NULL);
/* preserve the first error */
if (message_impl->status == MESSAGE_STATUS_OK) {
message_impl->status = 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) {
ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
assert(message_impl != NULL);
assert(size <= message_impl->capacity);
message_impl->size = size;
}
/*
* Test if the integrity of a message. This means that the status must be
* MESSAGE_STATUS_OK and that the base, read_offset, size and capacity of the
* message are within the range of valid values. The message's base pointer
* may be NULL if the buffer has not been assigned yet, that is not invalid.
*/
bool ODK_Message_IsValid(ODK_Message* message) {
assert(message);
ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
if (message_impl == NULL) {
return false;
}
if (message_impl->status != MESSAGE_STATUS_OK) {
return false;
}
if (message_impl->read_offset > message_impl->capacity ||
message_impl->size > message_impl->capacity ||
message_impl->read_offset > message_impl->size) {
message_impl->status = MESSAGE_STATUS_OVERFLOW_ERROR;
return false;
}
return true;
}

View File

@@ -0,0 +1,41 @@
/*
* 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.
*/
#ifndef WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_PRIV_H_
#define WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_PRIV_H_
#ifdef __cplusplus
extern "C" {
#endif
/*
* This file must only be included by odk_message.c and serialization_base.c.
*/
#include <stddef.h>
#include <stdint.h>
/*
* This is the implementation of a message. This structure is private, i.e. it
* should only be included by files that are allowed to modify the internals of
* a message, that being odk_message.c and serialization_base.c. To ensure
* proper alignment and message size, an ODK_Message_Impl should never be
* allocated directly, instead allocate ODK_Message and cast to ODK_Message_Impl
* because ODK_Message_Impl may be smaller than ODK_Message.
*/
typedef struct {
uint8_t* base;
size_t capacity;
size_t size;
size_t read_offset;
ODK_MessageStatus status;
} ODK_Message_Impl;
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_PRIV_H_

View File

@@ -34,3 +34,13 @@ int odk_add_overflow_ux(size_t a, size_t b, size_t* c) {
}
return 1;
}
int odk_mul_overflow_ux(size_t a, size_t b, size_t* c) {
if (b > 0 && a > SIZE_MAX / b) {
return 1;
}
if (c) {
*c = a * b;
}
return 0;
}

View File

@@ -15,6 +15,7 @@ extern "C" {
int odk_sub_overflow_u64(uint64_t a, uint64_t b, uint64_t* c);
int odk_add_overflow_u64(uint64_t a, uint64_t b, uint64_t* c);
int odk_add_overflow_ux(size_t a, size_t b, size_t* c);
int odk_mul_overflow_ux(size_t a, size_t b, size_t* c);
#ifdef __cplusplus
}

View File

@@ -13,20 +13,20 @@
/* @@ private serialize */
static void Pack_ODK_NonceValues(Message* msg, ODK_NonceValues const* obj) {
static void Pack_ODK_NonceValues(ODK_Message* msg, ODK_NonceValues const* obj) {
Pack_uint16_t(msg, &obj->api_minor_version);
Pack_uint16_t(msg, &obj->api_major_version);
Pack_uint32_t(msg, &obj->nonce);
Pack_uint32_t(msg, &obj->session_id);
}
static void Pack_ODK_CoreMessage(Message* msg, ODK_CoreMessage const* obj) {
static void Pack_ODK_CoreMessage(ODK_Message* msg, ODK_CoreMessage const* obj) {
Pack_uint32_t(msg, &obj->message_type);
Pack_uint32_t(msg, &obj->message_length);
Pack_ODK_NonceValues(msg, &obj->nonce_values);
}
static void Pack_OEMCrypto_KeyObject(Message* msg,
static void Pack_OEMCrypto_KeyObject(ODK_Message* msg,
OEMCrypto_KeyObject const* obj) {
Pack_OEMCrypto_Substring(msg, &obj->key_id);
Pack_OEMCrypto_Substring(msg, &obj->key_data_iv);
@@ -35,7 +35,7 @@ static void Pack_OEMCrypto_KeyObject(Message* msg,
Pack_OEMCrypto_Substring(msg, &obj->key_control);
}
static void Pack_ODK_TimerLimits(Message* msg, ODK_TimerLimits const* obj) {
static void Pack_ODK_TimerLimits(ODK_Message* msg, ODK_TimerLimits const* obj) {
Pack_bool(msg, &obj->soft_enforce_rental_duration);
Pack_bool(msg, &obj->soft_enforce_playback_duration);
Pack_uint64_t(msg, &obj->earliest_playback_start_seconds);
@@ -44,10 +44,11 @@ static void Pack_ODK_TimerLimits(Message* msg, ODK_TimerLimits const* obj) {
Pack_uint64_t(msg, &obj->initial_renewal_duration_seconds);
}
static void Pack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense const* obj) {
static void Pack_ODK_ParsedLicense(ODK_Message* msg,
ODK_ParsedLicense const* obj) {
/* hand-coded */
if (obj->key_array_length > ODK_MAX_NUM_KEYS) {
SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR);
ODK_Message_SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR);
return;
}
Pack_OEMCrypto_Substring(msg, &obj->enc_mac_keys_iv);
@@ -64,7 +65,7 @@ static void Pack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense const* obj) {
}
}
static void Pack_ODK_ParsedProvisioning(Message* msg,
static void Pack_ODK_ParsedProvisioning(ODK_Message* msg,
ODK_ParsedProvisioning const* obj) {
Pack_enum(msg, obj->key_type);
Pack_OEMCrypto_Substring(msg, &obj->enc_private_key);
@@ -74,19 +75,19 @@ static void Pack_ODK_ParsedProvisioning(Message* msg,
/* @@ odk serialize */
void Pack_ODK_PreparedLicenseRequest(Message* msg,
void Pack_ODK_PreparedLicenseRequest(ODK_Message* msg,
ODK_PreparedLicenseRequest const* obj) {
Pack_ODK_CoreMessage(msg, &obj->core_message);
}
void Pack_ODK_PreparedRenewalRequest(Message* msg,
void Pack_ODK_PreparedRenewalRequest(ODK_Message* msg,
ODK_PreparedRenewalRequest const* obj) {
Pack_ODK_CoreMessage(msg, &obj->core_message);
Pack_uint64_t(msg, &obj->playback_time);
}
void Pack_ODK_PreparedProvisioningRequest(
Message* msg, ODK_PreparedProvisioningRequest const* obj) {
ODK_Message* msg, ODK_PreparedProvisioningRequest const* obj) {
Pack_ODK_CoreMessage(msg, &obj->core_message);
Pack_uint32_t(msg, &obj->device_id_length);
PackArray(msg, &obj->device_id[0], sizeof(obj->device_id));
@@ -94,18 +95,20 @@ void Pack_ODK_PreparedProvisioningRequest(
/* @@ kdo serialize */
void Pack_ODK_LicenseResponse(Message* msg, ODK_LicenseResponse const* obj) {
void Pack_ODK_LicenseResponse(ODK_Message* msg,
ODK_LicenseResponse const* obj) {
Pack_ODK_PreparedLicenseRequest(msg, &obj->request);
Pack_ODK_ParsedLicense(msg, (const ODK_ParsedLicense*)obj->parsed_license);
PackArray(msg, &obj->request_hash[0], sizeof(obj->request_hash));
}
void Pack_ODK_RenewalResponse(Message* msg, ODK_RenewalResponse const* obj) {
void Pack_ODK_RenewalResponse(ODK_Message* msg,
ODK_RenewalResponse const* obj) {
Pack_ODK_PreparedRenewalRequest(msg, &obj->request);
Pack_uint64_t(msg, &obj->renewal_duration_seconds);
}
void Pack_ODK_ProvisioningResponse(Message* msg,
void Pack_ODK_ProvisioningResponse(ODK_Message* msg,
ODK_ProvisioningResponse const* obj) {
Pack_ODK_PreparedProvisioningRequest(msg, &obj->request);
Pack_ODK_ParsedProvisioning(
@@ -116,20 +119,21 @@ void Pack_ODK_ProvisioningResponse(Message* msg,
/* @@ private deserialize */
static void Unpack_ODK_NonceValues(Message* msg, ODK_NonceValues* obj) {
static void Unpack_ODK_NonceValues(ODK_Message* msg, ODK_NonceValues* obj) {
Unpack_uint16_t(msg, &obj->api_minor_version);
Unpack_uint16_t(msg, &obj->api_major_version);
Unpack_uint32_t(msg, &obj->nonce);
Unpack_uint32_t(msg, &obj->session_id);
}
static void Unpack_ODK_CoreMessage(Message* msg, ODK_CoreMessage* obj) {
static void Unpack_ODK_CoreMessage(ODK_Message* msg, ODK_CoreMessage* obj) {
Unpack_uint32_t(msg, &obj->message_type);
Unpack_uint32_t(msg, &obj->message_length);
Unpack_ODK_NonceValues(msg, &obj->nonce_values);
}
static void Unpack_OEMCrypto_KeyObject(Message* msg, OEMCrypto_KeyObject* obj) {
static void Unpack_OEMCrypto_KeyObject(ODK_Message* msg,
OEMCrypto_KeyObject* obj) {
Unpack_OEMCrypto_Substring(msg, &obj->key_id);
Unpack_OEMCrypto_Substring(msg, &obj->key_data_iv);
Unpack_OEMCrypto_Substring(msg, &obj->key_data);
@@ -137,7 +141,7 @@ static void Unpack_OEMCrypto_KeyObject(Message* msg, OEMCrypto_KeyObject* obj) {
Unpack_OEMCrypto_Substring(msg, &obj->key_control);
}
static void Unpack_ODK_TimerLimits(Message* msg, ODK_TimerLimits* obj) {
static void Unpack_ODK_TimerLimits(ODK_Message* msg, ODK_TimerLimits* obj) {
Unpack_bool(msg, &obj->soft_enforce_rental_duration);
Unpack_bool(msg, &obj->soft_enforce_playback_duration);
Unpack_uint64_t(msg, &obj->earliest_playback_start_seconds);
@@ -146,7 +150,7 @@ static void Unpack_ODK_TimerLimits(Message* msg, ODK_TimerLimits* obj) {
Unpack_uint64_t(msg, &obj->initial_renewal_duration_seconds);
}
static void Unpack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense* obj) {
static void Unpack_ODK_ParsedLicense(ODK_Message* msg, ODK_ParsedLicense* obj) {
Unpack_OEMCrypto_Substring(msg, &obj->enc_mac_keys_iv);
Unpack_OEMCrypto_Substring(msg, &obj->enc_mac_keys);
Unpack_OEMCrypto_Substring(msg, &obj->pst);
@@ -156,7 +160,7 @@ static void Unpack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense* obj) {
Unpack_ODK_TimerLimits(msg, &obj->timer_limits);
Unpack_uint32_t(msg, &obj->key_array_length);
if (obj->key_array_length > ODK_MAX_NUM_KEYS) {
SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR);
ODK_Message_SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR);
return;
}
uint32_t i;
@@ -165,7 +169,7 @@ static void Unpack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense* obj) {
}
}
static void Unpack_ODK_ParsedProvisioning(Message* msg,
static void Unpack_ODK_ParsedProvisioning(ODK_Message* msg,
ODK_ParsedProvisioning* obj) {
obj->key_type = (OEMCrypto_PrivateKeyType)Unpack_enum(msg);
Unpack_OEMCrypto_Substring(msg, &obj->enc_private_key);
@@ -175,42 +179,42 @@ static void Unpack_ODK_ParsedProvisioning(Message* msg,
/* @ kdo deserialize */
void Unpack_ODK_PreparedLicenseRequest(Message* msg,
void Unpack_ODK_PreparedLicenseRequest(ODK_Message* msg,
ODK_PreparedLicenseRequest* obj) {
Unpack_ODK_CoreMessage(msg, &obj->core_message);
}
void Unpack_ODK_PreparedRenewalRequest(Message* msg,
void Unpack_ODK_PreparedRenewalRequest(ODK_Message* msg,
ODK_PreparedRenewalRequest* obj) {
Unpack_ODK_CoreMessage(msg, &obj->core_message);
Unpack_uint64_t(msg, &obj->playback_time);
}
void Unpack_ODK_PreparedProvisioningRequest(
Message* msg, ODK_PreparedProvisioningRequest* obj) {
ODK_Message* msg, ODK_PreparedProvisioningRequest* obj) {
Unpack_ODK_CoreMessage(msg, &obj->core_message);
Unpack_uint32_t(msg, &obj->device_id_length);
UnpackArray(msg, &obj->device_id[0], sizeof(obj->device_id));
}
void Unpack_ODK_PreparedCommonRequest(Message* msg,
void Unpack_ODK_PreparedCommonRequest(ODK_Message* msg,
ODK_PreparedCommonRequest* obj) {
Unpack_ODK_CoreMessage(msg, &obj->core_message);
}
/* @@ odk deserialize */
void Unpack_ODK_LicenseResponse(Message* msg, ODK_LicenseResponse* obj) {
void Unpack_ODK_LicenseResponse(ODK_Message* msg, ODK_LicenseResponse* obj) {
Unpack_ODK_PreparedLicenseRequest(msg, &obj->request);
Unpack_ODK_ParsedLicense(msg, obj->parsed_license);
UnpackArray(msg, &obj->request_hash[0], sizeof(obj->request_hash));
}
void Unpack_ODK_RenewalResponse(Message* msg, ODK_RenewalResponse* obj) {
void Unpack_ODK_RenewalResponse(ODK_Message* msg, ODK_RenewalResponse* obj) {
Unpack_ODK_PreparedRenewalRequest(msg, &obj->request);
Unpack_uint64_t(msg, &obj->renewal_duration_seconds);
}
void Unpack_ODK_ProvisioningResponse(Message* msg,
void Unpack_ODK_ProvisioningResponse(ODK_Message* msg,
ODK_ProvisioningResponse* obj) {
Unpack_ODK_PreparedProvisioningRequest(msg, &obj->request);
Unpack_ODK_ParsedProvisioning(msg, obj->parsed_provisioning);

View File

@@ -16,34 +16,34 @@ extern "C" {
#endif
/* odk pack */
void Pack_ODK_PreparedLicenseRequest(Message* msg,
void Pack_ODK_PreparedLicenseRequest(ODK_Message* msg,
const ODK_PreparedLicenseRequest* obj);
void Pack_ODK_PreparedRenewalRequest(Message* msg,
void Pack_ODK_PreparedRenewalRequest(ODK_Message* msg,
const ODK_PreparedRenewalRequest* obj);
void Pack_ODK_PreparedProvisioningRequest(
Message* msg, const ODK_PreparedProvisioningRequest* obj);
ODK_Message* msg, const ODK_PreparedProvisioningRequest* obj);
/* odk unpack */
void Unpack_ODK_LicenseResponse(Message* msg, ODK_LicenseResponse* obj);
void Unpack_ODK_RenewalResponse(Message* msg, ODK_RenewalResponse* obj);
void Unpack_ODK_ProvisioningResponse(Message* msg,
void Unpack_ODK_LicenseResponse(ODK_Message* msg, ODK_LicenseResponse* obj);
void Unpack_ODK_RenewalResponse(ODK_Message* msg, ODK_RenewalResponse* obj);
void Unpack_ODK_ProvisioningResponse(ODK_Message* msg,
ODK_ProvisioningResponse* obj);
/* kdo pack */
void Pack_ODK_LicenseResponse(Message* msg, const ODK_LicenseResponse* obj);
void Pack_ODK_RenewalResponse(Message* msg, const ODK_RenewalResponse* obj);
void Pack_ODK_ProvisioningResponse(Message* msg,
void Pack_ODK_LicenseResponse(ODK_Message* msg, const ODK_LicenseResponse* obj);
void Pack_ODK_RenewalResponse(ODK_Message* msg, const ODK_RenewalResponse* obj);
void Pack_ODK_ProvisioningResponse(ODK_Message* msg,
const ODK_ProvisioningResponse* obj);
/* kdo unpack */
void Unpack_ODK_PreparedLicenseRequest(Message* msg,
void Unpack_ODK_PreparedLicenseRequest(ODK_Message* msg,
ODK_PreparedLicenseRequest* obj);
void Unpack_ODK_PreparedRenewalRequest(Message* msg,
void Unpack_ODK_PreparedRenewalRequest(ODK_Message* msg,
ODK_PreparedRenewalRequest* obj);
void Unpack_ODK_PreparedProvisioningRequest(
Message* msg, ODK_PreparedProvisioningRequest* obj);
ODK_Message* msg, ODK_PreparedProvisioningRequest* obj);
void Unpack_ODK_PreparedCommonRequest(Message* msg,
void Unpack_ODK_PreparedCommonRequest(ODK_Message* msg,
ODK_PreparedCommonRequest* obj);
#ifdef __cplusplus

View File

@@ -4,71 +4,61 @@
#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"
struct _Message {
uint8_t* base;
size_t capacity;
size_t size; /* bytes written */
size_t read_offset; /* bytes read */
MessageStatus status;
};
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;
/*
* 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(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;
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->status = MESSAGE_STATUS_OVERFLOW_ERROR;
message_impl->status = MESSAGE_STATUS_OVERFLOW_ERROR;
}
}
void Pack_enum(Message* message, int value) {
void Pack_enum(ODK_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;
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_uint16_t(Message* message, const uint16_t* value) {
if (!ValidMessage(message)) return;
void Pack_uint16_t(ODK_Message* message, const uint16_t* value) {
assert(value);
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;
void Pack_uint32_t(ODK_Message* message, const uint32_t* value) {
assert(value);
uint8_t data[4] = {0};
data[0] = *value >> 24;
data[1] = *value >> 16;
@@ -77,160 +67,112 @@ void Pack_uint32_t(Message* message, const uint32_t* value) {
PackBytes(message, data, sizeof(data));
}
void Pack_uint64_t(Message* message, const uint64_t* value) {
if (!ValidMessage(message)) return;
void Pack_uint64_t(ODK_Message* message, const uint64_t* value) {
assert(value);
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;
void PackArray(ODK_Message* message, const uint8_t* base, size_t size) {
PackBytes(message, base, size);
}
void Pack_OEMCrypto_Substring(Message* msg, const OEMCrypto_Substring* obj) {
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(msg, &offset);
Pack_uint32_t(msg, &length);
Pack_uint32_t(message, &offset);
Pack_uint32_t(message, &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;
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->status = MESSAGE_STATUS_UNDERFLOW_ERROR;
message_impl->status = MESSAGE_STATUS_UNDERFLOW_ERROR;
}
}
int Unpack_enum(Message* message) {
int Unpack_enum(ODK_Message* message) {
uint32_t v32;
Unpack_uint32_t(message, &v32);
return v32;
}
void Unpack_bool(Message* message, bool* value) {
if (!ValidMessage(message)) return;
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_uint16_t(Message* message, uint16_t* value) {
if (!ValidMessage(message)) return;
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(Message* message, uint32_t* value) {
if (!ValidMessage(message)) return;
void Unpack_uint32_t(ODK_Message* message, uint32_t* value) {
ODK_Message_Impl* message_impl = GetMessageImpl(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(Message* message, uint64_t* value) {
if (!ValidMessage(message)) return;
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(Message* msg, OEMCrypto_Substring* obj) {
void Unpack_OEMCrypto_Substring(ODK_Message* message,
OEMCrypto_Substring* obj) {
uint32_t offset = 0, length = 0;
Unpack_uint32_t(msg, &offset);
Unpack_uint32_t(msg, &length);
if (!ValidMessage(msg)) return;
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:
* 0 < offset and offset + length < message->capacity - message->size
* or offset + length + message->size < message->capacity
* 0 < offset and offset + length < message_impl->capacity -
* message_impl->size or offset + length + message_impl->size <
* message_impl->capacity
*/
size_t substring_end = 0; /* = offset + length; */
size_t end = 0; /* = substring_end + message->size; */
size_t end = 0; /* = substring_end + message_impl->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;
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(Message* message, uint8_t* address, size_t size) {
if (!ValidMessage(message)) return;
void UnpackArray(ODK_Message* message, uint8_t* address, size_t size) {
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;
}
/*
* 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); }

View File

@@ -13,74 +13,24 @@ extern "C" {
#include <stdint.h>
#include "OEMCryptoCENCCommon.h"
#include "odk_message.h"
#define SIZE_OF_MESSAGE_STRUCT 64
void Pack_enum(ODK_Message* message, int value);
void Pack_bool(ODK_Message* message, const bool* value);
void Pack_uint16_t(ODK_Message* message, const uint16_t* value);
void Pack_uint32_t(ODK_Message* message, const uint32_t* value);
void Pack_uint64_t(ODK_Message* message, const uint64_t* value);
void PackArray(ODK_Message* message, const uint8_t* base, size_t size);
void Pack_OEMCrypto_Substring(ODK_Message* msg, const OEMCrypto_Substring* obj);
/*
* Description:
* Point |msg| to stack-array |blk|.
* |blk| is guaranteed large enough to hold a |Message| struct.
* |blk| cannot be used in the same scope as a variable name.
* |msg| points to valid memory in the same scope |AllocateMessage| is used.
* Parameters:
* msg: pointer to pointer to |Message| struct
* blk: variable name for stack-array
*/
#define AllocateMessage(msg, blk) \
uint8_t blk[SIZE_OF_MESSAGE_STRUCT]; \
*(msg) = (Message*)(blk)
typedef struct _Message Message;
typedef enum {
MESSAGE_STATUS_OK,
MESSAGE_STATUS_UNKNOWN_ERROR,
MESSAGE_STATUS_OVERFLOW_ERROR,
MESSAGE_STATUS_UNDERFLOW_ERROR,
MESSAGE_STATUS_PARSE_ERROR,
MESSAGE_STATUS_NULL_POINTER_ERROR,
MESSAGE_STATUS_API_VALUE_ERROR
} MessageStatus;
bool ValidMessage(Message* message);
void Pack_enum(Message* message, int value);
void Pack_bool(Message* message, const bool* value);
void Pack_uint16_t(Message* message, const uint16_t* value);
void Pack_uint32_t(Message* message, const uint32_t* value);
void Pack_uint64_t(Message* message, const uint64_t* value);
void PackArray(Message* message, const uint8_t* base, size_t size);
void Pack_OEMCrypto_Substring(Message* msg, const OEMCrypto_Substring* obj);
int Unpack_enum(Message* message);
void Unpack_bool(Message* message, bool* value);
void Unpack_uint16_t(Message* message, uint16_t* value);
void Unpack_uint32_t(Message* message, uint32_t* value);
void Unpack_uint64_t(Message* message, uint64_t* value);
void UnpackArray(Message* message, uint8_t* address,
int Unpack_enum(ODK_Message* message);
void Unpack_bool(ODK_Message* message, bool* value);
void Unpack_uint16_t(ODK_Message* message, uint16_t* value);
void Unpack_uint32_t(ODK_Message* message, uint32_t* value);
void Unpack_uint64_t(ODK_Message* message, uint64_t* value);
void UnpackArray(ODK_Message* message, uint8_t* address,
size_t size); /* copy out */
void Unpack_OEMCrypto_Substring(Message* msg, OEMCrypto_Substring* obj);
/*
* Initialize a message structure to reference a separate buffer. The caller
* is responsible for ensuring that the buffer remains allocated for the
* lifetime of the message.
*/
void InitMessage(Message* message, uint8_t* buffer, size_t capacity);
/*
* Reset an existing the message to an empty state
*/
void ResetMessage(Message* message);
uint8_t* GetBase(Message* message);
size_t GetCapacity(Message* message);
size_t GetSize(Message* message);
void SetSize(Message* message, size_t size);
MessageStatus GetStatus(Message* message);
void SetStatus(Message* message, MessageStatus status);
size_t GetOffset(Message* message);
size_t SizeOfMessageStruct();
void Unpack_OEMCrypto_Substring(ODK_Message* msg, OEMCrypto_Substring* obj);
#ifdef __cplusplus
} // extern "C"