odk: core serialization structs & functions

odk directory copied from wvgerrit.
branch oemcrypto-v16
commit 0c9a7dc

Bug: 140758896
Test: odk_test
Change-Id: I0c631f771b794468a63e4395f6b9c3b60a1dfd4f
This commit is contained in:
Robert Shih
2019-09-12 23:31:31 -07:00
parent 9ea47dc64a
commit 2443fe807a
22 changed files with 4642 additions and 0 deletions

View File

@@ -0,0 +1,316 @@
/*
* 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 <stddef.h>
#include <stdint.h>
#include <string.h>
#include "odk.h"
#include "odk_overflow.h"
#include "odk_serialize.h"
#include "odk_structs.h"
#include "odk_structs_priv.h"
#include "serialization_base.h"
#define ODK_LICENSE_REQUEST_SIZE 20
#define ODK_RENEWAL_REQUEST_SIZE 28
#define ODK_PROVISIONING_REQUEST_SIZE 88
/* @ private odk functions */
static OEMCryptoResult ODK_PrepareRequest(uint8_t* buffer, size_t buffer_length,
size_t* core_message_length,
uint32_t message_type,
const ODK_NonceValues* nonce_values,
ODK_CoreMessage* core_message) {
if (!nonce_values || !core_message_length || !core_message ||
*core_message_length > buffer_length) {
return ODK_ERROR_CORE_MESSAGE;
}
Message* msg = NULL;
AllocateMessage(&msg, message_block);
InitMessage(msg, buffer, *core_message_length);
*core_message = (ODK_CoreMessage){
message_type, 0, *nonce_values,
};
switch (message_type) {
case ODK_License_Request_Type: {
core_message->message_length = ODK_LICENSE_REQUEST_SIZE;
Pack_ODK_PreparedLicense(msg, (ODK_PreparedLicense*)core_message);
break;
}
case ODK_Renewal_Request_Type: {
core_message->message_length = ODK_RENEWAL_REQUEST_SIZE;
Pack_ODK_RenewalMessage(msg, (ODK_RenewalMessage*)core_message);
break;
}
case ODK_Provisioning_Request_Type: {
core_message->message_length = ODK_PROVISIONING_REQUEST_SIZE;
Pack_ODK_ProvisioningMessage(msg, (ODK_ProvisioningMessage*)core_message);
break;
}
default: {
return ODK_ERROR_CORE_MESSAGE;
}
}
*core_message_length = core_message->message_length;
if (GetStatus(msg) != MESSAGE_STATUS_OK ||
GetSize(msg) != *core_message_length) {
return OEMCrypto_ERROR_SHORT_BUFFER;
}
return OEMCrypto_SUCCESS;
}
static OEMCryptoResult ODK_ParseResponse(const uint8_t* buf,
size_t message_length,
uint32_t message_type,
const ODK_NonceValues* nonce_values,
ODK_CoreMessage* const core_message) {
Message* msg = NULL;
AllocateMessage(&msg, message_block);
InitMessage(msg, (uint8_t*)buf, message_length);
SetSize(msg, message_length);
switch (message_type) {
case ODK_License_Response_Type: {
Unpack_ODK_LicenseResponse(msg, (ODK_LicenseResponse*)core_message);
break;
}
case ODK_Renewal_Response_Type: {
Unpack_ODK_RenewalMessage(msg, (ODK_RenewalMessage*)core_message);
break;
}
case ODK_Provisioning_Response_Type: {
Unpack_ODK_ProvisioningResponse(msg,
(ODK_ProvisioningResponse*)core_message);
break;
}
default: {
return ODK_ERROR_CORE_MESSAGE;
}
}
if (GetStatus(msg) != MESSAGE_STATUS_OK ||
message_type != core_message->message_type ||
GetOffset(msg) != core_message->message_length) {
return ODK_ERROR_CORE_MESSAGE;
}
if (nonce_values) {
/* always verify nonce_values for Renewal and Provisioning responses */
if (nonce_values->api_version != core_message->nonce_values.api_version ||
nonce_values->nonce != core_message->nonce_values.nonce ||
nonce_values->session_id != core_message->nonce_values.session_id) {
return OEMCrypto_ERROR_INVALID_NONCE;
}
}
return OEMCrypto_SUCCESS;
}
/* @ public odk functions */
/* @@ prepare request functions */
OEMCryptoResult ODK_PrepareCoreLicenseRequest(
uint8_t* message, size_t message_length, size_t* core_message_length,
const ODK_NonceValues* nonce_values) {
ODK_PreparedLicense license_request = {0};
return ODK_PrepareRequest(message, message_length, core_message_length,
ODK_License_Request_Type, nonce_values,
&license_request.core_message);
}
OEMCryptoResult ODK_PrepareCoreRenewalRequest(
uint8_t* message, size_t message_length, size_t* core_message_length,
const ODK_NonceValues* nonce_values,
const ODK_ClockValues* clock_values, uint64_t system_time_seconds) {
ODK_RenewalMessage renewal_request = {
{0},
};
if (odk_sub_overflow_u64(system_time_seconds,
clock_values->time_of_first_decrypt,
&renewal_request.playback_time)) {
return ODK_ERROR_CORE_MESSAGE;
}
return ODK_PrepareRequest(message, message_length, core_message_length,
ODK_Renewal_Request_Type, nonce_values,
&renewal_request.core_message);
}
OEMCryptoResult ODK_PrepareCoreProvisioningRequest(
uint8_t* message, size_t message_length, size_t* core_message_length,
const ODK_NonceValues* nonce_values,
const uint8_t* device_id, size_t device_id_length) {
ODK_ProvisioningMessage provisioning_request = {
{0},
};
if (device_id_length > sizeof(provisioning_request.device_id)) {
return ODK_ERROR_CORE_MESSAGE;
}
provisioning_request.device_id_length = device_id_length;
if (device_id) {
memcpy(provisioning_request.device_id, device_id, device_id_length);
}
return ODK_PrepareRequest(message, message_length, core_message_length,
ODK_Provisioning_Request_Type, nonce_values,
&provisioning_request.core_message);
}
/* @@ parse request functions */
OEMCryptoResult ODK_ParseLicense(const uint8_t* message, size_t message_length,
size_t core_message_length,
bool initial_license_load,
bool usage_entry_present,
const uint8_t* request_hash,
ODK_TimerLimits* timer_limits,
ODK_ClockValues* clock_values,
ODK_NonceValues* nonce_values,
ODK_ParsedLicense* parsed_license) {
if (!nonce_values || !parsed_license) {
return ODK_ERROR_CORE_MESSAGE;
}
ODK_LicenseResponse license_response = {{0}, parsed_license};
OEMCryptoResult err = ODK_ParseResponse(
message, message_length, ODK_License_Response_Type, NULL,
&license_response.core_message);
if (err != OEMCrypto_SUCCESS) {
return err;
}
if (license_response.core_message.nonce_values.api_version != 16) {
return ODK_UNSUPPORTED_API;
}
if (parsed_license->nonce_required) {
if (initial_license_load) {
if (nonce_values->nonce != license_response.core_message.nonce_values.nonce ||
nonce_values->session_id != license_response.core_message.nonce_values.session_id) {
return OEMCrypto_ERROR_INVALID_NONCE;
}
} else { /* !initial_license_load */
nonce_values->nonce = license_response.core_message.nonce_values.nonce;
nonce_values->session_id = license_response.core_message.nonce_values.session_id;
}
}
if (initial_license_load &&
memcmp(request_hash, parsed_license->request_hash, ODK_SHA256_HASH_SIZE)) {
return ODK_ERROR_CORE_MESSAGE;
}
if (usage_entry_present && parsed_license->pst.length == 0) {
return ODK_ERROR_CORE_MESSAGE;
}
return err;
}
OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
size_t core_message_length,
const ODK_NonceValues* nonce_values,
uint64_t system_time,
const ODK_TimerLimits* timer_limits,
ODK_ClockValues* clock_values,
uint64_t* timer_value) {
if (!nonce_values || !timer_limits || !clock_values || !timer_value) {
return ODK_ERROR_CORE_MESSAGE;
}
ODK_RenewalMessage renewal_response = {
{0},
};
OEMCryptoResult err = ODK_ParseResponse(
message, message_length, ODK_Renewal_Response_Type, nonce_values,
&renewal_response.core_message);
if (err) {
return err;
}
/* Reference:
* Doc: License Duration and Renewal (Changes for OEMCrypto v16)
* Section: Renewal Message
*/
uint64_t playback_timer = 0;
if (odk_sub_overflow_u64(clock_values->time_when_timer_expires, system_time,
&playback_timer)) {
return ODK_TIMER_EXPIRED;
}
uint64_t time_since_playback_began = 0;
uint64_t time_since_reset = 0;
uint64_t time_since_message_signed = 0;
/* ... or use clock_values->time_of_license_signed ? */
if (odk_sub_overflow_u64(system_time, clock_values->time_of_first_decrypt,
&time_since_playback_began) ||
odk_sub_overflow_u64(timer_limits->renewal_playback_duration_seconds,
playback_timer, &time_since_reset) ||
odk_sub_overflow_u64(time_since_playback_began,
renewal_response.playback_time,
&time_since_message_signed) ||
time_since_message_signed >= time_since_reset ||
odk_add_overflow_u64(system_time,
timer_limits->renewal_playback_duration_seconds,
&clock_values->time_when_timer_expires)) {
return ODK_ERROR_CORE_MESSAGE;
}
/* todo: when to return ODK_DISABLE_TIMER */
*timer_value = timer_limits->renewal_playback_duration_seconds;
return ODK_SET_TIMER;
}
OEMCryptoResult ODK_ParseProvisioning(
const uint8_t* message, size_t message_length,
size_t core_message_length,
const ODK_NonceValues* nonce_values,
const uint8_t* device_id,
size_t device_id_length, ODK_ParsedProvisioning* parsed_response) {
if (!nonce_values || !device_id || !parsed_response) {
return ODK_ERROR_CORE_MESSAGE;
}
ODK_ProvisioningResponse provisioning_response = {{
{0},
},
parsed_response};
if (device_id_length > ODK_DEVICE_ID_LEN_MAX) {
return ODK_ERROR_CORE_MESSAGE;
}
OEMCryptoResult err = ODK_ParseResponse(
message, message_length, ODK_Provisioning_Response_Type,
nonce_values, &provisioning_response.core_provisioning.core_message);
if (err) {
return err;
}
if (memcmp(device_id, provisioning_response.core_provisioning.device_id,
device_id_length)) {
return ODK_ERROR_CORE_MESSAGE;
}
uint8_t zero[ODK_DEVICE_ID_LEN_MAX] = {0};
/* check bytes beyond device_id_length are 0 */
if (memcmp(
zero,
provisioning_response.core_provisioning.device_id + device_id_length,
ODK_DEVICE_ID_LEN_MAX - device_id_length)) {
return ODK_ERROR_CORE_MESSAGE;
}
return OEMCrypto_SUCCESS;
}