Update to ODK v18.3

This commit is contained in:
Jacob Trimble
2023-07-20 18:11:31 +00:00
parent 2bfd670424
commit 74178f968f
39 changed files with 14570 additions and 600 deletions

View File

@@ -14,6 +14,7 @@ package {
// all of the 'license_kinds' from "vendor_widevine_license"
// to get the below license kinds:
// legacy_by_exception_only (by exception only)
// legacy_proprietary (by exception only)
default_applicable_licenses: ["vendor_widevine_license"],
}
@@ -37,6 +38,7 @@ cc_library_static {
proprietary: true,
owner: "widevine",
min_sdk_version: "UpsideDownCake",
}
// ----------------------------------------------------------------
@@ -93,6 +95,10 @@ cc_test {
"libwv_kdo",
],
shared_libs: [
"libprotobuf-cpp-lite",
],
srcs: [
"test/odk_test.cpp",
"test/odk_test_helper.cpp",

View File

@@ -106,6 +106,8 @@ typedef enum OEMCryptoResult {
OPK_ERROR_REMOTE_CALL = OPK_ERROR_BASE,
OPK_ERROR_INCOMPATIBLE_VERSION = OPK_ERROR_BASE + 1,
OPK_ERROR_NO_PERSISTENT_DATA = OPK_ERROR_BASE + 2,
OPK_ERROR_PREHOOK_FAILURE = OPK_ERROR_BASE + 3,
OPK_ERROR_POSTHOOK_FAILURE = OPK_ERROR_BASE + 4,
} OEMCryptoResult;
/* clang-format on */
@@ -139,11 +141,23 @@ typedef enum OEMCrypto_LicenseType {
typedef enum OEMCrypto_PrivateKeyType {
OEMCrypto_RSA_Private_Key = 0,
OEMCrypto_ECC_Private_Key = 1,
OEMCrypto_PrivateKeyType_MaxValue = OEMCrypto_ECC_Private_Key,
} OEMCrypto_PrivateKeyType;
/**
* Used to indicate a substring of a signed message in OEMCrypto_LoadKeys and
* other functions which must verify that a parameter is contained within a
* The base for (delayed) timers, i.e. from what time the (delayed) timer
* starts.
*/
typedef enum OEMCrypto_TimerDelayBase {
OEMCrypto_License_Start = 0,
OEMCrypto_License_Load = 1,
OEMCrypto_First_Decrypt = 2,
OEMCrypto_TimerDelayBase_MaxValue = OEMCrypto_First_Decrypt,
} OEMCrypto_TimerDelayBase;
/**
* Used to indicate a substring of a signed message in ODK_ParseLicense
* and other functions which must verify that a parameter is contained within a
* signed message.
*/
typedef struct {
@@ -209,7 +223,7 @@ typedef struct {
/**
* Points to the relevant fields for a content key. The fields are extracted
* from the License Response message offered to OEMCrypto_LoadKeys(). Each
* from the License Response message offered to ODK_ParseLicense(). Each
* field points to one of the components of the key. Key data, key control,
* and both IV fields are 128 bits (16 bytes):
* @param key_id: the unique id of this key.
@@ -226,7 +240,7 @@ typedef struct {
* the content key from the key_data field.
*
* The memory for the OEMCrypto_KeyObject fields is allocated and freed
* by the caller of OEMCrypto_LoadKeys().
* by the caller of ODK_ParseLicense().
*/
typedef struct {
OEMCrypto_Substring key_id;

View File

@@ -55,6 +55,18 @@ bool CoreProvisioningRequestFromMessage(
const std::string& oemcrypto_core_message,
ODK_ProvisioningRequest* core_provisioning_request);
/**
* Counterpart (deserializer) of ODK_PrepareCoreProvisioning40Request
* (serializer)
*
* Parameters:
* [in] oemcrypto_core_message
* [out] core_provisioning_request
*/
bool CoreProvisioning40RequestFromMessage(
const std::string& oemcrypto_core_message,
ODK_Provisioning40Request* core_provisioning_request);
/**
* Counterpart (deserializer) of ODK_PrepareCoreRenewedProvisioningRequest
* (serializer)

View File

@@ -8,6 +8,7 @@
#include <stdint.h>
#include <iostream>
#include <ostream>
#include <string>
namespace oemcrypto_core_message {
@@ -25,10 +26,9 @@ struct CoreMessageFeatures {
// 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;
// number. The default is 18.3.
uint32_t maximum_major_version = 18;
uint32_t maximum_minor_version = 3;
bool operator==(const CoreMessageFeatures &other) const;
bool operator!=(const CoreMessageFeatures &other) const {

View File

@@ -39,7 +39,7 @@ using oemcrypto_core_message::features::CoreMessageFeatures;
* [out] oemcrypto_core_message
*/
bool CreateCoreLicenseResponse(const CoreMessageFeatures& features,
const ODK_ParsedLicense& parsed_lic,
const ODK_Packing_ParsedLicense& parsed_lic,
const ODK_LicenseRequest& core_request,
const std::string& core_request_sha256,
std::string* oemcrypto_core_message);
@@ -72,6 +72,21 @@ bool CreateCoreProvisioningResponse(const CoreMessageFeatures& features,
const ODK_ParsedProvisioning& parsed_prov,
const ODK_ProvisioningRequest& core_request,
std::string* oemcrypto_core_message);
/**
* Counterpart (serializer) of ODK_ParseProvisioning40 (deserializer)
* struct-input variant
*
* Parameters:
* [in] features feature support for response message.
* [in] core_request
* [out] oemcrypto_core_message
*/
bool CreateCoreProvisioning40Response(
const CoreMessageFeatures& features,
const ODK_Provisioning40Request& core_request,
std::string* oemcrypto_core_message);
} // namespace serialize
} // namespace oemcrypto_core_message

View File

@@ -17,6 +17,7 @@
#include <cstdint>
#include <string>
#include "OEMCryptoCENCCommon.h"
#include "core_message_features.h"
#include "core_message_types.h"
#include "license_protocol.pb.h"
@@ -42,8 +43,8 @@ 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);
const std::string& core_request_sha256, bool nonce_required,
bool uses_padding, std::string* oemcrypto_core_message);
/**
* Counterpart (serializer) of ODK_ParseProvisioning (deserializer)
@@ -59,6 +60,7 @@ bool CreateCoreProvisioningResponseFromProto(
const oemcrypto_core_message::features::CoreMessageFeatures& features,
const std::string& serialized_provisioning_response,
const ODK_ProvisioningRequest& core_request,
OEMCrypto_PrivateKeyType device_key_type,
std::string* oemcrypto_core_message);
} // namespace serialize

View File

@@ -30,23 +30,25 @@
* KDO provides a corresponding writer.
*
* Table: ODK vs KDO (s: serialize; d: deserialize)
* +----------------------------------------+---------------------------------------+
* +------------------------------------------+------------------------------------------+
* | ODK | KDO |
* +---+------------------------------------+---+-----------------------------------+
* +---+--------------------------------------+---+--------------------------------------+
* | s | ODK_PrepareCoreLicenseRequest | d | CoreLicenseRequestFromMessage |
* | +------------------------------------+ +-----------------------------------+
* | +--------------------------------------+ +--------------------------------------+
* | | ODK_PrepareCoreRenewalRequest | | CoreRenewalRequestFromMessage |
* | +------------------------------------+ +-----------------------------------+
* | | ODK_PrepareCoreProvisioningRequest | | CoreProvisioningRequestFromMessage|
* | +------------------------------------+ +-----------------------------------+
* | +--------------------------------------+ +--------------------------------------+
* | | ODK_PrepareCoreProvisioningRequest | | CoreProvisioningRequestFromMessage |
* | | ODK_PrepareCoreProvisioning40Request | | CoreProvisioning40RequestFromMessage |
* | +--------------------------------------+ +--------------------------------------+
* | | ODK_PrepareCommonRequest | | CoreCommonRequestFromMessage |
* +---+------------------------------------+---+-----------------------------------+
* +---+--------------------------------------+---+--------------------------------------+
* | d | ODK_ParseLicense | s | CreateCoreLicenseResponse |
* | +------------------------------------+ +-----------------------------------+
* | +--------------------------------------+ +--------------------------------------+
* | | ODK_ParseRenewal | | CreateCoreRenewalResponse |
* | +------------------------------------+ +-----------------------------------+
* | +--------------------------------------+ +--------------------------------------+
* | | ODK_ParseProvisioning | | CreateCoreProvisioningResponse |
* +---+------------------------------------+---+-----------------------------------+
* | | ODK_ParseProvisioning40 | | CreateCoreProvisioning40Response |
* +---+--------------------------------------+---+--------------------------------------+
*
*********************************************************************/
// clang-format on
@@ -66,12 +68,27 @@ namespace oemcrypto_core_message {
* Input structure for CreateCommonResponse
*/
struct ODK_CommonRequest {
uint32_t message_type;
uint32_t message_length;
uint16_t api_minor_version;
uint16_t api_major_version;
uint32_t nonce;
uint32_t session_id;
};
struct ODK_MessageCounter {
uint64_t master_generation_number;
uint32_t provisioning_count;
uint32_t license_count;
uint32_t decrypt_count;
uint16_t major_version;
uint16_t minor_version;
uint16_t patch_version;
uint8_t soc_vendor[16];
uint8_t chipset_model[16];
uint8_t extra[12];
};
/**
* Output structure for CoreLicenseRequestFromMessage
* Input structure for CreateCoreLicenseResponse
@@ -81,6 +98,7 @@ struct ODK_LicenseRequest {
uint16_t api_major_version;
uint32_t nonce;
uint32_t session_id;
ODK_MessageCounter counter_info;
};
/**
@@ -108,6 +126,20 @@ struct ODK_ProvisioningRequest {
std::string device_id;
uint16_t renewal_type;
std::string renewal_data;
ODK_MessageCounter counter_info;
};
/**
* Output structure for CoreProvisioningRequest40FromMessage
* Input structure for CreateCoreProvisioning40Response
*/
struct ODK_Provisioning40Request {
uint16_t api_minor_version;
uint16_t api_major_version;
uint32_t nonce;
uint32_t session_id;
std::string device_info;
ODK_MessageCounter counter_info;
};
} // namespace oemcrypto_core_message

View File

@@ -259,6 +259,8 @@ OEMCryptoResult ODK_DeactivateUsageEntry(ODK_ClockValues* clock_values);
* of the message. (in) size of buffer reserved for the core message, in
* bytes. (out) actual length of the core message, in bytes.
* @param[in] nonce_values: pointer to the session's nonce data.
* @param[in] message_count_info: information used for server-side anomaly
* detection
*
* @retval OEMCrypto_SUCCESS
* @retval OEMCrypto_ERROR_SHORT_BUFFER: core_message_size is too small
@@ -269,7 +271,8 @@ OEMCryptoResult ODK_DeactivateUsageEntry(ODK_ClockValues* clock_values);
*/
OEMCryptoResult ODK_PrepareCoreLicenseRequest(
uint8_t* message, size_t message_length, size_t* core_message_size,
const ODK_NonceValues* nonce_values);
const ODK_NonceValues* nonce_values,
const ODK_MessageCounterInfo* counter_info);
/**
* Modifies the message to include a core renewal request at the beginning of
@@ -337,11 +340,8 @@ OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message,
* of the message. (in) size of buffer reserved for the core message, in
* bytes. (out) actual length of the core message, in bytes.
* @param[in] nonce_values: pointer to the session's nonce data.
* @param[in] device_id: For devices with a keybox, this is the device ID from
* the keybox. For devices with an OEM Certificate, this is a device
* unique id string.
* @param[in] device_id_length: length of device_id. The device ID can be at
* most 64 bytes.
* @param[in] message_count_info: information used for server-side anomaly
* detection
*
* @retval OEMCrypto_SUCCESS
* @retval OEMCrypto_ERROR_SHORT_BUFFER: core_message_size is too small
@@ -352,8 +352,44 @@ OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message,
*/
OEMCryptoResult ODK_PrepareCoreProvisioningRequest(
uint8_t* message, size_t message_length, size_t* core_message_length,
const ODK_NonceValues* nonce_values, const uint8_t* device_id,
size_t device_id_length);
const ODK_NonceValues* nonce_values,
const ODK_MessageCounterInfo* counter_info);
/**
* Modifies the message to include a core provisioning 4.0 request at the
* beginning of the message buffer. The values in nonce_values are used to
* populate the message.
*
* This shall be called by OEMCrypto from
* OEMCrypto_PrepAndSignProvisioningRequest.
*
* NOTE: if the message pointer is null and/or input core_message_length is
* zero, this function returns OEMCrypto_ERROR_SHORT_BUFFER and sets output
* core_message_size to the size needed.
*
* @param[in,out] message: Pointer to memory for the entire message. Modified by
* the ODK library.
* @param[in] message_length: length of the entire message buffer.
* @param[in,out] core_message_size: length of the core message at the beginning
* of the message. (in) size of buffer reserved for the core message, in
* bytes. (out) actual length of the core message, in bytes.
* @param[in] nonce_values: pointer to the session's nonce data.
* @param[in] device_info: Encoded device hardware info in CBOR format.
* @param[in] device_info_length: length of device_info.
* @param[in] message_count_info: information used for server-side anomaly
* detection
*
* @retval OEMCrypto_SUCCESS
* @retval OEMCrypto_ERROR_SHORT_BUFFER: core_message_size is too small
* @retval OEMCrypto_ERROR_INVALID_CONTEXT
*
* @version
* This method is new in version 18 of the API.
*/
OEMCryptoResult ODK_PrepareCoreProvisioning40Request(
uint8_t* message, size_t message_length, size_t* core_message_length,
const ODK_NonceValues* nonce_values, const uint8_t* device_info,
size_t device_info_length, const ODK_MessageCounterInfo* counter_info);
/**
* Modifies the message to include a core renewal provisioning request at the
@@ -515,6 +551,7 @@ 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] system_time_seconds: The current system's time in seconds.
* @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
@@ -522,13 +559,19 @@ OEMCryptoResult ODK_RefreshV15Values(const ODK_TimerLimits* timer_limits,
* @param[in,out] nonce_values: The session's nonce values. These will be
* updated.
* @param[out] parsed_license: the destination for the data.
* @param[out] timer_value: set if playback timer should be started.
*
* @retval OEMCrypto_SUCCESS
* @retval ODK_ERROR_CORE_MESSAGE: if the message did not parse correctly, or
* there were other incorrect values. An error should be returned to the
* CDM layer.
* @retval ODK_UNSUPPORTED_API
* @retval OEMCrypto_ERROR_INVALID_NONCE
* @retval ODK_SET_TIMER: if the playback timer has been started successfully
* @retval ODK_DISABLE_TIMER: if the playtime timer has been started
* successfully then is disabled.
* @retval ODK_TIMER_EXPIRED: if the license is attempted to be loaded after the
* rental duration expires.
* @retval OEMCrypto_ERROR_INVALåID_NONCE
*
* @version
* This method is new in version 16 of the API.
@@ -536,8 +579,9 @@ 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,
ODK_TimerLimits* timer_limits, ODK_ClockValues* clock_values,
ODK_NonceValues* nonce_values, ODK_ParsedLicense* parsed_license);
uint64_t system_time_seconds, ODK_TimerLimits* timer_limits,
ODK_ClockValues* clock_values, ODK_NonceValues* nonce_values,
ODK_ParsedLicense* parsed_license, uint64_t* timer_value);
/**
* The function ODK_ParseRenewal will parse the message and verify its
@@ -564,7 +608,8 @@ OEMCryptoResult ODK_ParseLicense(
* @param[in] message_length: length of the entire message buffer.
* @param[in] core_message_size: length of the core message, at the beginning of
* the message buffer.
* @param[in] nonce_values: pointer to the session's nonce data.
* @param[in,out] nonce_values: pointer to the session's nonce data. These might
* be updated if the server returns a lower API version.
* @param[in] system_time_seconds: the current time on OEMCrypto's clock, in
* seconds.
* @param[in] timer_limits: timer limits specified in the license.
@@ -591,7 +636,7 @@ OEMCryptoResult ODK_ParseLicense(
*/
OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
size_t core_message_length,
const ODK_NonceValues* nonce_values,
ODK_NonceValues* nonce_values,
uint64_t system_time_seconds,
const ODK_TimerLimits* timer_limits,
ODK_ClockValues* clock_values,
@@ -604,8 +649,8 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
* If the message does not parse correctly, ODK_ParseProvisioning will return
* an error that OEMCrypto should return to the CDM layer above.
*
* If the API in the message is larger than 16, then ODK_UNSUPPORTED_API is
* returned.
* If the API in the message is larger than ODK_MAJOR_VERSION, then
* ODK_UNSUPPORTED_API is returned.
*
* ODK_ParseProvisioning shall verify that nonce_values->nonce and
* nonce_values->session_id are the same as those in the message. Otherwise
@@ -620,11 +665,13 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
* @param[in] message_length: length of the entire message buffer.
* @param[in] core_message_size: length of the core message, at the beginning of
* the message buffer.
* @param[in] nonce_values: pointer to the session's nonce data.
* @param[in/out] nonce_values: pointer to the session's nonce data. These might
* be updated if the server returns a lower API version.
* @param[in] device_id: a pointer to a buffer containing the device ID of the
* device. The ODK function will verify it matches that in the message.
* @param[in] device_id_length: the length of the device ID.
* @param[out] parsed_response: destination for the parse data.
* @param[out] counter_info: destination for counter portion of parse data.
* @param[out] parsed_response: destination for response portion of parse data.
*
* @retval OEMCrypto_SUCCESS
* @retval ODK_ERROR_CORE_MESSAGE: the message did not parse correctly, or there
@@ -638,9 +685,45 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
*/
OEMCryptoResult ODK_ParseProvisioning(
const uint8_t* message, size_t message_length, size_t core_message_length,
const ODK_NonceValues* nonce_values, const uint8_t* device_id,
ODK_NonceValues* nonce_values, const uint8_t* device_id,
size_t device_id_length, ODK_ParsedProvisioning* parsed_response);
/**
* The function ODK_ParseProvisioning40 will parse the message and verify the
* nonce values match those in the request.
*
* If the message does not parse correctly, ODK_ParseProvisioning40 will return
* an error that OEMCrypto should return to the CDM layer above.
*
* If the API in the message is larger than ODK_MAJOR_VERSION, then
* ODK_UNSUPPORTED_API is returned.
*
* ODK_ParseProvisioning40 shall verify that nonce_values->nonce and
* nonce_values->session_id are the same as those in the message. Otherwise
* it shall return OEMCrypto_ERROR_INVALID_NONCE.
*
* @param[in] message: pointer to the message buffer.
* @param[in] message_length: length of the entire message buffer.
* @param[in] core_message_size: length of the core message, at the beginning of
* the message buffer.
* @param[in,out] nonce_values: pointer to the session's nonce data. These might
* be updated if the server returns a lower API version.
*
* @retval OEMCrypto_SUCCESS
* @retval ODK_ERROR_CORE_MESSAGE: the message did not parse correctly, or there
* were other incorrect values. An error should be returned to the CDM
* layer.
* @retval ODK_UNSUPPORTED_API
* @retval OEMCrypto_ERROR_INVALID_NONCE
*
* @version
* This method is new in version 18 of the API.
*/
OEMCryptoResult ODK_ParseProvisioning40(const uint8_t* message,
size_t message_length,
size_t core_message_length,
ODK_NonceValues* nonce_values);
/**
* The function ODK_ParseProvisioning will parse the message and verify the
* API version is at most the version passed in.

View File

@@ -36,6 +36,8 @@ extern "C" {
#if defined(__GNUC__) || defined(__clang__)
#define ALIGNED __attribute__((aligned))
#elif _MSC_VER
#define ALIGNED __declspec(align(8))
#else
#define ALIGNED
#error ODK_Message must be aligned to the maximum useful alignment of the \
@@ -61,7 +63,8 @@ typedef enum {
MESSAGE_STATUS_NOT_INITIALIZED = 0x2990b6c6,
MESSAGE_STATUS_OUT_OF_MEMORY = 0x7c5c64cc,
MESSAGE_STATUS_MAP_SHARED_MEMORY_FAILED = 0x7afecacf,
MESSAGE_STATUS_SECURE_BUFFER_ERROR = 0x78f0e873
MESSAGE_STATUS_SECURE_BUFFER_ERROR = 0x78f0e873,
MESSAGE_STATUS_BUFFER_TOO_LARGE = 0x5bfcfb21
} ODK_MessageStatus;
/*

View File

@@ -15,11 +15,11 @@ extern "C" {
#include "odk_target.h"
/* The version of this library. */
#define ODK_MAJOR_VERSION 17
#define ODK_MINOR_VERSION 1
#define ODK_MAJOR_VERSION 18
#define ODK_MINOR_VERSION 3
/* ODK Version string. Date changed automatically on each release. */
#define ODK_RELEASE_DATE "ODK v17.1 2022-06-17"
#define ODK_RELEASE_DATE "ODK v18.3 2023-07-07"
/* The lowest version number for an ODK message. */
#define ODK_FIRST_VERSION 16
@@ -28,6 +28,11 @@ extern "C" {
#define ODK_DEVICE_ID_LEN_MAX 64
#define ODK_SHA256_HASH_SIZE 32
#define ODK_KEYBOX_RENEWAL_DATA_SIZE 1600
/* The max length of the encoded device info in CBOR format. Make sure it gets
* updated when more device info is included. Refer to
* https://www.rfc-editor.org/rfc/rfc8949.html#name-specification-of-the-cbor-e
* for an estimation of the required length. */
#define ODK_DEVICE_INFO_LEN_MAX 768
/// @addtogroup odk_timer
/// @{
@@ -92,7 +97,8 @@ typedef struct {
*
* @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.
* and reloaded with usage entry as time_of_license_received. This is
* also used to track the start of the rental clock time.
* @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
@@ -161,6 +167,47 @@ typedef struct {
/// @addtogroup odk_parser
/// @{
/**
* This counter information is used by the license and provisioning servers to
* keep track of requests. Values should be updated after every successful
* provisioning request, license request, and decrypt call.
*
* @param provisioning_count: number of times a provisioning request was made on
* this device in the current instance. May be reset to 0 on device power off.
* @param license_count: number of times a license request was made on this
* device in the current instance. May be reset to 0 on device power off.
* @param decrypt_count: number of times OEMCrypto_DecryptCENC() has been called
* on this device in the current instance. May be reset to 0 on device power
* off.
* @param master_generation_number: current master generation number value from
* the OEMCrypto usage table. Persists across reboots.
* @param soc_vendor: name of the system-on-a-chip vendor for the device,
* limited to 16 bytes
* @param chipset_model: name of the chipset on the device, limited to 16 bytes
* @param major_version: major version of the TA binary. This is different from
* the OEMCrypto version that is being implemented.
* @param minor_version: minor version of the TA binary, if applicable. This is
* different from the OEMCrypto version that is being implemented.
* @param patch_version: patch version of the TA binary, if applicable. This is
* different from the OEMCrypto version that is being implemented.
* @param extra: unused in V18
*
* @version
* This struct was added in API version 18.
*/
typedef struct {
uint64_t master_generation_number;
uint32_t provisioning_count;
uint32_t license_count;
uint32_t decrypt_count;
uint16_t major_version;
uint16_t minor_version;
uint16_t patch_version;
uint8_t soc_vendor[16];
uint8_t chipset_model[16];
uint8_t extra[12];
} ODK_MessageCounterInfo;
/**
* The parsed license structure contains information from the license
* message. The function ODK_ParseLicense will fill in the fields of this
@@ -178,11 +225,12 @@ typedef struct {
* @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 renewal_delay_base: what time the timer starting is based off of.
* @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 18.
*/
typedef struct {
OEMCrypto_Substring enc_mac_keys_iv;
@@ -194,10 +242,51 @@ typedef struct {
ODK_TimerLimits timer_limits;
uint32_t watermarking;
OEMCrypto_DTCP2_CMI_Packet dtcp2_required;
OEMCrypto_TimerDelayBase renewal_delay_base;
uint32_t key_array_length;
OEMCrypto_KeyObject key_array[ODK_MAX_NUM_KEYS];
} ODK_ParsedLicense;
/**
* The parsed license structure contains information from the license
* message. The function ODK_ParseLicense will fill in the fields of this
* message. All substrings are contained within the message body.
*
* @param enc_mac_keys_iv: IV for decrypting new mac_key. Size is 128 bits.
* @param enc_mac_keys: encrypted mac_keys for generating new mac_keys. Size is
* 512 bits.
* @param pst: the Provider Session Token.
* @param srm_restriction_data: optional data specifying the minimum SRM
* version.
* @param license_type: specifies if the license contains content keys or
* 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 renewal_delay_base: what time the timer starting is based off of.
* @param key_array_length: number of keys present.
* @param key_array: set of keys to be installed. This is a pointer to an array
* to allow packing a number of keys greater than |ODK_MAX_NUM_KEYS|.
*
* @version
* This struct changed in API version 18.
*/
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 watermarking;
OEMCrypto_DTCP2_CMI_Packet dtcp2_required;
OEMCrypto_TimerDelayBase renewal_delay_base;
uint32_t key_array_length;
OEMCrypto_KeyObject* key_array;
} ODK_Packing_ParsedLicense;
/**
* The parsed provisioning structure contains information from the license
* message. The function ODK_ParseProvisioning will fill in the fields of

View File

@@ -11,10 +11,10 @@
#include <string>
#include "OEMCryptoCENCCommon.h"
#include "odk_message.h"
#include "odk_serialize.h"
#include "odk_structs.h"
#include "odk_structs_priv.h"
#include "serialization_base.h"
namespace oemcrypto_core_message {
namespace deserialize {
@@ -89,12 +89,62 @@ bool ParseRequest(uint32_t message_type,
} // namespace
static bool GetNonceFromMessage(const std::string& oemcrypto_core_message,
ODK_NonceValues* nonce_values) {
if (nonce_values == nullptr) return false;
if (oemcrypto_core_message.size() < sizeof(ODK_CoreMessage)) return false;
ODK_CoreMessage core_message;
const uint8_t* buf =
reinterpret_cast<const uint8_t*>(oemcrypto_core_message.c_str());
ODK_Message msg = ODK_Message_Create(const_cast<uint8_t*>(buf),
oemcrypto_core_message.size());
ODK_Message_SetSize(&msg, sizeof(ODK_CoreMessage));
Unpack_ODK_CoreMessage(&msg, &core_message);
if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK) return false;
*nonce_values = core_message.nonce_values;
return true;
}
bool CopyCounterInfo(ODK_MessageCounter* dest, ODK_MessageCounterInfo* src) {
if (!src || !dest) return false;
dest->master_generation_number = src->master_generation_number;
dest->license_count = src->license_count;
dest->provisioning_count = src->provisioning_count;
dest->decrypt_count = src->decrypt_count;
dest->major_version = src->major_version;
dest->minor_version = src->minor_version;
dest->patch_version = src->patch_version;
memcpy(&dest->soc_vendor, &src->soc_vendor, sizeof(dest->soc_vendor));
memcpy(&dest->chipset_model, &src->chipset_model,
sizeof(dest->chipset_model));
memcpy(&dest->extra, &src->extra, sizeof(dest->extra));
return true;
}
bool CoreLicenseRequestFromMessage(const std::string& oemcrypto_core_message,
ODK_LicenseRequest* core_license_request) {
const auto unpacker = Unpack_ODK_PreparedLicenseRequest;
ODK_PreparedLicenseRequest prepared_license = {};
ODK_NonceValues nonce;
if (!GetNonceFromMessage(oemcrypto_core_message, &nonce)) return false;
if (nonce.api_major_version <= 17) {
const auto unpacker = Unpack_ODK_PreparedLicenseRequestV17;
ODK_PreparedLicenseRequestV17 prepared_license = {};
return ParseRequest(ODK_License_Request_Type, oemcrypto_core_message,
core_license_request, &prepared_license, unpacker);
}
const auto unpacker = Unpack_ODK_PreparedLicenseRequest;
ODK_PreparedLicenseRequest prepared_license = {};
if (!ParseRequest(ODK_License_Request_Type, oemcrypto_core_message,
core_license_request, &prepared_license, unpacker)) {
return false;
}
if (!CopyCounterInfo(&core_license_request->counter_info,
&prepared_license.counter_info)) {
return false;
}
return true;
}
bool CoreRenewalRequestFromMessage(const std::string& oemcrypto_core_message,
@@ -112,10 +162,35 @@ bool CoreRenewalRequestFromMessage(const std::string& oemcrypto_core_message,
bool CoreProvisioningRequestFromMessage(
const std::string& oemcrypto_core_message,
ODK_ProvisioningRequest* core_provisioning_request) {
const auto unpacker = Unpack_ODK_PreparedProvisioningRequest;
// Need to partially parse in order to get the nonce values, which will tell
// us the major/minor version
ODK_NonceValues nonce;
if (!GetNonceFromMessage(oemcrypto_core_message, &nonce)) return false;
if (nonce.api_major_version == 18) {
// Use special case unpacker for v18.0
const auto unpacker = nonce.api_minor_version == 0
? Unpack_ODK_PreparedProvisioningRequestV180
: Unpack_ODK_PreparedProvisioningRequest;
ODK_PreparedProvisioningRequest prepared_provision = {};
if (!ParseRequest(ODK_Provisioning_Request_Type, oemcrypto_core_message,
core_provisioning_request, &prepared_provision, unpacker)) {
core_provisioning_request, &prepared_provision,
unpacker)) {
return false;
}
if (!CopyCounterInfo(&core_provisioning_request->counter_info,
&prepared_provision.counter_info)) {
return false;
}
} else {
// V17 and older
const auto unpacker = Unpack_ODK_PreparedProvisioningRequestV17;
ODK_PreparedProvisioningRequestV17 prepared_provision = {};
if (!ParseRequest(ODK_Provisioning_Request_Type, oemcrypto_core_message,
core_provisioning_request, &prepared_provision,
unpacker)) {
return false;
}
const uint8_t* device_id = prepared_provision.device_id;
@@ -123,15 +198,46 @@ bool CoreProvisioningRequestFromMessage(
if (device_id_length > ODK_DEVICE_ID_LEN_MAX) {
return false;
}
if (device_id_length > 0) {
uint8_t zero[ODK_DEVICE_ID_LEN_MAX] = {};
if (memcmp(zero, device_id + device_id_length,
ODK_DEVICE_ID_LEN_MAX - device_id_length)) {
ODK_DEVICE_ID_LEN_MAX - device_id_length) != 0) {
return false;
}
core_provisioning_request->device_id.assign(
reinterpret_cast<const char*>(device_id), device_id_length);
}
core_provisioning_request->renewal_type = OEMCrypto_NoRenewal;
core_provisioning_request->renewal_data.clear();
}
return true;
}
bool CoreProvisioning40RequestFromMessage(
const std::string& oemcrypto_core_message,
ODK_Provisioning40Request* core_provisioning_request) {
const auto unpacker = Unpack_ODK_PreparedProvisioning40Request;
ODK_PreparedProvisioning40Request prepared_provision = {};
if (!ParseRequest(ODK_Provisioning40_Request_Type, oemcrypto_core_message,
core_provisioning_request, &prepared_provision, unpacker)) {
return false;
}
if (!CopyCounterInfo(&core_provisioning_request->counter_info,
&prepared_provision.counter_info)) {
return false;
}
const uint8_t* device_info = prepared_provision.device_info;
const uint32_t device_info_length = prepared_provision.device_info_length;
if (device_info_length > ODK_DEVICE_INFO_LEN_MAX) {
return false;
}
uint8_t zero[ODK_DEVICE_INFO_LEN_MAX] = {};
if (memcmp(zero, device_info + device_info_length,
ODK_DEVICE_INFO_LEN_MAX - device_info_length) != 0) {
return false;
}
core_provisioning_request->device_info.assign(
reinterpret_cast<const char*>(device_info), device_info_length);
return true;
}
@@ -152,7 +258,7 @@ bool CoreRenewedProvisioningRequestFromMessage(
}
uint8_t zero[ODK_DEVICE_ID_LEN_MAX] = {};
if (memcmp(zero, device_id + device_id_length,
ODK_DEVICE_ID_LEN_MAX - device_id_length)) {
ODK_DEVICE_ID_LEN_MAX - device_id_length) != 0) {
return false;
}
core_provisioning_request->device_id.assign(
@@ -173,8 +279,16 @@ bool CoreCommonRequestFromMessage(const std::string& oemcrypto_core_message,
ODK_CommonRequest* common_request) {
const auto unpacker = Unpack_ODK_PreparedCommonRequest;
ODK_PreparedCommonRequest prepared_common = {};
return ParseRequest(ODK_Common_Request_Type, oemcrypto_core_message,
const bool success =
ParseRequest(ODK_Common_Request_Type, oemcrypto_core_message,
common_request, &prepared_common, unpacker);
if (success) {
const auto& core_message = prepared_common.core_message;
common_request->message_type = core_message.message_type;
common_request->message_length = core_message.message_length;
}
return success;
}
} // namespace deserialize

View File

@@ -4,6 +4,8 @@
#include "core_message_features.h"
#include <ostream>
namespace oemcrypto_core_message {
namespace features {
const CoreMessageFeatures CoreMessageFeatures::kDefaultFeatures;
@@ -23,7 +25,10 @@ CoreMessageFeatures CoreMessageFeatures::DefaultFeatures(
features.maximum_minor_version = 5; // 16.5
break;
case 17:
features.maximum_minor_version = 1; // 17.1
features.maximum_minor_version = 2; // 17.2
break;
case 18:
features.maximum_minor_version = 3; // 18.3
break;
default:
features.maximum_minor_version = 0;

View File

@@ -25,13 +25,13 @@ namespace {
* computing the API version of the response.
*
* Template arguments:
* T: struct to be deserialized by odk
* S: kdo input struct
*/
template <typename T, typename S>
template <typename S>
bool CreateResponseHeader(const CoreMessageFeatures& features,
ODK_MessageType message_type, const S& core_request,
T& response) {
ODK_MessageType message_type,
ODK_CoreMessage* response_header,
const S& core_request) {
// Bad major version.
if ((features.maximum_major_version > ODK_MAJOR_VERSION) ||
(features.maximum_major_version == ODK_MAJOR_VERSION &&
@@ -40,20 +40,24 @@ bool CreateResponseHeader(const CoreMessageFeatures& features,
return false;
}
auto* header = &response.request.core_message;
header->message_type = message_type;
header->nonce_values.api_major_version = core_request.api_major_version;
header->nonce_values.api_minor_version = core_request.api_minor_version;
header->nonce_values.nonce = core_request.nonce;
header->nonce_values.session_id = core_request.session_id;
response_header->message_type = message_type;
response_header->nonce_values.api_major_version =
core_request.api_major_version;
response_header->nonce_values.api_minor_version =
core_request.api_minor_version;
response_header->nonce_values.nonce = core_request.nonce;
response_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;
response_header->nonce_values.api_major_version =
features.maximum_major_version;
response_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;
response_header->nonce_values.api_minor_version =
features.maximum_minor_version;
}
return true;
}
@@ -63,19 +67,18 @@ bool CreateResponseHeader(const CoreMessageFeatures& features,
*
* 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,
template <typename T, typename P>
bool CreateResponse(ODK_MessageType message_type,
std::string* oemcrypto_core_message,
ODK_CoreMessage* response_header, 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) {
if (response_header->message_type != message_type ||
response_header->nonce_values.api_major_version < ODK_FIRST_VERSION) {
// This indicates CreateResponseHeader was not called.
return false;
}
@@ -89,8 +92,8 @@ bool CreateResponse(ODK_MessageType message_type, const S& core_request,
}
uint32_t message_length = static_cast<uint32_t>(ODK_Message_GetSize(&msg));
msg = ODK_Message_Create(buf.data() + sizeof(header->message_type),
sizeof(header->message_length));
msg = ODK_Message_Create(buf.data() + sizeof(response_header->message_type),
sizeof(response_header->message_length));
Pack_uint32_t(&msg, &message_length);
oemcrypto_core_message->assign(reinterpret_cast<const char*>(buf.data()),
message_length);
@@ -98,10 +101,10 @@ bool CreateResponse(ODK_MessageType message_type, const S& core_request,
}
bool CopyDeviceId(const ODK_ProvisioningRequest& src,
ODK_ProvisioningResponse* dest) {
ODK_ProvisioningResponseV16* dest) {
auto& request = dest->request;
const std::string& device_id = src.device_id;
if (request.device_id_length > sizeof(request.device_id)) {
if (device_id.size() > sizeof(request.device_id)) {
return false;
}
request.device_id_length = static_cast<uint32_t>(device_id.size());
@@ -113,56 +116,24 @@ bool CopyDeviceId(const ODK_ProvisioningRequest& src,
} // namespace
bool CreateCoreLicenseResponse(const CoreMessageFeatures& features,
const ODK_ParsedLicense& parsed_lic,
const ODK_Packing_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)) {
ODK_Packing_LicenseResponse license_response{
{}, const_cast<ODK_Packing_ParsedLicense*>(&parsed_lic), {}};
if (!CreateResponseHeader(features, ODK_License_Response_Type,
&license_response.core_message, core_request)) {
return false;
}
if (ODK_MAX_NUM_KEYS < license_response.parsed_license->key_array_length) {
if (license_response.core_message.nonce_values.api_major_version == 16) {
if (core_request_sha256.size() != sizeof(license_response.request_hash))
return false;
memcpy(license_response.request_hash, core_request_sha256.data(),
sizeof(license_response.request_hash));
}
if (license_response.request.core_message.nonce_values.api_major_version ==
16) {
ODK_LicenseResponseV16 license_response_v16;
license_response_v16.request = license_response.request;
license_response_v16.parsed_license.enc_mac_keys_iv =
license_response.parsed_license->enc_mac_keys_iv;
license_response_v16.parsed_license.enc_mac_keys =
license_response.parsed_license->enc_mac_keys;
license_response_v16.parsed_license.pst =
license_response.parsed_license->pst;
license_response_v16.parsed_license.srm_restriction_data =
license_response.parsed_license->srm_restriction_data;
license_response_v16.parsed_license.license_type =
license_response.parsed_license->license_type;
license_response_v16.parsed_license.nonce_required =
license_response.parsed_license->nonce_required;
license_response_v16.parsed_license.timer_limits =
license_response.parsed_license->timer_limits;
license_response_v16.parsed_license.key_array_length =
license_response.parsed_license->key_array_length;
uint32_t i;
for (i = 0; i < license_response_v16.parsed_license.key_array_length &&
i < license_response.parsed_license->key_array_length;
i++) {
license_response_v16.parsed_license.key_array[i] =
license_response.parsed_license->key_array[i];
}
if (core_request_sha256.size() != sizeof(license_response_v16.request_hash))
return false;
memcpy(license_response_v16.request_hash, core_request_sha256.data(),
sizeof(license_response_v16.request_hash));
return CreateResponse(ODK_License_Response_Type, core_request,
oemcrypto_core_message, license_response_v16,
Pack_ODK_LicenseResponseV16);
}
return CreateResponse(ODK_License_Response_Type, core_request,
oemcrypto_core_message, license_response,
return CreateResponse(ODK_License_Response_Type, oemcrypto_core_message,
&license_response.core_message, license_response,
Pack_ODK_LicenseResponse);
}
@@ -173,13 +144,14 @@ bool CreateCoreRenewalResponse(const CoreMessageFeatures& features,
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)) {
if (!CreateResponseHeader(features, ODK_Renewal_Response_Type,
&renewal_response.request.core_message,
core_request)) {
return false;
}
return CreateResponse(ODK_Renewal_Response_Type, core_request,
oemcrypto_core_message, renewal_response,
Pack_ODK_RenewalResponse);
return CreateResponse(ODK_Renewal_Response_Type, oemcrypto_core_message,
&renewal_response.request.core_message,
renewal_response, Pack_ODK_RenewalResponse);
}
bool CreateCoreProvisioningResponse(const CoreMessageFeatures& features,
@@ -188,17 +160,42 @@ bool CreateCoreProvisioningResponse(const CoreMessageFeatures& features,
std::string* oemcrypto_core_message) {
ODK_ProvisioningResponse prov_response{
{}, const_cast<ODK_ParsedProvisioning*>(&parsed_prov)};
if (!CopyDeviceId(core_request, &prov_response)) {
return false;
}
if (!CreateResponseHeader(features, ODK_Provisioning_Response_Type,
core_request, prov_response)) {
&prov_response.core_message, core_request)) {
return false;
}
return CreateResponse(ODK_Provisioning_Response_Type, core_request,
oemcrypto_core_message, prov_response,
if (prov_response.core_message.nonce_values.api_major_version <= 17) {
ODK_ProvisioningResponseV16 prov_response_v16;
if (!CopyDeviceId(core_request, &prov_response_v16)) {
return false;
}
prov_response_v16.request.core_message = prov_response.core_message;
prov_response_v16.parsed_provisioning = prov_response.parsed_provisioning;
return CreateResponse(ODK_Provisioning_Response_Type,
oemcrypto_core_message,
&prov_response_v16.request.core_message,
prov_response_v16, Pack_ODK_ProvisioningResponseV16);
}
return CreateResponse(ODK_Provisioning_Response_Type, oemcrypto_core_message,
&prov_response.core_message, prov_response,
Pack_ODK_ProvisioningResponse);
}
bool CreateCoreProvisioning40Response(
const CoreMessageFeatures& features,
const ODK_Provisioning40Request& core_request,
std::string* oemcrypto_core_message) {
ODK_Provisioning40Response prov_response = {};
if (!CreateResponseHeader(features, ODK_Provisioning_Response_Type,
&prov_response.core_message, core_request)) {
return false;
}
return CreateResponse(ODK_Provisioning_Response_Type, oemcrypto_core_message,
&prov_response.core_message, prov_response,
Pack_ODK_Provisioning40Response);
}
} // namespace serialize
} // namespace oemcrypto_core_message

View File

@@ -9,6 +9,7 @@
#include <cstdint>
#include <cstring>
#include <string>
#include <vector>
#include "core_message_serialize.h"
#include "license_protocol.pb.h"
@@ -83,7 +84,8 @@ bool CreateCoreLicenseResponseFromProto(const CoreMessageFeatures& features,
return false;
}
ODK_ParsedLicense parsed_lic{};
ODK_Packing_ParsedLicense parsed_lic{};
std::vector<OEMCrypto_KeyObject> key_array;
bool any_content = false;
bool any_entitlement = false;
@@ -110,12 +112,8 @@ bool CreateCoreLicenseResponseFromProto(const CoreMessageFeatures& features,
} else {
any_content = true;
}
if (parsed_lic.key_array_length >= ODK_MAX_NUM_KEYS) {
return false;
}
uint32_t& n = parsed_lic.key_array_length;
parsed_lic.key_array[n++] =
KeyContainerToOecKey(serialized_license, k, uses_padding);
key_array.push_back(
KeyContainerToOecKey(serialized_license, k, uses_padding));
break;
}
default: {
@@ -147,6 +145,19 @@ bool CreateCoreLicenseResponseFromProto(const CoreMessageFeatures& features,
}
parsed_lic.nonce_required = nonce_required;
const auto& policy = lic.policy();
switch (policy.initial_renewal_delay_base()) {
case video_widevine::License_Policy::LICENSE_LOAD:
parsed_lic.renewal_delay_base = OEMCrypto_License_Load;
break;
case video_widevine::License_Policy::FIRST_DECRYPT:
parsed_lic.renewal_delay_base = OEMCrypto_First_Decrypt;
break;
case video_widevine::License_Policy::TIMER_DELAY_BASE_UNSPECIFIED:
case video_widevine::License_Policy::LICENSE_START:
default:
parsed_lic.renewal_delay_base = OEMCrypto_License_Start;
break;
}
ODK_TimerLimits& timer_limits = parsed_lic.timer_limits;
timer_limits.soft_enforce_rental_duration =
policy.soft_enforce_rental_duration();
@@ -160,23 +171,23 @@ bool CreateCoreLicenseResponseFromProto(const CoreMessageFeatures& features,
policy.renewal_delay_seconds() +
policy.renewal_recovery_duration_seconds();
parsed_lic.key_array = key_array.data();
parsed_lic.key_array_length = static_cast<uint32_t>(key_array.size());
return CreateCoreLicenseResponse(features, parsed_lic, core_request,
core_request_sha256, oemcrypto_core_message);
}
bool CreateCoreProvisioningResponseFromProto(
const CoreMessageFeatures& features,
bool DeserializeProvisioningResponse(
const std::string& serialized_provisioning_resp,
const ODK_ProvisioningRequest& core_request,
std::string* oemcrypto_core_message) {
ODK_ParsedProvisioning parsed_prov{};
const OEMCrypto_PrivateKeyType device_key_type,
ODK_ParsedProvisioning& parsed_prov) {
video_widevine::ProvisioningResponse prov;
if (!prov.ParseFromString(serialized_provisioning_resp)) {
return false;
}
parsed_prov.key_type =
OEMCrypto_RSA_Private_Key; // TODO(b/148404408): ECC or RSA
parsed_prov.key_type = device_key_type;
if (prov.has_device_rsa_key()) {
parsed_prov.enc_private_key =
GetOecSubstring(serialized_provisioning_resp, prov.device_rsa_key());
@@ -189,7 +200,19 @@ bool CreateCoreProvisioningResponseFromProto(
parsed_prov.encrypted_message_key =
GetOecSubstring(serialized_provisioning_resp, prov.wrapping_key());
}
return true;
}
bool CreateCoreProvisioningResponseFromProto(
const CoreMessageFeatures& features,
const std::string& serialized_provisioning_resp,
const ODK_ProvisioningRequest& core_request,
const OEMCrypto_PrivateKeyType device_key_type,
std::string* oemcrypto_core_message) {
ODK_ParsedProvisioning parsed_prov{};
if (!DeserializeProvisioningResponse(serialized_provisioning_resp,
device_key_type, parsed_prov))
return false;
return CreateCoreProvisioningResponse(features, parsed_prov, core_request,
oemcrypto_core_message);
}

View File

@@ -6,14 +6,15 @@
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "odk_message.h"
#include "odk_overflow.h"
#include "odk_serialize.h"
#include "odk_structs.h"
#include "odk_structs_priv.h"
#include "odk_util.h"
#include "serialization_base.h"
/* @ private odk functions */
@@ -31,7 +32,7 @@ static OEMCryptoResult ODK_PrepareRequest(
/* The core message should be at the beginning of the buffer, and with a
* shorter length. */
if (sizeof(ODK_CoreMessage) > prepared_request_buffer_length) {
if (ODK_CORE_MESSAGE_SIZE > prepared_request_buffer_length) {
return ODK_ERROR_CORE_MESSAGE;
}
ODK_CoreMessage* core_message = (ODK_CoreMessage*)prepared_request_buffer;
@@ -45,12 +46,23 @@ static OEMCryptoResult ODK_PrepareRequest(
* message buffer has been correctly initialized by the caller. */
switch (message_type) {
case ODK_License_Request_Type: {
if (nonce_values->api_major_version > 17) {
core_message->message_length = ODK_LICENSE_REQUEST_SIZE;
if (sizeof(ODK_PreparedLicenseRequest) > prepared_request_buffer_length) {
if (sizeof(ODK_PreparedLicenseRequest) >
prepared_request_buffer_length) {
return ODK_ERROR_CORE_MESSAGE;
}
Pack_ODK_PreparedLicenseRequest(
&msg, (ODK_PreparedLicenseRequest*)prepared_request_buffer);
} else {
core_message->message_length = ODK_LICENSE_REQUEST_SIZE_V17;
if (sizeof(ODK_PreparedLicenseRequestV17) >
prepared_request_buffer_length) {
return ODK_ERROR_CORE_MESSAGE;
}
Pack_ODK_PreparedLicenseRequestV17(
&msg, (ODK_PreparedLicenseRequestV17*)prepared_request_buffer);
}
break;
}
case ODK_Renewal_Request_Type: {
@@ -63,6 +75,7 @@ static OEMCryptoResult ODK_PrepareRequest(
break;
}
case ODK_Provisioning_Request_Type: {
if (nonce_values->api_major_version > 17) {
core_message->message_length = ODK_PROVISIONING_REQUEST_SIZE;
if (sizeof(ODK_PreparedProvisioningRequest) >
prepared_request_buffer_length) {
@@ -70,6 +83,25 @@ static OEMCryptoResult ODK_PrepareRequest(
}
Pack_ODK_PreparedProvisioningRequest(
&msg, (ODK_PreparedProvisioningRequest*)prepared_request_buffer);
} else {
core_message->message_length = ODK_PROVISIONING_REQUEST_SIZE_V17;
if (sizeof(ODK_PreparedProvisioningRequestV17) >
prepared_request_buffer_length) {
return ODK_ERROR_CORE_MESSAGE;
}
Pack_ODK_PreparedProvisioningRequestV17(
&msg, (ODK_PreparedProvisioningRequestV17*)prepared_request_buffer);
}
break;
}
case ODK_Provisioning40_Request_Type: {
core_message->message_length = ODK_PROVISIONING40_REQUEST_SIZE;
if (sizeof(ODK_PreparedProvisioning40Request) >
prepared_request_buffer_length) {
return ODK_ERROR_CORE_MESSAGE;
}
Pack_ODK_PreparedProvisioning40Request(
&msg, (ODK_PreparedProvisioning40Request*)prepared_request_buffer);
break;
}
case ODK_Renewed_Provisioning_Request_Type: {
@@ -169,15 +201,26 @@ static OEMCryptoResult ODK_ParseCoreHeader(const uint8_t* message,
/* @@ prepare request functions */
OEMCryptoResult ODK_PrepareCoreLicenseRequest(
uint8_t* message, size_t message_length, size_t* core_message_length,
const ODK_NonceValues* nonce_values) {
if (core_message_length == NULL || nonce_values == NULL) {
uint8_t* message, size_t message_length, size_t* core_message_size,
const ODK_NonceValues* nonce_values,
const ODK_MessageCounterInfo* counter_info) {
if (core_message_size == NULL || nonce_values == NULL ||
counter_info == NULL) {
return ODK_ERROR_CORE_MESSAGE;
}
if (nonce_values->api_major_version > 17) {
ODK_PreparedLicenseRequest license_request = {0};
memcpy(&license_request.counter_info, counter_info,
sizeof(license_request.counter_info));
return ODK_PrepareRequest(
message, message_length, core_message_length, ODK_License_Request_Type,
message, message_length, core_message_size, ODK_License_Request_Type,
nonce_values, &license_request, sizeof(ODK_PreparedLicenseRequest));
} else {
ODK_PreparedLicenseRequestV17 license_request = {0};
return ODK_PrepareRequest(
message, message_length, core_message_size, ODK_License_Request_Type,
nonce_values, &license_request, sizeof(ODK_PreparedLicenseRequestV17));
}
}
OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message,
@@ -230,23 +273,53 @@ OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message,
OEMCryptoResult ODK_PrepareCoreProvisioningRequest(
uint8_t* message, size_t message_length, size_t* core_message_length,
const ODK_NonceValues* nonce_values, const uint8_t* device_id,
size_t device_id_length) {
if (core_message_length == NULL || nonce_values == NULL) {
const ODK_NonceValues* nonce_values,
const ODK_MessageCounterInfo* counter_info) {
if (core_message_length == NULL || nonce_values == NULL ||
counter_info == NULL) {
return ODK_ERROR_CORE_MESSAGE;
}
if (nonce_values->api_major_version > 17) {
ODK_PreparedProvisioningRequest provisioning_request = {0};
if (device_id_length > sizeof(provisioning_request.device_id)) {
return ODK_ERROR_CORE_MESSAGE;
}
provisioning_request.device_id_length = (uint32_t)device_id_length;
if (device_id) {
memcpy(provisioning_request.device_id, device_id, device_id_length);
}
memcpy(&provisioning_request.counter_info, counter_info,
sizeof(ODK_MessageCounterInfo));
return ODK_PrepareRequest(message, message_length, core_message_length,
ODK_Provisioning_Request_Type, nonce_values,
&provisioning_request,
sizeof(ODK_PreparedProvisioningRequest));
} else {
ODK_PreparedProvisioningRequestV17 provisioning_request = {0};
return ODK_PrepareRequest(message, message_length, core_message_length,
ODK_Provisioning_Request_Type, nonce_values,
&provisioning_request,
sizeof(ODK_PreparedProvisioningRequestV17));
}
}
OEMCryptoResult ODK_PrepareCoreProvisioning40Request(
uint8_t* message, size_t message_length, size_t* core_message_length,
const ODK_NonceValues* nonce_values, const uint8_t* device_info,
size_t device_info_length, const ODK_MessageCounterInfo* counter_info) {
if (core_message_length == NULL || nonce_values == NULL ||
counter_info == NULL) {
return ODK_ERROR_CORE_MESSAGE;
}
ODK_PreparedProvisioning40Request provisioning_request = {0};
if (device_info_length > sizeof(provisioning_request.device_info)) {
return ODK_ERROR_CORE_MESSAGE;
}
provisioning_request.device_info_length = (uint32_t)device_info_length;
if (device_info) {
memcpy(provisioning_request.device_info, device_info, device_info_length);
}
memcpy(&provisioning_request.counter_info, counter_info,
sizeof(provisioning_request.counter_info));
return ODK_PrepareRequest(message, message_length, core_message_length,
ODK_Provisioning40_Request_Type, nonce_values,
&provisioning_request,
sizeof(provisioning_request));
}
OEMCryptoResult ODK_PrepareCoreRenewedProvisioningRequest(
@@ -285,14 +358,15 @@ OEMCryptoResult ODK_PrepareCoreRenewedProvisioningRequest(
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) {
uint64_t system_time_seconds, ODK_TimerLimits* timer_limits,
ODK_ClockValues* clock_values, ODK_NonceValues* nonce_values,
ODK_ParsedLicense* parsed_license, uint64_t* timer_value) {
if (message == NULL || timer_limits == NULL || clock_values == NULL ||
nonce_values == NULL || parsed_license == NULL) {
return ODK_ERROR_CORE_MESSAGE;
}
const OEMCryptoResult err =
OEMCryptoResult err =
ODK_ParseCoreHeader(message, message_length, core_message_length,
ODK_License_Response_Type, nonce_values);
if (err != OEMCrypto_SUCCESS) {
@@ -303,69 +377,15 @@ OEMCryptoResult ODK_ParseLicense(
license_response.parsed_license = parsed_license;
ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length);
ODK_Message_SetSize(&msg, core_message_length);
if (nonce_values->api_major_version == 16) {
ODK_LicenseResponseV16 license_response_v16 = {0};
Unpack_ODK_LicenseResponseV16(&msg, &license_response_v16);
if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK ||
ODK_Message_GetOffset(&msg) != core_message_length) {
return ODK_ERROR_CORE_MESSAGE;
}
// Need to manually set parsed_license fields to
// license_response_v16.parsed_license field values since
// license_response_v16 is no longer a pointer so parsed_license doesn't get
// updated during the unpacking.
parsed_license->enc_mac_keys_iv =
license_response_v16.parsed_license.enc_mac_keys_iv;
parsed_license->enc_mac_keys =
license_response_v16.parsed_license.enc_mac_keys;
parsed_license->pst = license_response_v16.parsed_license.pst;
parsed_license->srm_restriction_data =
license_response_v16.parsed_license.srm_restriction_data;
parsed_license->license_type =
license_response_v16.parsed_license.license_type;
parsed_license->nonce_required =
license_response_v16.parsed_license.nonce_required;
parsed_license->timer_limits =
license_response_v16.parsed_license.timer_limits;
parsed_license->key_array_length =
license_response_v16.parsed_license.key_array_length;
uint32_t i;
for (i = 0; i < parsed_license->key_array_length; i++) {
parsed_license->key_array[i] =
license_response_v16.parsed_license.key_array[i];
}
// Set fields not used in V16 to default values.
parsed_license->watermarking = 0;
// Set fields not used in V16 to default values.
parsed_license->dtcp2_required.dtcp2_required = 0;
parsed_license->dtcp2_required.cmi_descriptor_0.id = 0;
parsed_license->dtcp2_required.cmi_descriptor_0.extension = 0;
parsed_license->dtcp2_required.cmi_descriptor_0.length = 1;
parsed_license->dtcp2_required.cmi_descriptor_0.data = 0;
parsed_license->dtcp2_required.cmi_descriptor_1.id = 1;
parsed_license->dtcp2_required.cmi_descriptor_1.extension = 0;
parsed_license->dtcp2_required.cmi_descriptor_1.length = 3;
parsed_license->dtcp2_required.cmi_descriptor_1.data[0] = 0;
parsed_license->dtcp2_required.cmi_descriptor_1.data[1] = 0;
parsed_license->dtcp2_required.cmi_descriptor_1.data[2] = 0;
parsed_license->dtcp2_required.cmi_descriptor_2.id = 2;
parsed_license->dtcp2_required.cmi_descriptor_2.extension = 0;
parsed_license->dtcp2_required.cmi_descriptor_2.length = 3;
parsed_license->dtcp2_required.cmi_descriptor_2.data[0] = 0;
parsed_license->dtcp2_required.cmi_descriptor_2.data[1] = 0;
parsed_license->dtcp2_required.cmi_descriptor_2.data[2] = 0;
license_response.request = license_response_v16.request;
} else {
Unpack_ODK_LicenseResponse(&msg, &license_response);
if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK ||
ODK_Message_GetOffset(&msg) != core_message_length) {
return ODK_ERROR_CORE_MESSAGE;
}
}
/* If the license has a provider session token (pst), then OEMCrypto should
* have a usage entry loaded. The opposite is also an error. */
@@ -382,26 +402,38 @@ OEMCryptoResult ODK_ParseLicense(
*/
if (parsed_license->nonce_required && initial_license_load) {
if (nonce_values->nonce !=
license_response.request.core_message.nonce_values.nonce ||
license_response.core_message.nonce_values.nonce ||
nonce_values->session_id !=
license_response.request.core_message.nonce_values.session_id) {
license_response.core_message.nonce_values.session_id) {
return OEMCrypto_ERROR_INVALID_NONCE;
}
} else { /* !initial_license_load, or can't tell if initial. */
nonce_values->nonce =
license_response.request.core_message.nonce_values.nonce;
nonce_values->nonce = license_response.core_message.nonce_values.nonce;
nonce_values->session_id =
license_response.request.core_message.nonce_values.session_id;
license_response.core_message.nonce_values.session_id;
/* Start the rental clock if not already started for reloading an offline
* license without a nonce. */
if (!parsed_license->nonce_required &&
clock_values->time_of_license_request_signed == 0) {
clock_values->time_of_license_request_signed = system_time_seconds;
}
}
bool license_load =
(parsed_license->renewal_delay_base == OEMCrypto_License_Load);
*timer_limits = parsed_license->timer_limits;
/* And update the clock values state. */
clock_values->timer_status = ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED;
if (nonce_values->api_major_version == 18 && license_load) {
err = ODK_AttemptFirstPlayback(system_time_seconds, timer_limits,
clock_values, timer_value);
return err;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
size_t core_message_length,
const ODK_NonceValues* nonce_values,
ODK_NonceValues* nonce_values,
uint64_t system_time,
const ODK_TimerLimits* timer_limits,
ODK_ClockValues* clock_values,
@@ -413,7 +445,7 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
const OEMCryptoResult err =
ODK_ParseCoreHeader(message, message_length, core_message_length,
ODK_Renewal_Response_Type, NULL);
ODK_Renewal_Response_Type, nonce_values);
if (err != OEMCrypto_SUCCESS) {
return err;
}
@@ -439,10 +471,14 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
*/
/* If a renewal request is lost in transit, we should throw it out and create
* a new one. We use the timestamp to make sure we have the latest request.
* We only do this if playback has already started. This allows us to reload
* an offline license and also reload a renewal before starting playback.
* We only do this if a renewal has been requested for this session. This
* allows us to reload an offline license and also reload a renewal from a
* previous session before starting playback.
* TODO: b/290249855 - This is reversed. It should be "!=" instead of "<".
* We will not fix this in the current release, because it is already in
* production code. Instead, this will be fixed in v19.
*/
if (clock_values->timer_status != ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED &&
if (clock_values->time_of_renewal_request > 0 &&
clock_values->time_of_renewal_request <
renewal_response.request.playback_time) {
return ODK_STALE_RENEWAL;
@@ -454,7 +490,7 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
OEMCryptoResult ODK_ParseProvisioning(
const uint8_t* message, size_t message_length, size_t core_message_length,
const ODK_NonceValues* nonce_values, const uint8_t* device_id,
ODK_NonceValues* nonce_values, const uint8_t* device_id,
size_t device_id_length, ODK_ParsedProvisioning* parsed_response) {
if (message == NULL || nonce_values == NULL || device_id == NULL ||
parsed_response == NULL) {
@@ -462,11 +498,14 @@ OEMCryptoResult ODK_ParseProvisioning(
}
const OEMCryptoResult err =
ODK_ParseCoreHeader(message, message_length, core_message_length,
ODK_Provisioning_Response_Type, NULL);
ODK_Provisioning_Response_Type, nonce_values);
if (err != OEMCrypto_SUCCESS) {
return err;
}
ODK_ProvisioningResponse provisioning_response = {0};
if (nonce_values->api_major_version <= 17) {
// Do v16/v17
ODK_ProvisioningResponseV16 provisioning_response = {0};
provisioning_response.parsed_provisioning = parsed_response;
if (device_id_length > ODK_DEVICE_ID_LEN_MAX) {
@@ -475,7 +514,7 @@ OEMCryptoResult ODK_ParseProvisioning(
ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length);
ODK_Message_SetSize(&msg, core_message_length);
Unpack_ODK_ProvisioningResponse(&msg, &provisioning_response);
Unpack_ODK_ProvisioningResponseV16(&msg, &provisioning_response);
if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK ||
ODK_Message_GetOffset(&msg) != core_message_length) {
return ODK_ERROR_CORE_MESSAGE;
@@ -491,14 +530,55 @@ OEMCryptoResult ODK_ParseProvisioning(
device_id_length) != 0) {
return ODK_ERROR_CORE_MESSAGE;
}
} else {
// v18
ODK_ProvisioningResponse provisioning_response = {0};
provisioning_response.parsed_provisioning = parsed_response;
const uint8_t zero[ODK_DEVICE_ID_LEN_MAX] = {0};
/* check bytes beyond device_id_length are 0 */
if (crypto_memcmp(zero,
provisioning_response.request.device_id + device_id_length,
ODK_DEVICE_ID_LEN_MAX - device_id_length) != 0) {
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.core_message.nonce_values))) {
return OEMCrypto_ERROR_INVALID_NONCE;
}
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult ODK_ParseProvisioning40(const uint8_t* message,
size_t message_length,
size_t core_message_length,
ODK_NonceValues* nonce_values) {
if (message == NULL || nonce_values == NULL) {
return ODK_ERROR_CORE_MESSAGE;
}
const OEMCryptoResult err =
ODK_ParseCoreHeader(message, message_length, core_message_length,
ODK_Provisioning_Response_Type, nonce_values);
if (err != OEMCrypto_SUCCESS) {
return err;
}
ODK_Provisioning40Response provisioning_response = {0};
ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length);
ODK_Message_SetSize(&msg, core_message_length);
Unpack_ODK_Provisioning40Response(&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.core_message.nonce_values))) {
return OEMCrypto_ERROR_INVALID_NONCE;
}
return OEMCrypto_SUCCESS;
}

View File

@@ -9,6 +9,7 @@
'target_name': 'odk',
'type': 'static_library',
'standalone_static_library' : 1,
'hard_dependency': 1,
'include_dirs': [
'../include',
'../../include',

View File

@@ -25,6 +25,14 @@ extern "C" {
#define oemcrypto_be32toh OSSwapBigToHostInt32
#define oemcrypto_htobe64 OSSwapHostToBigInt64
#define oemcrypto_be64toh OSSwapBigToHostInt64
#elif defined(_WIN32)
#include <winsock2.h>
#define oemcrypto_htobe16 htons
#define oemcrypto_be16toh ntohs
#define oemcrypto_htobe32 htonl
#define oemcrypto_be32toh ntohl
#define oemcrypto_htobe64 htonll
#define oemcrypto_be64toh ntohll
#else /* defined(__linux__) || defined(__ANDROID__) */
uint32_t oemcrypto_htobe16(uint16_t u16);
uint32_t oemcrypto_be16toh(uint16_t u16);

View File

@@ -8,20 +8,13 @@
#include <stdio.h>
#include <string.h>
#include "odk_assert.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
* implementation. If static_assert is not available, the runtime assert in
* InitMessage will catch the mismatch at the time a message is initialized.
*/
#ifdef static_assert
static_assert(
odk_static_assert(
sizeof(ODK_Message) >= sizeof(ODK_Message_Impl),
"sizeof(ODK_Message) is too small. You can increase "
"SIZE_OF_ODK_MESSAGE_IMPL in odk_message.h to make it large enough.");
#endif
/*
* Create a message structure that references a separate data buffer. An
@@ -34,7 +27,6 @@ static_assert(
* unchanged by this function.
*/
ODK_Message ODK_Message_Create(uint8_t* buffer, size_t capacity) {
assert(sizeof(ODK_Message) >= sizeof(ODK_Message_Impl));
ODK_Message message;
ODK_Message_Impl* message_impl = (ODK_Message_Impl*)&message;
message_impl->base = buffer;

View File

@@ -2,6 +2,8 @@
// source code may only be used and distributed under the Widevine
// License Agreement.
#include "odk_overflow.h"
#include <stddef.h>
#include <stdint.h>

View File

@@ -6,6 +6,8 @@
* This code is auto-generated, do not edit
*/
#include "odk_serialize.h"
#include "odk_structs_priv.h"
#include "serialization_base.h"
@@ -45,7 +47,8 @@ static void Pack_ODK_TimerLimits(ODK_Message* msg, ODK_TimerLimits const* obj) {
}
static void Pack_ODK_ParsedLicense(ODK_Message* msg,
ODK_ParsedLicense const* obj) {
ODK_Packing_ParsedLicense const* obj,
const ODK_NonceValues* nonce_values) {
/* hand-coded */
if (obj->key_array_length > ODK_MAX_NUM_KEYS) {
ODK_Message_SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR);
@@ -58,6 +61,7 @@ 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);
if (nonce_values->api_major_version >= 17) {
Pack_uint32_t(msg, &obj->watermarking);
Pack_uint8_t(msg, &obj->dtcp2_required.dtcp2_required);
if (obj->dtcp2_required.dtcp2_required) {
@@ -78,27 +82,10 @@ static void Pack_ODK_ParsedLicense(ODK_Message* msg,
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;
if (nonce_values->api_major_version >= 18) {
Pack_enum(msg, obj->renewal_delay_base);
}
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++) {
@@ -114,11 +101,31 @@ static void Pack_ODK_ParsedProvisioning(ODK_Message* msg,
Pack_OEMCrypto_Substring(msg, &obj->encrypted_message_key);
}
static void Pack_ODK_MessageCounterInfo(ODK_Message* msg,
ODK_MessageCounterInfo const* obj) {
Pack_uint64_t(msg, &obj->master_generation_number);
Pack_uint32_t(msg, &obj->provisioning_count);
Pack_uint32_t(msg, &obj->license_count);
Pack_uint32_t(msg, &obj->decrypt_count);
Pack_uint16_t(msg, &obj->major_version);
Pack_uint16_t(msg, &obj->minor_version);
Pack_uint16_t(msg, &obj->patch_version);
PackArray(msg, &obj->soc_vendor[0], sizeof(obj->soc_vendor));
PackArray(msg, &obj->chipset_model[0], sizeof(obj->chipset_model));
PackArray(msg, &obj->extra[0], sizeof(obj->extra));
}
/* @@ odk serialize */
void Pack_ODK_PreparedLicenseRequest(ODK_Message* msg,
ODK_PreparedLicenseRequest const* obj) {
Pack_ODK_CoreMessage(msg, &obj->core_message);
Pack_ODK_MessageCounterInfo(msg, &obj->counter_info);
}
void Pack_ODK_PreparedLicenseRequestV17(
ODK_Message* msg, ODK_PreparedLicenseRequestV17 const* obj) {
Pack_ODK_CoreMessage(msg, &obj->core_message);
}
void Pack_ODK_PreparedRenewalRequest(ODK_Message* msg,
@@ -130,10 +137,28 @@ void Pack_ODK_PreparedRenewalRequest(ODK_Message* msg,
void Pack_ODK_PreparedProvisioningRequest(
ODK_Message* msg, const ODK_PreparedProvisioningRequest* obj) {
Pack_ODK_CoreMessage(msg, &obj->core_message);
// Fake device_id_length for older servers, since we removed device id from
// the v18 request
uint32_t device_id_len = 64;
Pack_uint32_t(msg, &device_id_len);
Pack_ODK_MessageCounterInfo(msg, &obj->counter_info);
}
void Pack_ODK_PreparedProvisioningRequestV17(
ODK_Message* msg, const ODK_PreparedProvisioningRequestV17* obj) {
Pack_ODK_CoreMessage(msg, &obj->core_message);
Pack_uint32_t(msg, &obj->device_id_length);
PackArray(msg, &obj->device_id[0], sizeof(obj->device_id));
}
void Pack_ODK_PreparedProvisioning40Request(
ODK_Message* msg, const ODK_PreparedProvisioning40Request* obj) {
Pack_ODK_CoreMessage(msg, &obj->core_message);
Pack_uint32_t(msg, &obj->device_info_length);
PackArray(msg, &obj->device_info[0], sizeof(obj->device_info));
Pack_ODK_MessageCounterInfo(msg, &obj->counter_info);
}
void Pack_ODK_PreparedRenewedProvisioningRequest(
ODK_Message* msg, const ODK_PreparedRenewedProvisioningRequest* obj) {
Pack_ODK_CoreMessage(msg, &obj->core_message);
@@ -147,16 +172,14 @@ void Pack_ODK_PreparedRenewedProvisioningRequest(
/* @@ kdo serialize */
void Pack_ODK_LicenseResponse(ODK_Message* msg,
ODK_LicenseResponse const* obj) {
Pack_ODK_PreparedLicenseRequest(msg, &obj->request);
Pack_ODK_ParsedLicense(msg, (const ODK_ParsedLicense*)obj->parsed_license);
}
void Pack_ODK_LicenseResponseV16(ODK_Message* msg,
ODK_LicenseResponseV16 const* obj) {
Pack_ODK_PreparedLicenseRequest(msg, &obj->request);
Pack_ODK_ParsedLicenseV16(msg, &obj->parsed_license);
ODK_Packing_LicenseResponse const* obj) {
Pack_ODK_CoreMessage(msg, &obj->core_message);
Pack_ODK_ParsedLicense(msg,
(const ODK_Packing_ParsedLicense*)obj->parsed_license,
&obj->core_message.nonce_values);
if ((&obj->core_message.nonce_values)->api_major_version == 16) {
PackArray(msg, &obj->request_hash[0], sizeof(obj->request_hash));
}
}
void Pack_ODK_RenewalResponse(ODK_Message* msg,
@@ -167,11 +190,23 @@ void Pack_ODK_RenewalResponse(ODK_Message* msg,
void Pack_ODK_ProvisioningResponse(ODK_Message* msg,
const ODK_ProvisioningResponse* obj) {
Pack_ODK_PreparedProvisioningRequest(msg, &obj->request);
Pack_ODK_CoreMessage(msg, &obj->core_message);
Pack_ODK_ParsedProvisioning(
msg, (const ODK_ParsedProvisioning*)obj->parsed_provisioning);
}
void Pack_ODK_ProvisioningResponseV16(ODK_Message* msg,
const ODK_ProvisioningResponseV16* obj) {
Pack_ODK_PreparedProvisioningRequestV17(msg, &obj->request);
Pack_ODK_ParsedProvisioning(
msg, (const ODK_ParsedProvisioning*)obj->parsed_provisioning);
}
void Pack_ODK_Provisioning40Response(ODK_Message* msg,
const ODK_Provisioning40Response* obj) {
Pack_ODK_CoreMessage(msg, &obj->core_message);
}
/* @ deserialize */
/* @@ private deserialize */
@@ -207,14 +242,16 @@ static void Unpack_ODK_TimerLimits(ODK_Message* msg, ODK_TimerLimits* obj) {
Unpack_uint64_t(msg, &obj->initial_renewal_duration_seconds);
}
static void Unpack_ODK_ParsedLicense(ODK_Message* msg, ODK_ParsedLicense* obj) {
static void Unpack_ODK_ParsedLicense(ODK_Message* msg, ODK_ParsedLicense* obj,
const ODK_NonceValues* nonce_values) {
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_OEMCrypto_LicenseType(msg, &obj->license_type);
Unpack_bool(msg, &obj->nonce_required);
Unpack_ODK_TimerLimits(msg, &obj->timer_limits);
if (nonce_values->api_major_version >= 17) {
Unpack_uint32_t(msg, &obj->watermarking);
Unpack_uint8_t(msg, &obj->dtcp2_required.dtcp2_required);
if (obj->dtcp2_required.dtcp2_required) {
@@ -234,45 +271,11 @@ static void Unpack_ODK_ParsedLicense(ODK_Message* msg, ODK_ParsedLicense* obj) {
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]);
if (nonce_values->api_major_version >= 18) {
Unpack_OEMCrypto_TimerDelayBase(msg, &obj->renewal_delay_base);
}
}
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);
@@ -286,17 +289,37 @@ static void Unpack_ODK_ParsedLicenseV16(ODK_Message* msg,
static void Unpack_ODK_ParsedProvisioning(ODK_Message* msg,
ODK_ParsedProvisioning* obj) {
obj->key_type = (OEMCrypto_PrivateKeyType)Unpack_enum(msg);
Unpack_OEMCrypto_PrivateKeyType(msg, &obj->key_type);
Unpack_OEMCrypto_Substring(msg, &obj->enc_private_key);
Unpack_OEMCrypto_Substring(msg, &obj->enc_private_key_iv);
Unpack_OEMCrypto_Substring(msg, &obj->encrypted_message_key);
}
static void Unpack_ODK_MessageCounterInfo(ODK_Message* msg,
ODK_MessageCounterInfo* obj) {
Unpack_uint64_t(msg, &obj->master_generation_number);
Unpack_uint32_t(msg, &obj->provisioning_count);
Unpack_uint32_t(msg, &obj->license_count);
Unpack_uint32_t(msg, &obj->decrypt_count);
Unpack_uint16_t(msg, &obj->major_version);
Unpack_uint16_t(msg, &obj->minor_version);
Unpack_uint16_t(msg, &obj->patch_version);
UnpackArray(msg, &obj->soc_vendor[0], sizeof(obj->soc_vendor));
UnpackArray(msg, &obj->chipset_model[0], sizeof(obj->chipset_model));
UnpackArray(msg, &obj->extra[0], sizeof(obj->extra));
}
/* @ kdo deserialize */
void Unpack_ODK_PreparedLicenseRequest(ODK_Message* msg,
ODK_PreparedLicenseRequest* obj) {
Unpack_ODK_CoreMessage(msg, &obj->core_message);
Unpack_ODK_MessageCounterInfo(msg, &obj->counter_info);
}
void Unpack_ODK_PreparedLicenseRequestV17(ODK_Message* msg,
ODK_PreparedLicenseRequestV17* obj) {
Unpack_ODK_CoreMessage(msg, &obj->core_message);
}
void Unpack_ODK_PreparedRenewalRequest(ODK_Message* msg,
@@ -308,10 +331,34 @@ void Unpack_ODK_PreparedRenewalRequest(ODK_Message* msg,
void Unpack_ODK_PreparedProvisioningRequest(
ODK_Message* msg, ODK_PreparedProvisioningRequest* obj) {
Unpack_ODK_CoreMessage(msg, &obj->core_message);
// Fake device_id_length for older servers, since we removed device id from
// the v18 request
uint32_t device_id_len = 0;
Unpack_uint32_t(msg, &device_id_len);
Unpack_ODK_MessageCounterInfo(msg, &obj->counter_info);
}
void Unpack_ODK_PreparedProvisioningRequestV180(
ODK_Message* msg, ODK_PreparedProvisioningRequest* obj) {
Unpack_ODK_CoreMessage(msg, &obj->core_message);
Unpack_ODK_MessageCounterInfo(msg, &obj->counter_info);
}
void Unpack_ODK_PreparedProvisioningRequestV17(
ODK_Message* msg, ODK_PreparedProvisioningRequestV17* obj) {
Unpack_ODK_CoreMessage(msg, &obj->core_message);
Unpack_uint32_t(msg, &obj->device_id_length);
UnpackArray(msg, &obj->device_id[0], sizeof(obj->device_id));
}
void Unpack_ODK_PreparedProvisioning40Request(
ODK_Message* msg, ODK_PreparedProvisioning40Request* obj) {
Unpack_ODK_CoreMessage(msg, &obj->core_message);
Unpack_uint32_t(msg, &obj->device_info_length);
UnpackArray(msg, &obj->device_info[0], sizeof(obj->device_info));
Unpack_ODK_MessageCounterInfo(msg, &obj->counter_info);
}
void Unpack_ODK_PreparedRenewedProvisioningRequest(
ODK_Message* msg, ODK_PreparedRenewedProvisioningRequest* obj) {
Unpack_ODK_CoreMessage(msg, &obj->core_message);
@@ -329,15 +376,12 @@ void Unpack_ODK_PreparedCommonRequest(ODK_Message* msg,
/* @@ odk deserialize */
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);
Unpack_ODK_CoreMessage(msg, &obj->core_message);
Unpack_ODK_ParsedLicense(msg, obj->parsed_license,
&obj->core_message.nonce_values);
if ((&obj->core_message.nonce_values)->api_major_version == 16) {
UnpackArray(msg, &obj->request_hash[0], sizeof(obj->request_hash));
}
}
void Unpack_ODK_RenewalResponse(ODK_Message* msg, ODK_RenewalResponse* obj) {
@@ -347,6 +391,17 @@ void Unpack_ODK_RenewalResponse(ODK_Message* msg, ODK_RenewalResponse* obj) {
void Unpack_ODK_ProvisioningResponse(ODK_Message* msg,
ODK_ProvisioningResponse* obj) {
Unpack_ODK_PreparedProvisioningRequest(msg, &obj->request);
Unpack_ODK_CoreMessage(msg, &obj->core_message);
Unpack_ODK_ParsedProvisioning(msg, obj->parsed_provisioning);
}
void Unpack_ODK_ProvisioningResponseV16(ODK_Message* msg,
ODK_ProvisioningResponseV16* obj) {
Unpack_ODK_PreparedProvisioningRequestV17(msg, &obj->request);
Unpack_ODK_ParsedProvisioning(msg, obj->parsed_provisioning);
}
void Unpack_ODK_Provisioning40Response(ODK_Message* msg,
ODK_Provisioning40Response* obj) {
Unpack_ODK_CoreMessage(msg, &obj->core_message);
}

View File

@@ -8,8 +8,8 @@
#ifndef WIDEVINE_ODK_SRC_ODK_SERIALIZE_H_
#define WIDEVINE_ODK_SRC_ODK_SERIALIZE_H_
#include "odk_message.h"
#include "odk_structs_priv.h"
#include "serialization_base.h"
#ifdef __cplusplus
extern "C" {
@@ -18,37 +18,56 @@ extern "C" {
/* odk pack */
void Pack_ODK_PreparedLicenseRequest(ODK_Message* msg,
const ODK_PreparedLicenseRequest* obj);
void Pack_ODK_PreparedLicenseRequestV17(
ODK_Message* msg, const ODK_PreparedLicenseRequestV17* obj);
void Pack_ODK_PreparedRenewalRequest(ODK_Message* msg,
const ODK_PreparedRenewalRequest* obj);
void Pack_ODK_PreparedProvisioningRequest(
ODK_Message* msg, const ODK_PreparedProvisioningRequest* obj);
void Pack_ODK_PreparedProvisioningRequestV17(
ODK_Message* msg, const ODK_PreparedProvisioningRequestV17* obj);
void Pack_ODK_PreparedProvisioning40Request(
ODK_Message* msg, const ODK_PreparedProvisioning40Request* obj);
void Pack_ODK_PreparedRenewedProvisioningRequest(
ODK_Message* msg, const ODK_PreparedRenewedProvisioningRequest* obj);
/* odk unpack */
void Unpack_ODK_CoreMessage(ODK_Message* msg, ODK_CoreMessage* obj);
void Unpack_ODK_LicenseResponse(ODK_Message* msg, ODK_LicenseResponse* obj);
void Unpack_ODK_LicenseResponseV16(ODK_Message* msg,
ODK_LicenseResponseV16* obj);
void Unpack_ODK_RenewalResponse(ODK_Message* msg, ODK_RenewalResponse* obj);
void Unpack_ODK_ProvisioningResponse(ODK_Message* msg,
ODK_ProvisioningResponse* obj);
void Unpack_ODK_ProvisioningResponseV16(ODK_Message* msg,
ODK_ProvisioningResponseV16* obj);
void Unpack_ODK_Provisioning40Response(ODK_Message* msg,
ODK_Provisioning40Response* 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_LicenseResponse(ODK_Message* msg,
const ODK_Packing_LicenseResponse* obj);
void Pack_ODK_RenewalResponse(ODK_Message* msg, const ODK_RenewalResponse* obj);
void Pack_ODK_ProvisioningResponse(ODK_Message* msg,
const ODK_ProvisioningResponse* obj);
void Pack_ODK_ProvisioningResponseV16(ODK_Message* msg,
const ODK_ProvisioningResponseV16* obj);
void Pack_ODK_Provisioning40Response(ODK_Message* msg,
const ODK_Provisioning40Response* obj);
/* kdo unpack */
void Unpack_ODK_PreparedLicenseRequest(ODK_Message* msg,
ODK_PreparedLicenseRequest* obj);
void Unpack_ODK_PreparedLicenseRequestV17(ODK_Message* msg,
ODK_PreparedLicenseRequestV17* obj);
void Unpack_ODK_PreparedRenewalRequest(ODK_Message* msg,
ODK_PreparedRenewalRequest* obj);
void Unpack_ODK_PreparedProvisioningRequest(
ODK_Message* msg, ODK_PreparedProvisioningRequest* obj);
void Unpack_ODK_PreparedProvisioningRequestV180(
ODK_Message* msg, ODK_PreparedProvisioningRequest* obj);
void Unpack_ODK_PreparedProvisioningRequestV17(
ODK_Message* msg, ODK_PreparedProvisioningRequestV17* obj);
void Unpack_ODK_PreparedProvisioning40Request(
ODK_Message* msg, ODK_PreparedProvisioning40Request* obj);
void Unpack_ODK_PreparedRenewedProvisioningRequest(
ODK_Message* msg, ODK_PreparedRenewedProvisioningRequest* obj);

View File

@@ -25,8 +25,10 @@ typedef uint32_t ODK_MessageType;
#define ODK_Provisioning_Request_Type ((ODK_MessageType)5u)
#define ODK_Provisioning_Response_Type ((ODK_MessageType)6u)
#define ODK_Renewed_Provisioning_Request_Type ((ODK_MessageType)11u)
#define ODK_Provisioning40_Request_Type ((ODK_MessageType)12u)
// Reserve future message types to support forward compatibility.
// TODO(b/244580447): 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)
@@ -40,18 +42,35 @@ typedef struct {
typedef struct {
ODK_CoreMessage core_message;
ODK_MessageCounterInfo counter_info;
} ODK_PreparedLicenseRequest;
typedef struct {
ODK_CoreMessage core_message;
} ODK_PreparedLicenseRequestV17;
typedef struct {
ODK_CoreMessage core_message;
uint64_t playback_time;
} ODK_PreparedRenewalRequest;
typedef struct {
ODK_CoreMessage core_message;
ODK_MessageCounterInfo counter_info;
} ODK_PreparedProvisioningRequest;
typedef struct {
ODK_CoreMessage core_message;
uint32_t device_id_length;
uint8_t device_id[ODK_DEVICE_ID_LEN_MAX];
} ODK_PreparedProvisioningRequest;
} ODK_PreparedProvisioningRequestV17;
typedef struct {
ODK_CoreMessage core_message;
uint32_t device_info_length;
uint8_t device_info[ODK_DEVICE_INFO_LEN_MAX];
ODK_MessageCounterInfo counter_info;
} ODK_PreparedProvisioning40Request;
typedef struct {
ODK_CoreMessage core_message;
@@ -67,27 +86,16 @@ typedef struct {
} 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_CoreMessage core_message;
ODK_ParsedLicense* parsed_license;
uint8_t request_hash[ODK_SHA256_HASH_SIZE];
} ODK_LicenseResponse;
typedef struct {
ODK_PreparedLicenseRequest request;
ODK_ParsedLicenseV16 parsed_license;
ODK_CoreMessage core_message;
ODK_Packing_ParsedLicense* parsed_license;
uint8_t request_hash[ODK_SHA256_HASH_SIZE];
} ODK_LicenseResponseV16;
} ODK_Packing_LicenseResponse;
typedef struct {
ODK_PreparedRenewalRequest request;
@@ -95,18 +103,33 @@ typedef struct {
} ODK_RenewalResponse;
typedef struct {
ODK_PreparedProvisioningRequest request;
ODK_CoreMessage core_message;
ODK_ParsedProvisioning* parsed_provisioning;
} ODK_ProvisioningResponse;
// Used by V16 and V17
typedef struct {
ODK_PreparedProvisioningRequestV17 request;
ODK_ParsedProvisioning* parsed_provisioning;
} ODK_ProvisioningResponseV16;
typedef struct {
ODK_CoreMessage core_message;
} ODK_Provisioning40Response;
// These are the sum of sizeof of each individual member of the request structs
// without any padding added by the compiler. Make sure they get updated when
// request structs change. Refer to test suite OdkSizeTest in
// ../test/odk_test.cpp for validations of each of the defined request sizes.
#define ODK_LICENSE_REQUEST_SIZE 20u
#define ODK_CORE_MESSAGE_SIZE 20u
#define ODK_LICENSE_REQUEST_SIZE 90u
#define ODK_LICENSE_REQUEST_SIZE_V17 20u
#define ODK_RENEWAL_REQUEST_SIZE 28u
#define ODK_PROVISIONING_REQUEST_SIZE 88u
#define ODK_PROVISIONING_REQUEST_SIZE 94u
#define ODK_PROVISIONING_REQUEST_SIZE_V17 88u
#define ODK_PROVISIONING40_REQUEST_SIZE 862u
#define ODK_RENEWED_PROVISIONING_REQUEST_SIZE 1694u
#define ODK_MESSAGECOUNTERINFO_SIZE 70u
// These are the possible timer status values.
#define ODK_CLOCK_TIMER_STATUS_UNDEFINED 0u // Should not happen.

View File

@@ -254,11 +254,6 @@ OEMCryptoResult ODK_InitializeSessionValues(ODK_TimerLimits* timer_limits,
if (timer_limits == NULL || clock_values == NULL || nonce_values == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
/* Check that the API version passed in from OEMCrypto matches the version of
* this ODK library. */
if (api_major_version != ODK_MAJOR_VERSION) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
timer_limits->soft_enforce_rental_duration = false;
timer_limits->soft_enforce_playback_duration = false;
timer_limits->earliest_playback_start_seconds = 0;
@@ -268,7 +263,7 @@ OEMCryptoResult ODK_InitializeSessionValues(ODK_TimerLimits* timer_limits,
ODK_InitializeClockValues(clock_values, 0);
nonce_values->api_major_version = ODK_MAJOR_VERSION;
nonce_values->api_major_version = api_major_version;
nonce_values->api_minor_version = ODK_MINOR_VERSION;
nonce_values->nonce = 0;
nonce_values->session_id = session_id;
@@ -300,6 +295,7 @@ OEMCryptoResult ODK_InitializeClockValues(ODK_ClockValues* clock_values,
clock_values->time_of_license_request_signed = system_time_seconds;
clock_values->time_of_first_decrypt = 0;
clock_values->time_of_last_decrypt = 0;
clock_values->time_of_renewal_request = 0;
clock_values->time_when_timer_expires = 0;
clock_values->timer_status = ODK_CLOCK_TIMER_STATUS_LICENSE_NOT_LOADED;
clock_values->status = kUnused;

View File

@@ -108,10 +108,40 @@ static void UnpackBytes(ODK_Message* message, uint8_t* ptr, size_t count) {
}
}
int Unpack_enum(ODK_Message* message) {
uint32_t v32;
void Unpack_OEMCrypto_LicenseType(ODK_Message* message,
OEMCrypto_LicenseType* value) {
assert(value);
uint32_t v32 = 0;
Unpack_uint32_t(message, &v32);
return (int)v32;
if (v32 <= OEMCrypto_LicenseType_MaxValue) {
*value = (OEMCrypto_LicenseType)v32;
} else {
ODK_Message_SetStatus(message, MESSAGE_STATUS_PARSE_ERROR);
}
}
void Unpack_OEMCrypto_PrivateKeyType(ODK_Message* message,
OEMCrypto_PrivateKeyType* value) {
assert(value);
uint32_t v32 = 0;
Unpack_uint32_t(message, &v32);
if (v32 <= OEMCrypto_PrivateKeyType_MaxValue) {
*value = (OEMCrypto_PrivateKeyType)v32;
} else {
ODK_Message_SetStatus(message, MESSAGE_STATUS_PARSE_ERROR);
}
}
void Unpack_OEMCrypto_TimerDelayBase(ODK_Message* message,
OEMCrypto_TimerDelayBase* value) {
assert(value);
uint32_t v32 = 0;
Unpack_uint32_t(message, &v32);
if (v32 <= OEMCrypto_TimerDelayBase_MaxValue) {
*value = (OEMCrypto_TimerDelayBase)v32;
} else {
ODK_Message_SetStatus(message, MESSAGE_STATUS_PARSE_ERROR);
}
}
void Unpack_bool(ODK_Message* message, bool* value) {

View File

@@ -25,7 +25,12 @@ void PackArray(ODK_Message* message, const uint8_t* base, size_t size);
void Pack_OEMCrypto_Substring(ODK_Message* message,
const OEMCrypto_Substring* obj);
int Unpack_enum(ODK_Message* message);
void Unpack_OEMCrypto_LicenseType(ODK_Message* message,
OEMCrypto_LicenseType* value);
void Unpack_OEMCrypto_PrivateKeyType(ODK_Message* message,
OEMCrypto_PrivateKeyType* value);
void Unpack_OEMCrypto_TimerDelayBase(ODK_Message* message,
OEMCrypto_TimerDelayBase* value);
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);

View File

@@ -11,6 +11,7 @@ package {
// all of the 'license_kinds' from "vendor_widevine_license"
// to get the below license kinds:
// legacy_by_exception_only (by exception only)
// legacy_proprietary (by exception only)
default_applicable_licenses: ["vendor_widevine_license"],
}

View File

@@ -18,6 +18,7 @@ package {
// all of the 'license_kinds' from "vendor_widevine_license"
// to get the below license kinds:
// legacy_by_exception_only (by exception only)
// legacy_proprietary (by exception only)
default_applicable_licenses: ["vendor_widevine_license"],
}

View File

@@ -113,15 +113,14 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
OEMCryptoResult ODK_PrepareCoreProvisioningRequest(
uint8_t* message, size_t message_length, size_t* core_message_length,
const ODK_NonceValues* nonce_values, const uint8_t* device_id,
size_t device_id_length) {
const ODK_NonceValues* nonce_values,
const ODK_MessageCounterInfo* counter_info) {
OEMCryptoResult (*original_function)(uint8_t*, size_t, size_t*,
const ODK_NonceValues*, const uint8_t*,
size_t);
const ODK_NonceValues*,
const ODK_MessageCounterInfo*);
original_function = dlsym(RTLD_NEXT, "ODK_PrepareCoreProvisioningRequest");
OEMCryptoResult oem_crypto_result =
(*original_function)(message, message_length, core_message_length,
nonce_values, device_id, device_id_length);
OEMCryptoResult oem_crypto_result = (*original_function)(
message, message_length, core_message_length, nonce_values, counter_info);
char* file_name = GetFileName("provisioning_request_corpus");
// Provisioning Request format expected by fuzzer - [Core Provisioning
@@ -134,18 +133,19 @@ OEMCryptoResult ODK_PrepareCoreProvisioningRequest(
OEMCryptoResult ODK_ParseProvisioning(
const uint8_t* message, size_t message_length, size_t core_message_length,
const ODK_NonceValues* nonce_values, const uint8_t* device_id,
size_t device_id_length, ODK_ParsedProvisioning* parsed_response) {
size_t device_id_length, ODK_MessageCounterInfo* counter_info,
ODK_ParsedProvisioning* parsed_response) {
struct ODK_ParseProvisioning_Args parse_provisioning_args;
parse_provisioning_args.nonce_values = *nonce_values;
memcpy(parse_provisioning_args.device_id, device_id, device_id_length);
parse_provisioning_args.device_id_length = device_id_length;
OEMCryptoResult (*original_function)(const uint8_t*, size_t, size_t,
const ODK_NonceValues*, const uint8_t*,
size_t, ODK_ParsedProvisioning*);
OEMCryptoResult (*original_function)(
const uint8_t*, size_t, size_t, const ODK_NonceValues*, const uint8_t*,
size_t, ODK_MessageCounterInfo*, ODK_ParsedProvisioning*);
original_function = dlsym(RTLD_NEXT, "ODK_ParseProvisioning");
OEMCryptoResult oem_crypto_result = (*original_function)(
message, message_length, core_message_length, nonce_values, device_id,
device_id_length, parsed_response);
device_id_length, counter_info, parsed_response);
char* file_name = GetFileName("provisioning_response_corpus");
// Provisioning Response format expected by fuzzer -

View File

@@ -23,7 +23,7 @@
'-Wno-error=cast-qual',
],
'cflags_cc': [
'-std=c++11',
'-std=c++14',
'-g3',
'-O0',
'-fsanitize=fuzzer,address,undefined',

View File

@@ -4,8 +4,12 @@
#include "fuzzing/odk_fuzz_helper.h"
#include <string>
#include <vector>
#include "core_message_types.h"
#include "odk.h"
#include "odk_attributes.h"
#include "odk_structs.h"
namespace oemcrypto_core_message {
using features::CoreMessageFeatures;
@@ -39,7 +43,11 @@ OEMCryptoResult odk_serialize_LicenseRequest(
const void* in UNUSED, uint8_t* out, size_t* size,
const ODK_LicenseRequest& core_license_request UNUSED,
const ODK_NonceValues* nonce_values) {
return ODK_PrepareCoreLicenseRequest(out, SIZE_MAX, size, nonce_values);
// TODO(mattfedd): hook up counters to fuzzer
const ODK_MessageCounterInfo counter_info = {0, 0, 0, 0, 0,
0, 0, {0}, {0}, {0}};
return ODK_PrepareCoreLicenseRequest(out, SIZE_MAX, size, nonce_values,
&counter_info);
}
OEMCryptoResult odk_serialize_RenewalRequest(
@@ -54,12 +62,13 @@ OEMCryptoResult odk_serialize_RenewalRequest(
OEMCryptoResult odk_serialize_ProvisioningRequest(
const void* in UNUSED, uint8_t* out, size_t* size,
const ODK_ProvisioningRequest& core_provisioning,
const ODK_ProvisioningRequest& core_provisioning UNUSED,
const ODK_NonceValues* nonce_values) {
const std::string& device_id = core_provisioning.device_id;
return ODK_PrepareCoreProvisioningRequest(
out, SIZE_MAX, size, nonce_values,
reinterpret_cast<const uint8_t*>(device_id.data()), device_id.size());
// TODO(mattfedd): hook up counters to fuzzer
const ODK_MessageCounterInfo counter_info = {0, 0, 0, 0, 0,
0, 0, {0}, {0}, {0}};
return ODK_PrepareCoreProvisioningRequest(out, SIZE_MAX, size, nonce_values,
&counter_info);
}
OEMCryptoResult odk_deserialize_LicenseResponse(const uint8_t* message,
@@ -69,9 +78,9 @@ OEMCryptoResult odk_deserialize_LicenseResponse(const uint8_t* message,
ODK_ParsedLicense* parsed_lic) {
return ODK_ParseLicense(message, SIZE_MAX, core_message_length,
static_cast<bool>(a->initial_license_load),
static_cast<bool>(a->usage_entry_present),
static_cast<bool>(a->usage_entry_present), 0,
&a->timer_limits, &a->clock_values, nonce_values,
parsed_lic);
parsed_lic, nullptr);
}
OEMCryptoResult odk_deserialize_RenewalResponse(
@@ -119,13 +128,32 @@ bool kdo_serialize_LicenseResponse(const ODK_ParseLicense_Args* args,
const ODK_ParsedLicense& parsed_lic,
std::string* oemcrypto_core_message) {
const auto& nonce_values = args->nonce_values;
ODK_LicenseRequest core_request{nonce_values.api_minor_version,
nonce_values.api_major_version,
nonce_values.nonce, nonce_values.session_id};
const ODK_MessageCounter counter_info = {0, 0, 0, 0, 0, 0, 0, {0}, {0}, {0}};
ODK_LicenseRequest core_request{
nonce_values.api_minor_version, nonce_values.api_major_version,
nonce_values.nonce, nonce_values.session_id, counter_info};
std::string core_request_sha_256(
reinterpret_cast<const char*>(args->request_hash), ODK_SHA256_HASH_SIZE);
ODK_Packing_ParsedLicense parsed_license;
parsed_license.enc_mac_keys_iv = parsed_lic.enc_mac_keys_iv;
parsed_license.enc_mac_keys = parsed_lic.enc_mac_keys;
parsed_license.pst = parsed_lic.pst;
parsed_license.srm_restriction_data = parsed_lic.srm_restriction_data;
parsed_license.license_type = parsed_lic.license_type;
parsed_license.nonce_required = parsed_lic.nonce_required;
parsed_license.timer_limits = parsed_lic.timer_limits;
parsed_license.watermarking = parsed_lic.watermarking;
parsed_license.dtcp2_required = parsed_lic.dtcp2_required;
parsed_license.renewal_delay_base = parsed_lic.renewal_delay_base;
parsed_license.key_array_length = parsed_lic.key_array_length;
std::vector<OEMCrypto_KeyObject> key_array;
size_t i;
for (i = 0; i < parsed_lic.key_array_length; i++) {
key_array.push_back(parsed_lic.key_array[i]);
}
parsed_license.key_array = key_array.data();
return serialize::CreateCoreLicenseResponse(
CoreMessageFeatures::kDefaultFeatures, parsed_lic, core_request,
CoreMessageFeatures::kDefaultFeatures, parsed_license, core_request,
core_request_sha_256, oemcrypto_core_message);
}
@@ -151,11 +179,17 @@ bool kdo_serialize_ProvisioningResponse(
if (args->device_id_length > sizeof(args->device_id)) {
return false;
}
const ODK_MessageCounter counter_info = {0, 0, 0, 0, 0, 0, 0, {0}, {0}, {0}};
ODK_ProvisioningRequest core_request{
nonce_values.api_minor_version, nonce_values.api_major_version,
nonce_values.nonce, nonce_values.session_id,
nonce_values.api_minor_version,
nonce_values.api_major_version,
nonce_values.nonce,
nonce_values.session_id,
std::string(reinterpret_cast<const char*>(args->device_id),
args->device_id_length)};
args->device_id_length),
0,
"",
counter_info};
return serialize::CreateCoreProvisioningResponse(
CoreMessageFeatures::kDefaultFeatures, parsed_prov, core_request,
oemcrypto_core_message);

View File

@@ -2,14 +2,30 @@
// source code may only be used and distributed under the Widevine
// License Agreement.
#include <ostream>
#include <string>
#include <tuple>
#include <vector>
#include "OEMCryptoCENCCommon.h"
#include "core_message_deserialize.h"
#include "core_message_features.h"
#include "core_message_serialize_proto.h"
#include "core_message_types.h"
#include "gtest/gtest.h"
#include "odk.h"
#include "third_party/absl/strings/escaping.h"
namespace wvodk_test {
using oemcrypto_core_message::ODK_CommonRequest;
using oemcrypto_core_message::ODK_ProvisioningRequest;
using oemcrypto_core_message::deserialize::CoreCommonRequestFromMessage;
using oemcrypto_core_message::deserialize::CoreProvisioningRequestFromMessage;
using oemcrypto_core_message::features::CoreMessageFeatures;
using oemcrypto_core_message::serialize::
CreateCoreProvisioningResponseFromProto;
TEST(CoreMessageTest, RenwalRequest) {
std::string oem =
"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst"
@@ -36,4 +52,145 @@ TEST(CoreMessageTest, RenwalRequest) {
char* m = reinterpret_cast<char*>(message);
VLOG(0) << absl::BytesToHexString(std::string(m, core_message_length));
}
TEST(CoreMessageTest, ParseCoreCommonRequestFromMessage) {
// Core message header format:
// message_type : 4 bytes
// message_length : 4 bytes
// minor_version : 2 bytes
// major_version : 2 bytes
// nonce : 4 bytes
// session_id : 4 bytes
const char kv16CoreMessageLicenseRequest[] =
"0000000100000014000300100000000100000001";
std::string oemcrypto_core_message =
absl::HexStringToBytes(kv16CoreMessageLicenseRequest);
ODK_CommonRequest odk_common_request;
ASSERT_TRUE(CoreCommonRequestFromMessage(oemcrypto_core_message,
&odk_common_request));
EXPECT_EQ(odk_common_request.message_type, 1);
EXPECT_EQ(odk_common_request.message_length, 20);
EXPECT_EQ(odk_common_request.api_minor_version, 3);
EXPECT_EQ(odk_common_request.api_major_version, 16);
EXPECT_EQ(odk_common_request.nonce, 1);
EXPECT_EQ(odk_common_request.session_id, 1);
}
struct TestParameters_18V0 {
std::string message;
uint16_t expected_api_minor_version;
uint16_t expected_api_major_version;
uint32_t expected_nonce;
uint32_t expected_session_id;
uint64_t expected_master_generation_number;
};
void PrintTo(const TestParameters_18V0& p, std::ostream* os) {
*os << "request = " << p.message << ", expected : {version = v"
<< p.expected_api_major_version << "." << p.expected_api_minor_version
<< ", nonce = " << p.expected_nonce
<< ", session_id = " << p.expected_session_id
<< ", master_generation_number = " << p.expected_master_generation_number
<< "}";
}
class ProvisioningRoundTripTest_18V0
: public ::testing::Test,
public ::testing::WithParamInterface<TestParameters_18V0> {};
// Make sure that the first version of the V18 provisioning request (no hidden
// 4-byte value, all 0s in message counter struct) will still parse with
// current v18 code. This test is in this file rather than odk_test.cpp
// because of the use of absl::HexStringToBytes
TEST_P(ProvisioningRoundTripTest_18V0, ProvisioningRoundtrip) {
TestParameters_18V0 tc = GetParam();
ODK_ProvisioningRequest request;
// Make sure we can parse the request
ASSERT_TRUE(CoreProvisioningRequestFromMessage(
absl::HexStringToBytes(tc.message), &request));
EXPECT_EQ(request.api_minor_version, tc.expected_api_minor_version);
EXPECT_EQ(request.api_major_version, tc.expected_api_major_version);
EXPECT_EQ(request.nonce, tc.expected_nonce);
EXPECT_EQ(request.session_id, tc.expected_session_id);
if (request.api_major_version >= 18) {
EXPECT_EQ(request.counter_info.master_generation_number,
tc.expected_master_generation_number);
}
// Make sure we can create a response from that request with the same core
// message
const CoreMessageFeatures features =
CoreMessageFeatures::DefaultFeatures(ODK_MAJOR_VERSION);
std::string serialized_provisioning_resp;
video_widevine::ProvisioningResponse provisioning_response;
provisioning_response.set_device_certificate("device_certificate");
provisioning_response.set_device_rsa_key("device_rsa_key");
provisioning_response.set_device_rsa_key_iv("device_rsa_key_iv");
if (!provisioning_response.SerializeToString(&serialized_provisioning_resp)) {
FAIL() << "Cannot set up prov response";
}
std::string oemcrypto_core_message;
EXPECT_TRUE(CreateCoreProvisioningResponseFromProto(
features, serialized_provisioning_resp, request,
OEMCrypto_RSA_Private_Key, &oemcrypto_core_message));
// Extract core message from generated prov response and match values with
// request
ODK_CommonRequest odk_common_request;
ASSERT_TRUE(CoreCommonRequestFromMessage(oemcrypto_core_message,
&odk_common_request));
EXPECT_EQ(odk_common_request.message_type, 6u);
EXPECT_EQ(odk_common_request.nonce, tc.expected_nonce);
EXPECT_EQ(odk_common_request.session_id, tc.expected_session_id);
}
std::vector<TestParameters_18V0> TestCases() {
return std::vector<TestParameters_18V0>{
// Source: ODKTest ProvisionRequestRoundtrip running on v18.0 ODK checkout
{"000000050000005a00000012deadbeefcafebabe12345678abcdffff0000000c0000003"
"200000154001200000004ffffffffffffffffffffffffffffffffdddddddddddddddddd"
"ddddddddddddddeeeeeeeeeeeeeeeeeeeeeeee",
0, 18, 0xdeadbeef, 0xcafebabe, 0x12345678abcdffff},
// same as previous request, but replace counter info with all 0s
{"000000050000005a00000012deadbeefcafebabe0000000000000000000000000000000"
"00000000000000000000000000000000000000000000000000000000000000000000000"
"00000000000000000000000000000000000000",
0, 18, 0xdeadbeef, 0xcafebabe, 0x0},
// Source: ODKTest ProvisionRequestRoundtrip running on v17.2 ODK checkout
{"000000050000005800020011deadbeefcafebabe00000020fffffffffffffffffffffff"
"fffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000"
"0000000000000000000000000000000000",
2, 17, 0xdeadbeef, 0xcafebabe, 0x0},
// Source: ODKTest ProvisionRequestRoundtrip running on v18.2 ODK checkout
{"000000050000005e00020012deadbeefcafebabe0000004012345678abcdffff0000000"
"c0000003200000154001200020004ffffffffffffffffffffffffffffffffdddddddddd"
"ddddddddddddddddddddddeeeeeeeeeeeeeeeeeeeeeeee",
2, 18, 0xdeadbeef, 0xcafebabe, 0x12345678abcdffff},
// Source: CDM unit tests on oemcrypto-v18 internal commit 5c77383 (pre
// v18.0 -> v18.1 ODK bump)
{"000000050000005a00000012b85dfa09000000000000000000000000000000000000000"
"00000000000000000000000000000000000000000000000000000000000000000000000"
"00000000000000000000000000000000000000",
0, 18, 0xb85dfa09, 0x0, 0x0},
// Same as above but non-zero counter info
{"000000050000005a00000012b85dfa09000000001000000000000001000000000000000"
"00000000000000000000000000000000000000000000000000000000000000000000000"
"00000000000000000000000000000000000000",
0, 18, 0xb85dfa09, 0x0, 0x1000000000000001},
// Source: CDM unit tests on oemcrypto-v18 internal commit fc46827a (post
// v18.0 -> v18.1 ODK bump)
{"000000050000005e000100127c8ac703000000000000004000000000000000000000000"
"00000000000000000001200010000746573740000000000000000000000007465737400"
"0000000000000000000000000000000000000000000000",
1, 18, 0x7c8ac703, 0x0, 0x0},
};
}
INSTANTIATE_TEST_SUITE_P(ProvisioningRoundTripTests_18V0,
ProvisioningRoundTripTest_18V0,
::testing::ValuesIn(TestCases()));
} // namespace wvodk_test

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -4,16 +4,22 @@
#include "odk.h"
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <ostream>
#include <string>
#include <vector>
#include "OEMCryptoCENCCommon.h"
#include "core_message_deserialize.h"
#include "core_message_features.h"
#include "core_message_serialize.h"
#include "core_message_serialize_proto.h"
#include "core_message_types.h"
#include "gtest/gtest.h"
#include "odk_overflow.h"
#include "odk_structs.h"
#include "odk_structs_priv.h"
#include "odk_test_helper.h"
@@ -21,11 +27,16 @@ namespace wvodk_test {
namespace {
using oemcrypto_core_message::ODK_CommonRequest;
using oemcrypto_core_message::ODK_LicenseRequest;
using oemcrypto_core_message::ODK_MessageCounter;
using oemcrypto_core_message::ODK_Provisioning40Request;
using oemcrypto_core_message::ODK_ProvisioningRequest;
using oemcrypto_core_message::ODK_RenewalRequest;
using oemcrypto_core_message::deserialize::CoreCommonRequestFromMessage;
using oemcrypto_core_message::deserialize::CoreLicenseRequestFromMessage;
using oemcrypto_core_message::deserialize::CoreProvisioning40RequestFromMessage;
using oemcrypto_core_message::deserialize::CoreProvisioningRequestFromMessage;
using oemcrypto_core_message::deserialize::CoreRenewalRequestFromMessage;
using oemcrypto_core_message::deserialize::
@@ -34,7 +45,10 @@ using oemcrypto_core_message::deserialize::
using oemcrypto_core_message::features::CoreMessageFeatures;
using oemcrypto_core_message::serialize::CreateCoreLicenseResponse;
using oemcrypto_core_message::serialize::CreateCoreProvisioning40Response;
using oemcrypto_core_message::serialize::CreateCoreProvisioningResponse;
using oemcrypto_core_message::serialize::
CreateCoreProvisioningResponseFromProto;
using oemcrypto_core_message::serialize::CreateCoreRenewalResponse;
constexpr uint32_t kExtraPayloadSize = 128u;
@@ -59,6 +73,40 @@ void PrintTo(const VersionParameters& p, std::ostream* os) {
<< p.response_minor_version;
}
void SetDefaultSerializedProvisioningResponse(std::string* serialized_message) {
// Create a dummy provisioning response
video_widevine::ProvisioningResponse provisioning_response;
provisioning_response.set_device_certificate("device_certificate");
provisioning_response.set_device_rsa_key("device_rsa_key");
provisioning_response.set_device_rsa_key_iv("device_rsa_key_iv");
if (!provisioning_response.SerializeToString(serialized_message)) {
FAIL();
}
}
bool CheckCounterInfoIsEqual(ODK_MessageCounterInfo* a, ODK_MessageCounter* b) {
if (!a || !b) return false;
EXPECT_EQ(a->master_generation_number, b->master_generation_number);
EXPECT_EQ(a->provisioning_count, b->provisioning_count);
EXPECT_EQ(a->license_count, b->license_count);
EXPECT_EQ(a->decrypt_count, b->decrypt_count);
EXPECT_EQ(a->major_version, b->major_version);
EXPECT_EQ(a->minor_version, b->minor_version);
EXPECT_EQ(a->patch_version, b->patch_version);
for (size_t i = 0; i < sizeof(a->soc_vendor); i++) {
EXPECT_EQ(a->soc_vendor[i], b->soc_vendor[i]);
}
for (size_t i = 0; i < sizeof(a->chipset_model); i++) {
EXPECT_EQ(a->chipset_model[i], b->chipset_model[i]);
}
for (size_t i = 0; i < sizeof(a->extra); i++) {
EXPECT_EQ(a->extra[i], b->extra[i]);
}
return true;
}
template <typename T, typename F, typename G>
void ValidateRequest(uint32_t message_type,
const std::vector<ODK_Field>& extra_fields,
@@ -241,13 +289,19 @@ TEST(OdkTest, NullRequestTest) {
memset(&nonce_values, 0, sizeof(nonce_values));
ODK_ClockValues clock_values;
memset(&clock_values, 0, sizeof(clock_values));
ODK_MessageCounterInfo counter_info;
memset(&counter_info, 0, sizeof(counter_info));
// Assert that nullptr does not cause a core dump.
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreLicenseRequest(
nullptr, 0uL, nullptr, &nonce_values));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreLicenseRequest(nullptr, 0uL, nullptr, &nonce_values,
&counter_info));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreLicenseRequest(nullptr, 0uL, &core_message_length,
nullptr));
nullptr, &counter_info));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreLicenseRequest(nullptr, 0uL, &core_message_length,
&nonce_values, nullptr));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreRenewalRequest(nullptr, 0uL, nullptr, &nonce_values,
@@ -261,18 +315,49 @@ TEST(OdkTest, NullRequestTest) {
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreProvisioningRequest(
nullptr, 0uL, &core_message_length, nullptr, nullptr, 0uL));
nullptr, 0uL, &core_message_length, nullptr, &counter_info));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreProvisioningRequest(nullptr, 0uL, nullptr,
&nonce_values, nullptr, 0uL));
&nonce_values, &counter_info));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreProvisioningRequest(
nullptr, 0uL, &core_message_length, &nonce_values, nullptr));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreProvisioning40Request(
nullptr, 0uL, &core_message_length,
nullptr, nullptr, 0uL, &counter_info));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreProvisioning40Request(
nullptr, 0uL, nullptr, &nonce_values,
nullptr, 0uL, &counter_info));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreProvisioning40Request(
nullptr, 0uL, &core_message_length,
&nonce_values, nullptr, 0uL, nullptr));
// Null device id in provisioning request is ok
if (nonce_values.api_major_version > 17) {
uint8_t message[ODK_PROVISIONING_REQUEST_SIZE] = {0};
core_message_length = ODK_PROVISIONING_REQUEST_SIZE;
EXPECT_EQ(OEMCrypto_SUCCESS,
ODK_PrepareCoreProvisioningRequest(
message, ODK_PROVISIONING_REQUEST_SIZE, &core_message_length,
&nonce_values, nullptr, 0uL));
&nonce_values, &counter_info));
} else {
uint8_t message[ODK_PROVISIONING_REQUEST_SIZE_V17] = {0};
core_message_length = ODK_PROVISIONING_REQUEST_SIZE_V17;
EXPECT_EQ(OEMCrypto_SUCCESS,
ODK_PrepareCoreProvisioningRequest(
message, ODK_PROVISIONING_REQUEST_SIZE_V17,
&core_message_length, &nonce_values, &counter_info));
}
// Null device info in provisioning 4.0 request is ok
uint8_t message_prov4[ODK_PROVISIONING40_REQUEST_SIZE] = {0};
core_message_length = ODK_PROVISIONING40_REQUEST_SIZE;
EXPECT_EQ(
OEMCrypto_SUCCESS,
ODK_PrepareCoreProvisioning40Request(
message_prov4, ODK_PROVISIONING40_REQUEST_SIZE, &core_message_length,
&nonce_values, nullptr, 0uL, &counter_info));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreRenewedProvisioningRequest(
@@ -316,26 +401,26 @@ 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, 0, &timer_limits, &clock_values,
&nonce_values, nullptr, nullptr));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_ParseLicense(message, message_size, core_message_length, true,
true, 0, &timer_limits, &clock_values, nullptr,
&parsed_license, nullptr));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_ParseLicense(message, message_size, core_message_length, true,
true, 0, &timer_limits, nullptr, &nonce_values,
&parsed_license, nullptr));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_ParseLicense(message, message_size, core_message_length, true,
true, 0, nullptr, &clock_values, &nonce_values,
&parsed_license, nullptr));
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, 0, &timer_limits, &clock_values,
&nonce_values, &parsed_license, nullptr));
constexpr uint64_t system_time = 0;
uint64_t timer_value = 0;
@@ -373,6 +458,13 @@ TEST(OdkTest, NullResponseTest) {
ODK_ParseProvisioning(nullptr, message_size, core_message_length,
&nonce_values, device_id,
ODK_DEVICE_ID_LEN_MAX, &parsed_response));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_ParseProvisioning40(message, message_size, core_message_length,
nullptr));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_ParseProvisioning40(nullptr, message_size, core_message_length,
&nonce_values));
}
TEST(OdkTest, PrepareCoreLicenseRequest) {
@@ -380,9 +472,12 @@ TEST(OdkTest, PrepareCoreLicenseRequest) {
size_t core_message_length = sizeof(license_message);
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
EXPECT_EQ(OEMCrypto_SUCCESS, ODK_PrepareCoreLicenseRequest(
license_message, sizeof(license_message),
&core_message_length, &nonce_values));
ODK_MessageCounterInfo counter_info;
memset(&counter_info, 0, sizeof(counter_info));
EXPECT_EQ(OEMCrypto_SUCCESS,
ODK_PrepareCoreLicenseRequest(
license_message, sizeof(license_message), &core_message_length,
&nonce_values, &counter_info));
}
TEST(OdkTest, PrepareCoreLicenseRequestSize) {
@@ -390,18 +485,20 @@ TEST(OdkTest, PrepareCoreLicenseRequestSize) {
size_t core_message_length = sizeof(license_message);
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
ODK_MessageCounterInfo counter_info;
memset(&counter_info, 0, sizeof(counter_info));
// message length smaller than core message length
size_t core_message_length_invalid = core_message_length + 1;
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreLicenseRequest(
license_message, sizeof(license_message),
&core_message_length_invalid, &nonce_values));
&core_message_length_invalid, &nonce_values, &counter_info));
// message length larger than core message length
uint8_t license_message_large[ODK_LICENSE_REQUEST_SIZE * 2] = {0};
EXPECT_EQ(OEMCrypto_SUCCESS,
ODK_PrepareCoreLicenseRequest(license_message_large,
sizeof(license_message_large),
&core_message_length, &nonce_values));
ODK_PrepareCoreLicenseRequest(
license_message_large, sizeof(license_message_large),
&core_message_length, &nonce_values, &counter_info));
}
TEST(OdkTest, PrepareCoreRenewalRequest) {
@@ -446,12 +543,27 @@ TEST(OdkTest, PrepareCoreProvisioningRequest) {
size_t core_message_length = sizeof(provisioning_message);
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0};
EXPECT_EQ(
OEMCrypto_SUCCESS,
ODK_MessageCounterInfo counter_info;
memset(&counter_info, 0, sizeof(counter_info));
EXPECT_EQ(OEMCrypto_SUCCESS,
ODK_PrepareCoreProvisioningRequest(
provisioning_message, sizeof(provisioning_message),
&core_message_length, &nonce_values, device_id, sizeof(device_id)));
&core_message_length, &nonce_values, &counter_info));
}
TEST(OdkTest, PrepareCoreProvisioning40Request) {
uint8_t provisioning_message[ODK_PROVISIONING40_REQUEST_SIZE] = {0};
size_t core_message_length = sizeof(provisioning_message);
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
ODK_MessageCounterInfo counter_info;
memset(&counter_info, 0, sizeof(counter_info));
uint8_t device_info[ODK_DEVICE_INFO_LEN_MAX] = {0};
EXPECT_EQ(OEMCrypto_SUCCESS,
ODK_PrepareCoreProvisioning40Request(
provisioning_message, sizeof(provisioning_message),
&core_message_length, &nonce_values, device_info,
sizeof(device_info), &counter_info));
}
TEST(OdkTest, PrepareCoreRenewedProvisioningRequest) {
@@ -469,17 +581,19 @@ TEST(OdkTest, PrepareCoreRenewedProvisioningRequest) {
OEMCrypto_RenewalACert, renewal_data, sizeof(renewal_data)));
}
TEST(OdkTest, PrepareCoreProvisioningRequestDeviceId) {
uint8_t provisioning_message[ODK_PROVISIONING_REQUEST_SIZE] = {0};
TEST(OdkTest, PrepareCoreProvisioning40RequestDeviceInfo) {
uint8_t provisioning_message[ODK_PROVISIONING40_REQUEST_SIZE] = {0};
size_t core_message_length = sizeof(provisioning_message);
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
uint8_t device_id_invalid[ODK_DEVICE_ID_LEN_MAX + 1] = {0};
ODK_MessageCounterInfo counter_info;
memset(&counter_info, 0, sizeof(counter_info));
uint8_t device_info_invalid[ODK_DEVICE_INFO_LEN_MAX + 1] = {0};
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreProvisioningRequest(
ODK_PrepareCoreProvisioning40Request(
provisioning_message, sizeof(provisioning_message),
&core_message_length, &nonce_values, device_id_invalid,
sizeof(device_id_invalid)));
&core_message_length, &nonce_values, device_info_invalid,
sizeof(device_info_invalid), &counter_info));
}
TEST(OdkTest, PrepareCoreRenewedProvisioningRequestDeviceId) {
@@ -514,13 +628,36 @@ TEST(OdkTest, PrepareCoreRenewedProvisioningRequestRenewalDataInvalid) {
// Serialize and de-serialize license request
TEST(OdkTest, LicenseRequestRoundtrip) {
std::vector<ODK_Field> empty;
ODK_MessageCounterInfo counter_info;
counter_info.master_generation_number = 0x12345678abcdffff;
counter_info.provisioning_count = 12;
counter_info.license_count = 50;
counter_info.decrypt_count = 340;
counter_info.major_version = ODK_MAJOR_VERSION;
counter_info.minor_version = ODK_MINOR_VERSION;
counter_info.patch_version = 4;
memset(counter_info.soc_vendor, 0xff, sizeof(counter_info.soc_vendor));
memset(counter_info.chipset_model, 0xdd, sizeof(counter_info.chipset_model));
memset(counter_info.extra, 0xee, sizeof(counter_info.extra));
std::vector<ODK_Field> extra_fields = {
{ODK_MESSAGECOUNTER, &counter_info, "counter_info"},
};
auto odk_prepare_func = [&](uint8_t* const buf, size_t* size,
ODK_NonceValues* nonce_values) {
return ODK_PrepareCoreLicenseRequest(buf, SIZE_MAX, size, nonce_values);
return ODK_PrepareCoreLicenseRequest(buf, SIZE_MAX, size, nonce_values,
&counter_info);
};
auto kdo_parse_func = CoreLicenseRequestFromMessage;
ValidateRequest<ODK_LicenseRequest>(ODK_License_Request_Type, empty,
auto kdo_parse_func = [&](const std::string& oemcrypto_core_message,
ODK_LicenseRequest* core_license_request) {
bool ok = CoreLicenseRequestFromMessage(oemcrypto_core_message,
core_license_request);
if (!ok) return false;
ok = CheckCounterInfoIsEqual(&counter_info,
&core_license_request->counter_info);
return ok;
};
ValidateRequest<ODK_LicenseRequest>(ODK_License_Request_Type, extra_fields,
odk_prepare_func, kdo_parse_func);
}
@@ -550,23 +687,38 @@ TEST(OdkTest, RenewalRequestRoundtrip) {
}
TEST(OdkTest, ProvisionRequestRoundtrip) {
uint32_t device_id_length = ODK_DEVICE_ID_LEN_MAX / 2;
uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0};
memset(device_id, 0xff, device_id_length);
ODK_MessageCounterInfo counter_info;
counter_info.master_generation_number = 0x12345678abcdffff;
counter_info.provisioning_count = 12;
counter_info.license_count = 50;
counter_info.decrypt_count = 340;
counter_info.major_version = ODK_MAJOR_VERSION;
counter_info.minor_version = ODK_MINOR_VERSION;
counter_info.patch_version = 4;
memset(counter_info.soc_vendor, 0xff, sizeof(counter_info.soc_vendor));
memset(counter_info.chipset_model, 0xdd, sizeof(counter_info.chipset_model));
memset(counter_info.extra, 0xee, sizeof(counter_info.extra));
// Fake device_id_length for older servers, since we removed device id from
// the v18 request
uint32_t fake_device_id_length = 64;
std::vector<ODK_Field> extra_fields = {
{ODK_UINT32, &device_id_length, "device_id_length"},
{ODK_DEVICEID, device_id, "device_id"},
{ODK_UINT32, &(fake_device_id_length), "fake_device_id_length"},
{ODK_MESSAGECOUNTER, &counter_info, "counter_info"},
};
auto odk_prepare_func = [&](uint8_t* const buf, size_t* size,
const ODK_NonceValues* nonce_values) {
return ODK_PrepareCoreProvisioningRequest(buf, SIZE_MAX, size, nonce_values,
device_id, device_id_length);
&counter_info);
};
auto kdo_parse_func =
[&](const std::string& oemcrypto_core_message,
ODK_ProvisioningRequest* core_provisioning_request) {
bool ok = CoreProvisioningRequestFromMessage(oemcrypto_core_message,
core_provisioning_request);
if (!ok) return false;
ok = CheckCounterInfoIsEqual(&counter_info,
&core_provisioning_request->counter_info);
return ok;
};
ValidateRequest<ODK_ProvisioningRequest>(ODK_Provisioning_Request_Type,
@@ -574,6 +726,47 @@ TEST(OdkTest, ProvisionRequestRoundtrip) {
kdo_parse_func);
}
TEST(OdkTest, ProvisionRequest40Roundtrip) {
uint32_t device_info_length = ODK_DEVICE_INFO_LEN_MAX / 2;
uint8_t device_info[ODK_DEVICE_INFO_LEN_MAX] = {0};
memset(device_info, 0xaa, device_info_length);
ODK_MessageCounterInfo counter_info;
counter_info.master_generation_number = 0x12345678abcdffff;
counter_info.provisioning_count = 12;
counter_info.license_count = 50;
counter_info.decrypt_count = 340;
counter_info.major_version = ODK_MAJOR_VERSION;
counter_info.minor_version = ODK_MINOR_VERSION;
counter_info.patch_version = 4;
memset(counter_info.soc_vendor, 0xff, sizeof(counter_info.soc_vendor));
memset(counter_info.chipset_model, 0xdd, sizeof(counter_info.chipset_model));
memset(counter_info.extra, 0xee, sizeof(counter_info.extra));
std::vector<ODK_Field> extra_fields = {
{ODK_UINT32, &device_info_length, "device_info_length"},
{ODK_DEVICEINFO, device_info, "device_info"},
{ODK_MESSAGECOUNTER, &counter_info, "counter_info"},
};
auto odk_prepare_func = [&](uint8_t* const buf, size_t* size,
const ODK_NonceValues* nonce_values) {
return ODK_PrepareCoreProvisioning40Request(
buf, SIZE_MAX, size, nonce_values, device_info, device_info_length,
&counter_info);
};
auto kdo_parse_func =
[&](const std::string& oemcrypto_core_message,
ODK_Provisioning40Request* core_provisioning_request) {
bool ok = CoreProvisioning40RequestFromMessage(
oemcrypto_core_message, core_provisioning_request);
if (!ok) return false;
ok = CheckCounterInfoIsEqual(&counter_info,
&core_provisioning_request->counter_info);
return ok;
};
ValidateRequest<ODK_Provisioning40Request>(ODK_Provisioning40_Request_Type,
extra_fields, odk_prepare_func,
kdo_parse_func);
}
TEST(OdkTest, RenewedProvisionRequestRoundtrip) {
uint32_t device_id_length = ODK_DEVICE_ID_LEN_MAX / 2;
uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0};
@@ -618,9 +811,9 @@ 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, 0, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license));
&(params.parsed_license), nullptr);
EXPECT_EQ(OEMCrypto_ERROR_INVALID_NONCE, err);
delete[] buf;
}
@@ -635,9 +828,9 @@ 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, 0, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license));
&(params.parsed_license), nullptr);
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err);
delete[] buf;
}
@@ -653,9 +846,9 @@ TEST(OdkTest, ParseLicenseNullSubstring) {
&buf_size);
OEMCryptoResult result = ODK_ParseLicense(
buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load,
params.usage_entry_present, &(params.timer_limits),
params.usage_entry_present, 0, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license));
&(params.parsed_license), nullptr);
EXPECT_EQ(OEMCrypto_SUCCESS, result);
delete[] buf;
}
@@ -671,9 +864,9 @@ TEST(OdkTest, ParseLicenseErrorSubstringOffset) {
&buf_size);
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, 0, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license));
&(params.parsed_license), nullptr);
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err);
delete[] buf;
@@ -687,9 +880,9 @@ TEST(OdkTest, ParseLicenseErrorSubstringOffset) {
&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, 0, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license));
&(params.parsed_license), nullptr);
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err);
delete[] buf;
}
@@ -701,7 +894,10 @@ TEST(OdkTest, ParseRenewalErrorTimer) {
uint32_t buf_size = 0;
ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf,
&buf_size);
params.clock_values.time_of_renewal_request = 0;
// Set the time for the last renewal request, as seen in clock_values, to be
// after the time in the request.
// TODO: b/290249855 - This is reversed. It should be +5.
params.clock_values.time_of_renewal_request = params.playback_clock - 5;
OEMCryptoResult err = ODK_ParseRenewal(
buf, buf_size, buf_size, &(params.core_message.nonce_values),
params.system_time, &(params.timer_limits), &(params.clock_values),
@@ -710,20 +906,50 @@ TEST(OdkTest, ParseRenewalErrorTimer) {
delete[] buf;
}
TEST(OdkTest, ParsePrivisioningErrorDeviceId) {
ODK_ProvisioningResponseParams params;
ODK_SetDefaultProvisioningResponseParams(&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 device_id
params.device_id[0] = 0;
OEMCryptoResult err = ODK_ParseProvisioning(
buf, buf_size + 16, buf_size, &(params.core_message.nonce_values),
params.device_id, params.device_id_length, &(params.parsed_provisioning));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err);
delete[] buf;
TEST(OdkTest, ProvisionResponseFromProto) {
std::string serialized_provisioning_resp;
EXPECT_NO_FATAL_FAILURE(
SetDefaultSerializedProvisioningResponse(&serialized_provisioning_resp));
ODK_ProvisioningRequest core_request = {
.api_minor_version = ODK_MINOR_VERSION,
.api_major_version = ODK_MAJOR_VERSION,
.nonce = 0xdeadbeef,
.session_id = 0xcafebabe,
};
const CoreMessageFeatures features =
CoreMessageFeatures::DefaultFeatures(ODK_MAJOR_VERSION);
std::string oemcrypto_core_message;
EXPECT_TRUE(CreateCoreProvisioningResponseFromProto(
features, serialized_provisioning_resp, core_request,
OEMCrypto_RSA_Private_Key, &oemcrypto_core_message));
}
// Verify de-serialize common request.
TEST(OdkTest, ParseCoreCommonRequestFromMessage) {
std::string serialized_provisioning_resp;
EXPECT_NO_FATAL_FAILURE(
SetDefaultSerializedProvisioningResponse(&serialized_provisioning_resp));
ODK_ProvisioningRequest core_request = {
.api_minor_version = ODK_MINOR_VERSION,
.api_major_version = ODK_MAJOR_VERSION,
.nonce = 0xdeadbeef,
.session_id = 0xcafebabe,
};
const CoreMessageFeatures features =
CoreMessageFeatures::DefaultFeatures(ODK_MAJOR_VERSION);
std::string oemcrypto_core_message;
EXPECT_TRUE(CreateCoreProvisioningResponseFromProto(
features, serialized_provisioning_resp, core_request,
OEMCrypto_RSA_Private_Key, &oemcrypto_core_message));
ODK_CommonRequest odk_common_request;
ASSERT_TRUE(CoreCommonRequestFromMessage(oemcrypto_core_message,
&odk_common_request));
EXPECT_EQ(odk_common_request.message_type, 6u);
EXPECT_EQ(odk_common_request.message_length, 48u);
EXPECT_EQ(odk_common_request.api_minor_version, ODK_MINOR_VERSION);
EXPECT_EQ(odk_common_request.api_major_version, ODK_MAJOR_VERSION);
EXPECT_EQ(odk_common_request.nonce, 0xdeadbeef);
EXPECT_EQ(odk_common_request.session_id, 0xcafebabe);
}
class OdkVersionTest : public ::testing::Test,
@@ -735,8 +961,12 @@ class OdkVersionTest : public ::testing::Test,
GetParam().response_major_version;
params->core_message.nonce_values.api_minor_version =
GetParam().response_minor_version;
features_ =
CoreMessageFeatures::DefaultFeatures(GetParam().maximum_major_version);
if (GetParam().maximum_major_version > 0) {
features_ = CoreMessageFeatures::DefaultFeatures(
GetParam().maximum_major_version);
} else {
features_ = CoreMessageFeatures::kDefaultFeatures;
}
}
CoreMessageFeatures features_;
};
@@ -756,17 +986,36 @@ TEST_P(OdkVersionTest, LicenseResponseRoundtrip) {
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, 0, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license));
&(params.parsed_license), nullptr);
};
ODK_Packing_ParsedLicense parsed_license;
parsed_license.enc_mac_keys_iv = params.parsed_license.enc_mac_keys_iv;
parsed_license.enc_mac_keys = params.parsed_license.enc_mac_keys;
parsed_license.pst = params.parsed_license.pst;
parsed_license.srm_restriction_data =
params.parsed_license.srm_restriction_data;
parsed_license.license_type = params.parsed_license.license_type;
parsed_license.nonce_required = params.parsed_license.nonce_required;
parsed_license.timer_limits = params.parsed_license.timer_limits;
parsed_license.watermarking = params.parsed_license.watermarking;
parsed_license.dtcp2_required = params.parsed_license.dtcp2_required;
parsed_license.renewal_delay_base = params.parsed_license.renewal_delay_base;
parsed_license.key_array_length = params.parsed_license.key_array_length;
std::vector<OEMCrypto_KeyObject> key_array;
for (size_t i = 0; i < params.parsed_license.key_array_length; i++) {
key_array.push_back(params.parsed_license.key_array[i]);
}
parsed_license.key_array = key_array.data();
const std::string request_hash_string(
reinterpret_cast<const char*>(request_hash_read),
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(features_, parsed_license, core_request,
request_hash_string,
oemcrypto_core_message);
};
ValidateResponse<ODK_LicenseRequest>(GetParam(), &(params.core_message),
@@ -774,6 +1023,84 @@ TEST_P(OdkVersionTest, LicenseResponseRoundtrip) {
kdo_prepare_func);
}
// Serialize and de-serialize license response with more keys than
// ODK_MAX_NUM_KEYS.
TEST_P(OdkVersionTest, LicenseResponseRoundtripMoreThanMaxKeys) {
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
uint8_t request_hash_read[ODK_SHA256_HASH_SIZE];
memcpy(request_hash_read, params.request_hash, sizeof(request_hash_read));
uint8_t* buf = nullptr;
uint32_t buf_size = 0;
ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf,
&buf_size);
uint8_t* zero = new uint8_t[buf_size]{};
size_t bytes_read = 0;
// zero-out input
EXPECT_EQ(OEMCrypto_SUCCESS,
ODK_IterFields(ODK_READ, zero, buf_size, &bytes_read,
params.extra_fields));
// Parse buf with odk
const OEMCryptoResult parse_result = ODK_ParseLicense(
buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load,
params.usage_entry_present, 0, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license), nullptr);
EXPECT_EQ(OEMCrypto_SUCCESS, parse_result);
size_t size_out = 0;
if (parse_result != OEMCrypto_SUCCESS) {
ODK_IterFields(ODK_FieldMode::ODK_DUMP, buf, buf_size, &size_out,
params.extra_fields);
}
ODK_Packing_ParsedLicense parsed_license;
parsed_license.enc_mac_keys_iv = params.parsed_license.enc_mac_keys_iv;
parsed_license.enc_mac_keys = params.parsed_license.enc_mac_keys;
parsed_license.pst = params.parsed_license.pst;
parsed_license.srm_restriction_data =
params.parsed_license.srm_restriction_data;
parsed_license.license_type = params.parsed_license.license_type;
parsed_license.nonce_required = params.parsed_license.nonce_required;
parsed_license.timer_limits = params.parsed_license.timer_limits;
parsed_license.watermarking = params.parsed_license.watermarking;
parsed_license.dtcp2_required = params.parsed_license.dtcp2_required;
parsed_license.renewal_delay_base = params.parsed_license.renewal_delay_base;
parsed_license.key_array_length = ODK_MAX_NUM_KEYS + 1;
std::vector<OEMCrypto_KeyObject> key_array;
for (size_t i = 0; i < ODK_MAX_NUM_KEYS + 1; i++) {
OEMCrypto_KeyObject key = {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}};
key_array.push_back(key);
}
parsed_license.key_array = key_array.data();
const std::string request_hash_string(
reinterpret_cast<const char*>(request_hash_read),
sizeof(request_hash_read));
// serialize odk output to oemcrypto_core_message
std::string oemcrypto_core_message;
ODK_LicenseRequest core_request = {};
core_request.api_major_version = GetParam().request_major_version;
core_request.api_minor_version = GetParam().request_minor_version;
core_request.nonce = params.core_message.nonce_values.nonce;
core_request.session_id = params.core_message.nonce_values.session_id;
bool result =
CreateCoreLicenseResponse(features_, parsed_license, core_request,
request_hash_string, &oemcrypto_core_message);
EXPECT_FALSE(result);
delete[] buf;
delete[] zero;
}
TEST_P(OdkVersionTest, RenewalResponseRoundtrip) {
ODK_RenewalResponseParams params;
ODK_SetDefaultRenewalResponseParams(&params);
@@ -806,7 +1133,8 @@ TEST_P(OdkVersionTest, RenewalResponseRoundtrip) {
TEST_P(OdkVersionTest, ProvisionResponseRoundtrip) {
ODK_ProvisioningResponseParams params;
ODK_SetDefaultProvisioningResponseParams(&params);
ODK_SetDefaultProvisioningResponseParams(&params,
GetParam().response_major_version);
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;
@@ -821,8 +1149,12 @@ TEST_P(OdkVersionTest, ProvisionResponseRoundtrip) {
};
auto kdo_prepare_func = [&](ODK_ProvisioningRequest& core_request,
std::string* oemcrypto_core_message) {
// use device_id for V17 and V16
core_request.device_id.assign(reinterpret_cast<char*>(device_id),
device_id_length);
// use counter info for V18
memcpy(&core_request.counter_info, &params.counter_info,
sizeof(params.counter_info));
return CreateCoreProvisioningResponse(features_, params.parsed_provisioning,
core_request, oemcrypto_core_message);
};
@@ -831,12 +1163,30 @@ TEST_P(OdkVersionTest, ProvisionResponseRoundtrip) {
kdo_prepare_func);
}
TEST_P(OdkVersionTest, Provision40ResponseRoundtrip) {
ODK_Provisioning40ResponseParams params;
ODK_SetDefaultProvisioning40ResponseParams(&params);
SetRequestVersion(&params);
auto odk_parse_func = [&](const uint8_t* buf, size_t size) {
OEMCryptoResult err = ODK_ParseProvisioning40(
buf, size + 16, size, &(params.core_message.nonce_values));
return err;
};
auto kdo_prepare_func = [&](ODK_Provisioning40Request& core_request,
std::string* oemcrypto_core_message) {
return CreateCoreProvisioning40Response(features_, core_request,
oemcrypto_core_message);
};
ValidateResponse<ODK_Provisioning40Request>(
GetParam(), &(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;
@@ -862,16 +1212,26 @@ std::vector<VersionParameters> TestCases() {
{ODK_MAJOR_VERSION, kOldMajor, kOldMajorMinor, kOldMajor, kOldMajorMinor},
// If the server is restricted to v16, then the response can be at
// most 16.5
// These tests cases must be updated whenever we roll the minor version
// number.
{16, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 16, 5},
{17, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 17, 2},
{18, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 18, 3},
// 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},
{17, 17, 1, 17, 1},
{ODK_MAJOR_VERSION, 16, 3, 16, 3},
{ODK_MAJOR_VERSION, 16, 4, 16, 4},
{ODK_MAJOR_VERSION, 16, 5, 16, 5},
{ODK_MAJOR_VERSION, 17, 1, 17, 1},
{ODK_MAJOR_VERSION, 17, 2, 17, 2},
{ODK_MAJOR_VERSION, 18, 1, 18, 1},
{ODK_MAJOR_VERSION, 18, 2, 18, 2},
{ODK_MAJOR_VERSION, 18, 3, 18, 3},
{0, 16, 3, 16, 3},
{0, 16, 4, 16, 4},
{0, 16, 5, 16, 5},
{0, 17, 1, 17, 1},
{0, 17, 2, 17, 2},
{0, 18, 3, 18, 3}, // Change to 19 when the default version is updated.
};
return test_cases;
}
@@ -887,13 +1247,20 @@ TEST(OdkSizeTest, LicenseRequest) {
uint16_t api_major_version = 0;
uint32_t nonce = 0;
uint32_t session_id = 0;
ODK_MessageCounterInfo counter_info;
memset(&counter_info, 0, sizeof(counter_info));
ODK_NonceValues nonce_values{api_minor_version, api_major_version, nonce,
session_id};
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
ODK_PrepareCoreLicenseRequest(message, message_length,
&core_message_length, &nonce_values));
&core_message_length, &nonce_values,
&counter_info));
// the core_message_length should be appropriately set
if (nonce_values.api_major_version > 17) {
EXPECT_EQ(ODK_LICENSE_REQUEST_SIZE, core_message_length);
} else {
EXPECT_EQ(ODK_LICENSE_REQUEST_SIZE_V17, core_message_length);
}
}
TEST(OdkSizeTest, RenewalRequest) {
@@ -948,15 +1315,20 @@ TEST(OdkSizeTest, ProvisioningRequest) {
uint16_t api_major_version = 0;
uint32_t nonce = 0;
uint32_t session_id = 0;
uint32_t device_id_length = 0;
ODK_MessageCounterInfo counter_info;
memset(&counter_info, 0, sizeof(counter_info));
ODK_NonceValues nonce_values{api_minor_version, api_major_version, nonce,
session_id};
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
ODK_PrepareCoreProvisioningRequest(
message, message_length, &core_message_length, &nonce_values,
nullptr, device_id_length));
ODK_PrepareCoreProvisioningRequest(message, message_length,
&core_message_length,
&nonce_values, &counter_info));
// the core_message_length should be appropriately set
if (nonce_values.api_major_version > 17) {
EXPECT_EQ(ODK_PROVISIONING_REQUEST_SIZE, core_message_length);
} else {
EXPECT_EQ(ODK_PROVISIONING_REQUEST_SIZE_V17, core_message_length);
}
}
// Verify the version string contains the right version numbers.
@@ -970,6 +1342,37 @@ TEST(OdkTest, CheckReleaseVersion) {
<< "Version mismatch in odk_structs.h";
}
TEST(OdkOverflowTest, SubtractU64) {
uint64_t result = 0;
EXPECT_FALSE(odk_sub_overflow_u64(10, 5, &result));
EXPECT_EQ(result, static_cast<uint64_t>(10 - 5));
EXPECT_TRUE(odk_sub_overflow_u64(5, 10, &result));
}
TEST(OdkOverflowTest, AddU64) {
uint64_t result = 0;
EXPECT_FALSE(odk_add_overflow_u64(2, 2, &result));
EXPECT_EQ(result, static_cast<uint64_t>(2 + 2));
EXPECT_TRUE(odk_add_overflow_u64(0xffffffffffffffff, 1, &result));
EXPECT_TRUE(odk_add_overflow_u64(1, 0xffffffffffffffff, &result));
}
TEST(OdkOverflowTest, AddUX) {
size_t result = 0;
EXPECT_FALSE(odk_add_overflow_ux(2, 2, &result));
EXPECT_EQ(result, static_cast<uint64_t>(2 + 2));
EXPECT_TRUE(odk_add_overflow_ux(SIZE_MAX, 1, &result));
EXPECT_TRUE(odk_add_overflow_ux(1, SIZE_MAX, &result));
}
TEST(OdkOverflowTest, MultiplyUX) {
size_t result = 0;
EXPECT_FALSE(odk_mul_overflow_ux(2, 7, &result));
EXPECT_EQ(result, static_cast<uint64_t>(2 * 7));
EXPECT_TRUE(odk_mul_overflow_ux(SIZE_MAX >> 1, 4, &result));
EXPECT_TRUE(odk_mul_overflow_ux(4, SIZE_MAX >> 1, &result));
}
} // namespace
} // namespace wvodk_test

