Update to ODK v18.3
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
'target_name': 'odk',
|
||||
'type': 'static_library',
|
||||
'standalone_static_library' : 1,
|
||||
'hard_dependency': 1,
|
||||
'include_dirs': [
|
||||
'../include',
|
||||
'../../include',
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"],
|
||||
}
|
||||
|
||||
|
||||
@@ -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"],
|
||||
}
|
||||
|
||||
|
||||
@@ -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 -
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
'-Wno-error=cast-qual',
|
||||
],
|
||||
'cflags_cc': [
|
||||
'-std=c++11',
|
||||
'-std=c++14',
|
||||
'-g3',
|
||||
'-O0',
|
||||
'-fsanitize=fuzzer,address,undefined',
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
4132
oemcrypto/odk/test/odk_golden_v16.cpp
Normal file
4132
oemcrypto/odk/test/odk_golden_v16.cpp
Normal file
File diff suppressed because it is too large
Load Diff
3846
oemcrypto/odk/test/odk_golden_v17.cpp
Normal file
3846
oemcrypto/odk/test/odk_golden_v17.cpp
Normal file
File diff suppressed because it is too large
Load Diff
4574
oemcrypto/odk/test/odk_golden_v18.cpp
Normal file
4574
oemcrypto/odk/test/odk_golden_v18.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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(¶ms);
|
||||
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(¶ms,
|
||||
GetParam().response_major_version);
|
||||
SetRequestVersion(¶ms);
|
||||
// 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(¶ms);
|
||||
@@ -806,7 +1133,8 @@ TEST_P(OdkVersionTest, RenewalResponseRoundtrip) {
|
||||
|
||||
TEST_P(OdkVersionTest, ProvisionResponseRoundtrip) {
|
||||
ODK_ProvisioningResponseParams params;
|
||||
ODK_SetDefaultProvisioningResponseParams(¶ms);
|
||||
ODK_SetDefaultProvisioningResponseParams(¶ms,
|
||||
GetParam().response_major_version);
|
||||
SetRequestVersion(¶ms);
|
||||
// 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, ¶ms.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(¶ms);
|
||||
SetRequestVersion(¶ms);
|
||||
|
||||
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
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(¶ms, 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(¶ms.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(¶ms, 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(¶ms, 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(¶ms.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);
|
||||
|
||||
Reference in New Issue
Block a user