Update ODK to v17.1

This commit is contained in:
Jacob Trimble
2022-12-13 11:36:17 -08:00
parent c1401c6a1c
commit 2bfd670424
59 changed files with 1557 additions and 441 deletions

View File

@@ -1,5 +1,5 @@
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// source code may only be used and distributed under the Widevine
// License Agreement.
#include "core_message_deserialize.h"
@@ -10,6 +10,7 @@
#include <cstring>
#include <string>
#include "OEMCryptoCENCCommon.h"
#include "odk_serialize.h"
#include "odk_structs.h"
#include "odk_structs_priv.h"
@@ -52,6 +53,7 @@ bool ParseRequest(uint32_t message_type,
core_request->api_minor_version = core_message.nonce_values.api_minor_version;
core_request->nonce = core_message.nonce_values.nonce;
core_request->session_id = core_message.nonce_values.session_id;
// Verify that the minor version matches the released version for the given
// major version.
if (core_request->api_major_version < ODK_FIRST_VERSION) {
@@ -68,10 +70,13 @@ bool ParseRequest(uint32_t message_type,
// For v16, a release and a renewal use the same message structure.
// However, for future API versions, the release might be a separate
// message. Otherwise, we expect an exact match of message types.
// A provisioning request may contain a renewed provisioning message.
if (message_type != ODK_Common_Request_Type &&
core_message.message_type != message_type &&
!(message_type == ODK_Renewal_Request_Type &&
core_message.message_type == ODK_Release_Request_Type)) {
core_message.message_type == ODK_Release_Request_Type) &&
!(message_type == ODK_Provisioning_Request_Type &&
core_message.message_type == ODK_Renewed_Provisioning_Request_Type)) {
return false;
}
// Verify that the amount of buffer we read, which is GetOffset, is not more
@@ -125,6 +130,42 @@ bool CoreProvisioningRequestFromMessage(
}
core_provisioning_request->device_id.assign(
reinterpret_cast<const char*>(device_id), device_id_length);
core_provisioning_request->renewal_type = OEMCrypto_NoRenewal;
core_provisioning_request->renewal_data.clear();
return true;
}
bool CoreRenewedProvisioningRequestFromMessage(
const std::string& oemcrypto_core_message,
ODK_ProvisioningRequest* core_provisioning_request) {
const auto unpacker = Unpack_ODK_PreparedRenewedProvisioningRequest;
ODK_PreparedRenewedProvisioningRequest prepared_provision = {};
if (!ParseRequest(ODK_Renewed_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);
if (prepared_provision.renewal_data_length >
sizeof(prepared_provision.renewal_data)) {
return false;
}
core_provisioning_request->renewal_type = OEMCrypto_RenewalACert;
core_provisioning_request->renewal_data.assign(
reinterpret_cast<const char*>(prepared_provision.renewal_data),
prepared_provision.renewal_data_length);
return true;
}

View File

@@ -0,0 +1,41 @@
// Copyright 2021 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
#include "core_message_features.h"
namespace oemcrypto_core_message {
namespace features {
const CoreMessageFeatures CoreMessageFeatures::kDefaultFeatures;
bool CoreMessageFeatures::operator==(const CoreMessageFeatures &other) const {
return maximum_major_version == other.maximum_major_version &&
maximum_minor_version == other.maximum_minor_version;
}
CoreMessageFeatures CoreMessageFeatures::DefaultFeatures(
uint32_t maximum_major_version) {
CoreMessageFeatures features;
features.maximum_major_version = maximum_major_version;
// The default minor version is the highest for each major version.
switch (maximum_major_version) {
case 16:
features.maximum_minor_version = 5; // 16.5
break;
case 17:
features.maximum_minor_version = 1; // 17.1
break;
default:
features.maximum_minor_version = 0;
}
return features;
}
std::ostream &operator<<(std::ostream &os,
const CoreMessageFeatures &features) {
return os << "v" << features.maximum_major_version << "."
<< features.maximum_minor_version;
}
} // namespace features
} // namespace oemcrypto_core_message

View File

@@ -1,5 +1,5 @@
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// source code may only be used and distributed under the Widevine
// License Agreement.
#include "core_message_serialize.h"
@@ -13,6 +13,7 @@
#include "odk_serialize.h"
#include "odk_structs.h"
#include "odk_structs_priv.h"
#include "odk_target.h"
#include "serialization_base.h"
namespace oemcrypto_core_message {
@@ -20,7 +21,45 @@ namespace serialize {
namespace {
/**
* Template for parsing requests
* Template for copying nonce values from request to response, and also
* computing the API version of the response.
*
* Template arguments:
* T: struct to be deserialized by odk
* S: kdo input struct
*/
template <typename T, typename S>
bool CreateResponseHeader(const CoreMessageFeatures& features,
ODK_MessageType message_type, const S& core_request,
T& response) {
// Bad major version.
if ((features.maximum_major_version > ODK_MAJOR_VERSION) ||
(features.maximum_major_version == ODK_MAJOR_VERSION &&
features.maximum_minor_version > ODK_MINOR_VERSION)) {
// TODO(b/147513335): this should be logged.
return false;
}
auto* header = &response.request.core_message;
header->message_type = message_type;
header->nonce_values.api_major_version = core_request.api_major_version;
header->nonce_values.api_minor_version = core_request.api_minor_version;
header->nonce_values.nonce = core_request.nonce;
header->nonce_values.session_id = core_request.session_id;
// The message API version for the response is the minimum of our version and
// the request's version.
if (core_request.api_major_version > features.maximum_major_version) {
header->nonce_values.api_major_version = features.maximum_major_version;
header->nonce_values.api_minor_version = features.maximum_minor_version;
} else if (core_request.api_major_version == features.maximum_major_version &&
core_request.api_minor_version > features.maximum_minor_version) {
header->nonce_values.api_minor_version = features.maximum_minor_version;
}
return true;
}
/**
* Template for parsing requests and packing response
*
* Template arguments:
* T: struct to be deserialized by odk
@@ -34,21 +73,11 @@ bool CreateResponse(ODK_MessageType message_type, const S& core_request,
if (!oemcrypto_core_message) {
return false;
}
auto* header = &response.request.core_message;
header->message_type = message_type;
header->nonce_values.api_major_version = core_request.api_major_version;
header->nonce_values.api_minor_version = core_request.api_minor_version;
header->nonce_values.nonce = core_request.nonce;
header->nonce_values.session_id = core_request.session_id;
// The message API version for the response is the minimum of our version and
// the request's version.
if (core_request.api_major_version > ODK_MAJOR_VERSION) {
header->nonce_values.api_major_version = ODK_MAJOR_VERSION;
header->nonce_values.api_minor_version = ODK_MINOR_VERSION;
} else if (core_request.api_major_version == ODK_MAJOR_VERSION &&
core_request.api_minor_version > ODK_MINOR_VERSION) {
header->nonce_values.api_minor_version = ODK_MINOR_VERSION;
if (header->message_type != message_type ||
header->nonce_values.api_major_version < ODK_FIRST_VERSION) {
// This indicates CreateResponseHeader was not called.
return false;
}
static constexpr size_t BUF_CAPACITY = 2048;
@@ -59,7 +88,7 @@ bool CreateResponse(ODK_MessageType message_type, const S& core_request,
return false;
}
uint32_t message_length = ODK_Message_GetSize(&msg);
uint32_t message_length = static_cast<uint32_t>(ODK_Message_GetSize(&msg));
msg = ODK_Message_Create(buf.data() + sizeof(header->message_type),
sizeof(header->message_length));
Pack_uint32_t(&msg, &message_length);
@@ -75,7 +104,7 @@ bool CopyDeviceId(const ODK_ProvisioningRequest& src,
if (request.device_id_length > sizeof(request.device_id)) {
return false;
}
request.device_id_length = device_id.size();
request.device_id_length = static_cast<uint32_t>(device_id.size());
memset(request.device_id, 0, sizeof(request.device_id));
memcpy(request.device_id, device_id.data(), request.device_id_length);
return true;
@@ -83,33 +112,78 @@ bool CopyDeviceId(const ODK_ProvisioningRequest& src,
} // namespace
bool CreateCoreLicenseResponse(const ODK_ParsedLicense& parsed_lic,
bool CreateCoreLicenseResponse(const CoreMessageFeatures& features,
const ODK_ParsedLicense& parsed_lic,
const ODK_LicenseRequest& core_request,
const std::string& core_request_sha256,
std::string* oemcrypto_core_message) {
ODK_LicenseResponse license_response{
{}, const_cast<ODK_ParsedLicense*>(&parsed_lic), {0}};
if (core_request_sha256.size() != sizeof(license_response.request_hash))
{}, const_cast<ODK_ParsedLicense*>(&parsed_lic)};
if (!CreateResponseHeader(features, ODK_License_Response_Type, core_request,
license_response)) {
return false;
memcpy(license_response.request_hash, core_request_sha256.data(),
sizeof(license_response.request_hash));
}
if (ODK_MAX_NUM_KEYS < license_response.parsed_license->key_array_length) {
return false;
}
if (license_response.request.core_message.nonce_values.api_major_version ==
16) {
ODK_LicenseResponseV16 license_response_v16;
license_response_v16.request = license_response.request;
license_response_v16.parsed_license.enc_mac_keys_iv =
license_response.parsed_license->enc_mac_keys_iv;
license_response_v16.parsed_license.enc_mac_keys =
license_response.parsed_license->enc_mac_keys;
license_response_v16.parsed_license.pst =
license_response.parsed_license->pst;
license_response_v16.parsed_license.srm_restriction_data =
license_response.parsed_license->srm_restriction_data;
license_response_v16.parsed_license.license_type =
license_response.parsed_license->license_type;
license_response_v16.parsed_license.nonce_required =
license_response.parsed_license->nonce_required;
license_response_v16.parsed_license.timer_limits =
license_response.parsed_license->timer_limits;
license_response_v16.parsed_license.key_array_length =
license_response.parsed_license->key_array_length;
uint32_t i;
for (i = 0; i < license_response_v16.parsed_license.key_array_length &&
i < license_response.parsed_license->key_array_length;
i++) {
license_response_v16.parsed_license.key_array[i] =
license_response.parsed_license->key_array[i];
}
if (core_request_sha256.size() != sizeof(license_response_v16.request_hash))
return false;
memcpy(license_response_v16.request_hash, core_request_sha256.data(),
sizeof(license_response_v16.request_hash));
return CreateResponse(ODK_License_Response_Type, core_request,
oemcrypto_core_message, license_response_v16,
Pack_ODK_LicenseResponseV16);
}
return CreateResponse(ODK_License_Response_Type, core_request,
oemcrypto_core_message, license_response,
Pack_ODK_LicenseResponse);
}
bool CreateCoreRenewalResponse(const ODK_RenewalRequest& core_request,
bool CreateCoreRenewalResponse(const CoreMessageFeatures& features,
const ODK_RenewalRequest& core_request,
uint64_t renewal_duration_seconds,
std::string* oemcrypto_core_message) {
ODK_RenewalResponse renewal_response{{}, core_request.playback_time_seconds};
renewal_response.request.playback_time = core_request.playback_time_seconds;
renewal_response.renewal_duration_seconds = renewal_duration_seconds;
if (!CreateResponseHeader(features, ODK_Renewal_Response_Type, core_request,
renewal_response)) {
return false;
}
return CreateResponse(ODK_Renewal_Response_Type, core_request,
oemcrypto_core_message, renewal_response,
Pack_ODK_RenewalResponse);
}
bool CreateCoreProvisioningResponse(const ODK_ParsedProvisioning& parsed_prov,
bool CreateCoreProvisioningResponse(const CoreMessageFeatures& features,
const ODK_ParsedProvisioning& parsed_prov,
const ODK_ProvisioningRequest& core_request,
std::string* oemcrypto_core_message) {
ODK_ProvisioningResponse prov_response{
@@ -117,6 +191,10 @@ bool CreateCoreProvisioningResponse(const ODK_ParsedProvisioning& parsed_prov,
if (!CopyDeviceId(core_request, &prov_response)) {
return false;
}
if (!CreateResponseHeader(features, ODK_Provisioning_Response_Type,
core_request, prov_response)) {
return false;
}
return CreateResponse(ODK_Provisioning_Response_Type, core_request,
oemcrypto_core_message, prov_response,
Pack_ODK_ProvisioningResponse);

View File

@@ -1,5 +1,5 @@
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// source code may only be used and distributed under the Widevine
// License Agreement.
#include "core_message_serialize_proto.h"
@@ -20,6 +20,7 @@
namespace oemcrypto_core_message {
namespace serialize {
namespace {
using oemcrypto_core_message::features::CoreMessageFeatures;
/* @ private functions */
@@ -70,7 +71,8 @@ OEMCrypto_KeyObject KeyContainerToOecKey(
// @ public create response functions
bool CreateCoreLicenseResponseFromProto(const std::string& serialized_license,
bool CreateCoreLicenseResponseFromProto(const CoreMessageFeatures& features,
const std::string& serialized_license,
const ODK_LicenseRequest& core_request,
const std::string& core_request_sha256,
const bool nonce_required,
@@ -99,8 +101,11 @@ bool CreateCoreLicenseResponseFromProto(const std::string& serialized_license,
}
case video_widevine::License_KeyContainer::CONTENT:
case video_widevine::License_KeyContainer::OPERATOR_SESSION:
case video_widevine::License_KeyContainer::OEM_CONTENT:
case video_widevine::License_KeyContainer::OEM_ENTITLEMENT:
case video_widevine::License_KeyContainer::ENTITLEMENT: {
if (k.type() == video_widevine::License_KeyContainer::ENTITLEMENT) {
if (k.type() == video_widevine::License_KeyContainer::ENTITLEMENT ||
k.type() == video_widevine::License_KeyContainer::OEM_ENTITLEMENT) {
any_entitlement = true;
} else {
any_content = true;
@@ -133,12 +138,13 @@ bool CreateCoreLicenseResponseFromProto(const std::string& serialized_license,
parsed_lic.pst =
GetOecSubstring(serialized_license, lid.provider_session_token());
}
if (lic.has_srm_requirement()) {
parsed_lic.srm_restriction_data =
GetOecSubstring(serialized_license, lic.srm_requirement());
}
if (lic.policy().has_watermarking_control()) {
parsed_lic.watermarking = lic.policy().watermarking_control();
}
parsed_lic.nonce_required = nonce_required;
const auto& policy = lic.policy();
ODK_TimerLimits& timer_limits = parsed_lic.timer_limits;
@@ -154,11 +160,12 @@ bool CreateCoreLicenseResponseFromProto(const std::string& serialized_license,
policy.renewal_delay_seconds() +
policy.renewal_recovery_duration_seconds();
return CreateCoreLicenseResponse(parsed_lic, core_request,
return CreateCoreLicenseResponse(features, parsed_lic, core_request,
core_request_sha256, oemcrypto_core_message);
}
bool CreateCoreProvisioningResponseFromProto(
const CoreMessageFeatures& features,
const std::string& serialized_provisioning_resp,
const ODK_ProvisioningRequest& core_request,
std::string* oemcrypto_core_message) {
@@ -183,7 +190,7 @@ bool CreateCoreProvisioningResponseFromProto(
GetOecSubstring(serialized_provisioning_resp, prov.wrapping_key());
}
return CreateCoreProvisioningResponse(parsed_prov, core_request,
return CreateCoreProvisioningResponse(features, parsed_prov, core_request,
oemcrypto_core_message);
}

View File

@@ -1,5 +1,5 @@
# Copyright 2019 Google LLC. All rights reserved. This file and proprietary
# source code may only be used and distributed under the Widevine Master License
# source code may only be used and distributed under the Widevine License
# Agreement.
# These files are used by the server and by some ODK test code. These files are
@@ -7,6 +7,7 @@
{
'sources': [
'core_message_deserialize.cpp',
'core_message_features.cpp',
'core_message_serialize.cpp',
'core_message_serialize_proto.cpp',
],

View File

@@ -1,5 +1,5 @@
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// source code may only be used and distributed under the Widevine
// License Agreement.
#include "odk.h"
@@ -72,6 +72,17 @@ static OEMCryptoResult ODK_PrepareRequest(
&msg, (ODK_PreparedProvisioningRequest*)prepared_request_buffer);
break;
}
case ODK_Renewed_Provisioning_Request_Type: {
core_message->message_length = ODK_RENEWED_PROVISIONING_REQUEST_SIZE;
if (sizeof(ODK_PreparedRenewedProvisioningRequest) >
prepared_request_buffer_length) {
return ODK_ERROR_CORE_MESSAGE;
}
Pack_ODK_PreparedRenewedProvisioningRequest(
&msg,
(ODK_PreparedRenewedProvisioningRequest*)prepared_request_buffer);
break;
}
default: {
return ODK_ERROR_CORE_MESSAGE;
}
@@ -91,64 +102,65 @@ static OEMCryptoResult ODK_PrepareRequest(
return OEMCrypto_SUCCESS;
}
static OEMCryptoResult ODK_ParseResponse(
const uint8_t* message, size_t message_length, size_t core_message_length,
ODK_MessageType message_type, const ODK_NonceValues* nonce_values,
void* response_buffer, uint32_t response_buffer_length) {
if (message == NULL || response_buffer == NULL ||
core_message_length > message_length) {
/* Parse the core message and verify that it has the right type. The nonce
* values are updated to hold the response's API version.
*/
static OEMCryptoResult ODK_ParseCoreHeader(const uint8_t* message,
size_t message_length,
size_t core_message_length,
ODK_MessageType message_type,
ODK_NonceValues* nonce_values) {
// The core_message_length is the length of the core message, which is a
// substring of the complete message.
if (message == NULL || core_message_length > message_length) {
return ODK_ERROR_CORE_MESSAGE;
}
ODK_CoreMessage core_message;
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. */
/* The core message should be at the beginning of the buffer. The core message
* is the part we are parsing. */
ODK_Message_SetSize(&msg, core_message_length);
Unpack_ODK_CoreMessage(&msg, &core_message);
/* Parse message and unpack it into response buffer. */
switch (message_type) {
case ODK_License_Response_Type: {
if (sizeof(ODK_LicenseResponse) > response_buffer_length) {
return ODK_ERROR_CORE_MESSAGE;
}
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);
break;
}
case ODK_Provisioning_Response_Type: {
if (sizeof(ODK_ProvisioningResponse) > response_buffer_length) {
return ODK_ERROR_CORE_MESSAGE;
}
Unpack_ODK_ProvisioningResponse(
&msg, (ODK_ProvisioningResponse*)response_buffer);
break;
}
default: {
return ODK_ERROR_CORE_MESSAGE;
}
}
ODK_CoreMessage* core_message = (ODK_CoreMessage*)response_buffer;
if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK ||
message_type != core_message->message_type ||
ODK_Message_GetOffset(&msg) != core_message->message_length) {
message_type != core_message.message_type) {
return ODK_ERROR_CORE_MESSAGE;
}
// The current offset should be the end of the header, which is the message
// type, message length, api version, and nonce fields. The header can't be
// larger than the whole core message. Also, the core message specifies its
// length, which should be exactly the length of the core message buffer.
if (ODK_Message_GetOffset(&msg) > core_message.message_length ||
core_message.message_length != core_message_length) {
return ODK_ERROR_CORE_MESSAGE;
}
/* We do not support future API version. Also, this function should not be
* used for legacy licenses without a core message. */
if (core_message.nonce_values.api_major_version > ODK_MAJOR_VERSION ||
core_message.nonce_values.api_major_version < ODK_FIRST_VERSION) {
return ODK_UNSUPPORTED_API;
}
if (nonce_values) {
/* always verify nonce_values for Renewal and Provisioning responses */
if (!ODK_NonceValuesEqual(nonce_values, &(core_message->nonce_values))) {
return OEMCrypto_ERROR_INVALID_NONCE;
/* If the server sent us an older format, record the message's API version.
*/
if (nonce_values->api_major_version >
core_message.nonce_values.api_major_version) {
// If the major version is smaller, use both values from the server.
nonce_values->api_major_version =
core_message.nonce_values.api_major_version;
nonce_values->api_minor_version =
core_message.nonce_values.api_minor_version;
} else if (nonce_values->api_major_version ==
core_message.nonce_values.api_major_version &&
nonce_values->api_minor_version >
core_message.nonce_values.api_minor_version) {
// Otherwise, if the major versions are equal, but the minor is smaller,
// then we should lower the minor version.
nonce_values->api_minor_version =
core_message.nonce_values.api_minor_version;
}
}
return OEMCrypto_SUCCESS;
}
@@ -162,9 +174,7 @@ OEMCryptoResult ODK_PrepareCoreLicenseRequest(
if (core_message_length == NULL || nonce_values == NULL) {
return ODK_ERROR_CORE_MESSAGE;
}
ODK_PreparedLicenseRequest license_request = {
{0, 0, {}},
};
ODK_PreparedLicenseRequest license_request = {0};
return ODK_PrepareRequest(
message, message_length, core_message_length, ODK_License_Request_Type,
nonce_values, &license_request, sizeof(ODK_PreparedLicenseRequest));
@@ -192,7 +202,7 @@ OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message,
return OEMCrypto_SUCCESS;
}
ODK_PreparedRenewalRequest renewal_request = {{0, 0, {}}, 0};
ODK_PreparedRenewalRequest renewal_request = {0};
/* First, we compute the time this request was made relative to the playback
* clock. */
if (clock_values->time_of_first_decrypt == 0) {
@@ -225,11 +235,7 @@ OEMCryptoResult ODK_PrepareCoreProvisioningRequest(
if (core_message_length == NULL || nonce_values == NULL) {
return ODK_ERROR_CORE_MESSAGE;
}
ODK_PreparedProvisioningRequest provisioning_request = {
{0, 0, {}},
0,
{0},
};
ODK_PreparedProvisioningRequest provisioning_request = {0};
if (device_id_length > sizeof(provisioning_request.device_id)) {
return ODK_ERROR_CORE_MESSAGE;
}
@@ -243,52 +249,124 @@ OEMCryptoResult ODK_PrepareCoreProvisioningRequest(
sizeof(ODK_PreparedProvisioningRequest));
}
OEMCryptoResult ODK_PrepareCoreRenewedProvisioningRequest(
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, uint16_t renewal_type, const uint8_t* renewal_data,
size_t renewal_data_length) {
if (core_message_length == NULL || nonce_values == NULL) {
return ODK_ERROR_CORE_MESSAGE;
}
ODK_PreparedRenewedProvisioningRequest provisioning_request = {0};
if (device_id_length > sizeof(provisioning_request.device_id)) {
return ODK_ERROR_CORE_MESSAGE;
}
provisioning_request.device_id_length = (uint32_t)device_id_length;
if (device_id) {
memcpy(provisioning_request.device_id, device_id, device_id_length);
}
if (renewal_data_length > sizeof(provisioning_request.renewal_data)) {
return ODK_ERROR_CORE_MESSAGE;
}
provisioning_request.renewal_type = renewal_type;
provisioning_request.renewal_data_length = (uint32_t)renewal_data_length;
if (renewal_data) {
memcpy(provisioning_request.renewal_data, renewal_data,
renewal_data_length);
}
return ODK_PrepareRequest(message, message_length, core_message_length,
ODK_Renewed_Provisioning_Request_Type, nonce_values,
&provisioning_request,
sizeof(provisioning_request));
}
/* @@ parse response 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 (message == NULL || request_hash == NULL || timer_limits == NULL ||
clock_values == NULL || nonce_values == NULL || parsed_license == NULL) {
ODK_TimerLimits* timer_limits, ODK_ClockValues* clock_values,
ODK_NonceValues* nonce_values, ODK_ParsedLicense* parsed_license) {
if (message == NULL || timer_limits == NULL || clock_values == NULL ||
nonce_values == NULL || parsed_license == NULL) {
return ODK_ERROR_CORE_MESSAGE;
}
ODK_LicenseResponse license_response = {{{0, 0, {}}}, NULL, {0}};
license_response.parsed_license = parsed_license;
const OEMCryptoResult err = ODK_ParseResponse(
message, message_length, core_message_length, ODK_License_Response_Type,
NULL, &license_response, sizeof(ODK_LicenseResponse));
const OEMCryptoResult err =
ODK_ParseCoreHeader(message, message_length, core_message_length,
ODK_License_Response_Type, nonce_values);
if (err != OEMCrypto_SUCCESS) {
return err;
}
/* We do not support future API version. Also, this function should not be
* used for legacy licenses. */
if (license_response.request.core_message.nonce_values.api_major_version >
ODK_MAJOR_VERSION ||
license_response.request.core_message.nonce_values.api_major_version <
ODK_FIRST_VERSION) {
return ODK_UNSUPPORTED_API;
ODK_LicenseResponse license_response = {0};
license_response.parsed_license = parsed_license;
ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length);
ODK_Message_SetSize(&msg, core_message_length);
if (nonce_values->api_major_version == 16) {
ODK_LicenseResponseV16 license_response_v16 = {0};
Unpack_ODK_LicenseResponseV16(&msg, &license_response_v16);
if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK ||
ODK_Message_GetOffset(&msg) != core_message_length) {
return ODK_ERROR_CORE_MESSAGE;
}
// Need to manually set parsed_license fields to
// license_response_v16.parsed_license field values since
// license_response_v16 is no longer a pointer so parsed_license doesn't get
// updated during the unpacking.
parsed_license->enc_mac_keys_iv =
license_response_v16.parsed_license.enc_mac_keys_iv;
parsed_license->enc_mac_keys =
license_response_v16.parsed_license.enc_mac_keys;
parsed_license->pst = license_response_v16.parsed_license.pst;
parsed_license->srm_restriction_data =
license_response_v16.parsed_license.srm_restriction_data;
parsed_license->license_type =
license_response_v16.parsed_license.license_type;
parsed_license->nonce_required =
license_response_v16.parsed_license.nonce_required;
parsed_license->timer_limits =
license_response_v16.parsed_license.timer_limits;
parsed_license->key_array_length =
license_response_v16.parsed_license.key_array_length;
uint32_t i;
for (i = 0; i < parsed_license->key_array_length; i++) {
parsed_license->key_array[i] =
license_response_v16.parsed_license.key_array[i];
}
// Set fields not used in V16 to default values.
parsed_license->watermarking = 0;
// Set fields not used in V16 to default values.
parsed_license->dtcp2_required.dtcp2_required = 0;
parsed_license->dtcp2_required.cmi_descriptor_0.id = 0;
parsed_license->dtcp2_required.cmi_descriptor_0.extension = 0;
parsed_license->dtcp2_required.cmi_descriptor_0.length = 1;
parsed_license->dtcp2_required.cmi_descriptor_0.data = 0;
parsed_license->dtcp2_required.cmi_descriptor_1.id = 1;
parsed_license->dtcp2_required.cmi_descriptor_1.extension = 0;
parsed_license->dtcp2_required.cmi_descriptor_1.length = 3;
parsed_license->dtcp2_required.cmi_descriptor_1.data[0] = 0;
parsed_license->dtcp2_required.cmi_descriptor_1.data[1] = 0;
parsed_license->dtcp2_required.cmi_descriptor_1.data[2] = 0;
parsed_license->dtcp2_required.cmi_descriptor_2.id = 2;
parsed_license->dtcp2_required.cmi_descriptor_2.extension = 0;
parsed_license->dtcp2_required.cmi_descriptor_2.length = 3;
parsed_license->dtcp2_required.cmi_descriptor_2.data[0] = 0;
parsed_license->dtcp2_required.cmi_descriptor_2.data[1] = 0;
parsed_license->dtcp2_required.cmi_descriptor_2.data[2] = 0;
license_response.request = license_response_v16.request;
} else {
Unpack_ODK_LicenseResponse(&msg, &license_response);
if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK ||
ODK_Message_GetOffset(&msg) != core_message_length) {
return ODK_ERROR_CORE_MESSAGE;
}
}
/* If the server sent us an older format, record the license's API version. */
if (nonce_values->api_major_version >
license_response.request.core_message.nonce_values.api_major_version) {
nonce_values->api_major_version =
license_response.request.core_message.nonce_values.api_major_version;
nonce_values->api_minor_version =
license_response.request.core_message.nonce_values.api_minor_version;
} else if (nonce_values->api_minor_version >
license_response.request.core_message.nonce_values
.api_minor_version) {
nonce_values->api_minor_version =
license_response.request.core_message.nonce_values.api_minor_version;
}
/* If the license has a provider session token (pst), then OEMCrypto should
* have a usage entry loaded. The opposite is also an error. */
if ((usage_entry_present && parsed_license->pst.length == 0) ||
@@ -315,15 +393,6 @@ OEMCryptoResult ODK_ParseLicense(
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
* message body. Here, when we process the license response, we verify that
* the server has the same hash of the core request. */
if (initial_license_load && parsed_license->nonce_required &&
crypto_memcmp(request_hash, license_response.request_hash,
ODK_SHA256_HASH_SIZE)) {
return ODK_ERROR_CORE_MESSAGE;
}
*timer_limits = parsed_license->timer_limits;
/* And update the clock values state. */
clock_values->timer_status = ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED;
@@ -342,17 +411,27 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
return ODK_ERROR_CORE_MESSAGE;
}
ODK_RenewalResponse renewal_response = {
{{0, 0, {}}, 0},
0,
};
const OEMCryptoResult err = ODK_ParseResponse(
message, message_length, core_message_length, ODK_Renewal_Response_Type,
nonce_values, &renewal_response, sizeof(ODK_RenewalResponse));
const OEMCryptoResult err =
ODK_ParseCoreHeader(message, message_length, core_message_length,
ODK_Renewal_Response_Type, NULL);
if (err != OEMCrypto_SUCCESS) {
return err;
}
ODK_RenewalResponse renewal_response = {0};
ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length);
ODK_Message_SetSize(&msg, core_message_length);
Unpack_ODK_RenewalResponse(&msg, &renewal_response);
if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK ||
ODK_Message_GetOffset(&msg) != core_message_length) {
return ODK_ERROR_CORE_MESSAGE;
}
/* always verify nonce_values for Renewal and Provisioning responses */
if (!ODK_NonceValuesEqualExcludingVersion(
nonce_values,
&(renewal_response.request.core_message.nonce_values))) {
return OEMCrypto_ERROR_INVALID_NONCE;
}
/* Reference:
* Doc: License Duration and Renewal (Changes for OEMCrypto v16)
@@ -381,21 +460,31 @@ OEMCryptoResult ODK_ParseProvisioning(
parsed_response == NULL) {
return ODK_ERROR_CORE_MESSAGE;
}
ODK_ProvisioningResponse provisioning_response = {{{0, 0, {}}, 0, {0}}, NULL};
const OEMCryptoResult err =
ODK_ParseCoreHeader(message, message_length, core_message_length,
ODK_Provisioning_Response_Type, NULL);
if (err != OEMCrypto_SUCCESS) {
return err;
}
ODK_ProvisioningResponse provisioning_response = {0};
provisioning_response.parsed_provisioning = parsed_response;
if (device_id_length > ODK_DEVICE_ID_LEN_MAX) {
return ODK_ERROR_CORE_MESSAGE;
}
const OEMCryptoResult err = ODK_ParseResponse(
message, message_length, core_message_length,
ODK_Provisioning_Response_Type, nonce_values, &provisioning_response,
sizeof(ODK_ProvisioningResponse));
if (err != OEMCrypto_SUCCESS) {
return err;
ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length);
ODK_Message_SetSize(&msg, core_message_length);
Unpack_ODK_ProvisioningResponse(&msg, &provisioning_response);
if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK ||
ODK_Message_GetOffset(&msg) != core_message_length) {
return ODK_ERROR_CORE_MESSAGE;
}
/* always verify nonce_values for Renewal and Provisioning responses */
if (!ODK_NonceValuesEqualExcludingVersion(
nonce_values,
&(provisioning_response.request.core_message.nonce_values))) {
return OEMCrypto_ERROR_INVALID_NONCE;
}
if (crypto_memcmp(device_id, provisioning_response.request.device_id,
@@ -413,3 +502,10 @@ OEMCryptoResult ODK_ParseProvisioning(
return OEMCrypto_SUCCESS;
}
bool CheckApiVersionAtMost(const ODK_NonceValues* nonce_values,
uint16_t major_version, uint16_t minor_version) {
return nonce_values->api_major_version < major_version ||
(nonce_values->api_major_version == major_version &&
nonce_values->api_minor_version <= minor_version);
}

View File

@@ -1,12 +1,14 @@
# Copyright 2019 Google LLC. All rights reserved. This file and proprietary
# source code may only be used and distributed under the Widevine Master License
# source code may only be used and distributed under the Widevine License
# Agreement.
{
'targets': [
{
'toolsets' : [ 'target' ],
'target_name': 'odk',
'type': 'static_library',
'standalone_static_library' : 1,
'include_dirs': [
'../include',
'../../include',
@@ -14,9 +16,23 @@
'includes' : [
'odk.gypi',
],
'cflags': [
# TODO(b/172518513): Remove this
'-Wno-error=cast-qual',
],
'defines': [
# Needed for <endian.h> to work.
'_DEFAULT_SOURCE',
],
'direct_dependent_settings': {
'defines': [
# Needed for <endian.h> to work.
'_DEFAULT_SOURCE',
],
'include_dirs': [
'.',
'../include',
'../../include',
],
}
},

View File

@@ -1,5 +1,5 @@
# Copyright 2019 Google LLC. All rights reserved. This file and proprietary
# source code may only be used and distributed under the Widevine Master License
# source code may only be used and distributed under the Widevine License
# Agreement.
# These files are built into the ODK library on the device. They are also used

View File

@@ -1,5 +1,5 @@
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// source code may only be used and distributed under the Widevine
// License Agreement.
#ifndef WIDEVINE_ODK_SRC_ODK_ASSERT_H_

View File

@@ -1,5 +1,5 @@
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// source code may only be used and distributed under the Widevine
// License Agreement.
#ifndef WIDEVINE_ODK_SRC_ODK_ENDIAN_H_
@@ -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
#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

@@ -1,5 +1,5 @@
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// source code may only be used and distributed under the Widevine
// License Agreement.
#include "odk_message.h"
@@ -26,9 +26,12 @@ static_assert(
/*
* 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. If |buffer|
* is NULL or |capacity| is zero, the message is invalid and the status
* will be set to MESSAGE_STATUS_NOT_INITIALIZED.
* 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));
@@ -36,25 +39,28 @@ ODK_Message ODK_Message_Create(uint8_t* buffer, size_t capacity) {
ODK_Message_Impl* message_impl = (ODK_Message_Impl*)&message;
message_impl->base = buffer;
message_impl->capacity = capacity;
ODK_Message_Clear(&message);
if (buffer == NULL || capacity == 0) {
message_impl->status = MESSAGE_STATUS_NOT_INITIALIZED;
}
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 status is reset to
* MESSAGE_STATUS_OK.
* 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);
ODK_Message_Reset(message);
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);
}
}
/*
@@ -122,7 +128,10 @@ ODK_MessageStatus ODK_Message_GetStatus(ODK_Message* message) {
void ODK_Message_SetStatus(ODK_Message* message, ODK_MessageStatus status) {
ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
assert(message_impl != NULL);
message_impl->status = status;
/* preserve the first error */
if (message_impl->status == MESSAGE_STATUS_OK) {
message_impl->status = status;
}
}
/*
@@ -132,13 +141,15 @@ void ODK_Message_SetStatus(ODK_Message* message, ODK_MessageStatus status) {
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.
* 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);
@@ -149,10 +160,6 @@ bool ODK_Message_IsValid(ODK_Message* message) {
if (message_impl->status != MESSAGE_STATUS_OK) {
return false;
}
if (message_impl->base == NULL) {
message_impl->status = MESSAGE_STATUS_NULL_POINTER_ERROR;
return false;
}
if (message_impl->read_offset > message_impl->capacity ||
message_impl->size > message_impl->capacity ||
message_impl->read_offset > message_impl->size) {

View File

@@ -1,5 +1,5 @@
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// source code may only be used and distributed under the Widevine
// License Agreement.
#ifndef WIDEVINE_ODK_SRC_ODK_MESSAGE_PRIV_H_

View File

@@ -1,5 +1,5 @@
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// source code may only be used and distributed under the Widevine
// License Agreement.
#include <stddef.h>
@@ -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

@@ -1,5 +1,5 @@
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// source code may only be used and distributed under the Widevine
// License Agreement.
#ifndef WIDEVINE_ODK_SRC_ODK_OVERFLOW_H_
@@ -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

@@ -1,5 +1,5 @@
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// source code may only be used and distributed under the Widevine
// License Agreement.
/*
@@ -58,6 +58,47 @@ static void Pack_ODK_ParsedLicense(ODK_Message* msg,
Pack_enum(msg, obj->license_type);
Pack_bool(msg, &obj->nonce_required);
Pack_ODK_TimerLimits(msg, &obj->timer_limits);
Pack_uint32_t(msg, &obj->watermarking);
Pack_uint8_t(msg, &obj->dtcp2_required.dtcp2_required);
if (obj->dtcp2_required.dtcp2_required) {
Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.id);
Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.extension);
Pack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_0.length);
Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.data);
Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.id);
Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.extension);
Pack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_1.length);
Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[0]);
Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[1]);
Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[2]);
Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.id);
Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.extension);
Pack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_2.length);
Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[0]);
Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[1]);
Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[2]);
}
Pack_uint32_t(msg, &obj->key_array_length);
size_t i;
for (i = 0; i < (size_t)obj->key_array_length; i++) {
Pack_OEMCrypto_KeyObject(msg, &obj->key_array[i]);
}
}
static void Pack_ODK_ParsedLicenseV16(ODK_Message* msg,
ODK_ParsedLicenseV16 const* obj) {
/* hand-coded */
if (obj->key_array_length > ODK_MAX_NUM_KEYS) {
ODK_Message_SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR);
return;
}
Pack_OEMCrypto_Substring(msg, &obj->enc_mac_keys_iv);
Pack_OEMCrypto_Substring(msg, &obj->enc_mac_keys);
Pack_OEMCrypto_Substring(msg, &obj->pst);
Pack_OEMCrypto_Substring(msg, &obj->srm_restriction_data);
Pack_enum(msg, obj->license_type);
Pack_bool(msg, &obj->nonce_required);
Pack_ODK_TimerLimits(msg, &obj->timer_limits);
Pack_uint32_t(msg, &obj->key_array_length);
size_t i;
for (i = 0; i < (size_t)obj->key_array_length; i++) {
@@ -87,18 +128,34 @@ void Pack_ODK_PreparedRenewalRequest(ODK_Message* msg,
}
void Pack_ODK_PreparedProvisioningRequest(
ODK_Message* msg, ODK_PreparedProvisioningRequest const* obj) {
ODK_Message* msg, const ODK_PreparedProvisioningRequest* 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));
}
void Pack_ODK_PreparedRenewedProvisioningRequest(
ODK_Message* msg, const ODK_PreparedRenewedProvisioningRequest* 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));
Pack_uint16_t(msg, &obj->renewal_type);
Pack_uint32_t(msg, &obj->renewal_data_length);
PackArray(msg, &obj->renewal_data[0], sizeof(obj->renewal_data));
}
/* @@ kdo serialize */
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);
}
void Pack_ODK_LicenseResponseV16(ODK_Message* msg,
ODK_LicenseResponseV16 const* obj) {
Pack_ODK_PreparedLicenseRequest(msg, &obj->request);
Pack_ODK_ParsedLicenseV16(msg, &obj->parsed_license);
PackArray(msg, &obj->request_hash[0], sizeof(obj->request_hash));
}
@@ -109,7 +166,7 @@ void Pack_ODK_RenewalResponse(ODK_Message* msg,
}
void Pack_ODK_ProvisioningResponse(ODK_Message* msg,
ODK_ProvisioningResponse const* obj) {
const ODK_ProvisioningResponse* obj) {
Pack_ODK_PreparedProvisioningRequest(msg, &obj->request);
Pack_ODK_ParsedProvisioning(
msg, (const ODK_ParsedProvisioning*)obj->parsed_provisioning);
@@ -126,7 +183,7 @@ static void Unpack_ODK_NonceValues(ODK_Message* msg, ODK_NonceValues* obj) {
Unpack_uint32_t(msg, &obj->session_id);
}
static void Unpack_ODK_CoreMessage(ODK_Message* msg, ODK_CoreMessage* obj) {
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);
@@ -158,6 +215,64 @@ static void Unpack_ODK_ParsedLicense(ODK_Message* msg, ODK_ParsedLicense* obj) {
obj->license_type = (OEMCrypto_LicenseType)Unpack_enum(msg);
Unpack_bool(msg, &obj->nonce_required);
Unpack_ODK_TimerLimits(msg, &obj->timer_limits);
Unpack_uint32_t(msg, &obj->watermarking);
Unpack_uint8_t(msg, &obj->dtcp2_required.dtcp2_required);
if (obj->dtcp2_required.dtcp2_required) {
Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.id);
Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.extension);
Unpack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_0.length);
Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.data);
Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.id);
Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.extension);
Unpack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_1.length);
Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[0]);
Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[1]);
Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[2]);
Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.id);
Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.extension);
Unpack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_2.length);
Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[0]);
Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[1]);
Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[2]);
} else {
obj->dtcp2_required.dtcp2_required = 0;
obj->dtcp2_required.cmi_descriptor_0.id = 0;
obj->dtcp2_required.cmi_descriptor_0.extension = 0;
obj->dtcp2_required.cmi_descriptor_0.length = 0;
obj->dtcp2_required.cmi_descriptor_0.data = 0;
obj->dtcp2_required.cmi_descriptor_1.id = 0;
obj->dtcp2_required.cmi_descriptor_1.extension = 0;
obj->dtcp2_required.cmi_descriptor_1.length = 0;
obj->dtcp2_required.cmi_descriptor_1.data[0] = 0;
obj->dtcp2_required.cmi_descriptor_1.data[1] = 0;
obj->dtcp2_required.cmi_descriptor_1.data[2] = 0;
obj->dtcp2_required.cmi_descriptor_2.id = 0;
obj->dtcp2_required.cmi_descriptor_2.extension = 0;
obj->dtcp2_required.cmi_descriptor_2.length = 0;
obj->dtcp2_required.cmi_descriptor_2.data[0] = 0;
obj->dtcp2_required.cmi_descriptor_2.data[1] = 0;
obj->dtcp2_required.cmi_descriptor_2.data[2] = 0;
}
Unpack_uint32_t(msg, &obj->key_array_length);
if (obj->key_array_length > ODK_MAX_NUM_KEYS) {
ODK_Message_SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR);
return;
}
uint32_t i;
for (i = 0; i < obj->key_array_length; i++) {
Unpack_OEMCrypto_KeyObject(msg, &obj->key_array[i]);
}
}
static void Unpack_ODK_ParsedLicenseV16(ODK_Message* msg,
ODK_ParsedLicenseV16* obj) {
Unpack_OEMCrypto_Substring(msg, &obj->enc_mac_keys_iv);
Unpack_OEMCrypto_Substring(msg, &obj->enc_mac_keys);
Unpack_OEMCrypto_Substring(msg, &obj->pst);
Unpack_OEMCrypto_Substring(msg, &obj->srm_restriction_data);
obj->license_type = (OEMCrypto_LicenseType)Unpack_enum(msg);
Unpack_bool(msg, &obj->nonce_required);
Unpack_ODK_TimerLimits(msg, &obj->timer_limits);
Unpack_uint32_t(msg, &obj->key_array_length);
if (obj->key_array_length > ODK_MAX_NUM_KEYS) {
ODK_Message_SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR);
@@ -197,6 +312,16 @@ void Unpack_ODK_PreparedProvisioningRequest(
UnpackArray(msg, &obj->device_id[0], sizeof(obj->device_id));
}
void Unpack_ODK_PreparedRenewedProvisioningRequest(
ODK_Message* msg, ODK_PreparedRenewedProvisioningRequest* 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));
Unpack_uint16_t(msg, &obj->renewal_type);
Unpack_uint32_t(msg, &obj->renewal_data_length);
UnpackArray(msg, &obj->renewal_data[0], obj->renewal_data_length);
}
void Unpack_ODK_PreparedCommonRequest(ODK_Message* msg,
ODK_PreparedCommonRequest* obj) {
Unpack_ODK_CoreMessage(msg, &obj->core_message);
@@ -206,6 +331,12 @@ void Unpack_ODK_PreparedCommonRequest(ODK_Message* msg,
void Unpack_ODK_LicenseResponse(ODK_Message* msg, ODK_LicenseResponse* obj) {
Unpack_ODK_PreparedLicenseRequest(msg, &obj->request);
Unpack_ODK_ParsedLicense(msg, obj->parsed_license);
}
void Unpack_ODK_LicenseResponseV16(ODK_Message* msg,
ODK_LicenseResponseV16* obj) {
Unpack_ODK_PreparedLicenseRequest(msg, &obj->request);
Unpack_ODK_ParsedLicenseV16(msg, &obj->parsed_license);
UnpackArray(msg, &obj->request_hash[0], sizeof(obj->request_hash));
}

View File

@@ -1,5 +1,5 @@
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// source code may only be used and distributed under the Widevine
// License Agreement.
/*
@@ -22,15 +22,22 @@ void Pack_ODK_PreparedRenewalRequest(ODK_Message* msg,
const ODK_PreparedRenewalRequest* obj);
void Pack_ODK_PreparedProvisioningRequest(
ODK_Message* msg, const ODK_PreparedProvisioningRequest* obj);
void Pack_ODK_PreparedRenewedProvisioningRequest(
ODK_Message* msg, const ODK_PreparedRenewedProvisioningRequest* obj);
/* odk unpack */
void Unpack_ODK_CoreMessage(ODK_Message* msg, ODK_CoreMessage* obj);
void Unpack_ODK_LicenseResponse(ODK_Message* msg, ODK_LicenseResponse* obj);
void Unpack_ODK_LicenseResponseV16(ODK_Message* msg,
ODK_LicenseResponseV16* 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(ODK_Message* msg, const ODK_LicenseResponse* obj);
void Pack_ODK_LicenseResponseV16(ODK_Message* msg,
const ODK_LicenseResponseV16* obj);
void Pack_ODK_RenewalResponse(ODK_Message* msg, const ODK_RenewalResponse* obj);
void Pack_ODK_ProvisioningResponse(ODK_Message* msg,
const ODK_ProvisioningResponse* obj);
@@ -42,6 +49,8 @@ void Unpack_ODK_PreparedRenewalRequest(ODK_Message* msg,
ODK_PreparedRenewalRequest* obj);
void Unpack_ODK_PreparedProvisioningRequest(
ODK_Message* msg, ODK_PreparedProvisioningRequest* obj);
void Unpack_ODK_PreparedRenewedProvisioningRequest(
ODK_Message* msg, ODK_PreparedRenewedProvisioningRequest* obj);
void Unpack_ODK_PreparedCommonRequest(ODK_Message* msg,
ODK_PreparedCommonRequest* obj);

View File

@@ -1,5 +1,5 @@
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// source code may only be used and distributed under the Widevine
// License Agreement.
#ifndef WIDEVINE_ODK_SRC_ODK_STRUCTS_PRIV_H_
@@ -24,6 +24,7 @@ typedef uint32_t ODK_MessageType;
#define ODK_Renewal_Response_Type ((ODK_MessageType)4u)
#define ODK_Provisioning_Request_Type ((ODK_MessageType)5u)
#define ODK_Provisioning_Response_Type ((ODK_MessageType)6u)
#define ODK_Renewed_Provisioning_Request_Type ((ODK_MessageType)11u)
// Reserve future message types to support forward compatibility.
#define ODK_Release_Request_Type ((ODK_MessageType)7u)
@@ -32,8 +33,8 @@ typedef uint32_t ODK_MessageType;
#define ODK_Common_Response_Type ((ODK_MessageType)10u)
typedef struct {
ODK_MessageType message_type;
uint32_t message_length;
ODK_MessageType message_type; // Type of core message (defined above)
uint32_t message_length; // Length of core message.
ODK_NonceValues nonce_values;
} ODK_CoreMessage;
@@ -52,16 +53,42 @@ typedef struct {
uint8_t device_id[ODK_DEVICE_ID_LEN_MAX];
} ODK_PreparedProvisioningRequest;
typedef struct {
ODK_CoreMessage core_message;
uint32_t device_id_length;
uint8_t device_id[ODK_DEVICE_ID_LEN_MAX];
uint16_t renewal_type;
uint32_t renewal_data_length;
uint8_t renewal_data[ODK_KEYBOX_RENEWAL_DATA_SIZE];
} ODK_PreparedRenewedProvisioningRequest;
typedef struct {
ODK_CoreMessage core_message;
} ODK_PreparedCommonRequest;
typedef struct {
OEMCrypto_Substring enc_mac_keys_iv;
OEMCrypto_Substring enc_mac_keys;
OEMCrypto_Substring pst;
OEMCrypto_Substring srm_restriction_data;
OEMCrypto_LicenseType license_type;
bool nonce_required;
ODK_TimerLimits timer_limits;
uint32_t key_array_length;
OEMCrypto_KeyObject key_array[ODK_MAX_NUM_KEYS];
} ODK_ParsedLicenseV16;
typedef struct {
ODK_PreparedLicenseRequest request;
ODK_ParsedLicense* parsed_license;
uint8_t request_hash[ODK_SHA256_HASH_SIZE];
} ODK_LicenseResponse;
typedef struct {
ODK_PreparedLicenseRequest request;
ODK_ParsedLicenseV16 parsed_license;
uint8_t request_hash[ODK_SHA256_HASH_SIZE];
} ODK_LicenseResponseV16;
typedef struct {
ODK_PreparedRenewalRequest request;
uint64_t renewal_duration_seconds;
@@ -76,26 +103,27 @@ typedef struct {
// without any padding added by the compiler. Make sure they get updated when
// request structs change. Refer to test suite OdkSizeTest in
// ../test/odk_test.cpp for validations of each of the defined request sizes.
#define ODK_LICENSE_REQUEST_SIZE 20
#define ODK_RENEWAL_REQUEST_SIZE 28
#define ODK_PROVISIONING_REQUEST_SIZE 88
#define ODK_LICENSE_REQUEST_SIZE 20u
#define ODK_RENEWAL_REQUEST_SIZE 28u
#define ODK_PROVISIONING_REQUEST_SIZE 88u
#define ODK_RENEWED_PROVISIONING_REQUEST_SIZE 1694u
// These are the possible timer status values.
#define ODK_CLOCK_TIMER_STATUS_UNDEFINED 0 // Should not happen.
#define ODK_CLOCK_TIMER_STATUS_UNDEFINED 0u // Should not happen.
// When the structure has been initialized, but no license is loaded.
#define ODK_CLOCK_TIMER_STATUS_LICENSE_NOT_LOADED 1
#define ODK_CLOCK_TIMER_STATUS_LICENSE_NOT_LOADED 1u
// After the license is loaded, before a successful decrypt.
#define ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED 2
#define ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED 2u
// After the license is loaded, if a renewal has also been loaded.
#define ODK_CLOCK_TIMER_STATUS_RENEWAL_LOADED 3
#define ODK_CLOCK_TIMER_STATUS_RENEWAL_LOADED 3u
// The first decrypt has occurred and the timer is active.
#define ODK_CLOCK_TIMER_STATUS_ACTIVE 4
#define ODK_CLOCK_TIMER_STATUS_ACTIVE 4u
// The first decrypt has occurred and the timer is unlimited.
#define ODK_CLOCK_TIMER_STATUS_UNLIMITED 5
#define ODK_CLOCK_TIMER_STATUS_UNLIMITED 5u
// The timer has transitioned from active to expired.
#define ODK_CLOCK_TIMER_STATUS_EXPIRED 6
#define ODK_CLOCK_TIMER_STATUS_EXPIRED 6u
// The license has been marked as inactive.
#define ODK_CLOCK_TIMER_STATUS_LICENSE_INACTIVE 7
#define ODK_CLOCK_TIMER_STATUS_LICENSE_INACTIVE 7u
// A helper function for computing timer limits when a renewal is loaded.
OEMCryptoResult ODK_ComputeRenewalDuration(const ODK_TimerLimits* timer_limits,

View File

@@ -1,5 +1,5 @@
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// source code may only be used and distributed under the Widevine
// License Agreement.
#include <stdint.h>
@@ -71,7 +71,7 @@ static OEMCryptoResult ODK_CheckRentalWindow(
/* rental_clock = time since license signed. */
uint64_t rental_clock = 0;
if (odk_sub_overflow_u64(system_time_seconds,
clock_values->time_of_license_signed,
clock_values->time_of_license_request_signed,
&rental_clock)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
@@ -180,7 +180,7 @@ OEMCryptoResult ODK_ComputeRenewalDuration(const ODK_TimerLimits* timer_limits,
}
/* If this is before the license was signed, something is odd. Return an
* error. */
if (system_time_seconds < clock_values->time_of_license_signed) {
if (system_time_seconds < clock_values->time_of_license_request_signed) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
@@ -297,7 +297,7 @@ OEMCryptoResult ODK_InitializeClockValues(ODK_ClockValues* clock_values,
if (clock_values == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
clock_values->time_of_license_signed = system_time_seconds;
clock_values->time_of_license_request_signed = system_time_seconds;
clock_values->time_of_first_decrypt = 0;
clock_values->time_of_last_decrypt = 0;
clock_values->time_when_timer_expires = 0;
@@ -308,7 +308,7 @@ OEMCryptoResult ODK_InitializeClockValues(ODK_ClockValues* clock_values,
/* This is called when OEMCrypto reloads a usage entry. */
OEMCryptoResult ODK_ReloadClockValues(ODK_ClockValues* clock_values,
uint64_t time_of_license_signed,
uint64_t time_of_license_request_signed,
uint64_t time_of_first_decrypt,
uint64_t time_of_last_decrypt,
enum OEMCrypto_Usage_Entry_Status status,
@@ -316,7 +316,7 @@ OEMCryptoResult ODK_ReloadClockValues(ODK_ClockValues* clock_values,
if (clock_values == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
clock_values->time_of_license_signed = time_of_license_signed;
clock_values->time_of_license_request_signed = time_of_license_request_signed;
clock_values->time_of_first_decrypt = time_of_first_decrypt;
clock_values->time_of_last_decrypt = time_of_last_decrypt;
clock_values->time_when_timer_expires = 0;
@@ -336,7 +336,7 @@ OEMCryptoResult ODK_AttemptFirstPlayback(uint64_t system_time_seconds,
/* All times are relative to when the license was signed. */
uint64_t rental_time = 0;
if (odk_sub_overflow_u64(system_time_seconds,
clock_values->time_of_license_signed,
clock_values->time_of_license_request_signed,
&rental_time)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}

View File

@@ -1,5 +1,5 @@
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// source code may only be used and distributed under the Widevine
// License Agreement.
#include "odk_util.h"
@@ -24,11 +24,10 @@ int crypto_memcmp(const void* in_a, const void* in_b, size_t len) {
return x;
}
bool ODK_NonceValuesEqual(const ODK_NonceValues* a, const ODK_NonceValues* b) {
bool ODK_NonceValuesEqualExcludingVersion(const ODK_NonceValues* a,
const ODK_NonceValues* b) {
if (a == NULL || b == NULL) {
return (a == b);
}
return (a->api_major_version == b->api_major_version &&
a->api_minor_version == b->api_minor_version &&
a->nonce == b->nonce && a->session_id == b->session_id);
return (a->nonce == b->nonce && a->session_id == b->session_id);
}

View File

@@ -1,5 +1,5 @@
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// source code may only be used and distributed under the Widevine
// License Agreement.
#ifndef WIDEVINE_ODK_SRC_ODK_UTIL_H_
@@ -20,7 +20,8 @@ extern "C" {
* return value when a != b is undefined, other than being non-zero. */
int crypto_memcmp(const void* a, const void* b, size_t len);
bool ODK_NonceValuesEqual(const ODK_NonceValues* a, const ODK_NonceValues* b);
bool ODK_NonceValuesEqualExcludingVersion(const ODK_NonceValues* a,
const ODK_NonceValues* b);
#ifdef __cplusplus
} // extern "C"

View File

@@ -1,5 +1,5 @@
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// source code may only be used and distributed under the Widevine
// License Agreement.
#include "serialization_base.h"
@@ -29,7 +29,8 @@ 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), (void*)ptr, count);
memcpy((void*)(message_impl->base + message_impl->size), (const void*)ptr,
count);
message_impl->size += count;
} else {
message_impl->status = MESSAGE_STATUS_OVERFLOW_ERROR;
@@ -37,7 +38,7 @@ static void PackBytes(ODK_Message* message, const uint8_t* ptr, size_t count) {
}
void Pack_enum(ODK_Message* message, int value) {
uint32_t v32 = value;
uint32_t v32 = (uint32_t)value;
Pack_uint32_t(message, &v32);
}
@@ -48,6 +49,13 @@ void Pack_bool(ODK_Message* message, const bool* value) {
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};
@@ -113,6 +121,13 @@ void Unpack_bool(ODK_Message* message, bool* 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};
@@ -154,10 +169,18 @@ void Unpack_OEMCrypto_Substring(ODK_Message* message,
/* 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_impl->capacity -
* message_impl->size or offset + length + message_impl->size <
* message_impl->capacity
*
* 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) ||

View File

@@ -1,5 +1,5 @@
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// source code may only be used and distributed under the Widevine
// License Agreement.
#ifndef WIDEVINE_ODK_SRC_SERIALIZATION_BASE_H_
@@ -17,6 +17,7 @@ extern "C" {
void Pack_enum(ODK_Message* message, int value);
void Pack_bool(ODK_Message* message, const bool* value);
void Pack_uint8_t(ODK_Message* message, const uint8_t* 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);
@@ -26,6 +27,7 @@ void Pack_OEMCrypto_Substring(ODK_Message* message,
int Unpack_enum(ODK_Message* message);
void Unpack_bool(ODK_Message* message, bool* value);
void Unpack_uint8_t(ODK_Message* message, uint8_t* 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);