View File

@@ -4,6 +4,9 @@
{
'sources': [
'odk_golden_v16.cpp',
'odk_golden_v17.cpp',
'odk_golden_v18.cpp',
'odk_test.cpp',
'odk_test_helper.cpp',
'odk_test_helper.h',

View File

@@ -8,7 +8,10 @@
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <ios>
#include <iostream>
#include <ostream>
#include <string>
#include <vector>
@@ -75,6 +78,7 @@ void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params,
.length = 3,
.data = {0, 0, 0},
}},
.renewal_delay_base = OEMCrypto_License_Start,
.key_array_length = 3,
.key_array =
{
@@ -203,6 +207,11 @@ void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params,
".cmi_descriptor_data"});
}
}
if (odk_major_version >= 18) {
params->extra_fields.push_back(
{ODK_UINT32, &(params->parsed_license.renewal_delay_base),
".renewal_delay_base"});
}
params->extra_fields.push_back({ODK_UINT32,
&(params->parsed_license.key_array_length),
".key_array_length"});
@@ -288,7 +297,7 @@ void ODK_SetDefaultRenewalResponseParams(ODK_RenewalResponseParams* params) {
}
void ODK_SetDefaultProvisioningResponseParams(
ODK_ProvisioningResponseParams* params) {
ODK_ProvisioningResponseParams* params, uint32_t odk_major_version) {
ODK_SetDefaultCoreFields(&(params->core_message),
ODK_Provisioning_Response_Type);
params->device_id_length = ODK_DEVICE_ID_LEN_MAX / 2;
@@ -301,17 +310,34 @@ void ODK_SetDefaultProvisioningResponseParams(
.enc_private_key_iv = {.offset = 2, .length = 3},
.encrypted_message_key = {.offset = 4, .length = 5},
};
params->extra_fields = {
{ODK_UINT32, &(params->device_id_length), "device_id_length"},
{ODK_DEVICEID, params->device_id, "device_id"},
{ODK_UINT32, &(params->parsed_provisioning).key_type, "key_type"},
params->extra_fields = {};
// V17 uses device_id
if (odk_major_version <= 17) {
params->extra_fields.push_back(
{ODK_UINT32, &(params->device_id_length), "device_id_length"});
params->extra_fields.push_back(
{ODK_DEVICEID, params->device_id, "device_id"});
}
params->extra_fields.push_back(
{ODK_UINT32, &(params->parsed_provisioning).key_type, "key_type"});
params->extra_fields.push_back(
{ODK_SUBSTRING, &(params->parsed_provisioning).enc_private_key,
"enc_private_key"},
"enc_private_key"});
params->extra_fields.push_back(
{ODK_SUBSTRING, &(params->parsed_provisioning).enc_private_key_iv,
"enc_private_key_iv"},
"enc_private_key_iv"});
params->extra_fields.push_back(
{ODK_SUBSTRING, &(params->parsed_provisioning).encrypted_message_key,
"encrypted_message_key"},
};
"encrypted_message_key"});
}
void ODK_SetDefaultProvisioning40ResponseParams(
ODK_Provisioning40ResponseParams* params) {
ODK_SetDefaultCoreFields(&(params->core_message),
ODK_Provisioning_Response_Type);
params->extra_fields = {};
}
size_t ODK_FieldLength(ODK_FieldType type) {
@@ -330,6 +356,10 @@ size_t ODK_FieldLength(ODK_FieldType type) {
return sizeof(uint32_t) + sizeof(uint32_t);
case ODK_DEVICEID:
return ODK_DEVICE_ID_LEN_MAX;
case ODK_MESSAGECOUNTER:
return ODK_MESSAGECOUNTERINFO_SIZE;
case ODK_DEVICEINFO:
return ODK_DEVICE_INFO_LEN_MAX;
case ODK_RENEWALDATA:
return ODK_KEYBOX_RENEWAL_DATA_SIZE;
case ODK_HASH:
@@ -343,6 +373,9 @@ size_t ODK_AllocSize(ODK_FieldType type) {
if (type == ODK_SUBSTRING) {
return sizeof(OEMCrypto_Substring);
}
if (type == ODK_MESSAGECOUNTER) {
return sizeof(ODK_MessageCounterInfo);
}
return ODK_FieldLength(type);
}
@@ -388,6 +421,7 @@ OEMCryptoResult ODK_WriteSingleField(uint8_t* buf, const ODK_Field* field) {
break;
}
case ODK_DEVICEID:
case ODK_DEVICEINFO:
case ODK_RENEWALDATA:
case ODK_HASH: {
const size_t field_len = ODK_FieldLength(field->type);
@@ -396,6 +430,27 @@ OEMCryptoResult ODK_WriteSingleField(uint8_t* buf, const ODK_Field* field) {
break;
}
case ODK_MESSAGECOUNTER: {
// Size required in field->value, which may get padding from the compiler.
const size_t src_len = ODK_AllocSize(field->type);
// Size taken up in serialized message buffer, which is tightly packed.
const size_t dest_len = ODK_FieldLength(field->type);
const uint8_t* const write_src = static_cast<uint8_t*>(field->value);
// Copy data from field to buf, fixing endian-ness
ODK_MessageCounterInfo info;
memcpy(&info, write_src, src_len);
info.master_generation_number =
oemcrypto_htobe64(info.master_generation_number);
info.provisioning_count = oemcrypto_htobe32(info.provisioning_count);
info.license_count = oemcrypto_htobe32(info.license_count);
info.decrypt_count = oemcrypto_htobe32(info.decrypt_count);
info.major_version = oemcrypto_htobe16(info.major_version);
info.minor_version = oemcrypto_htobe16(info.minor_version);
info.patch_version = oemcrypto_htobe16(info.patch_version);
memcpy(buf, &info, dest_len);
break;
}
default:
return ODK_ERROR_CORE_MESSAGE;
}
@@ -448,6 +503,7 @@ OEMCryptoResult ODK_ReadSingleField(const uint8_t* buf,
break;
}
case ODK_DEVICEID:
case ODK_DEVICEINFO:
case ODK_RENEWALDATA:
case ODK_HASH: {
const size_t field_len = ODK_FieldLength(field->type);
@@ -455,6 +511,55 @@ OEMCryptoResult ODK_ReadSingleField(const uint8_t* buf,
memcpy(id, buf, field_len);
break;
}
case ODK_MESSAGECOUNTER: {
// Size required in field->value, which may get padding from the compiler.
const size_t dest_len = ODK_AllocSize(field->type);
// Size taken up in serialized message buffer, which is tightly packed.
const size_t src_len = ODK_FieldLength(field->type);
uint8_t* const read_dest = static_cast<uint8_t*>(field->value);
// Copy data from buf to field, fixing endian-ness
uint8_t temp_buf[sizeof(ODK_MessageCounterInfo)] = {0};
memcpy(temp_buf, buf, src_len);
size_t index = 0;
ODK_MessageCounterInfo info;
uint64_t* u64 = reinterpret_cast<uint64_t*>(&temp_buf[index]);
info.master_generation_number = oemcrypto_be64toh(*u64);
index += sizeof(uint64_t);
uint32_t* u32 = reinterpret_cast<uint32_t*>(&temp_buf[index]);
info.provisioning_count = oemcrypto_be32toh(*u32);
index += sizeof(uint32_t);
u32 = reinterpret_cast<uint32_t*>(&temp_buf[index]);
info.license_count = oemcrypto_be32toh(*u32);
index += sizeof(uint32_t);
u32 = reinterpret_cast<uint32_t*>(&temp_buf[index]);
info.decrypt_count = oemcrypto_be32toh(*u32);
index += sizeof(uint32_t);
uint16_t* u16 = reinterpret_cast<uint16_t*>(&temp_buf[index]);
info.major_version = oemcrypto_be16toh(*u16);
index += sizeof(uint16_t);
u16 = reinterpret_cast<uint16_t*>(&temp_buf[index]);
info.minor_version = oemcrypto_be16toh(*u16);
index += sizeof(uint16_t);
u16 = reinterpret_cast<uint16_t*>(&temp_buf[index]);
info.patch_version = oemcrypto_be16toh(*u16);
index += sizeof(uint16_t);
memcpy(info.soc_vendor, &temp_buf[index], sizeof(info.soc_vendor));
index += sizeof(info.soc_vendor);
memcpy(info.chipset_model, &temp_buf[index], sizeof(info.chipset_model));
index += sizeof(info.chipset_model);
memcpy(info.extra, &temp_buf[index], sizeof(info.extra));
memcpy(read_dest, &info, dest_len);
break;
}
default:
return ODK_ERROR_CORE_MESSAGE;
}
@@ -508,6 +613,8 @@ OEMCryptoResult ODK_DumpSingleField(const uint8_t* buf,
break;
}
case ODK_DEVICEID:
case ODK_MESSAGECOUNTER:
case ODK_DEVICEINFO:
case ODK_RENEWALDATA:
case ODK_HASH: {
const size_t field_len = ODK_FieldLength(field->type);

View File

@@ -21,6 +21,8 @@ enum ODK_FieldType {
ODK_UINT64,
ODK_SUBSTRING,
ODK_DEVICEID,
ODK_DEVICEINFO,
ODK_MESSAGECOUNTER,
ODK_RENEWALDATA,
ODK_HASH,
// The "stressable" types are the ones we can put in a stress test that packs
@@ -71,10 +73,17 @@ struct ODK_ProvisioningResponseParams {
ODK_CoreMessage core_message;
uint8_t device_id[ODK_DEVICE_ID_LEN_MAX];
uint32_t device_id_length;
uint32_t padding_u32;
ODK_MessageCounterInfo counter_info;
ODK_ParsedProvisioning parsed_provisioning;
std::vector<ODK_Field> extra_fields;
};
struct ODK_Provisioning40ResponseParams {
ODK_CoreMessage core_message;
std::vector<ODK_Field> extra_fields;
};
// Default values in core_message for testing
void ODK_SetDefaultCoreFields(ODK_CoreMessage* core_message,
ODK_MessageType message_type);
@@ -82,7 +91,9 @@ void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params,
uint32_t odk_major_version);
void ODK_SetDefaultRenewalResponseParams(ODK_RenewalResponseParams* params);
void ODK_SetDefaultProvisioningResponseParams(
ODK_ProvisioningResponseParams* params);
ODK_ProvisioningResponseParams* params, uint32_t odk_major_version);
void ODK_SetDefaultProvisioning40ResponseParams(
ODK_Provisioning40ResponseParams* params);
size_t ODK_FieldLength(ODK_FieldType type);
size_t ODK_AllocSize(ODK_FieldType type);
@@ -92,8 +103,8 @@ OEMCryptoResult ODK_WriteSingleField(uint8_t* buf, const ODK_Field* field);
// Load buf to ODK_Field
OEMCryptoResult ODK_ReadSingleField(const uint8_t* buf, const ODK_Field* field);
OEMCryptoResult ODK_DumpSingleField(const uint8_t* buf, const ODK_Field* field);
OEMCryptoResult ODK_IterFields(ODK_FieldMode mode, uint8_t* buf,
const size_t size_in, size_t* size_out,
OEMCryptoResult ODK_IterFields(ODK_FieldMode mode, uint8_t* buf, size_t size_in,
size_t* size_out,
const std::vector<ODK_Field>& fields);
void ODK_ExpectEqualBuf(const void* s1, const void* s2, size_t n,
const std::vector<ODK_Field>& fields);

View File

@@ -6,7 +6,9 @@
#include "OEMCryptoCENCCommon.h"
#include "gtest/gtest.h"
#include "odk.h"
#include "odk_structs.h"
#include "odk_structs_priv.h"
#include "odk_test_helper.h"
namespace {
@@ -23,6 +25,99 @@ constexpr uint64_t kRentalClockStart = 1000u;
// renewal is not loaded.
constexpr uint64_t kGracePeriod = 5u;
constexpr uint32_t kExtraPayloadSize = 128u;
constexpr uint32_t kSystemTime = 20u;
namespace wvodk_test {
TEST(OdkTimerBasicTest, ParseLicenseTimerSet) {
// playback timer is successfully started
::wvodk_test::ODK_LicenseResponseParams params;
ODK_SetDefaultLicenseResponseParams(&params, ODK_MAJOR_VERSION);
params.parsed_license.renewal_delay_base = OEMCrypto_License_Load;
params.parsed_license.timer_limits.soft_enforce_rental_duration = false;
params.parsed_license.timer_limits.soft_enforce_playback_duration = false;
params.parsed_license.timer_limits.earliest_playback_start_seconds = 10;
params.parsed_license.timer_limits.total_playback_duration_seconds = 0;
params.parsed_license.timer_limits.rental_duration_seconds = 10;
params.parsed_license.timer_limits.initial_renewal_duration_seconds = 0;
OEMCryptoResult result =
ODK_InitializeClockValues(&params.clock_values, kSystemTime);
EXPECT_EQ(OEMCrypto_SUCCESS, result);
params.clock_values.time_of_license_request_signed = 5;
params.clock_values.status = kActive;
uint8_t* buf = nullptr;
uint32_t buf_size = 0;
ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf,
&buf_size);
result = ODK_ParseLicense(
buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load,
params.usage_entry_present, kSystemTime, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license), nullptr);
EXPECT_EQ(ODK_SET_TIMER, result);
delete[] buf;
}
TEST(OdkTimerBasicTest, ParseLicenseTimerDisabled) {
// playback timer is successfully started
::wvodk_test::ODK_LicenseResponseParams params;
ODK_SetDefaultLicenseResponseParams(&params, ODK_MAJOR_VERSION);
params.parsed_license.renewal_delay_base = OEMCrypto_License_Load;
params.parsed_license.timer_limits.soft_enforce_rental_duration = true;
params.parsed_license.timer_limits.earliest_playback_start_seconds = 3;
params.parsed_license.timer_limits.total_playback_duration_seconds = 0;
params.parsed_license.timer_limits.initial_renewal_duration_seconds = 0;
params.clock_values.time_of_first_decrypt = 10;
params.clock_values.time_of_license_request_signed = 5;
params.clock_values.status = kActive;
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, kSystemTime, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license), nullptr);
EXPECT_EQ(ODK_DISABLE_TIMER, result);
delete[] buf;
}
TEST(OdkTimerBasicTest, ParseRenewalTimerExpired) {
// playback timer is successfully started
::wvodk_test::ODK_LicenseResponseParams params;
ODK_SetDefaultLicenseResponseParams(&params, ODK_MAJOR_VERSION);
params.parsed_license.renewal_delay_base = OEMCrypto_License_Load;
params.parsed_license.timer_limits.rental_duration_seconds = 5;
params.parsed_license.timer_limits.earliest_playback_start_seconds = 3;
OEMCryptoResult result =
ODK_InitializeClockValues(&params.clock_values, kSystemTime);
EXPECT_EQ(OEMCrypto_SUCCESS, result);
params.clock_values.time_of_license_request_signed = 5;
uint8_t* buf = nullptr;
uint32_t buf_size = 0;
ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf,
&buf_size);
result = ODK_ParseLicense(
buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load,
params.usage_entry_present, kSystemTime, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license), nullptr);
EXPECT_EQ(ODK_TIMER_EXPIRED, result);
delete[] buf;
}
} // namespace wvodk_test
TEST(OdkTimerBasicTest, NullTest) {
// Assert that nullptr does not cause a core dump.
ODK_InitializeClockValues(nullptr, 0u);