Files
android/libwvdrmengine/oemcrypto/odk/kdo/src/oec_util.cpp
Robert Shih 2443fe807a odk: core serialization structs & functions
odk directory copied from wvgerrit.
branch oemcrypto-v16
commit 0c9a7dc

Bug: 140758896
Test: odk_test
Change-Id: I0c631f771b794468a63e4395f6b9c3b60a1dfd4f
2019-12-13 01:32:03 +00:00

210 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 Master
* License Agreement.
*/
#include "oec_util.h"
#include <stdint.h>
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <string>
#include "odk_overflow.h"
#include "odk_serialize.h"
#include "odk_structs.h"
#include "odk_structs_priv.h"
#include "oemcrypto_types.h"
#include "serialization_base.h"
using namespace oec_util;
namespace oec_util {
namespace {
/* @ private functions */
const int CURRENT_OEC_VERSION = 16;
/**
* Template for parsing requests
*
* Template arguments:
* S: kdo output struct
* T: struct serialized by odk
* U: auto-generated deserializing function for |T|
*/
template <typename S, typename T, typename U>
bool ParseRequest(uint32_t message_type, const string& oemcrypto_core_message,
S* core_request, T* prepared, const U unpacker) {
if (!core_request) {
return false;
}
const uint8_t* buf =
reinterpret_cast<const uint8_t*>(oemcrypto_core_message.c_str());
size_t buf_length = oemcrypto_core_message.size();
Message* msg = NULL;
AllocateMessage(&msg, message_block);
InitMessage(msg, const_cast<uint8_t*>(buf), buf_length);
SetSize(msg, buf_length);
unpacker(msg, prepared);
if (!ValidMessage(msg)) {
return false;
}
const auto& core_message = prepared->core_message;
core_request->api_version = core_message.nonce_values.api_version;
core_request->nonce = core_message.nonce_values.nonce;
core_request->session_id = core_message.nonce_values.session_id;
return core_message.message_type == message_type &&
core_message.message_length == GetOffset(msg) &&
core_request->api_version == CURRENT_OEC_VERSION;
}
/**
* Template for parsing requests
*
* Template arguments:
* T: struct to be deserialized by odk
* S: kdo input struct
* P: auto-generated serializing function for |T|
*/
template <typename T, typename S, typename P>
bool CreateResponse(uint32_t message_type, const S& core_request,
string* oemcrypto_core_message, T& response,
const P& packer) {
if (!oemcrypto_core_message) {
return false;
}
auto* header = reinterpret_cast<ODK_CoreMessage*>(&response);
header->message_type = message_type;
header->nonce_values.api_version = core_request.api_version;
header->nonce_values.nonce = core_request.nonce;
header->nonce_values.session_id = core_request.session_id;
uint8_t buf[2048] = {0};
Message* msg = NULL;
AllocateMessage(&msg, message_block);
InitMessage(msg, buf, sizeof(buf));
packer(msg, &response);
if (!ValidMessage(msg)) {
return false;
}
uint32_t message_length = GetSize(msg);
InitMessage(msg, buf + sizeof(header->message_type),
sizeof(header->message_length));
Pack_uint32_t(msg, &message_length);
oemcrypto_core_message->assign(reinterpret_cast<const char*>(buf),
message_length);
return true;
}
bool CopyDeviceId(ODK_ProvisioningResponse& dest,
const ODK_ProvisioningRequest& src) {
auto& core_provisioning = dest.core_provisioning;
const string& device_id = src.device_id;
core_provisioning.device_id_length = device_id.size();
if (core_provisioning.device_id_length >
sizeof(core_provisioning.device_id)) {
return false;
}
memset(core_provisioning.device_id, 0, sizeof(core_provisioning.device_id));
memcpy(core_provisioning.device_id, device_id.data(),
core_provisioning.device_id_length);
return true;
}
} // namespace
// @ public parse request (deserializer) functions
bool ParseLicenseRequest(const string& oemcrypto_core_message,
ODK_LicenseRequest* core_license_request) {
const auto unpacker = Unpack_ODK_PreparedLicense;
ODK_PreparedLicense prepared_license = {};
return ParseRequest(ODK_License_Request_Type, oemcrypto_core_message,
core_license_request, &prepared_license, unpacker);
}
bool ParseRenewalRequest(const string& oemcrypto_core_message,
ODK_RenewalRequest* core_renewal_request) {
const auto unpacker = Unpack_ODK_RenewalMessage;
ODK_RenewalMessage prepared_renewal = {};
if (!ParseRequest(ODK_Renewal_Request_Type, oemcrypto_core_message,
core_renewal_request, &prepared_renewal, unpacker)) {
return false;
}
core_renewal_request->playback_time = prepared_renewal.playback_time;
return true;
}
bool ParseProvisioningRequest(
const string& oemcrypto_core_message,
ODK_ProvisioningRequest* core_provisioning_request) {
const auto unpacker = Unpack_ODK_ProvisioningMessage;
ODK_ProvisioningMessage prepared_provision = {};
if (!ParseRequest(ODK_Provisioning_Request_Type, oemcrypto_core_message,
core_provisioning_request, &prepared_provision, unpacker)) {
return false;
}
const uint8_t* device_id = prepared_provision.device_id;
const uint32_t device_id_length = prepared_provision.device_id_length;
if (device_id_length > ODK_DEVICE_ID_LEN_MAX) {
return false;
}
uint8_t zero[ODK_DEVICE_ID_LEN_MAX] = {};
if (memcmp(zero, device_id + device_id_length,
ODK_DEVICE_ID_LEN_MAX - device_id_length)) {
return false;
}
core_provisioning_request->device_id.assign(
reinterpret_cast<const char*>(device_id), device_id_length);
return true;
}
// @ public create response functions
bool CreateCoreLicenseResponse(const ODK_ParsedLicense& parsed_lic,
const ODK_LicenseRequest& core_request,
string* oemcrypto_core_message) {
ODK_LicenseResponse license_response{
{}, const_cast<ODK_ParsedLicense*>(&parsed_lic)};
return CreateResponse(ODK_License_Response_Type, core_request,
oemcrypto_core_message, license_response,
Pack_ODK_LicenseResponse);
}
bool CreateCoreRenewalResponse(const ODK_RenewalRequest& core_request,
string* oemcrypto_core_message) {
ODK_RenewalMessage renewal{{}, core_request.playback_time};
renewal.playback_time = core_request.playback_time;
return CreateResponse(ODK_Renewal_Response_Type, core_request,
oemcrypto_core_message, renewal,
Pack_ODK_RenewalMessage);
}
bool CreateCoreProvisioningResponse(const ODK_ParsedProvisioning& parsed_prov,
const ODK_ProvisioningRequest& core_request,
string* oemcrypto_core_message) {
ODK_ProvisioningResponse prov_response{
{}, const_cast<ODK_ParsedProvisioning*>(&parsed_prov)};
if (!CopyDeviceId(prov_response, core_request)) {
return false;
}
return CreateResponse(ODK_Provisioning_Response_Type, core_request,
oemcrypto_core_message, prov_response,
Pack_ODK_ProvisioningResponse);
}
} // namespace oec_util