Revert "Merge latest oemcrypto-v17 change"

This reverts commit 642965c678.

Reason for revert: Droidfood Blocking Bug: 217145027

Change-Id: I669b72fcd91c62e28883b5f55eb36af274d85806
(cherry picked from commit 8dbea15e5da05b371572297041454569dc166c90)
Merged-In:I669b72fcd91c62e28883b5f55eb36af274d85806
This commit is contained in:
Daniel Chapin
2022-01-31 19:21:18 +00:00
committed by Android Build Coastguard Worker
parent 1397b61f87
commit d69b488be1
176 changed files with 296842 additions and 301106 deletions

View File

@@ -52,7 +52,6 @@ cc_library_static {
srcs: [
"src/core_message_deserialize.cpp",
"src/core_message_features.cpp",
"src/core_message_serialize.cpp",
"src/core_message_serialize_proto.cpp",
],

View File

@@ -89,9 +89,6 @@ typedef enum OEMCryptoResult {
OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION = 59,
OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION = 60,
OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING = 61,
OEMCrypto_ERROR_UNSUPPORTED_CIPHER = 62,
OEMCrypto_ERROR_DVR_FORBIDDEN = 63,
OEMCrypto_ERROR_INSUFFICIENT_PRIVILEGE = 64,
OEMCrypto_ERROR_INVALID_KEY = 65,
/* ODK return values */
ODK_ERROR_BASE = 1000,
@@ -146,62 +143,6 @@ typedef struct {
size_t length;
} OEMCrypto_Substring;
/**
* Used to specify information about CMI Descriptor 0.
* @param id: ID value of CMI Descriptor assigned by DTLA.
* @param length: byte length of the usage rules field.
* @param data: usage rules data.
*/
typedef struct {
uint8_t id; // 0x00
uint8_t extension; // 0x00
uint16_t length; // 0x01
uint8_t data;
} OEMCrypto_DTCP2_CMI_Descriptor_0;
/**
* Used to specify information about CMI Descriptor 1.
* @param id: ID value of CMI Descriptor assigned by DTLA.
* @param extension: specified by the CMI descriptor
* @param length: byte length of the usage rules field.
* @param data: usage rules data.
*/
typedef struct {
uint8_t id; // 0x01
uint8_t extension; // 0x00
uint16_t length; // 0x03
uint8_t data[3];
} OEMCrypto_DTCP2_CMI_Descriptor_1;
/**
* Used to specify information about CMI Descriptor 2.
* @param id: ID value of CMI Descriptor assigned by DTLA.
* @param extension: specified by the CMI descriptor
* @param length: byte length of the usage rules field.
* @param data: usage rules data.
*/
typedef struct {
uint8_t id; // 0x02
uint8_t extension; // 0x00
uint16_t length; // 0x03
uint8_t data[3];
} OEMCrypto_DTCP2_CMI_Descriptor_2;
/**
* Used to specify the required DTCP2 level. If dtcp2_required is 0, there are
* no requirements on any of the keys. If dtcp2_required is 1, any key with the
* kControlHDCPRequired bit set requires DTCP2 in its output.
* @param dtcp2_required: specifies whether dtcp2 is required. 0 = not required,
* 1 = DTCP2 required.
* @param cmi_descriptor_1: three bytes of CMI descriptor 1
*/
typedef struct {
uint8_t dtcp2_required; // 0 = not required. 1 = DTCP2 v1 required.
OEMCrypto_DTCP2_CMI_Descriptor_0 cmi_descriptor_0;
OEMCrypto_DTCP2_CMI_Descriptor_1 cmi_descriptor_1;
OEMCrypto_DTCP2_CMI_Descriptor_2 cmi_descriptor_2;
} OEMCrypto_DTCP2_CMI_Packet;
/**
* Points to the relevant fields for a content key. The fields are extracted
* from the License Response message offered to OEMCrypto_LoadKeys(). Each

View File

@@ -1,44 +0,0 @@
// Copyright 2021 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
#ifndef WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_FEATURES_H_
#define WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_FEATURES_H_
#include <stdint.h>
#include <iostream>
#include <string>
namespace oemcrypto_core_message {
namespace features {
// Features that may be supported by core messages. By restricting values in
// this structure, we can turn off features at runtime. This is plain data, and
// is essentially a version number.
struct CoreMessageFeatures {
// A default set of features.
static const CoreMessageFeatures kDefaultFeatures;
// Create the default feature set for the given major version number.
static CoreMessageFeatures DefaultFeatures(uint32_t maximum_major_version);
// This is the published version of the ODK Core Message library. The default
// behavior is for the server to restrict messages to at most this version
// number. The default is 16.5, the last version used by Chrome. This will
// change to 17.0 when v17 has been released.
uint32_t maximum_major_version = 17;
uint32_t maximum_minor_version = 0;
bool operator==(const CoreMessageFeatures &other) const;
bool operator!=(const CoreMessageFeatures &other) const {
return !(*this == other);
}
};
std::ostream &operator<<(std::ostream &os, const CoreMessageFeatures &features);
} // namespace features
} // namespace oemcrypto_core_message
#endif // WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_FEATURES_H_

View File

@@ -17,27 +17,23 @@
#ifndef WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_H_
#define WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_H_
#include "core_message_features.h"
#include "core_message_types.h"
#include "odk_structs.h"
namespace oemcrypto_core_message {
namespace serialize {
using oemcrypto_core_message::features::CoreMessageFeatures;
/**
* Counterpart (serializer) of ODK_ParseLicense (deserializer)
* struct-input variant
*
* Parameters:
* [in] features feature support for response message.
* [in] parsed_lic
* [in] core_request
* [in] core_request_sha256
* [out] oemcrypto_core_message
*/
bool CreateCoreLicenseResponse(const CoreMessageFeatures& features,
const ODK_ParsedLicense& parsed_lic,
bool CreateCoreLicenseResponse(const ODK_ParsedLicense& parsed_lic,
const ODK_LicenseRequest& core_request,
const std::string& core_request_sha256,
std::string* oemcrypto_core_message);
@@ -46,13 +42,11 @@ bool CreateCoreLicenseResponse(const CoreMessageFeatures& features,
* Counterpart (serializer) of ODK_ParseRenewal (deserializer)
*
* Parameters:
* [in] features feature support for response message.
* [in] core_request
* [in] renewal_duration_seconds
* [out] oemcrypto_core_message
*/
bool CreateCoreRenewalResponse(const CoreMessageFeatures& features,
const ODK_RenewalRequest& core_request,
bool CreateCoreRenewalResponse(const ODK_RenewalRequest& core_request,
uint64_t renewal_duration_seconds,
std::string* oemcrypto_core_message);
@@ -61,13 +55,11 @@ bool CreateCoreRenewalResponse(const CoreMessageFeatures& features,
* struct-input variant
*
* Parameters:
* [in] features feature support for response message.
* [in] parsed_prov
* [in] core_request
* [out] oemcrypto_core_message
*/
bool CreateCoreProvisioningResponse(const CoreMessageFeatures& features,
const ODK_ParsedProvisioning& parsed_prov,
bool CreateCoreProvisioningResponse(const ODK_ParsedProvisioning& parsed_prov,
const ODK_ProvisioningRequest& core_request,
std::string* oemcrypto_core_message);
} // namespace serialize

View File

@@ -17,46 +17,41 @@
#include <cstdint>
#include <string>
#include "core_message_features.h"
#include "core_message_types.h"
#include "license_protocol.pb.h"
namespace oemcrypto_core_message {
namespace serialize {
// @ public create response (serializer) functions accepting proto input
/**
* Counterpart (serializer) of ODK_ParseLicense (deserializer)
*
* Parameters:
* [in] features feature support for response message.
* [in] serialized_license
serialized video_widevine::License
* [in] core_request oemcrypto core message from request.
* [in] core_request_sha256 - hash of serialized core request.
* [in] nonce_required - if the device should require a nonce match.
* [in] uses_padding - if the keys use padding.
* [out] oemcrypto_core_message - the serialized oemcrypto core response.
*/
bool CreateCoreLicenseResponseFromProto(
const oemcrypto_core_message::features::CoreMessageFeatures& features,
const std::string& serialized_license,
const ODK_LicenseRequest& core_request,
const std::string& core_request_sha256, const bool nonce_required,
const bool uses_padding, std::string* oemcrypto_core_message);
bool CreateCoreLicenseResponseFromProto(const std::string& serialized_license,
const ODK_LicenseRequest& core_request,
const std::string& core_request_sha256,
const bool nonce_required,
std::string* oemcrypto_core_message);
/**
* Counterpart (serializer) of ODK_ParseProvisioning (deserializer)
*
* Parameters:
* [in] features feature support for response message.
* [in] serialized_provisioning_response
* serialized video_widevine::ProvisioningResponse
* [in] core_request
* [out] oemcrypto_core_message
*/
bool CreateCoreProvisioningResponseFromProto(
const oemcrypto_core_message::features::CoreMessageFeatures& features,
const std::string& serialized_provisioning_response,
const ODK_ProvisioningRequest& core_request,
std::string* oemcrypto_core_message);

View File

@@ -132,11 +132,11 @@ OEMCryptoResult ODK_InitializeClockValues(ODK_ClockValues* clock_values,
* This function sets the values in the clock_values structure. It shall be
* called from OEMCrypto_LoadUsageEntry. When a usage entry from a v15 or
* earlier license is loaded, the value time_of_license_loaded shall be used
* in place of time_of_license_request_signed.
* in place of time_of_license_signed.
*
* @param[in,out] clock_values: the session's clock data.
* @param[in] time_of_license_request_signed: the value time_license_received
* from the loaded usage entry.
* @param[in] time_of_license_signed: the value time_license_received from the
* loaded usage entry.
* @param[in] time_of_first_decrypt: the value time_of_first_decrypt from the
* loaded usage entry.
* @param[in] time_of_last_decrypt: the value time_of_last_decrypt from the
@@ -152,7 +152,7 @@ OEMCryptoResult ODK_InitializeClockValues(ODK_ClockValues* clock_values,
* This method is new in version 16 of the API.
*/
OEMCryptoResult ODK_ReloadClockValues(ODK_ClockValues* clock_values,
uint64_t time_of_license_request_signed,
uint64_t time_of_license_signed,
uint64_t time_of_first_decrypt,
uint64_t time_of_last_decrypt,
enum OEMCrypto_Usage_Entry_Status status,
@@ -469,6 +469,8 @@ OEMCryptoResult ODK_RefreshV15Values(const ODK_TimerLimits* timer_limits,
* and false when called for OEMCrypto_ReloadLicense.
* @param[in] usage_entry_present: true if the session has a new usage entry
* associated with it created via OEMCrypto_CreateNewUsageEntry.
* @param[in] request_hash: the hash of the license request core message. This
* was computed by OEMCrypto when the license request was signed.
* @param[in,out] timer_limits: The session's timer limits. These will be
* updated.
* @param[in,out] clock_values: The session's clock values. These will be
@@ -490,6 +492,7 @@ OEMCryptoResult ODK_RefreshV15Values(const ODK_TimerLimits* timer_limits,
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_SHA256_HASH_SIZE],
ODK_TimerLimits* timer_limits, ODK_ClockValues* clock_values,
ODK_NonceValues* nonce_values, ODK_ParsedLicense* parsed_license);
@@ -595,20 +598,6 @@ OEMCryptoResult ODK_ParseProvisioning(
const ODK_NonceValues* nonce_values, const uint8_t* device_id,
size_t device_id_length, ODK_ParsedProvisioning* parsed_response);
/**
* The function ODK_ParseProvisioning will parse the message and verify the
* API version is at most the version passed in.
*
* @param[in] nonce_values: pointer to the session's nonce data.
* @param[in] major_versioh: current API major version.
* @param[in] minor_version: current API minor version.
*
* @version
* This method is new in version 17 of the API.
*/
bool CheckApiVersionAtMost(const ODK_NonceValues* nonce_values,
uint16_t major_version, uint16_t minor_version);
/// @}
#ifdef __cplusplus

View File

@@ -1,6 +1,8 @@
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
/*
* Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
* source code may only be used and distributed under the Widevine
* License Agreement.
*/
#ifndef WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_H_
#define WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_H_
@@ -35,10 +37,10 @@ extern "C" {
*/
#if defined(__GNUC__) || defined(__clang__)
#define ALIGNED __attribute__((aligned))
# define ALIGNED __attribute__((aligned))
#else
#define ALIGNED
#error ODK_Message must be aligned to the maximum useful alignment of the \
# define ALIGNED
# error ODK_Message must be aligned to the maximum useful alignment of the \
machine you are compiling for. Define the ALIGNED macro accordingly.
#endif

View File

@@ -5,21 +5,21 @@
#ifndef WIDEVINE_ODK_INCLUDE_ODK_STRUCTS_H_
#define WIDEVINE_ODK_INCLUDE_ODK_STRUCTS_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "OEMCryptoCENCCommon.h"
#include "odk_target.h"
/* The version of this library. */
#define ODK_MAJOR_VERSION 17
#define ODK_MINOR_VERSION 0
#define ODK_MAJOR_VERSION 16
// TODO(b/163416999): Do not change minor version to 16.5 on master branch. The
// version 16.5 is reserved for Alcatraz, iOS, and other L3 platforms using
// third-party obfuscation tools. The version should not be used for CE CDM or
// Android CDM. We should jump straight to 17.0.
#define ODK_MINOR_VERSION 4
/* ODK Version string. Date changed automatically on each release. */
#define ODK_RELEASE_DATE "ODK v17.0 2022-01-24"
#define ODK_RELEASE_DATE "ODK v16.4 2020-10-23"
/* The lowest version number for an ODK message. */
#define ODK_FIRST_VERSION 16
@@ -89,9 +89,9 @@ typedef struct {
* on OEMCrypto's system clock, as described in the document "License
* Duration and Renewal".
*
* @param time_of_license_request_signed: Time that the license request was
* signed, based on OEMCrypto's system clock. This value shall be stored
* and reloaded with usage entry as time_of_license_received.
* @param time_of_license_signed: Time that the license request was signed,
* based on OEMCrypto's system clock. This value shall be stored and
* reloaded with usage entry as time_of_license_received.
* @param time_of_first_decrypt: Time of the first decrypt or call select key,
* based on OEMCrypto's system clock. This is 0 if the license has not
* been used to decrypt any data. This value shall be stored and reloaded
@@ -114,7 +114,7 @@ typedef struct {
* This struct changed in API version 16.2.
*/
typedef struct {
uint64_t time_of_license_request_signed;
uint64_t time_of_license_signed;
uint64_t time_of_first_decrypt;
uint64_t time_of_last_decrypt;
uint64_t time_of_renewal_request;
@@ -175,13 +175,11 @@ typedef struct {
* entitlement keys.
* @param nonce_required: indicates if the license requires a nonce.
* @param timer_limits: time limits of the for the license.
* @param watermarking: specifies if device supports watermarking.
* @param dtcp2_required: specifies if device supports DTCP.
* @param key_array_length: number of keys present.
* @param key_array: set of keys to be installed.
*
* @version
* This struct changed in API version 17.
* This struct changed in API version 16.2.
*/
typedef struct {
OEMCrypto_Substring enc_mac_keys_iv;
@@ -191,8 +189,6 @@ typedef struct {
OEMCrypto_LicenseType license_type;
bool nonce_required;
ODK_TimerLimits timer_limits;
uint32_t watermarking;
OEMCrypto_DTCP2_CMI_Packet dtcp2_required;
uint32_t key_array_length;
OEMCrypto_KeyObject key_array[ODK_MAX_NUM_KEYS];
} ODK_ParsedLicense;
@@ -220,8 +216,4 @@ typedef struct {
/// @}
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WIDEVINE_ODK_INCLUDE_ODK_STRUCTS_H_

View File

@@ -60,7 +60,7 @@ bool ParseRequest(uint32_t message_type,
} else if (core_request->api_major_version == 16) {
// For version 16, we demand a minor version of at least 2.
// We accept 16.2, 16.3, or higher.
if (core_request->api_minor_version < 2) return false;
if (core_request->api_major_version < 2) return false;
} else {
// Other versions do not (yet) have a restriction on minor number.
// In particular, future versions are accepted for forward compatibility.

View File

@@ -1,41 +0,0 @@
// 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 = 0; // 17.0
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

@@ -20,22 +20,18 @@ namespace serialize {
namespace {
/**
* Template for copying nonce values from request to response, and also
* computing the API version of the response.
* 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>
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.
template <typename T, typename S, typename P>
bool CreateResponse(uint32_t message_type, const S& core_request,
std::string* oemcrypto_core_message, T& response,
const P& packer) {
if (!oemcrypto_core_message) {
return false;
}
@@ -47,36 +43,9 @@ bool CreateResponseHeader(const CoreMessageFeatures& features,
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
* S: kdo input struct
* P: auto-generated serializing function for |T|
*/
template <typename T, typename S, typename P>
bool CreateResponse(ODK_MessageType message_type, const S& core_request,
std::string* oemcrypto_core_message, T& response,
const P& packer) {
if (!oemcrypto_core_message) {
return false;
}
auto* header = &response.request.core_message;
if (header->message_type != message_type ||
header->nonce_values.api_major_version < ODK_FIRST_VERSION) {
// This indicates CreateResponseHeader was not called.
return false;
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;
}
static constexpr size_t BUF_CAPACITY = 2048;
@@ -111,73 +80,33 @@ bool CopyDeviceId(const ODK_ProvisioningRequest& src,
} // namespace
bool CreateCoreLicenseResponse(const CoreMessageFeatures& features,
const ODK_ParsedLicense& parsed_lic,
bool CreateCoreLicenseResponse(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)};
if (!CreateResponseHeader(features, ODK_License_Response_Type, core_request,
license_response)) {
{}, const_cast<ODK_ParsedLicense*>(&parsed_lic), {0}};
if (core_request_sha256.size() != sizeof(license_response.request_hash))
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_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);
}
memcpy(license_response.request_hash, core_request_sha256.data(),
sizeof(license_response.request_hash));
return CreateResponse(ODK_License_Response_Type, core_request,
oemcrypto_core_message, license_response,
Pack_ODK_LicenseResponse);
}
bool CreateCoreRenewalResponse(const CoreMessageFeatures& features,
const ODK_RenewalRequest& core_request,
bool CreateCoreRenewalResponse(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 CoreMessageFeatures& features,
const ODK_ParsedProvisioning& parsed_prov,
bool CreateCoreProvisioningResponse(const ODK_ParsedProvisioning& parsed_prov,
const ODK_ProvisioningRequest& core_request,
std::string* oemcrypto_core_message) {
ODK_ProvisioningResponse prov_response{
@@ -185,10 +114,6 @@ bool CreateCoreProvisioningResponse(const CoreMessageFeatures& features,
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

@@ -20,7 +20,6 @@
namespace oemcrypto_core_message {
namespace serialize {
namespace {
using oemcrypto_core_message::features::CoreMessageFeatures;
/* @ private functions */
@@ -42,23 +41,17 @@ OEMCrypto_Substring GetOecSubstring(const std::string& message,
}
OEMCrypto_KeyObject KeyContainerToOecKey(
const std::string& proto, const video_widevine::License::KeyContainer& k,
const bool uses_padding) {
const std::string& proto, const video_widevine::License::KeyContainer& k) {
OEMCrypto_KeyObject obj = {};
obj.key_id = GetOecSubstring(proto, k.id());
obj.key_data_iv = GetOecSubstring(proto, k.iv());
OEMCrypto_Substring key_data = GetOecSubstring(proto, k.key());
// Strip off PKCS#5 padding. A key can either be 16 of 32 bytes, but that
// makes it hard to know if a key (when 32 bytes) is a 16 byte key with
// padding or a 32 byte key without padding.
if (uses_padding) {
const size_t PKCS5_PADDING_SIZE = 16;
key_data.length -= PKCS5_PADDING_SIZE;
}
obj.key_data = key_data;
// Strip off PKCS#5 padding - since we know the key is 16 or 32 bytes,
// the padding will always be 16 bytes.
const std::string& key_data = k.key();
const size_t PKCS5_PADDING_SIZE = 16;
obj.key_data = GetOecSubstring(
proto, key_data.substr(0, std::max(PKCS5_PADDING_SIZE, key_data.size()) -
PKCS5_PADDING_SIZE));
if (k.has_key_control()) {
const auto& key_control = k.key_control();
obj.key_control_iv = GetOecSubstring(proto, key_control.iv());
@@ -71,12 +64,10 @@ OEMCrypto_KeyObject KeyContainerToOecKey(
// @ public create response functions
bool CreateCoreLicenseResponseFromProto(const CoreMessageFeatures& features,
const std::string& serialized_license,
bool CreateCoreLicenseResponseFromProto(const std::string& serialized_license,
const ODK_LicenseRequest& core_request,
const std::string& core_request_sha256,
const bool nonce_required,
const bool uses_padding,
std::string* oemcrypto_core_message) {
video_widevine::License lic;
if (!lic.ParseFromString(serialized_license)) {
@@ -111,8 +102,7 @@ bool CreateCoreLicenseResponseFromProto(const CoreMessageFeatures& features,
return false;
}
uint32_t& n = parsed_lic.key_array_length;
parsed_lic.key_array[n++] =
KeyContainerToOecKey(serialized_license, k, uses_padding);
parsed_lic.key_array[n++] = KeyContainerToOecKey(serialized_license, k);
break;
}
default: {
@@ -135,13 +125,12 @@ bool CreateCoreLicenseResponseFromProto(const CoreMessageFeatures& features,
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;
@@ -157,12 +146,11 @@ bool CreateCoreLicenseResponseFromProto(const CoreMessageFeatures& features,
policy.renewal_delay_seconds() +
policy.renewal_recovery_duration_seconds();
return CreateCoreLicenseResponse(features, parsed_lic, core_request,
return CreateCoreLicenseResponse(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) {
@@ -187,7 +175,7 @@ bool CreateCoreProvisioningResponseFromProto(
GetOecSubstring(serialized_provisioning_resp, prov.wrapping_key());
}
return CreateCoreProvisioningResponse(features, parsed_prov, core_request,
return CreateCoreProvisioningResponse(parsed_prov, core_request,
oemcrypto_core_message);
}

View File

@@ -91,65 +91,64 @@ static OEMCryptoResult ODK_PrepareRequest(
return OEMCrypto_SUCCESS;
}
/* 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) {
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) {
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. The core message
* is the part we are parsing. */
/* 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. */
ODK_Message_SetSize(&msg, core_message_length);
Unpack_ODK_CoreMessage(&msg, &core_message);
if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK ||
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) {
/* 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;
/* 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) {
return ODK_ERROR_CORE_MESSAGE;
}
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;
}
}
return OEMCrypto_SUCCESS;
}
@@ -163,7 +162,9 @@ OEMCryptoResult ODK_PrepareCoreLicenseRequest(
if (core_message_length == NULL || nonce_values == NULL) {
return ODK_ERROR_CORE_MESSAGE;
}
ODK_PreparedLicenseRequest license_request = {0};
ODK_PreparedLicenseRequest license_request = {
{0, 0, {}},
};
return ODK_PrepareRequest(
message, message_length, core_message_length, ODK_License_Request_Type,
nonce_values, &license_request, sizeof(ODK_PreparedLicenseRequest));
@@ -191,7 +192,7 @@ OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message,
return OEMCrypto_SUCCESS;
}
ODK_PreparedRenewalRequest renewal_request = {0};
ODK_PreparedRenewalRequest renewal_request = {{0, 0, {}}, 0};
/* First, we compute the time this request was made relative to the playback
* clock. */
if (clock_values->time_of_first_decrypt == 0) {
@@ -224,7 +225,11 @@ OEMCryptoResult ODK_PrepareCoreProvisioningRequest(
if (core_message_length == NULL || nonce_values == NULL) {
return ODK_ERROR_CORE_MESSAGE;
}
ODK_PreparedProvisioningRequest provisioning_request = {0};
ODK_PreparedProvisioningRequest provisioning_request = {
{0, 0, {}},
0,
{0},
};
if (device_id_length > sizeof(provisioning_request.device_id)) {
return ODK_ERROR_CORE_MESSAGE;
}
@@ -243,88 +248,47 @@ OEMCryptoResult ODK_PrepareCoreProvisioningRequest(
OEMCryptoResult ODK_ParseLicense(
const uint8_t* message, size_t message_length, size_t core_message_length,
bool initial_license_load, bool usage_entry_present,
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) {
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) {
return ODK_ERROR_CORE_MESSAGE;
}
const OEMCryptoResult err =
ODK_ParseCoreHeader(message, message_length, core_message_length,
ODK_License_Response_Type, nonce_values);
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));
if (err != OEMCrypto_SUCCESS) {
return err;
}
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;
}
/* 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;
}
/* 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) ||
@@ -351,6 +315,15 @@ 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;
@@ -369,27 +342,17 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
return ODK_ERROR_CORE_MESSAGE;
}
const OEMCryptoResult err =
ODK_ParseCoreHeader(message, message_length, core_message_length,
ODK_Renewal_Response_Type, NULL);
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));
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)
@@ -418,31 +381,21 @@ OEMCryptoResult ODK_ParseProvisioning(
parsed_response == NULL) {
return ODK_ERROR_CORE_MESSAGE;
}
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};
ODK_ProvisioningResponse provisioning_response = {{{0, 0, {}}, 0, {0}}, NULL};
provisioning_response.parsed_provisioning = parsed_response;
if (device_id_length > ODK_DEVICE_ID_LEN_MAX) {
return ODK_ERROR_CORE_MESSAGE;
}
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;
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;
}
if (crypto_memcmp(device_id, provisioning_response.request.device_id,
@@ -460,10 +413,3 @@ 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,15 +1,16 @@
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
/*
* Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
* source code may only be used and distributed under the Widevine
* License Agreement.
*/
#include "odk_message.h"
#include "odk_message_priv.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "odk_message_priv.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

View File

@@ -1,9 +1,11 @@
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
/*
* Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
* source code may only be used and distributed under the Widevine
* License Agreement.
*/
#ifndef WIDEVINE_ODK_SRC_ODK_MESSAGE_PRIV_H_
#define WIDEVINE_ODK_SRC_ODK_MESSAGE_PRIV_H_
#ifndef WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_PRIV_H_
#define WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_PRIV_H_
#ifdef __cplusplus
extern "C" {
@@ -16,8 +18,6 @@ extern "C" {
#include <stddef.h>
#include <stdint.h>
#include "odk_message.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
@@ -38,4 +38,4 @@ typedef struct {
} // extern "C"
#endif
#endif // WIDEVINE_ODK_SRC_ODK_MESSAGE_PRIV_H_
#endif // WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_PRIV_H_

View File

@@ -58,47 +58,6 @@ 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++) {
@@ -140,12 +99,6 @@ 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));
}
@@ -173,7 +126,7 @@ static void Unpack_ODK_NonceValues(ODK_Message* msg, ODK_NonceValues* obj) {
Unpack_uint32_t(msg, &obj->session_id);
}
void Unpack_ODK_CoreMessage(ODK_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);
@@ -205,64 +158,6 @@ 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);
@@ -311,12 +206,6 @@ 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

@@ -24,18 +24,13 @@ void Pack_ODK_PreparedProvisioningRequest(
ODK_Message* msg, const ODK_PreparedProvisioningRequest* 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);

View File

@@ -14,26 +14,24 @@
extern "C" {
#endif
// We use a typedef here so `ODK_CoreMessage` will contain "simple types" which
// should work better with the auto code generator.
typedef uint32_t ODK_MessageType;
typedef enum {
ODK_License_Request_Type = 1,
ODK_License_Response_Type = 2,
ODK_Renewal_Request_Type = 3,
ODK_Renewal_Response_Type = 4,
ODK_Provisioning_Request_Type = 5,
ODK_Provisioning_Response_Type = 6,
#define ODK_License_Request_Type ((ODK_MessageType)1u)
#define ODK_License_Response_Type ((ODK_MessageType)2u)
#define ODK_Renewal_Request_Type ((ODK_MessageType)3u)
#define ODK_Renewal_Response_Type ((ODK_MessageType)4u)
#define ODK_Provisioning_Request_Type ((ODK_MessageType)5u)
#define ODK_Provisioning_Response_Type ((ODK_MessageType)6u)
// Reserve future message types to support forward compatibility.
#define ODK_Release_Request_Type ((ODK_MessageType)7u)
#define ODK_Release_Response_Type ((ODK_MessageType)8u)
#define ODK_Common_Request_Type ((ODK_MessageType)9u)
#define ODK_Common_Response_Type ((ODK_MessageType)10u)
// Reserve future message types to support forward compatibility.
ODK_Release_Request_Type = 7,
ODK_Release_Response_Type = 8,
ODK_Common_Request_Type = 9,
ODK_Common_Response_Type = 10,
} ODK_MessageType;
typedef struct {
ODK_MessageType message_type; // Type of core message (defined above)
uint32_t message_length; // Length of core message.
uint32_t message_type;
uint32_t message_length;
ODK_NonceValues nonce_values;
} ODK_CoreMessage;
@@ -56,28 +54,11 @@ 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;
} ODK_LicenseResponse;
typedef struct {
ODK_PreparedLicenseRequest request;
ODK_ParsedLicenseV16 parsed_license;
uint8_t request_hash[ODK_SHA256_HASH_SIZE];
} ODK_LicenseResponseV16;
} ODK_LicenseResponse;
typedef struct {
ODK_PreparedRenewalRequest request;

View File

@@ -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_request_signed,
clock_values->time_of_license_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_request_signed) {
if (system_time_seconds < clock_values->time_of_license_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_request_signed = system_time_seconds;
clock_values->time_of_license_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_request_signed,
uint64_t time_of_license_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_request_signed = time_of_license_request_signed;
clock_values->time_of_license_signed = time_of_license_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_request_signed,
clock_values->time_of_license_signed,
&rental_time)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}

View File

@@ -24,10 +24,11 @@ int crypto_memcmp(const void* in_a, const void* in_b, size_t len) {
return x;
}
bool ODK_NonceValuesEqualExcludingVersion(const ODK_NonceValues* a,
const ODK_NonceValues* b) {
bool ODK_NonceValuesEqual(const ODK_NonceValues* a, const ODK_NonceValues* b) {
if (a == NULL || b == NULL) {
return (a == b);
}
return (a->nonce == b->nonce && a->session_id == b->session_id);
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);
}

View File

@@ -20,8 +20,7 @@ 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_NonceValuesEqualExcludingVersion(const ODK_NonceValues* a,
const ODK_NonceValues* b);
bool ODK_NonceValuesEqual(const ODK_NonceValues* a, const ODK_NonceValues* b);
#ifdef __cplusplus
} // extern "C"

View File

@@ -49,13 +49,6 @@ 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};
@@ -121,13 +114,6 @@ 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};
@@ -137,7 +123,7 @@ void Unpack_uint16_t(ODK_Message* message, uint16_t* value) {
}
void Unpack_uint32_t(ODK_Message* message, uint32_t* value) {
ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
ODK_Message_Impl* message_impl = GetMessageImpl(message);
if (!message_impl) return;
uint8_t data[4] = {0};
UnpackBytes(message, data, sizeof(data));
@@ -169,18 +155,10 @@ 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:
*
* 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
* 0 < offset and offset + length < message_impl->capacity -
* message_impl->size or offset + length + message_impl->size <
* message_impl->capacity
*/
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

@@ -17,23 +17,20 @@ 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);
void PackArray(ODK_Message* message, const uint8_t* base, size_t size);
void Pack_OEMCrypto_Substring(ODK_Message* message,
const OEMCrypto_Substring* obj);
void Pack_OEMCrypto_Substring(ODK_Message* msg, const OEMCrypto_Substring* obj);
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);
void UnpackArray(ODK_Message* message, uint8_t* address,
size_t size); /* copy out */
void Unpack_OEMCrypto_Substring(ODK_Message* message, OEMCrypto_Substring* obj);
void Unpack_OEMCrypto_Substring(ODK_Message* msg, OEMCrypto_Substring* obj);
#ifdef __cplusplus
} // extern "C"

View File

@@ -6,7 +6,6 @@
#include "odk.h"
namespace oemcrypto_core_message {
using features::CoreMessageFeatures;
bool convert_byte_to_valid_boolean(const bool* in) {
const char* buf = reinterpret_cast<const char*>(in);
@@ -68,8 +67,8 @@ OEMCryptoResult odk_deserialize_LicenseResponse(const uint8_t* message,
return ODK_ParseLicense(message, SIZE_MAX, core_message_length,
static_cast<bool>(a->initial_license_load),
static_cast<bool>(a->usage_entry_present),
&a->timer_limits, &a->clock_values, nonce_values,
parsed_lic);
a->request_hash, &a->timer_limits, &a->clock_values,
nonce_values, parsed_lic);
}
OEMCryptoResult odk_deserialize_RenewalResponse(
@@ -123,8 +122,7 @@ bool kdo_serialize_LicenseResponse(const ODK_ParseLicense_Args* args,
std::string core_request_sha_256(
reinterpret_cast<const char*>(args->request_hash), ODK_SHA256_HASH_SIZE);
return serialize::CreateCoreLicenseResponse(
CoreMessageFeatures::kDefaultFeatures, parsed_lic, core_request,
core_request_sha_256, oemcrypto_core_message);
parsed_lic, core_request, core_request_sha_256, oemcrypto_core_message);
}
bool kdo_serialize_RenewalResponse(
@@ -136,8 +134,7 @@ bool kdo_serialize_RenewalResponse(
nonce_values.api_minor_version, nonce_values.api_major_version,
nonce_values.nonce, nonce_values.session_id, renewal_msg.playback_time};
return serialize::CreateCoreRenewalResponse(
CoreMessageFeatures::kDefaultFeatures, core_request,
args->timer_limits.initial_renewal_duration_seconds,
core_request, args->timer_limits.initial_renewal_duration_seconds,
oemcrypto_core_message);
}
@@ -154,8 +151,7 @@ bool kdo_serialize_ProvisioningResponse(
nonce_values.nonce, nonce_values.session_id,
std::string(reinterpret_cast<const char*>(args->device_id),
args->device_id_length)};
return serialize::CreateCoreProvisioningResponse(
CoreMessageFeatures::kDefaultFeatures, parsed_prov, core_request,
oemcrypto_core_message);
return serialize::CreateCoreProvisioningResponse(parsed_prov, core_request,
oemcrypto_core_message);
}
} // namespace oemcrypto_core_message

View File

@@ -7,7 +7,6 @@
#include <memory>
#include <string>
#include "core_message_features.h"
#include "core_message_serialize.h"
#include "fuzzing/odk_fuzz_structs.h"
#include "odk_attributes.h"

View File

@@ -9,7 +9,6 @@
#include "OEMCryptoCENCCommon.h"
#include "core_message_deserialize.h"
#include "core_message_features.h"
#include "core_message_serialize.h"
#include "core_message_types.h"
#include "gtest/gtest.h"
@@ -28,34 +27,12 @@ using oemcrypto_core_message::deserialize::CoreLicenseRequestFromMessage;
using oemcrypto_core_message::deserialize::CoreProvisioningRequestFromMessage;
using oemcrypto_core_message::deserialize::CoreRenewalRequestFromMessage;
using oemcrypto_core_message::features::CoreMessageFeatures;
using oemcrypto_core_message::serialize::CreateCoreLicenseResponse;
using oemcrypto_core_message::serialize::CreateCoreProvisioningResponse;
using oemcrypto_core_message::serialize::CreateCoreRenewalResponse;
constexpr uint32_t kExtraPayloadSize = 128u;
/* Used to parameterize tests by version number. The request is given one
* version number, and we will expect the response to have another version
* number. */
struct VersionParameters {
uint32_t maximum_major_version;
uint16_t request_major_version;
uint16_t request_minor_version;
uint16_t response_major_version;
uint16_t response_minor_version;
};
// This function is called by GTest when a parameterized test fails in order
// to log the parameter used for the failing test.
void PrintTo(const VersionParameters& p, std::ostream* os) {
*os << "max=v" << p.maximum_major_version << ", request = v"
<< p.request_major_version << "." << p.request_minor_version
<< ", response = v" << p.response_major_version << "."
<< p.response_minor_version;
}
template <typename T, typename F, typename G>
void ValidateRequest(uint32_t message_type,
const std::vector<ODK_Field>& extra_fields,
@@ -134,13 +111,12 @@ void ValidateRequest(uint32_t message_type,
* G: kdo serializer
*/
template <typename T, typename F, typename G>
void ValidateResponse(const VersionParameters& versions,
ODK_CoreMessage* core_message,
void ValidateResponse(ODK_CoreMessage* core_message,
const std::vector<ODK_Field>& extra_fields,
const F& odk_parse_func, const G& kdo_prepare_func) {
T t = {};
t.api_major_version = versions.request_major_version;
t.api_minor_version = versions.request_minor_version;
t.api_minor_version = core_message->nonce_values.api_minor_version;
t.api_major_version = core_message->nonce_values.api_major_version;
t.nonce = core_message->nonce_values.nonce;
t.session_id = core_message->nonce_values.session_id;
@@ -154,15 +130,12 @@ void ValidateResponse(const VersionParameters& versions,
EXPECT_EQ(OEMCrypto_SUCCESS, ODK_IterFields(ODK_READ, zero, buf_size,
&bytes_read, extra_fields));
// Parse buf with odk
const OEMCryptoResult parse_result = odk_parse_func(buf, buf_size);
EXPECT_EQ(OEMCrypto_SUCCESS, parse_result);
// parse buf with odk
EXPECT_EQ(OEMCrypto_SUCCESS, odk_parse_func(buf, buf_size));
size_t size_out = 0;
if (parse_result != OEMCrypto_SUCCESS) {
ODK_IterFields(ODK_FieldMode::ODK_DUMP, buf, buf_size, &size_out,
extra_fields);
}
ODK_IterFields(ODK_FieldMode::ODK_DUMP, buf, buf_size, &size_out,
extra_fields);
// serialize odk output to oemcrypto_core_message
std::string oemcrypto_core_message;
@@ -276,6 +249,7 @@ TEST(OdkTest, NullResponseTest) {
constexpr size_t message_size = 64;
uint8_t message[message_size] = {0};
size_t core_message_length = message_size;
uint8_t request_hash[ODK_SHA256_HASH_SIZE] = {0};
ODK_TimerLimits timer_limits;
ODK_ParsedLicense parsed_license;
ODK_NonceValues nonce_values;
@@ -284,26 +258,30 @@ TEST(OdkTest, NullResponseTest) {
memset(&clock_values, 0, sizeof(clock_values));
// Assert that nullptr does not cause a core dump.
EXPECT_EQ(
ODK_ERROR_CORE_MESSAGE,
ODK_ParseLicense(message, message_size, core_message_length, true, true,
&timer_limits, &clock_values, &nonce_values, nullptr));
EXPECT_EQ(
ODK_ERROR_CORE_MESSAGE,
ODK_ParseLicense(message, message_size, core_message_length, true, true,
&timer_limits, &clock_values, nullptr, &parsed_license));
EXPECT_EQ(
ODK_ERROR_CORE_MESSAGE,
ODK_ParseLicense(message, message_size, core_message_length, true, true,
&timer_limits, nullptr, &nonce_values, &parsed_license));
EXPECT_EQ(
ODK_ERROR_CORE_MESSAGE,
ODK_ParseLicense(message, message_size, core_message_length, true, true,
nullptr, &clock_values, &nonce_values, &parsed_license));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_ParseLicense(message, message_size, core_message_length, true,
true, request_hash, &timer_limits, &clock_values,
&nonce_values, nullptr));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_ParseLicense(message, message_size, core_message_length, true,
true, request_hash, &timer_limits, &clock_values,
nullptr, &parsed_license));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_ParseLicense(message, message_size, core_message_length, true,
true, request_hash, &timer_limits, nullptr,
&nonce_values, &parsed_license));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_ParseLicense(message, message_size, core_message_length, true,
true, request_hash, nullptr, &clock_values,
&nonce_values, &parsed_license));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_ParseLicense(message, message_size, core_message_length, true,
true, nullptr, &timer_limits, &clock_values,
&nonce_values, &parsed_license));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_ParseLicense(nullptr, message_size, core_message_length, true,
true, &timer_limits, &clock_values, &nonce_values,
&parsed_license));
true, request_hash, &timer_limits, &clock_values,
&nonce_values, &parsed_license));
constexpr uint64_t system_time = 0;
uint64_t timer_value = 0;
@@ -499,7 +477,7 @@ TEST(OdkTest, ProvisionRequestRoundtrip) {
TEST(OdkTest, ParseLicenseErrorNonce) {
ODK_LicenseResponseParams params;
ODK_SetDefaultLicenseResponseParams(&params, ODK_MAJOR_VERSION);
ODK_SetDefaultLicenseResponseParams(&params);
uint8_t* buf = nullptr;
uint32_t buf_size = 0;
ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf,
@@ -508,7 +486,7 @@ TEST(OdkTest, ParseLicenseErrorNonce) {
params.core_message.nonce_values.nonce = 0;
OEMCryptoResult err = ODK_ParseLicense(
buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load,
params.usage_entry_present, &(params.timer_limits),
params.usage_entry_present, params.request_hash, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license));
EXPECT_EQ(OEMCrypto_ERROR_INVALID_NONCE, err);
@@ -517,7 +495,7 @@ TEST(OdkTest, ParseLicenseErrorNonce) {
TEST(OdkTest, ParseLicenseErrorUsageEntry) {
ODK_LicenseResponseParams params;
ODK_SetDefaultLicenseResponseParams(&params, ODK_MAJOR_VERSION);
ODK_SetDefaultLicenseResponseParams(&params);
uint8_t* buf = nullptr;
uint32_t buf_size = 0;
ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf,
@@ -525,59 +503,25 @@ TEST(OdkTest, ParseLicenseErrorUsageEntry) {
params.usage_entry_present = false;
OEMCryptoResult err = ODK_ParseLicense(
buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load,
params.usage_entry_present, &(params.timer_limits),
params.usage_entry_present, params.request_hash, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err);
delete[] buf;
}
TEST(OdkTest, ParseLicenseNullSubstring) {
TEST(OdkTest, ParseLicenseErrorRequestHash) {
ODK_LicenseResponseParams params;
ODK_SetDefaultLicenseResponseParams(&params, ODK_MAJOR_VERSION);
params.parsed_license.srm_restriction_data.offset = 0;
params.parsed_license.srm_restriction_data.length = 0;
uint8_t* buf = nullptr;
uint32_t buf_size = 0;
ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf,
&buf_size);
OEMCryptoResult result = ODK_ParseLicense(
buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load,
params.usage_entry_present, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license));
EXPECT_EQ(OEMCrypto_SUCCESS, result);
delete[] buf;
}
TEST(OdkTest, ParseLicenseErrorSubstringOffset) {
// offset out of range
ODK_LicenseResponseParams params;
ODK_SetDefaultLicenseResponseParams(&params, ODK_MAJOR_VERSION);
params.parsed_license.enc_mac_keys_iv.offset = 1024;
ODK_SetDefaultLicenseResponseParams(&params);
uint8_t* buf = nullptr;
uint32_t buf_size = 0;
ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf,
&buf_size);
// temporarily mess up with request hash
params.request_hash[0] = 0xff;
OEMCryptoResult err = ODK_ParseLicense(
buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load,
params.usage_entry_present, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err);
delete[] buf;
// offset + length out of range
err = OEMCrypto_SUCCESS;
ODK_SetDefaultLicenseResponseParams(&params, ODK_MAJOR_VERSION);
params.parsed_license.enc_mac_keys_iv.length = buf_size;
buf = nullptr;
buf_size = 0;
ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf,
&buf_size);
err = ODK_ParseLicense(
buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load,
params.usage_entry_present, &(params.timer_limits),
params.usage_entry_present, params.request_hash, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err);
@@ -616,37 +560,17 @@ TEST(OdkTest, ParsePrivisioningErrorDeviceId) {
delete[] buf;
}
class OdkVersionTest : public ::testing::Test,
public ::testing::WithParamInterface<VersionParameters> {
protected:
template <typename P>
void SetRequestVersion(P* params) {
params->core_message.nonce_values.api_major_version =
GetParam().response_major_version;
params->core_message.nonce_values.api_minor_version =
GetParam().response_minor_version;
features_ =
CoreMessageFeatures::DefaultFeatures(GetParam().maximum_major_version);
}
CoreMessageFeatures features_;
};
// Serialize and de-serialize license response
TEST_P(OdkVersionTest, LicenseResponseRoundtrip) {
TEST(OdkTest, LicenseResponseRoundtrip) {
ODK_LicenseResponseParams params;
ODK_SetDefaultLicenseResponseParams(&params,
GetParam().response_major_version);
SetRequestVersion(&params);
// For v17, we do not use the hash to verify the request. However, the server
// needs to be backwards compatible, so it still needs to pass the hash into
// CreateCoreLiceseseResponse below. Save a copy of params.request_hash as it
// will be zero out during the test
ODK_SetDefaultLicenseResponseParams(&params);
// save a copy of params.request_hash as it will be zero out during the test
uint8_t request_hash_read[ODK_SHA256_HASH_SIZE];
memcpy(request_hash_read, params.request_hash, sizeof(request_hash_read));
auto odk_parse_func = [&](const uint8_t* buf, size_t size) {
return ODK_ParseLicense(
buf, size + kExtraPayloadSize, size, params.initial_license_load,
params.usage_entry_present, &(params.timer_limits),
params.usage_entry_present, request_hash_read, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license));
};
@@ -655,19 +579,18 @@ TEST_P(OdkVersionTest, LicenseResponseRoundtrip) {
sizeof(request_hash_read));
auto kdo_prepare_func = [&](const ODK_LicenseRequest& core_request,
std::string* oemcrypto_core_message) {
return CreateCoreLicenseResponse(features_, params.parsed_license,
core_request, request_hash_string,
return CreateCoreLicenseResponse(params.parsed_license, core_request,
request_hash_string,
oemcrypto_core_message);
};
ValidateResponse<ODK_LicenseRequest>(GetParam(), &(params.core_message),
ValidateResponse<ODK_LicenseRequest>(&(params.core_message),
params.extra_fields, odk_parse_func,
kdo_prepare_func);
}
TEST_P(OdkVersionTest, RenewalResponseRoundtrip) {
TEST(OdkTest, RenewalResponseRoundtrip) {
ODK_RenewalResponseParams params;
ODK_SetDefaultRenewalResponseParams(&params);
SetRequestVersion(&params);
const uint64_t playback_clock = params.playback_clock;
const uint64_t renewal_duration = params.renewal_duration;
auto odk_parse_func = [&](const uint8_t* buf, size_t size) {
@@ -686,18 +609,17 @@ TEST_P(OdkVersionTest, RenewalResponseRoundtrip) {
auto kdo_prepare_func = [&](ODK_RenewalRequest& core_request,
std::string* oemcrypto_core_message) {
core_request.playback_time_seconds = playback_clock;
return CreateCoreRenewalResponse(features_, core_request, renewal_duration,
return CreateCoreRenewalResponse(core_request, renewal_duration,
oemcrypto_core_message);
};
ValidateResponse<ODK_RenewalRequest>(GetParam(), &(params.core_message),
ValidateResponse<ODK_RenewalRequest>(&(params.core_message),
params.extra_fields, odk_parse_func,
kdo_prepare_func);
}
TEST_P(OdkVersionTest, ProvisionResponseRoundtrip) {
TEST(OdkTest, ProvisionResponseRoundtrip) {
ODK_ProvisioningResponseParams params;
ODK_SetDefaultProvisioningResponseParams(&params);
SetRequestVersion(&params);
// save a copy of params.device_id as it will be zero out during the test
const uint32_t device_id_length = params.device_id_length;
uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0};
@@ -713,61 +635,14 @@ TEST_P(OdkVersionTest, ProvisionResponseRoundtrip) {
std::string* oemcrypto_core_message) {
core_request.device_id.assign(reinterpret_cast<char*>(device_id),
device_id_length);
return CreateCoreProvisioningResponse(features_, params.parsed_provisioning,
return CreateCoreProvisioningResponse(params.parsed_provisioning,
core_request, oemcrypto_core_message);
};
ValidateResponse<ODK_ProvisioningRequest>(GetParam(), &(params.core_message),
ValidateResponse<ODK_ProvisioningRequest>(&(params.core_message),
params.extra_fields, odk_parse_func,
kdo_prepare_func);
}
// If the minor version is positive, we can test an older minor version.
const uint16_t kOldMinor = ODK_MINOR_VERSION > 0 ? ODK_MINOR_VERSION - 1 : 0;
// Similarly, if this isn't the first major version, we can test an older major
// version.
// TODO(b/163416999): Remove it in the future. This will be unecessarily
// complicated after we upgrade to version 17.
const uint16_t kOldMajor = ODK_MAJOR_VERSION > ODK_FIRST_VERSION
? ODK_MAJOR_VERSION - 1
: ODK_FIRST_VERSION;
// If there is an older major, then we should accept any minor version.
// Otherwise, this test won't make sense and we should just use a minor of 0.
const uint16_t kOldMajorMinor = ODK_MAJOR_VERSION > ODK_FIRST_VERSION ? 42 : 0;
// List of major and minor versions to test.
std::vector<VersionParameters> TestCases() {
std::vector<VersionParameters> test_cases{
// Fields: maximum major version,
// request major, request minor, response major, response minor,
{ODK_MAJOR_VERSION, ODK_MAJOR_VERSION, ODK_MINOR_VERSION,
ODK_MAJOR_VERSION, ODK_MINOR_VERSION},
{ODK_MAJOR_VERSION, ODK_MAJOR_VERSION, ODK_MINOR_VERSION + 1,
ODK_MAJOR_VERSION, ODK_MINOR_VERSION},
{ODK_MAJOR_VERSION, ODK_MAJOR_VERSION, kOldMinor, ODK_MAJOR_VERSION,
kOldMinor},
{ODK_MAJOR_VERSION, ODK_MAJOR_VERSION, 0, ODK_MAJOR_VERSION, 0},
{ODK_MAJOR_VERSION, ODK_MAJOR_VERSION + 1, 42, ODK_MAJOR_VERSION,
ODK_MINOR_VERSION},
{ODK_MAJOR_VERSION, kOldMajor, 0, kOldMajor, 0},
{ODK_MAJOR_VERSION, kOldMajor, kOldMajorMinor, kOldMajor, kOldMajorMinor},
// If the server is restricted to v16, then the response can be at
// most 16.5
{16, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 16, 5},
// Here are some known good versions. Make extra sure they work.
{16, 16, 3, 16, 3},
{16, 16, 4, 16, 4},
{16, 16, 5, 16, 5},
{17, 16, 3, 16, 3},
{17, 16, 4, 16, 4},
{17, 16, 5, 16, 5},
{17, 17, 0, 17, 0},
};
return test_cases;
}
INSTANTIATE_TEST_SUITE_P(OdkVersionTests, OdkVersionTest,
::testing::ValuesIn(TestCases()));
TEST(OdkSizeTest, LicenseRequest) {
uint8_t* message = nullptr;
size_t message_length = 0;

View File

@@ -20,7 +20,7 @@
namespace wvodk_test {
void ODK_SetDefaultCoreFields(ODK_CoreMessage* core_message,
ODK_MessageType message_type) {
uint32_t message_type) {
ASSERT_TRUE(core_message != nullptr);
core_message->message_type = message_type;
core_message->message_length = 0;
@@ -30,8 +30,7 @@ void ODK_SetDefaultCoreFields(ODK_CoreMessage* core_message,
core_message->nonce_values.session_id = 0xcafebabe;
}
void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params,
uint32_t odk_major_version) {
void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params) {
ODK_SetDefaultCoreFields(&(params->core_message), ODK_License_Response_Type);
params->initial_license_load = true;
params->usage_entry_present = true;
@@ -51,29 +50,6 @@ void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params,
.total_playback_duration_seconds = 12,
.initial_renewal_duration_seconds = 13,
},
.watermarking = 0,
.dtcp2_required = {.dtcp2_required = 0,
.cmi_descriptor_0 =
{
.id = 0,
.extension = 0,
.length = 1,
.data = 0,
},
.cmi_descriptor_1 =
{
.id = 1,
.extension = 0,
.length = 3,
.data = {0, 0, 0},
},
.cmi_descriptor_2 =
{
.id = 2,
.extension = 0,
.length = 3,
.data = {0, 0, 0},
}},
.key_array_length = 3,
.key_array =
{
@@ -128,132 +104,37 @@ void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params,
{ODK_UINT64,
&(params->parsed_license.timer_limits.initial_renewal_duration_seconds),
".initial_renewal_duration_seconds"},
};
if (odk_major_version >= 17) {
params->extra_fields.push_back(
{ODK_UINT32, &(params->parsed_license.watermarking), ".watermarking"});
params->extra_fields.push_back(
{ODK_UINT8, &(params->parsed_license.dtcp2_required.dtcp2_required),
".dtcp2_required"});
if (params->parsed_license.dtcp2_required.dtcp2_required) {
params->extra_fields.push_back(
{ODK_UINT8,
&(params->parsed_license.dtcp2_required.cmi_descriptor_0.id),
".cmi_descriptor_data"});
params->extra_fields.push_back(
{ODK_UINT8,
&(params->parsed_license.dtcp2_required.cmi_descriptor_0.extension),
".cmi_descriptor_data"});
params->extra_fields.push_back(
{ODK_UINT16,
&(params->parsed_license.dtcp2_required.cmi_descriptor_0.length),
".cmi_descriptor_data"});
params->extra_fields.push_back(
{ODK_UINT8,
&(params->parsed_license.dtcp2_required.cmi_descriptor_0.data),
".cmi_descriptor_data"});
params->extra_fields.push_back(
{ODK_UINT8,
&(params->parsed_license.dtcp2_required.cmi_descriptor_1.id),
".cmi_descriptor_data"});
params->extra_fields.push_back(
{ODK_UINT8,
&(params->parsed_license.dtcp2_required.cmi_descriptor_1.extension),
".cmi_descriptor_data"});
params->extra_fields.push_back(
{ODK_UINT16,
&(params->parsed_license.dtcp2_required.cmi_descriptor_1.length),
".cmi_descriptor_data"});
params->extra_fields.push_back(
{ODK_UINT8,
&(params->parsed_license.dtcp2_required.cmi_descriptor_1.data[0]),
".cmi_descriptor_data"});
params->extra_fields.push_back(
{ODK_UINT8,
&(params->parsed_license.dtcp2_required.cmi_descriptor_1.data[1]),
".cmi_descriptor_data"});
params->extra_fields.push_back(
{ODK_UINT8,
&(params->parsed_license.dtcp2_required.cmi_descriptor_1.data[2]),
".cmi_descriptor_data"});
params->extra_fields.push_back(
{ODK_UINT8,
&(params->parsed_license.dtcp2_required.cmi_descriptor_2.id),
".cmi_descriptor_data"});
params->extra_fields.push_back(
{ODK_UINT8,
&(params->parsed_license.dtcp2_required.cmi_descriptor_2.extension),
".cmi_descriptor_data"});
params->extra_fields.push_back(
{ODK_UINT16,
&(params->parsed_license.dtcp2_required.cmi_descriptor_2.length),
".cmi_descriptor_data"});
params->extra_fields.push_back(
{ODK_UINT8,
&(params->parsed_license.dtcp2_required.cmi_descriptor_2.data[0]),
".cmi_descriptor_data"});
params->extra_fields.push_back(
{ODK_UINT8,
&(params->parsed_license.dtcp2_required.cmi_descriptor_2.data[1]),
".cmi_descriptor_data"});
params->extra_fields.push_back(
{ODK_UINT8,
&(params->parsed_license.dtcp2_required.cmi_descriptor_2.data[2]),
".cmi_descriptor_data"});
}
}
params->extra_fields.push_back({ODK_UINT32,
&(params->parsed_license.key_array_length),
".key_array_length"});
params->extra_fields.push_back({ODK_SUBSTRING,
&(params->parsed_license.key_array[0].key_id),
".key_id"});
params->extra_fields.push_back(
{ODK_UINT32, &(params->parsed_license.key_array_length),
".key_array_length"},
{ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_id), ".key_id"},
{ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_data_iv),
".key_data_iv"});
params->extra_fields.push_back(
".key_data_iv"},
{ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_data),
".key_data"});
params->extra_fields.push_back(
".key_data"},
{ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_control_iv),
".key_control_iv"});
params->extra_fields.push_back(
".key_control_iv"},
{ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_control),
".key_control"});
params->extra_fields.push_back({ODK_SUBSTRING,
&(params->parsed_license.key_array[1].key_id),
".key_id"});
params->extra_fields.push_back(
".key_control"},
{ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_id), ".key_id"},
{ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_data_iv),
".key_data_iv"});
params->extra_fields.push_back(
".key_data_iv"},
{ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_data),
".key_data"});
params->extra_fields.push_back(
".key_data"},
{ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_control_iv),
".key_control_iv"});
params->extra_fields.push_back(
".key_control_iv"},
{ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_control),
".key_control"});
params->extra_fields.push_back({ODK_SUBSTRING,
&(params->parsed_license.key_array[2].key_id),
".key_id"});
params->extra_fields.push_back(
".key_control"},
{ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_id), ".key_id"},
{ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_data_iv),
".key_data_iv"});
params->extra_fields.push_back(
".key_data_iv"},
{ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_data),
".key_data"});
params->extra_fields.push_back(
".key_data"},
{ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_control_iv),
".key_control_iv"});
params->extra_fields.push_back(
".key_control_iv"},
{ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_control),
".key_control"});
if (odk_major_version == 16) {
params->extra_fields.push_back(
{ODK_HASH, params->request_hash, ".request_hash"});
}
".key_control"},
{ODK_HASH, params->request_hash, ".request_hash"},
};
}
void ODK_SetDefaultRenewalResponseParams(ODK_RenewalResponseParams* params) {
@@ -275,7 +156,7 @@ void ODK_SetDefaultRenewalResponseParams(ODK_RenewalResponseParams* params) {
.initial_renewal_duration_seconds = 300,
};
params->clock_values = {
.time_of_license_request_signed =
.time_of_license_signed =
params->system_time - params->playback_clock - 42,
.time_of_first_decrypt = params->system_time - params->playback_clock,
.time_of_last_decrypt = params->system_time - params->playback_clock,
@@ -295,7 +176,6 @@ void ODK_SetDefaultProvisioningResponseParams(
memset(params->device_id + params->device_id_length, 0,
ODK_DEVICE_ID_LEN_MAX - params->device_id_length);
params->parsed_provisioning = {
.key_type = OEMCrypto_RSA_Private_Key,
.enc_private_key = {.offset = 0, .length = 1},
.enc_private_key_iv = {.offset = 2, .length = 3},
.encrypted_message_key = {.offset = 4, .length = 5},
@@ -315,8 +195,6 @@ void ODK_SetDefaultProvisioningResponseParams(
size_t ODK_FieldLength(ODK_FieldType type) {
switch (type) {
case ODK_UINT8:
return sizeof(uint8_t);
case ODK_UINT16:
return sizeof(uint16_t);
case ODK_UINT32:
@@ -348,10 +226,6 @@ OEMCryptoResult ODK_WriteSingleField(uint8_t* buf, const ODK_Field* field) {
return ODK_ERROR_CORE_MESSAGE;
}
switch (field->type) {
case ODK_UINT8: {
memcpy(buf, field->value, sizeof(uint8_t));
break;
}
case ODK_UINT16: {
const uint16_t u16 =
oemcrypto_htobe16(*static_cast<uint16_t*>(field->value));
@@ -404,10 +278,6 @@ OEMCryptoResult ODK_ReadSingleField(const uint8_t* buf,
return ODK_ERROR_CORE_MESSAGE;
}
switch (field->type) {
case ODK_UINT8: {
memcpy(field->value, buf, sizeof(uint8_t));
break;
}
case ODK_UINT16: {
memcpy(field->value, buf, sizeof(uint16_t));
uint16_t* u16p = static_cast<uint16_t*>(field->value);
@@ -462,13 +332,6 @@ OEMCryptoResult ODK_DumpSingleField(const uint8_t* buf,
return ODK_ERROR_CORE_MESSAGE;
}
switch (field->type) {
case ODK_UINT8: {
uint8_t val;
memcpy(&val, buf, sizeof(uint8_t));
std::cerr << field->name << ": " << val << " = 0x" << std::hex << val
<< "\n";
break;
}
case ODK_UINT16: {
uint16_t val;
memcpy(&val, buf, sizeof(uint16_t));
@@ -564,30 +427,9 @@ OEMCryptoResult ODK_IterFields(ODK_FieldMode mode, uint8_t* buf,
return OEMCrypto_SUCCESS;
}
std::vector<ODK_Field> ODK_MakeTotalFields(
const std::vector<ODK_Field>& extra_fields, ODK_CoreMessage* core_message) {
std::vector<ODK_Field> total_fields = {
{ODK_UINT32, &(core_message->message_type), "message_type"},
{ODK_UINT32, &(core_message->message_length), "message_size"},
{ODK_UINT16, &(core_message->nonce_values.api_minor_version),
"api_minor_version"},
{ODK_UINT16, &(core_message->nonce_values.api_major_version),
"api_major_version"},
{ODK_UINT32, &(core_message->nonce_values.nonce), "nonce"},
{ODK_UINT32, &(core_message->nonce_values.session_id), "session_id"},
};
total_fields.insert(total_fields.end(), extra_fields.begin(),
extra_fields.end());
return total_fields;
}
// Expect the two buffers of size n to be equal. If not, dump the messages.
void ODK_ExpectEqualBuf(const void* s1, const void* s2, size_t n,
const std::vector<ODK_Field>& fields) {
if (memcmp(s1, s2, n) != 0) {
ODK_CoreMessage core_message;
std::vector<ODK_Field> total_fields =
ODK_MakeTotalFields(fields, &core_message);
const void* buffers[] = {s1, s2};
for (int i = 0; i < 2; i++) {
char _tmp[] = "/tmp/fileXXXXXX";
@@ -602,12 +444,11 @@ void ODK_ExpectEqualBuf(const void* s1, const void* s2, size_t n,
std::fstream out(tmp, std::ios::out | std::ios::binary);
out.write(static_cast<const char*>(buffers[i]), n);
out.close();
std::cerr << std::endl
<< "Message buffer " << i << " dumped to " << tmp << std::endl;
std::cerr << "buffer " << i << " dumped to " << tmp << std::endl;
size_t bytes_written;
uint8_t* buf =
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(buffers[i]));
ODK_IterFields(ODK_DUMP, buf, n, &bytes_written, total_fields);
ODK_IterFields(ODK_DUMP, buf, n, &bytes_written, fields);
}
FAIL();
}
@@ -630,9 +471,19 @@ void ODK_BuildMessageBuffer(ODK_CoreMessage* core_message,
uint8_t** buf, uint32_t* buf_size) {
ASSERT_TRUE(core_message != nullptr);
ASSERT_TRUE(buf_size != nullptr);
std::vector<ODK_Field> total_fields =
ODK_MakeTotalFields(extra_fields, core_message);
std::vector<ODK_Field> total_fields = {
{ODK_UINT32, &(core_message->message_type), "message_type"},
{ODK_UINT32, &(core_message->message_length), "message_size"},
{ODK_UINT16, &(core_message->nonce_values.api_minor_version),
"api_minor_version"},
{ODK_UINT16, &(core_message->nonce_values.api_major_version),
"api_major_version"},
{ODK_UINT32, &(core_message->nonce_values.nonce), "nonce"},
{ODK_UINT32, &(core_message->nonce_values.session_id), "session_id"},
};
total_fields.insert(total_fields.end(), extra_fields.begin(),
extra_fields.end());
for (auto& field : total_fields) {
*buf_size += ODK_FieldLength(field.type);
}

View File

@@ -15,7 +15,6 @@
namespace wvodk_test {
enum ODK_FieldType {
ODK_UINT8,
ODK_UINT16,
ODK_UINT32,
ODK_UINT64,
@@ -42,8 +41,6 @@ struct ODK_Field {
std::string name;
};
// This structure contains all parameters available in message version v16
// through the current version.
struct ODK_LicenseResponseParams {
ODK_CoreMessage core_message;
bool initial_license_load;
@@ -76,9 +73,8 @@ struct ODK_ProvisioningResponseParams {
// Default values in core_message for testing
void ODK_SetDefaultCoreFields(ODK_CoreMessage* core_message,
ODK_MessageType message_type);
void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params,
uint32_t odk_major_version);
uint32_t message_type);
void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params);
void ODK_SetDefaultRenewalResponseParams(ODK_RenewalResponseParams* params);
void ODK_SetDefaultProvisioningResponseParams(
ODK_ProvisioningResponseParams* params);

View File

@@ -38,7 +38,7 @@ TEST(OdkTimerBasicTest, Init) {
memset(&clock_values, 0, sizeof(clock_values));
uint64_t time = 42;
ODK_InitializeClockValues(&clock_values, time);
EXPECT_EQ(clock_values.time_of_license_request_signed, time);
EXPECT_EQ(clock_values.time_of_license_signed, time);
EXPECT_EQ(clock_values.time_of_first_decrypt, 0u);
EXPECT_EQ(clock_values.time_of_last_decrypt, 0u);
EXPECT_EQ(clock_values.time_when_timer_expires, 0u);
@@ -59,7 +59,7 @@ TEST(OdkTimerBasicTest, Reload) {
enum OEMCrypto_Usage_Entry_Status status = kInactiveUsed;
ODK_ReloadClockValues(&clock_values, lic_signed, first_decrypt, last_decrypt,
status, time);
EXPECT_EQ(clock_values.time_of_license_request_signed, lic_signed);
EXPECT_EQ(clock_values.time_of_license_signed, lic_signed);
EXPECT_EQ(clock_values.time_of_first_decrypt, first_decrypt);
EXPECT_EQ(clock_values.time_of_last_decrypt, last_decrypt);
EXPECT_EQ(clock_values.time_when_timer_expires, 0u);
@@ -95,7 +95,7 @@ class ODKTimerTest : public ::testing::Test {
// Start rental clock at kRentalClockStart. This happens when the license
// request is signed.
ODK_InitializeClockValues(&clock_values_, kRentalClockStart);
EXPECT_EQ(clock_values_.time_of_license_request_signed, kRentalClockStart);
EXPECT_EQ(clock_values_.time_of_license_signed, kRentalClockStart);
}
// Simulate loading or reloading a license in a new session. An offline
@@ -113,14 +113,14 @@ class ODKTimerTest : public ::testing::Test {
ODK_InitializeClockValues(&clock_values_, 0);
// When the usage entry is reloaded, the clock values are reloaded.
ODK_ReloadClockValues(&clock_values_,
old_clock_values.time_of_license_request_signed,
old_clock_values.time_of_license_signed,
old_clock_values.time_of_first_decrypt,
old_clock_values.time_of_last_decrypt,
old_clock_values.status, system_time);
EXPECT_EQ(clock_values_.timer_status,
ODK_CLOCK_TIMER_STATUS_LICENSE_NOT_LOADED);
// These shall not change:
EXPECT_EQ(clock_values_.time_of_license_request_signed, kRentalClockStart);
EXPECT_EQ(clock_values_.time_of_license_signed, kRentalClockStart);
EXPECT_EQ(clock_values_.time_of_first_decrypt,
old_clock_values.time_of_first_decrypt);
EXPECT_EQ(clock_values_.time_of_last_decrypt,
@@ -215,8 +215,8 @@ class ODKTimerTest : public ::testing::Test {
ODK_TIMER_EXPIRED);
// These should not have changed. In particular, if the license was unused
// before, it should reamin unused.
EXPECT_EQ(clock_values_.time_of_license_request_signed,
old_clock_values.time_of_license_request_signed);
EXPECT_EQ(clock_values_.time_of_license_signed,
old_clock_values.time_of_license_signed);
EXPECT_EQ(clock_values_.time_of_first_decrypt,
old_clock_values.time_of_first_decrypt);
EXPECT_EQ(clock_values_.time_of_last_decrypt,
@@ -226,7 +226,7 @@ class ODKTimerTest : public ::testing::Test {
// Verify that the clock values are correct.
void CheckClockValues(uint64_t time_of_last_decrypt) {
EXPECT_EQ(clock_values_.time_of_license_request_signed, kRentalClockStart);
EXPECT_EQ(clock_values_.time_of_license_signed, kRentalClockStart);
EXPECT_EQ(clock_values_.time_of_first_decrypt, start_of_playback_);
EXPECT_EQ(clock_values_.time_of_last_decrypt, time_of_last_decrypt);
EXPECT_EQ(clock_values_.status, kActive);