OEMCrypto and ODK v16.4

This update is not required for all devices. It is necessary for
supporting some use cases for offline licenses on devices that do not
support usage tables. Most devices are expected to support usage
tables.

There were no new changes to the OEMCrypto code. However, the ODK
library has been updated so the minior version has been updated to 4.

There were also some changes to the unit tests.
1. We added more tests for pattern decryption.
2. We added more tests for buffer overflow handling.
4. We added some support for fuzz testing. These tests are not quite
   ready for wide use.
This commit is contained in:
Fred Gylys-Colwell
2020-10-07 19:37:40 -07:00
parent 6433bf285f
commit ad3791e23f
133 changed files with 7405 additions and 4204 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -20,6 +20,7 @@
namespace wvoec3 {
// clang-format off
#ifdef DYNAMIC_ADAPTER
#define Level3_IsInApp _lcc00
#define Level3_Initialize _lcc01
@@ -91,6 +92,7 @@ namespace wvoec3 {
#define Level3_LoadEntitledContentKeys _lcc92
#define Level3_CopyBuffer _lcc93
#else
#define Level3_IsInApp _oecc00
#define Level3_Initialize _oecc01
#define Level3_Terminate _oecc02
#define Level3_InstallKeyboxOrOEMCert _oecc03
@@ -162,6 +164,7 @@ namespace wvoec3 {
#endif
#define Level3_GetInitializationState _oecl3o01
// clang-format on
extern "C" {

View File

@@ -1,6 +1,6 @@
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
/*********************************************************************
* OEMCryptoCENCCommon.h
@@ -20,7 +20,11 @@
extern "C" {
#endif
/// @addtogroup common_types
/// @{
/* clang-format off */
/** Error and result codes returned by OEMCrypto functions. */
typedef enum OEMCryptoResult {
OEMCrypto_SUCCESS = 0,
OEMCrypto_ERROR_INIT_FAILED = 1,
@@ -94,8 +98,7 @@ typedef enum OEMCryptoResult {
} OEMCryptoResult;
/* clang-format on */
/*
* OEMCrypto_Usage_Entry_Status.
/**
* Valid values for status in the usage table.
*/
typedef enum OEMCrypto_Usage_Entry_Status {
@@ -106,13 +109,14 @@ typedef enum OEMCrypto_Usage_Entry_Status {
kInactiveUnused = 4,
} OEMCrypto_Usage_Entry_Status;
/*
/**
* OEMCrypto_LicenseType is used in the license message to indicate if the key
* objects are for content keys, or for entitlement keys.
*/
typedef enum OEMCrypto_LicenseType {
OEMCrypto_ContentLicense = 0,
OEMCrypto_EntitlementLicense = 1
OEMCrypto_EntitlementLicense = 1,
OEMCrypto_LicenstType_MaxValue = OEMCrypto_EntitlementLicense,
} OEMCrypto_LicenseType;
/* Private key type used in the provisioning response. */
@@ -121,9 +125,7 @@ typedef enum OEMCrypto_PrivateKeyType {
OEMCrypto_ECC_Private_Key = 1,
} OEMCrypto_PrivateKeyType;
/*
* OEMCrypto_Substring
*
/**
* 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
* signed message.
@@ -133,23 +135,22 @@ typedef struct {
size_t length;
} OEMCrypto_Substring;
/*
* OEMCrypto_KeyObject
/**
* Points to the relevant fields for a content key. The fields are extracted
* from the License Response message offered to OEMCrypto_LoadKeys(). Each
* field points to one of the components of the key. Key data, key control,
* and both IV fields are 128 bits (16 bytes):
* key_id - the unique id of this key.
* key_id_length - the size of key_id. OEMCrypto may assume this is at
* @param key_id: the unique id of this key.
* @param key_id_length: the size of key_id. OEMCrypto may assume this is at
* most 16. However, OEMCrypto shall correctly handle key id lengths
* from 1 to 16 bytes.
* key_data_iv - the IV for performing AES-128-CBC decryption of the
* @param key_data_iv: the IV for performing AES-128-CBC decryption of the
* key_data field.
* key_data - the key data. It is encrypted (AES-128-CBC) with the
* @param key_data - the key data. It is encrypted (AES-128-CBC) with the
* session's derived encrypt key and the key_data_iv.
* key_control_iv - the IV for performing AES-128-CBC decryption of the
* @param key_control_iv: the IV for performing AES-128-CBC decryption of the
* key_control field.
* key_control - the key control block. It is encrypted (AES-128-CBC) with
* @param key_control: the key control block. It is encrypted (AES-128-CBC) with
* the content key from the key_data field.
*
* The memory for the OEMCrypto_KeyObject fields is allocated and freed
@@ -163,8 +164,10 @@ typedef struct {
OEMCrypto_Substring key_control;
} OEMCrypto_KeyObject;
/// @}
#ifdef __cplusplus
}
#endif
#endif /* WIDEVINE_ODK_INCLUDE_OEMCRYPTOCENCCOMMON_H_ */
#endif // WIDEVINE_ODK_INCLUDE_OEMCRYPTOCENCCOMMON_H_

View File

@@ -1,6 +1,6 @@
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
/*********************************************************************
* core_message_deserialize.h
@@ -53,7 +53,17 @@ bool CoreProvisioningRequestFromMessage(
const std::string& oemcrypto_core_message,
ODK_ProvisioningRequest* core_provisioning_request);
} /* namespace deserialize */
} /* namespace oemcrypto_core_message */
/**
* Serializer counterpart is not used and is therefore not implemented.
*
* Parameters:
* [in] oemcrypto_core_message
* [out] core_common_request
*/
bool CoreCommonRequestFromMessage(const std::string& oemcrypto_core_message,
ODK_CommonRequest* core_common_request);
#endif /* WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_DESERIALIZE_H_ */
} // namespace deserialize
} // namespace oemcrypto_core_message
#endif // WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_DESERIALIZE_H_

View File

@@ -1,6 +1,6 @@
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
/*********************************************************************
* core_message_serialize.h
@@ -62,7 +62,7 @@ bool CreateCoreRenewalResponse(const ODK_RenewalRequest& core_request,
bool CreateCoreProvisioningResponse(const ODK_ParsedProvisioning& parsed_prov,
const ODK_ProvisioningRequest& core_request,
std::string* oemcrypto_core_message);
} /* namespace serialize */
} /* namespace oemcrypto_core_message */
} // namespace serialize
} // namespace oemcrypto_core_message
#endif /* WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_H_ */
#endif // WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_H_

View File

@@ -1,6 +1,6 @@
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
/*********************************************************************
* core_message_serialize_proto.h
@@ -23,7 +23,7 @@
namespace oemcrypto_core_message {
namespace serialize {
/* @ public create response (serializer) functions accepting proto input */
// @ public create response (serializer) functions accepting proto input
/**
* Counterpart (serializer) of ODK_ParseLicense (deserializer)
@@ -56,7 +56,7 @@ bool CreateCoreProvisioningResponseFromProto(
const ODK_ProvisioningRequest& core_request,
std::string* oemcrypto_core_message);
} /* namespace serialize */
} /* namespace oemcrypto_core_message */
} // namespace serialize
} // namespace oemcrypto_core_message
#endif /* WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_PROTO_H_ */
#endif // WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_PROTO_H_

View File

@@ -1,8 +1,8 @@
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
/* clang-format off */
// clang-format off
/*********************************************************************
* core_message_types.h
*
@@ -38,6 +38,8 @@
* | | ODK_PrepareCoreRenewalRequest | | CoreRenewalRequestFromMessage |
* | +------------------------------------+ +-----------------------------------+
* | | ODK_PrepareCoreProvisioningRequest | | CoreProvisioningRequestFromMessage|
* | +------------------------------------+ +-----------------------------------+
* | | ODK_PrepareCommonRequest | | CoreCommonRequestFromMessage |
* +---+------------------------------------+---+-----------------------------------+
* | d | ODK_ParseLicense | s | CreateCoreLicenseResponse |
* | +------------------------------------+ +-----------------------------------+
@@ -47,7 +49,7 @@
* +---+------------------------------------+---+-----------------------------------+
*
*********************************************************************/
/* clang-format on */
// clang-format on
#ifndef WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_TYPES_H_
#define WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_TYPES_H_
@@ -57,7 +59,18 @@
namespace oemcrypto_core_message {
/* @ input/output structs */
// @ input/output structs
/**
* Output structure for CommonRequestFromMessage
* Input structure for CreateCommonResponse
*/
struct ODK_CommonRequest {
uint16_t api_minor_version;
uint16_t api_major_version;
uint32_t nonce;
uint32_t session_id;
};
/**
* Output structure for CoreLicenseRequestFromMessage
@@ -94,6 +107,6 @@ struct ODK_ProvisioningRequest {
std::string device_id;
};
} /* namespace oemcrypto_core_message */
} // namespace oemcrypto_core_message
#endif /* WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_TYPES_H_ */
#endif // WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_TYPES_H_

View File

@@ -1,11 +1,9 @@
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
/*********************************************************************
* odk.h
*
* OEMCrypto v16 Core Message Serialization library
/**
* @mainpage OEMCrypto v16 Core Message Serialization library
*
* For Widevine Modular DRM, there are six message types between a server and
* a client device: license request and response, provisioning request and
@@ -34,12 +32,30 @@
* ODK library shall be sanitized by the OEMCrypto implementer to prevent
* modification by any process running the REE.
*
* See the documents "Widevine Core Message Serialization" and "License
* Duration and Renewal" for a detailed description of the ODK API. You can
* See the documents
* <a href="../odk">Widevine Core Message Serialization</a>
* and
* <a href="../../lic_duration_and_renewal">License Duration and Renewal</a>
* for a detailed description of the ODK API. You can
* find these documents in the widevine repository as
* docs/Widevine_Core_Message_Serialization.pdf and
* docs/License_Duration_and_Renewal.pdf
*
* @defgroup odk_parser Core Message Parsing and Verification
* Functions that parse core messages and verify they are valid.
* TODO(fredgc): add documentation for parsing functions.
*
* @defgroup odk_packer Core Message Creation
* Functions that create core messages.
* TODO(fredgc): add documentation for packing functions.
*
* @defgroup odk_timer Timer and Clock Functions
* Functions related to enforcing timer and duration restrictions.
* TODO(fredgc): add documentation for timers and clocks.
*
* @defgroup common_types Common Types
* Enumerations and structures that are used by several OEMCrypto and ODK
* functions.
*********************************************************************/
#ifndef WIDEVINE_ODK_INCLUDE_ODK_H_
@@ -54,25 +70,23 @@
extern "C" {
#endif
/*
* ODK_InitializeSessionValues
*
* Description:
/// @addtogroup odk_timer
/// @{
/**
* This function initializes the session's data structures. It shall be
* called from OEMCrypto_OpenSession.
*
* Parameters:
* [out] timer_limits: the session's timer limits.
* [out] clock_values: the session's clock values.
* [out] nonce_values: the session's ODK nonce values.
* [in] api_major_version: the API version of OEMCrypto.
* [in] session_id: the session id of the newly created session.
* @param[out] timer_limits: the session's timer limits.
* @param[out] clock_values: the session's clock values.
* @param[out] nonce_values: the session's ODK nonce values.
* @param[in] api_major_version: the API version of OEMCrypto.
* @param[in] session_id: the session id of the newly created session.
*
* Returns:
* OEMCrypto_SUCCESS
* OEMCrypto_ERROR_INVALID_CONTEXT
* @retval OEMCrypto_SUCCESS
* @retval OEMCrypto_ERROR_INVALID_CONTEXT
*
* Version:
* @version
* This method is new in version 16 of the API.
*/
OEMCryptoResult ODK_InitializeSessionValues(ODK_TimerLimits* timer_limits,
@@ -81,72 +95,60 @@ OEMCryptoResult ODK_InitializeSessionValues(ODK_TimerLimits* timer_limits,
uint32_t api_major_version,
uint32_t session_id);
/*
* ODK_SetNonceValues
*
* Description:
/**
* This function sets the nonce value in the session's nonce structure. It
* shall be called from OEMCrypto_GenerateNonce.
*
* Parameters:
* [in/out] nonce_values: the session's nonce data.
* [in] nonce: the new nonce that was just generated.
* @param[in,out] nonce_values: the session's nonce data.
* @param[in] nonce: the new nonce that was just generated.
*
* Returns:
* true on success
* @retval true on success
*
* Version:
* @version
* This method is new in version 16 of the API.
*/
OEMCryptoResult ODK_SetNonceValues(ODK_NonceValues* nonce_values,
uint32_t nonce);
/*
* ODK_InitializeClockValues
*
* Description:
/**
* This function initializes the clock values in the session clock_values
* structure. It shall be called from OEMCrypto_PrepAndSignLicenseRequest.
*
* Parameters:
* [in/out] clock_values: the session's clock data.
* [in] system_time_seconds: the current time on OEMCrypto's monotonic clock.
* @param[in,out] clock_values: the session's clock data.
* @param[in] system_time_seconds: the current time on OEMCrypto's monotonic
* clock.
*
* Returns:
* OEMCrypto_SUCCESS
* OEMCrypto_ERROR_INVALID_CONTEXT
* @retval OEMCrypto_SUCCESS
* @retval OEMCrypto_ERROR_INVALID_CONTEXT
*
* Version:
* @version
* This method is new in version 16 of the API.
*/
OEMCryptoResult ODK_InitializeClockValues(ODK_ClockValues* clock_values,
uint64_t system_time_seconds);
/*
* ODK_ReloadClockValues
*
* Description:
/**
* This function sets the values in the clock_values structure. It shall be
* called from OEMCrypto_LoadUsageEntry. When a usage entry from a v15 or
* earlier license is loaded, the value time_of_license_loaded shall be used
* in place of time_of_license_signed.
*
* Parameters:
* [in/out] clock_values: the session's clock data.
* [in] time_of_license_signed: the value time_license_received from the
* @param[in,out] clock_values: the session's clock data.
* @param[in] time_of_license_signed: the value time_license_received from the
* loaded usage entry.
* [in] time_of_first_decrypt: the value time_of_first_decrypt from the
* @param[in] time_of_first_decrypt: the value time_of_first_decrypt from the
* loaded usage entry.
* [in] time_of_last_decrypt: the value time_of_last_decrypt from the loaded
* usage entry.
* [in] status: the value status from the loaded usage entry.
* [in] system_time_seconds: the current time on OEMCrypto's monotonic clock.
* @param[in] time_of_last_decrypt: the value time_of_last_decrypt from the
* loaded usage entry.
* @param[in] status: the value status from the loaded usage entry.
* @param[in] system_time_seconds: the current time on OEMCrypto's monotonic
* clock.
*
* Returns:
* OEMCrypto_SUCCESS
* OEMCrypto_ERROR_INVALID_CONTEXT
* @retval OEMCrypto_SUCCESS
* @retval OEMCrypto_ERROR_INVALID_CONTEXT
*
* Version:
* @version
* This method is new in version 16 of the API.
*/
OEMCryptoResult ODK_ReloadClockValues(ODK_ClockValues* clock_values,
@@ -156,10 +158,7 @@ OEMCryptoResult ODK_ReloadClockValues(ODK_ClockValues* clock_values,
enum OEMCrypto_Usage_Entry_Status status,
uint64_t system_time_seconds);
/*
* ODK_AttemptFirstPlayback
*
* Description:
/**
* This updates the clock values, and determines if playback may start based
* on the given system time. It uses the values in clock_values to determine
* if this is the first playback for the license or the first playback for
@@ -172,23 +171,21 @@ OEMCryptoResult ODK_ReloadClockValues(ODK_ClockValues* clock_values,
* ODK_SET_TIMER, then the timer should be set to the value pointed to by
* timer_value.
*
* Parameters:
* [in] system_time_seconds: the current time on OEMCrypto's monotonic clock,
* in seconds.
* [in] timer_limits: timer limits specified in the license.
* [in/out] clock_values: the sessions clock values.
* [out] timer_value: set to the new timer value. Only used if the return
* @param[in] system_time_seconds: the current time on OEMCrypto's monotonic
* clock, in seconds.
* @param[in] timer_limits: timer limits specified in the license.
* @param[in,out] clock_values: the sessions clock values.
* @param[out] timer_value: set to the new timer value. Only used if the return
* value is ODK_SET_TIMER. This must be non-null if OEMCrypto uses a
* hardware timer.
*
* Returns:
* ODK_SET_TIMER: Success. The timer should be reset to the specified value
* and playback is allowed.
* ODK_DISABLE_TIMER: Success, but disable timer. Unlimited playback is
* @retval ODK_SET_TIMER: Success. The timer should be reset to the specified
* value and playback is allowed.
* @retval ODK_DISABLE_TIMER: Success, but disable timer. Unlimited playback is
* allowed.
* ODK_TIMER_EXPIRED: Set timer as disabled. Playback is not allowed.
* @retval ODK_TIMER_EXPIRED: Set timer as disabled. Playback is not allowed.
*
* Version:
* @version
* This method is new in version 16 of the API.
*/
OEMCryptoResult ODK_AttemptFirstPlayback(uint64_t system_time_seconds,
@@ -196,10 +193,7 @@ OEMCryptoResult ODK_AttemptFirstPlayback(uint64_t system_time_seconds,
ODK_ClockValues* clock_values,
uint64_t* timer_value);
/*
* ODK_UpdateLastPlaybackTime
*
* Description:
/**
* Vendors that do not implement their own timer should call
* ODK_UpdateLastPlaybackTime regularly during playback. This updates the
* clock values, and determines if playback may continue based on the given
@@ -211,47 +205,43 @@ OEMCryptoResult ODK_AttemptFirstPlayback(uint64_t system_time_seconds,
* OEMCrypto_UpdateUsageEntry before updating the usage entry so that the
* clock values are accurate.
*
* Parameters:
* [in] system_time_seconds: the current time on OEMCrypto's monotonic clock,
* in seconds.
* [in] timer_limits: timer limits specified in the license.
* [in/out] clock_values: the sessions clock values.
* @param[in] system_time_seconds: the current time on OEMCrypto's monotonic
* clock, in seconds.
* @param[in] timer_limits: timer limits specified in the license.
* @param[in,out] clock_values: the sessions clock values.
*
* Returns:
* OEMCrypto_SUCCESS: Success. Playback is allowed.
* ODK_TIMER_EXPIRED: Set timer as disabled. Playback is not allowed.
* @retval OEMCrypto_SUCCESS: Success. Playback is allowed.
* @retval ODK_TIMER_EXPIRED: Set timer as disabled. Playback is not allowed.
*
* Version:
* @version
* This method is new in version 16 of the API.
*/
OEMCryptoResult ODK_UpdateLastPlaybackTime(uint64_t system_time_seconds,
const ODK_TimerLimits* timer_limits,
ODK_ClockValues* clock_values);
/*
* ODK_DeactivateUsageEntry
*
* Description:
/**
* This function modifies the session's clock values to indicate that the
* license has been deactivated. It shall be called from
* OEMCrypto_DeactivateUsageEntry
*
* Parameters:
* [in/out] clock_values: the sessions clock values.
* @param[in,out] clock_values: the sessions clock values.
*
* Returns:
* OEMCrypto_SUCCESS
* OEMCrypto_ERROR_INVALID_CONTEXT
* @retval OEMCrypto_SUCCESS
* @retval OEMCrypto_ERROR_INVALID_CONTEXT
*
* Version:
* @version
* This method is new in version 16 of the API.
*/
OEMCryptoResult ODK_DeactivateUsageEntry(ODK_ClockValues* clock_values);
/*
* ODK_PrepareCoreLicenseRequest
*
* Description:
/// @}
/// @addtogroup odk_packer
/// @{
/**
* Modifies the message to include a core license request at the beginning of
* the message buffer. The values in nonce_values are used to populate the
* message.
@@ -262,31 +252,26 @@ OEMCryptoResult ODK_DeactivateUsageEntry(ODK_ClockValues* clock_values);
* zero, this function returns OEMCrypto_ERROR_SHORT_BUFFER and sets output
* core_message_size to the size needed.
*
* Parameters:
* [in/out] message: Pointer to memory for the entire message. Modified by
* @param[in,out] message: Pointer to memory for the entire message. Modified by
* the ODK library.
* [in] message_length: length of the entire message buffer.
* [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
* @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.
* [in] nonce_values: pointer to the session's nonce data.
* @param[in] nonce_values: pointer to the session's nonce data.
*
* Returns:
* OEMCrypto_SUCCESS
* OEMCrypto_ERROR_SHORT_BUFFER: core_message_size is too small
* OEMCrypto_ERROR_INVALID_CONTEXT
* @retval OEMCrypto_SUCCESS
* @retval OEMCrypto_ERROR_SHORT_BUFFER: core_message_size is too small
* @retval OEMCrypto_ERROR_INVALID_CONTEXT
*
* Version:
* @version
* This method is new in version 16 of the API.
*/
OEMCryptoResult ODK_PrepareCoreLicenseRequest(
uint8_t* message, size_t message_length, size_t* core_message_size,
const ODK_NonceValues* nonce_values);
/*
* ODK_PrepareCoreRenewalRequest
*
* Description:
/**
* Modifies the message to include a core renewal request at the beginning of
* the message buffer. The values in nonce_values, clock_values and
* system_time_seconds are used to populate the message. The nonce_values
@@ -304,24 +289,22 @@ OEMCryptoResult ODK_PrepareCoreLicenseRequest(
* zero, this function returns OEMCrypto_ERROR_SHORT_BUFFER and sets output
* core_message_size to the size needed.
*
* Parameters:
* [in/out] message: Pointer to memory for the entire message. Modified by
* @param[in,out] message: Pointer to memory for the entire message. Modified by
* the ODK library.
* [in] message_length: length of the entire message buffer.
* [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
* @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.
* [in/out] nonce_values: pointer to the session's nonce data.
* [in/out] clock_values: the session's clock values.
* [in] system_time_seconds: the current time on OEMCrypto's clock, in
* @param[in,out] nonce_values: pointer to the session's nonce data.
* @param[in,out] clock_values: the session's clock values.
* @param[in] system_time_seconds: the current time on OEMCrypto's clock, in
* seconds.
*
* Returns:
* OEMCrypto_SUCCESS
* OEMCrypto_ERROR_SHORT_BUFFER: core_message_size is too small
* OEMCrypto_ERROR_INVALID_CONTEXT
* @retval OEMCrypto_SUCCESS
* @retval OEMCrypto_ERROR_SHORT_BUFFER: core_message_size is too small
* @retval OEMCrypto_ERROR_INVALID_CONTEXT
*
* Version:
* @version
* This method is new in version 16 of the API.
*/
OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message,
@@ -331,10 +314,7 @@ OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message,
ODK_ClockValues* clock_values,
uint64_t system_time_seconds);
/*
* ODK_PrepareCoreProvisioningRequest
*
* Description:
/**
* Modifies the message to include a core provisioning request at the
* beginning of the message buffer. The values in nonce_values are used to
* populate the message.
@@ -350,26 +330,24 @@ OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message,
* zero, this function returns OEMCrypto_ERROR_SHORT_BUFFER and sets output
* core_message_size to the size needed.
*
* Parameters:
* [in/out] message: Pointer to memory for the entire message. Modified by
* @param[in,out] message: Pointer to memory for the entire message. Modified by
* the ODK library.
* [in] message_length: length of the entire message buffer.
* [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
* @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.
* [in] nonce_values: pointer to the session's nonce data.
* [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.
* [in] device_id_length: length of device_id. The device ID can be at most
* 64 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.
*
* Returns:
* OEMCrypto_SUCCESS
* OEMCrypto_ERROR_SHORT_BUFFER: core_message_size is too small
* OEMCrypto_ERROR_INVALID_CONTEXT
* @retval OEMCrypto_SUCCESS
* @retval OEMCrypto_ERROR_SHORT_BUFFER: core_message_size is too small
* @retval OEMCrypto_ERROR_INVALID_CONTEXT
*
* Version:
* @version
* This method is new in version 16 of the API.
*/
OEMCryptoResult ODK_PrepareCoreProvisioningRequest(
@@ -377,30 +355,30 @@ OEMCryptoResult ODK_PrepareCoreProvisioningRequest(
const ODK_NonceValues* nonce_values, const uint8_t* device_id,
size_t device_id_length);
/*
* ODK_InitializeV15Values
*
* Description:
/// @}
/// @addtogroup odk_timer
/// @{
/**
* This function sets all limits in the timer_limits struct to the
* key_duration and initializes the other values. The field
* nonce_values.api_major_version will be set to 15. It shall be called from
* OEMCrypto_LoadKeys when loading a legacy license.
*
* Parameters:
* [out] timer_limits: The session's timer limits.
* [in/out] clock_values: The session's clock values.
* [in/out] nonce_values: The session's ODK nonce values.
* [in] key_duration: The duration from the first key's key control block. In
* practice, the key duration is the same for all keys and is the same
* as the license duration.
* [in] system_time_seconds: The current time on the system clock, as
* @param[out] timer_limits: The session's timer limits.
* @param[in,out] clock_values: The session's clock values.
* @param[in,out] nonce_values: The session's ODK nonce values.
* @param[in] key_duration: The duration from the first key's key control
* block. In practice, the key duration is the same for all keys and is
* the same as the license duration.
* @param[in] system_time_seconds: The current time on the system clock, as
* described in the document "License Duration and Renewal".
*
* Returns:
* OEMCrypto_SUCCESS
* OEMCrypto_ERROR_INVALID_CONTEXT
* @retval OEMCrypto_SUCCESS
* @retval OEMCrypto_ERROR_INVALID_CONTEXT
*
* Version:
* @version
* This method is new in version 16 of the API.
*/
OEMCryptoResult ODK_InitializeV15Values(ODK_TimerLimits* timer_limits,
@@ -409,10 +387,7 @@ OEMCryptoResult ODK_InitializeV15Values(ODK_TimerLimits* timer_limits,
uint32_t key_duration,
uint64_t system_time_seconds);
/*
* ODK_RefreshV15Values
*
* Description:
/**
* This function updates the clock_values as needed if a v15 renewal is
* accepted. The field nonce_values.api_major_version is verified to be 15.
*
@@ -420,28 +395,26 @@ OEMCryptoResult ODK_InitializeV15Values(ODK_TimerLimits* timer_limits,
* OEMCrypto shall pass in the current system time, and the key duration from
* the first object in the OEMCrypto_KeyRefreshObject.
*
* Parameters:
* [in] timer_limits: The session's timer limits.
* [in/out] clock_values: The session's clock values.
* [in] nonce_values: The session's ODK nonce values.
* [in] system_time_seconds: The current time on the system clock, as
* @param[in] timer_limits: The session's timer limits.
* @param[in,out] clock_values: The session's clock values.
* @param[in] nonce_values: The session's ODK nonce values.
* @param[in] system_time_seconds: The current time on the system clock, as
* described in the document "License Duration and Renewal".
* [in] new_key_duration: The duration from the first
* @param[in] new_key_duration: The duration from the first
* OEMCrypto_KeyRefreshObject in key_array.
* [out] timer_value: set to the new timer value. Only used if the return
* @param[out] timer_value: set to the new timer value. Only used if the return
* value is ODK_SET_TIMER. This must be non-null if OEMCrypto uses a
* hardware timer.
*
* Returns:
* OEMCrypto_SUCCESS
* OEMCrypto_ERROR_UNKNOWN_FAILURE
* ODK_SET_TIMER: Success. The timer should be reset to the specified value
* and playback is allowed.
* ODK_DISABLE_TIMER: Success, but disable timer. Unlimited playback is
* @retval OEMCrypto_SUCCESS
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE
* @retval ODK_SET_TIMER: Success. The timer should be reset to the specified
* value and playback is allowed.
* @retval ODK_DISABLE_TIMER: Success, but disable timer. Unlimited playback is
* allowed.
* ODK_TIMER_EXPIRED: Set timer as disabled. Playback is not allowed.
* @retval ODK_TIMER_EXPIRED: Set timer as disabled. Playback is not allowed.
*
* Version:
* @version
* This method is new in version 16 of the API.
*/
OEMCryptoResult ODK_RefreshV15Values(const ODK_TimerLimits* timer_limits,
@@ -451,10 +424,12 @@ OEMCryptoResult ODK_RefreshV15Values(const ODK_TimerLimits* timer_limits,
uint32_t new_key_duration,
uint64_t* timer_value);
/*
* ODK_ParseLicense
*
* Description:
/// @}
/// @addtogroup odk_parser
/// @{
/**
* The function ODK_ParseLicense will parse the message and verify fields in
* the message.
*
@@ -486,31 +461,32 @@ OEMCryptoResult ODK_RefreshV15Values(const ODK_TimerLimits* timer_limits,
* If usage_entry_present is true, then ODK_ParseLicense shall verify that
* the pst in the license has a nonzero length.
*
* Parameters:
* [in] message: pointer to the message buffer.
* [in] message_length: length of the entire message buffer.
* [in] core_message_size: length of the core message, at the beginning of
* @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.
* [in] initial_license_load: true when called for OEMCrypto_LoadLicense and
* false when called for OEMCrypto_ReloadLicense.
* [in] usage_entry_present: true if the session has a new usage entry
* @param[in] initial_license_load: true when called for OEMCrypto_LoadLicense
* 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.
* [in] request_hash: the hash of the license request core message. This was
* computed by OEMCrypto when the license request was signed.
* [in/out] timer_limits: The session's timer limits. These will be updated.
* [in/out] clock_values: The session's clock values. These will be updated.
* [in/out] nonce_values: The session's nonce values. These will be updated.
* [out] parsed_license: the destination for the data.
* @param[in] request_hash: the hash of the license request core message. This
* was computed by OEMCrypto when the license request was signed.
* @param[in,out] timer_limits: The session's timer limits. These will be
* updated.
* @param[in,out] clock_values: The session's clock values. These will be
* updated.
* @param[in,out] nonce_values: The session's nonce values. These will be
* updated.
* @param[out] parsed_license: the destination for the data.
*
* Returns:
* OEMCrypto_SUCCESS
* 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.
* ODK_UNSUPPORTED_API
* OEMCrypto_ERROR_INVALID_NONCE
* @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
*
* Version:
* @version
* This method is new in version 16 of the API.
*/
OEMCryptoResult ODK_ParseLicense(
@@ -520,10 +496,7 @@ OEMCryptoResult ODK_ParseLicense(
ODK_TimerLimits* timer_limits, ODK_ClockValues* clock_values,
ODK_NonceValues* nonce_values, ODK_ParsedLicense* parsed_license);
/*
* ODK_ParseRenewal
*
* Description:
/**
* The function ODK_ParseRenewal will parse the message and verify its
* contents. If the message does not parse correctly, an error of
* ODK_ERROR_CORE_MESSAGE is returned.
@@ -544,34 +517,33 @@ OEMCryptoResult ODK_ParseLicense(
* ODK_SET_TIMER, then OEMCrypto shall set the timer to the value pointed to
* by timer_value.
*
* Parameters:
* [in] message: pointer to the message buffer.
* [in] message_length: length of the entire message buffer.
* [in] core_message_size: length of the core message, at the beginning of
* @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.
* [in] nonce_values: pointer to the session's nonce data.
* [in] system_time_seconds: the current time on OEMCrypto's clock, in
* @param[in] nonce_values: pointer to the session's nonce data.
* @param[in] system_time_seconds: the current time on OEMCrypto's clock, in
* seconds.
* [in] timer_limits: timer limits specified in the license.
* [in/out] clock_values: the sessions clock values.
* [out] timer_value: set to the new timer value. Only used if the return
* @param[in] timer_limits: timer limits specified in the license.
* @param[in,out] clock_values: the sessions clock values.
* @param[out] timer_value: set to the new timer value. Only used if the return
* value is ODK_SET_TIMER. This must be non-null if OEMCrypto uses a
* hardware timer.
*
* Returns:
* 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.
* ODK_SET_TIMER: Success. The timer should be reset to the specified timer
* value.
* ODK_DISABLE_TIMER: Success, but disable timer. Unlimited playback is
* @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_SET_TIMER: Success. The timer should be reset to the specified
* timer value.
* @retval ODK_DISABLE_TIMER: Success, but disable timer. Unlimited playback is
* allowed.
* ODK_TIMER_EXPIRED: Set timer as disabled. Playback is not allowed.
* ODK_UNSUPPORTED_API
* ODK_STALE_RENEWAL: This renewal is not the most recently signed. It is
* rejected.
* OEMCrypto_ERROR_INVALID_NONCE
* @retval ODK_TIMER_EXPIRED: Set timer as disabled. Playback is not allowed.
* @retval ODK_UNSUPPORTED_API
* @retval ODK_STALE_RENEWAL: This renewal is not the most recently signed. It
* is rejected.
* @retval OEMCrypto_ERROR_INVALID_NONCE
*
* Version:
* @version
* This method is new in version 16 of the API.
*/
OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
@@ -582,10 +554,7 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
ODK_ClockValues* clock_values,
uint64_t* timer_value);
/*
* ODK_ParseProvisioning
*
* Description:
/**
* The function ODK_ParseProvisioning will parse the message and verify the
* nonce values match those in the license.
*
@@ -604,25 +573,24 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
* at message + core_message_length with size message_length -
* core_message_length.
*
* Parameters:
* [in] message: pointer to the message buffer.
* [in] message_length: length of the entire message buffer.
* [in] core_message_size: length of the core message, at the beginning of
* @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.
* [in] nonce_values: pointer to the session's nonce data.
* [in] device_id: a pointer to a buffer containing the device ID of the
* @param[in] nonce_values: pointer to the session's nonce data.
* @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.
* [in] device_id_length: the length of the device ID.
* [out] parsed_response: destination for the parse data.
* @param[in] device_id_length: the length of the device ID.
* @param[out] parsed_response: destination for the parse data.
*
* Returns:
* OEMCrypto_SUCCESS
* 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.
* ODK_UNSUPPORTED_API
* OEMCrypto_ERROR_INVALID_NONCE
* @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:
* @version
* This method is new in version 16 of the API.
*/
OEMCryptoResult ODK_ParseProvisioning(
@@ -630,8 +598,10 @@ OEMCryptoResult ODK_ParseProvisioning(
const ODK_NonceValues* nonce_values, const uint8_t* device_id,
size_t device_id_length, ODK_ParsedProvisioning* parsed_response);
/// @}
#ifdef __cplusplus
}
#endif
#endif /* WIDEVINE_ODK_INCLUDE_ODK_H_ */
#endif // WIDEVINE_ODK_INCLUDE_ODK_H_

View File

@@ -0,0 +1,14 @@
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#ifndef WIDEVINE_ODK_INCLUDE_ODK_ATTRIBUTES_H_
#define WIDEVINE_ODK_INCLUDE_ODK_ATTRIBUTES_H_
#if defined(__GNUC__) || defined(__clang__)
#define UNUSED __attribute__((__unused__))
#else
#define UNUSED
#endif
#endif // WIDEVINE_ODK_INCLUDE_ODK_ATTRIBUTES_H_

View File

@@ -1,6 +1,6 @@
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#ifndef WIDEVINE_ODK_INCLUDE_ODK_STRUCTS_H_
#define WIDEVINE_ODK_INCLUDE_ODK_STRUCTS_H_
@@ -12,10 +12,10 @@
/* The version of this library. */
#define ODK_MAJOR_VERSION 16
#define ODK_MINOR_VERSION 3
#define ODK_MINOR_VERSION 4
/* ODK Version string. Date changed automatically on each release. */
#define ODK_RELEASE_DATE "ODK v16.3 2020-06-02"
#define ODK_RELEASE_DATE "ODK v16.4 2020-10-07"
/* The lowest version number for an ODK message. */
#define ODK_FIRST_VERSION 16
@@ -24,10 +24,10 @@
#define ODK_DEVICE_ID_LEN_MAX 64
#define ODK_SHA256_HASH_SIZE 32
/*
* ODK_TimerLimits Structure
*
* Description:
/// @addtogroup odk_timer
/// @{
/**
* Timer limits are specified in a license and are used to determine when
* playback is allowed. See the document "License Duration and Renewal" for a
* discussion on the time restrictions that may be placed on a license. The
@@ -35,30 +35,30 @@
* license message. The fields are set when OEMCrypto calls the function
* ODK_ParseLicense or ODK_InitializeV15Values.
*
* Fields:
* soft_enforce_rental_duration: A boolean controlling the soft or hard
* @param soft_enforce_rental_duration: A boolean controlling the soft or hard
* enforcement of rental duration.
* soft_enforce_playback_duration: A boolean controlling the soft or hard
* @param soft_enforce_playback_duration: A boolean controlling the soft or hard
* enforcement of playback duration.
* earliest_playback_start_seconds: The earliest time that the first playback
* is allowed. Measured in seconds since the license request was signed. For
* most use cases, this is zero.
* rental_duration_seconds: Window of time for the allowed first playback.
* Measured in seconds since the earliest playback start. If
* @param earliest_playback_start_seconds: The earliest time that the first
* playback is allowed. Measured in seconds since the license request was
* signed. For most use cases, this is zero.
* @param rental_duration_seconds: Window of time for the allowed first
* playback. Measured in seconds since the earliest playback start. If
* soft_enforce_rental_duration is true, this applies only to the first
* playback. If soft_enforce_rental_duration is false, then this restricts
* any playback. A value of zero means no limit.
* total_playback_duration_seconds: Window of time for allowed playback.
* playback. If soft_enforce_rental_duration is false, then this
* restricts any playback. A value of zero means no limit.
* @param total_playback_duration_seconds: Window of time for allowed playback.
* Measured in seconds since the first playback start. If
* soft_enforce_playback_duration is true, this applies only to the start of
* playback for any session. If soft_enforce_playback_duration is false, then
* this restricts any playback. A value of zero means no limit.
* initial_renewal_duration_seconds: Window of time for allowed playback.
* soft_enforce_playback_duration is true, this applies only to the start
* of playback for any session. If soft_enforce_playback_duration is
* false, then this restricts any playback. A value of zero means no
* limit.
* @param initial_renewal_duration_seconds: Window of time for allowed playback.
* Measured in seconds since the first playback start. This value is only
* used to start the renewal timer. After a renewal message is loaded, the
* timer will be reset. A value of zero means no limit.
* used to start the renewal timer. After a renewal message is loaded,
* the timer will be reset. A value of zero means no limit.
*
* Version:
* @version
* This struct changed in API version 16.2.
*/
typedef struct {
@@ -70,10 +70,7 @@ typedef struct {
uint64_t initial_renewal_duration_seconds;
} ODK_TimerLimits;
/*
* ODK_ClockValues Structure
*
* Description:
/**
* Clock values are modified when decryption occurs or when a renewal is
* processed. They are used to track the current status of the license --
* i.e. has playback started? When does the timer expire? See the section
@@ -88,28 +85,28 @@ typedef struct {
* on OEMCrypto's system clock, as described in the document "License
* Duration and Renewal".
*
* Fields:
* time_of_license_signed: Time that the license request was signed, based on
* OEMCrypto's system clock. This value shall be stored and reloaded with
* usage entry as time_of_license_received.
* 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 with usage entry.
* time_of_last_decrypt: Time of the most recent decrypt call, based on
* @param time_of_license_signed: Time that the license request was signed,
* based on OEMCrypto's system clock. This value shall be stored and
* reloaded with usage entry as time_of_license_received.
* @param time_of_first_decrypt: Time of the first decrypt or call select key,
* based on OEMCrypto's system clock. This is 0 if the license has not
* been used to decrypt any data. This value shall be stored and reloaded
* with usage entry.
* @param time_of_last_decrypt: Time of the most recent decrypt call, based on
* OEMCrypto's system clock. This value shall be stored and reloaded with
* usage entry.
* time_of_renewal_request: Time of the most recent renewal request, based on
* OEMCrypto's system clock. This is used to verify that a renewal is not
* stale.
* time_when_timer_expires: Time that the current timer expires, based on
* OEMCrypto's system clock. If the timer is active, this is used by the ODK
* library to determine if it has expired.
* timer_status: Used internally by the ODK library to indicate the current
* timer status.
* status: The license or usage entry status. This value shall be stored and
* reloaded with usage entry.
* @param time_of_renewal_request: Time of the most recent renewal request,
* based on OEMCrypto's system clock. This is used to verify that a
* renewal is not stale.
* @param time_when_timer_expires: Time that the current timer expires, based on
* OEMCrypto's system clock. If the timer is active, this is used by the
* ODK library to determine if it has expired.
* @param timer_status: Used internally by the ODK library to indicate the
* current timer status.
* @param status: The license or usage entry status. This value shall be stored
* and reloaded with usage entry.
*
* Version:
* @version
* This struct changed in API version 16.2.
*/
typedef struct {
@@ -122,10 +119,7 @@ typedef struct {
enum OEMCrypto_Usage_Entry_Status status;
} ODK_ClockValues;
/*
* ODK_NonceValues Structure
*
* Description:
/**
* Nonce values are used to match a license or provisioning request to a
* license or provisioning response. They are also used to match a renewal
* request and response to a license. For this reason, the api_version might
@@ -137,18 +131,17 @@ typedef struct {
* in the license request and license response, we prevent an attack using
* the birthday paradox to generate nonce collisions on a single device.
*
* Fields:
* api_major_version: the API version of the license. This is initialized to
* the API version of the ODK library, but may be lower.
* api_minor_version: the minor version of the ODK library. This is used by
* the server to verify that device is not using an obsolete version of the
* ODK library.
* nonce: a randomly generated number used to prevent replay attacks.
* session_id: the session id of the session which signed the license or
* @param api_major_version: the API version of the license. This is initialized
* to the API version of the ODK library, but may be lower.
* @param api_minor_version: the minor version of the ODK library. This is used
* by the server to verify that device is not using an obsolete version
* of the ODK library.
* @param nonce: a randomly generated number used to prevent replay attacks.
* @param session_id: the session id of the session which signed the license or
* provisioning request. It is used to prevent replay attacks from one
* session to another.
*
* Version:
* @version
* This struct changed in API version 16.2.
*/
typedef struct {
@@ -158,28 +151,30 @@ typedef struct {
uint32_t session_id;
} ODK_NonceValues;
/*
* ODK_ParsedLicense Structure
*
* Description:
/// @}
/// @addtogroup odk_parser
/// @{
/**
* 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.
*
* Fields:
* enc_mac_keys_iv: IV for decrypting new mac_key. Size is 128 bits.
* enc_mac_keys: encrypted mac_keys for generating new mac_keys. Size is 512
* bits.
* pst: the Provider Session Token.
* srm_restriction_data: optional data specifying the minimum SRM version.
* license_type: specifies if the license contains content keys or
* @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.
* nonce_required: indicates if the license requires a nonce.
* timer_limits: time limits of the for the license.
* key_array_length: number of keys present.
* key_array: set of keys to be installed.
* @param nonce_required: indicates if the license requires a nonce.
* @param timer_limits: time limits of the for the license.
* @param key_array_length: number of keys present.
* @param key_array: set of keys to be installed.
*
* Version:
* @version
* This struct changed in API version 16.2.
*/
typedef struct {
@@ -194,21 +189,18 @@ typedef struct {
OEMCrypto_KeyObject key_array[ODK_MAX_NUM_KEYS];
} ODK_ParsedLicense;
/*
* ODK_ParsedProvisioning Structure
*
* Description:
/**
* The parsed provisioning structure contains information from the license
* message. The function ODK_ParseProvisioning will fill in the fields of
* this message. All substrings are contained within the message body.
*
* Fields:
* key_type: indicates if this key is an RSA or ECC private key.
* enc_private_key: encrypted private key for the DRM certificate.
* enc_private_key_iv: IV for decrypting new private key. Size is 128 bits.
* encrypted_message_key: used for provisioning 3.0 to derive keys.
* @param key_type: indicates if this key is an RSA or ECC private key.
* @param enc_private_key: encrypted private key for the DRM certificate.
* @param enc_private_key_iv: IV for decrypting new private key. Size is 128
* bits.
* @param encrypted_message_key: used for provisioning 3.0 to derive keys.
*
* Version:
* @version
* This struct changed in API version 16.2.
*/
typedef struct {
@@ -218,4 +210,6 @@ typedef struct {
OEMCrypto_Substring encrypted_message_key; /* Used for Prov 3.0 */
} ODK_ParsedProvisioning;
#endif /* WIDEVINE_ODK_INCLUDE_ODK_STRUCTS_H_ */
/// @}
#endif // WIDEVINE_ODK_INCLUDE_ODK_STRUCTS_H_

View File

@@ -1,13 +1,13 @@
/* Copyright 2019 Google LLC. All rights reserved. This file is distributed */
/* under the Widevine Master License Agreement. */
// Copyright 2019 Google LLC. All rights reserved. This file is distributed
// under the Widevine Master License Agreement.
/* Partners are expected to edit this file to support target specific code */
/* and limits. */
// Partners are expected to edit this file to support target specific code
// and limits.
#ifndef WIDEVINE_ODK_INCLUDE_ODK_TARGET_H_
#define WIDEVINE_ODK_INCLUDE_ODK_TARGET_H_
/* Maximum number of keys can be modified to suit target's resource tier. */
// Maximum number of keys can be modified to suit target's resource tier.
#define ODK_MAX_NUM_KEYS 32
#endif /* WIDEVINE_ODK_INCLUDE_ODK_TARGET_H_ */
#endif // WIDEVINE_ODK_INCLUDE_ODK_TARGET_H_

View File

@@ -39,8 +39,8 @@ bool ParseRequest(uint32_t message_type,
reinterpret_cast<const uint8_t*>(oemcrypto_core_message.c_str());
const size_t buf_length = oemcrypto_core_message.size();
Message* msg = nullptr;
AllocateMessage(&msg, message_block);
uint8_t blk[SIZE_OF_MESSAGE_STRUCT];
Message* msg = reinterpret_cast<Message*>(blk);
InitMessage(msg, const_cast<uint8_t*>(buf), buf_length);
SetSize(msg, buf_length);
@@ -70,7 +70,8 @@ bool ParseRequest(uint32_t message_type,
// For v16, a release and a renewal use the same message structure.
// However, for future API versions, the release might be a separate
// message. Otherwise, we expect an exact match of message types.
if (core_message.message_type != message_type &&
if (message_type != ODK_Common_Request_Type &&
core_message.message_type != message_type &&
!(message_type == ODK_Renewal_Request_Type &&
core_message.message_type == ODK_Release_Request_Type)) {
return false;
@@ -129,5 +130,13 @@ bool CoreProvisioningRequestFromMessage(
return true;
}
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,
common_request, &prepared_common, unpacker);
}
} // namespace deserialize
} // namespace oemcrypto_core_message

View File

@@ -50,8 +50,8 @@ bool CreateResponse(uint32_t message_type, const S& core_request,
static constexpr size_t BUF_CAPACITY = 2048;
std::vector<uint8_t> buf(BUF_CAPACITY, 0);
Message* msg = nullptr;
AllocateMessage(&msg, message_block);
uint8_t blk[SIZE_OF_MESSAGE_STRUCT];
Message* msg = reinterpret_cast<Message*>(blk);
InitMessage(msg, buf.data(), buf.capacity());
packer(msg, &response);
if (!ValidMessage(msg)) {

View File

@@ -90,17 +90,14 @@ bool CreateCoreLicenseResponseFromProto(const std::string& serialized_license,
parsed_lic.enc_mac_keys = GetOecSubstring(serialized_license, k.key());
break;
}
case video_widevine::License_KeyContainer::CONTENT: {
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);
break;
}
case video_widevine::License_KeyContainer::CONTENT:
case video_widevine::License_KeyContainer::OPERATOR_SESSION:
case video_widevine::License_KeyContainer::ENTITLEMENT: {
if (k.type() == video_widevine::License_KeyContainer::ENTITLEMENT) {
any_entitlement = true;
} else {
any_content = true;
}
if (parsed_lic.key_array_length >= ODK_MAX_NUM_KEYS) {
return false;
}

View File

@@ -1,6 +1,6 @@
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "odk.h"
@@ -19,7 +19,7 @@
static OEMCryptoResult ODK_PrepareRequest(
uint8_t* message, size_t message_length, size_t* core_message_length,
uint32_t message_type, const ODK_NonceValues* nonce_values,
ODK_MessageType message_type, const ODK_NonceValues* nonce_values,
void* prepared_request_buffer, size_t prepared_request_buffer_length) {
if (nonce_values == NULL || core_message_length == NULL ||
prepared_request_buffer == NULL ||
@@ -27,8 +27,8 @@ static OEMCryptoResult ODK_PrepareRequest(
return ODK_ERROR_CORE_MESSAGE;
}
Message* msg = NULL;
AllocateMessage(&msg, message_block);
uint8_t blk[SIZE_OF_MESSAGE_STRUCT];
Message* msg = (Message*)blk;
InitMessage(msg, message, *core_message_length);
/* The core message should be at the beginning of the buffer, and with a
@@ -95,18 +95,24 @@ static OEMCryptoResult ODK_PrepareRequest(
static OEMCryptoResult ODK_ParseResponse(
const uint8_t* message, size_t message_length, size_t core_message_length,
uint32_t message_type, const ODK_NonceValues* nonce_values,
ODK_MessageType message_type, const ODK_NonceValues* nonce_values,
void* response_buffer, uint32_t response_buffer_length) {
if (message == NULL || response_buffer == NULL ||
core_message_length > message_length) {
return ODK_ERROR_CORE_MESSAGE;
}
Message* msg = NULL;
AllocateMessage(&msg, message_block);
uint8_t blk[SIZE_OF_MESSAGE_STRUCT];
Message* msg = (Message*)blk;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
/* We initialize the message buffer with a size of the entire message
* length. */
/* TODO(b/164486737): Fix the cast-qual warning */
InitMessage(msg, (uint8_t*)message, message_length);
#pragma GCC diagnostic pop
/* The core message should be at the beginning of the buffer, and with a
* shorter length. The core message is the part we are parsing. */
SetSize(msg, core_message_length);
@@ -168,7 +174,7 @@ OEMCryptoResult ODK_PrepareCoreLicenseRequest(
return ODK_ERROR_CORE_MESSAGE;
}
ODK_PreparedLicenseRequest license_request = {
{0},
{0, 0, {}},
};
return ODK_PrepareRequest(
message, message_length, core_message_length, ODK_License_Request_Type,
@@ -197,7 +203,7 @@ OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message,
return OEMCrypto_SUCCESS;
}
ODK_PreparedRenewalRequest renewal_request = {{0}, 0};
ODK_PreparedRenewalRequest renewal_request = {{0, 0, {}}, 0};
/* First, we compute the time this request was made relative to the playback
* clock. */
if (clock_values->time_of_first_decrypt == 0) {
@@ -231,14 +237,14 @@ OEMCryptoResult ODK_PrepareCoreProvisioningRequest(
return ODK_ERROR_CORE_MESSAGE;
}
ODK_PreparedProvisioningRequest provisioning_request = {
{0},
{0, 0, {}},
0,
{0},
};
if (device_id_length > sizeof(provisioning_request.device_id)) {
return ODK_ERROR_CORE_MESSAGE;
}
provisioning_request.device_id_length = device_id_length;
provisioning_request.device_id_length = (uint32_t)device_id_length;
if (device_id) {
memcpy(provisioning_request.device_id, device_id, device_id_length);
}
@@ -261,7 +267,9 @@ OEMCryptoResult ODK_ParseLicense(
return ODK_ERROR_CORE_MESSAGE;
}
ODK_LicenseResponse license_response = {{{0}}, parsed_license, {0}};
ODK_LicenseResponse license_response = {{{0, 0, {}}}, NULL, {0}};
license_response.parsed_license = parsed_license;
const OEMCryptoResult err = ODK_ParseResponse(
message, message_length, core_message_length, ODK_License_Response_Type,
NULL, &license_response, sizeof(ODK_LicenseResponse));
@@ -299,21 +307,25 @@ OEMCryptoResult ODK_ParseLicense(
return ODK_ERROR_CORE_MESSAGE;
}
if (parsed_license->nonce_required) {
if (initial_license_load) {
/* If this is the first time we load this license, then we verify that the
* nonce values are the correct, otherwise we copy the nonce values. If the
* nonce values are not required to be correct, then we don't know if this is
* an initial load or not. In that case, we also copy the values so that we
* can use the nonce values later for a renewal.
*/
if (parsed_license->nonce_required && initial_license_load) {
if (nonce_values->nonce !=
license_response.request.core_message.nonce_values.nonce ||
nonce_values->session_id !=
license_response.request.core_message.nonce_values.session_id) {
return OEMCrypto_ERROR_INVALID_NONCE;
}
} else { /* !initial_license_load */
} else { /* !initial_license_load, or can't tell if initial. */
nonce_values->nonce =
license_response.request.core_message.nonce_values.nonce;
nonce_values->session_id =
license_response.request.core_message.nonce_values.session_id;
}
}
/* For v16, in order to be backwards compatible with a v15 license server,
* OEMCrypto stores a hash of the core license request and only signs the
* message body. Here, when we process the license response, we verify that
@@ -342,7 +354,7 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
}
ODK_RenewalResponse renewal_response = {
{{0}, 0},
{{0, 0, {}}, 0},
0,
};
const OEMCryptoResult err = ODK_ParseResponse(
@@ -359,8 +371,11 @@ 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.
*/
if (clock_values->time_of_renewal_request <
if (clock_values->timer_status != ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED &&
clock_values->time_of_renewal_request <
renewal_response.request.playback_time) {
return ODK_STALE_RENEWAL;
}
@@ -378,8 +393,9 @@ OEMCryptoResult ODK_ParseProvisioning(
return ODK_ERROR_CORE_MESSAGE;
}
ODK_ProvisioningResponse provisioning_response = {{{0}, 0, {0}},
parsed_response};
ODK_ProvisioningResponse provisioning_response = {{{0, 0, {}}, 0, {0}}, NULL};
provisioning_response.parsed_provisioning = parsed_response;
if (device_id_length > ODK_DEVICE_ID_LEN_MAX) {
return ODK_ERROR_CORE_MESSAGE;
}

View File

@@ -1,6 +1,6 @@
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#ifndef WIDEVINE_ODK_SRC_ODK_ASSERT_H_
#define WIDEVINE_ODK_SRC_ODK_ASSERT_H_
@@ -21,4 +21,4 @@ extern "C" {
}
#endif
#endif /* WIDEVINE_ODK_SRC_ODK_ASSERT_H_ */
#endif // WIDEVINE_ODK_SRC_ODK_ASSERT_H_

View File

@@ -1,6 +1,6 @@
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#ifndef WIDEVINE_ODK_SRC_ODK_ENDIAN_H_
#define WIDEVINE_ODK_SRC_ODK_ENDIAN_H_
@@ -26,4 +26,4 @@ uint64_t oemcrypto_be64toh(uint64_t u64);
}
#endif
#endif /* WIDEVINE_ODK_SRC_ODK_ENDIAN_H_ */
#endif // WIDEVINE_ODK_SRC_ODK_ENDIAN_H_

View File

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

View File

@@ -1,6 +1,6 @@
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#ifndef WIDEVINE_ODK_SRC_ODK_OVERFLOW_H_
#define WIDEVINE_ODK_SRC_ODK_OVERFLOW_H_
@@ -20,4 +20,4 @@ int odk_add_overflow_ux(size_t a, size_t b, size_t* c);
}
#endif
#endif /* WIDEVINE_ODK_SRC_ODK_OVERFLOW_H_ */
#endif // WIDEVINE_ODK_SRC_ODK_OVERFLOW_H_

View File

@@ -1,6 +1,6 @@
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
/*
* This code is auto-generated, do not edit
@@ -193,6 +193,10 @@ void Unpack_ODK_PreparedProvisioningRequest(
UnpackArray(msg, &obj->device_id[0], sizeof(obj->device_id));
}
void Unpack_ODK_PreparedCommonRequest(Message* msg,
ODK_PreparedCommonRequest* obj) {
Unpack_ODK_CoreMessage(msg, &obj->core_message);
}
/* @@ odk deserialize */
void Unpack_ODK_LicenseResponse(Message* msg, ODK_LicenseResponse* obj) {

View File

@@ -1,6 +1,6 @@
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
/*
* This code is auto-generated, do not edit
@@ -43,7 +43,10 @@ void Unpack_ODK_PreparedRenewalRequest(Message* msg,
void Unpack_ODK_PreparedProvisioningRequest(
Message* msg, ODK_PreparedProvisioningRequest* obj);
void Unpack_ODK_PreparedCommonRequest(Message* msg,
ODK_PreparedCommonRequest* obj);
#ifdef __cplusplus
} /* extern "C" */
} // extern "C"
#endif
#endif /* WIDEVINE_ODK_SRC_ODK_SERIALIZE_H_ */
#endif // WIDEVINE_ODK_SRC_ODK_SERIALIZE_H_

View File

@@ -1,6 +1,6 @@
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#ifndef WIDEVINE_ODK_SRC_ODK_STRUCTS_PRIV_H_
#define WIDEVINE_ODK_SRC_ODK_STRUCTS_PRIV_H_
@@ -22,9 +22,11 @@ typedef enum {
ODK_Provisioning_Request_Type = 5,
ODK_Provisioning_Response_Type = 6,
/* Reserve future message types to support forward compatibility. */
// Reserve future message types to support forward compatibility.
ODK_Release_Request_Type = 7,
ODK_Release_Response_Type = 8,
ODK_Common_Request_Type = 9,
ODK_Common_Response_Type = 10,
} ODK_MessageType;
typedef struct {
@@ -48,6 +50,10 @@ typedef struct {
uint8_t device_id[ODK_DEVICE_ID_LEN_MAX];
} ODK_PreparedProvisioningRequest;
typedef struct {
ODK_CoreMessage core_message;
} ODK_PreparedCommonRequest;
typedef struct {
ODK_PreparedLicenseRequest request;
ODK_ParsedLicense* parsed_license;
@@ -64,33 +70,32 @@ typedef struct {
ODK_ParsedProvisioning* parsed_provisioning;
} ODK_ProvisioningResponse;
/* 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. */
// 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 20
#define ODK_RENEWAL_REQUEST_SIZE 28
#define ODK_PROVISIONING_REQUEST_SIZE 88
/* These are the possible timer status values. */
#define ODK_CLOCK_TIMER_STATUS_UNDEFINED 0 /* Should not happen. */
/* When the structure has been initialized, but no license is loaded. */
// These are the possible timer status values.
#define ODK_CLOCK_TIMER_STATUS_UNDEFINED 0 // Should not happen.
// When the structure has been initialized, but no license is loaded.
#define ODK_CLOCK_TIMER_STATUS_LICENSE_NOT_LOADED 1
/* After the license is loaded, before a successful decrypt. */
// After the license is loaded, before a successful decrypt.
#define ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED 2
/* After the license is loaded, if a renewal has also been loaded. */
// After the license is loaded, if a renewal has also been loaded.
#define ODK_CLOCK_TIMER_STATUS_RENEWAL_LOADED 3
/* The first decrypt has occurred and the timer is active. */
// The first decrypt has occurred and the timer is active.
#define ODK_CLOCK_TIMER_STATUS_ACTIVE 4
/* The first decrypt has occurred and the timer is unlimited. */
// The first decrypt has occurred and the timer is unlimited.
#define ODK_CLOCK_TIMER_STATUS_UNLIMITED 5
/* The timer has transitioned from active to expired. */
// The timer has transitioned from active to expired.
#define ODK_CLOCK_TIMER_STATUS_EXPIRED 6
/* The license has been marked as inactive. */
// The license has been marked as inactive.
#define ODK_CLOCK_TIMER_STATUS_LICENSE_INACTIVE 7
/* A helper function for computing timer limits when a renewal is loaded. */
// A helper function for computing timer limits when a renewal is loaded.
OEMCryptoResult ODK_ComputeRenewalDuration(const ODK_TimerLimits* timer_limits,
ODK_ClockValues* clock_values,
uint64_t system_time_seconds,
@@ -101,4 +106,4 @@ OEMCryptoResult ODK_ComputeRenewalDuration(const ODK_TimerLimits* timer_limits,
}
#endif
#endif /* WIDEVINE_ODK_SRC_ODK_STRUCTS_PRIV_H_ */
#endif // WIDEVINE_ODK_SRC_ODK_STRUCTS_PRIV_H_

View File

@@ -1,11 +1,12 @@
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include <stdint.h>
#include <string.h>
#include "odk.h"
#include "odk_attributes.h"
#include "odk_overflow.h"
#include "odk_structs_priv.h"
@@ -311,7 +312,7 @@ OEMCryptoResult ODK_ReloadClockValues(ODK_ClockValues* clock_values,
uint64_t time_of_first_decrypt,
uint64_t time_of_last_decrypt,
enum OEMCrypto_Usage_Entry_Status status,
uint64_t system_time_seconds) {
uint64_t system_time_seconds UNUSED) {
if (clock_values == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}

View File

@@ -1,6 +1,6 @@
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "odk_util.h"

View File

@@ -1,6 +1,6 @@
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#ifndef WIDEVINE_ODK_SRC_ODK_UTIL_H_
#define WIDEVINE_ODK_SRC_ODK_UTIL_H_
@@ -23,6 +23,6 @@ int crypto_memcmp(const void* a, const void* b, size_t len);
bool ODK_NonceValuesEqual(const ODK_NonceValues* a, const ODK_NonceValues* b);
#ifdef __cplusplus
} /* extern "C" */
} // extern "C"
#endif
#endif /* WIDEVINE_ODK_SRC_ODK_UTIL_H_ */
#endif // WIDEVINE_ODK_SRC_ODK_UTIL_H_

View File

@@ -1,6 +1,6 @@
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "serialization_base.h"
@@ -9,7 +9,6 @@
#include <string.h>
#include "OEMCryptoCENCCommon.h"
#include "odk_assert.h"
#include "odk_overflow.h"
struct _Message {
@@ -20,13 +19,6 @@ struct _Message {
MessageStatus status;
};
/* TODO(b/150776214): this can be removed once AllocateMessage gets cleaned up
*/
/*
* odk_static_assert(SIZE_OF_MESSAGE_STRUCT >= sizeof(struct _Message),
* "SIZE_OF_MESSAGE_STRUCT too small");
*/
bool ValidMessage(Message* message) {
if (message == NULL) {
return false;
@@ -99,8 +91,8 @@ void PackArray(Message* message, const uint8_t* base, size_t size) {
}
void Pack_OEMCrypto_Substring(Message* msg, const OEMCrypto_Substring* obj) {
uint32_t offset = obj->offset;
uint32_t length = obj->length;
uint32_t offset = (uint32_t)obj->offset;
uint32_t length = (uint32_t)obj->length;
Pack_uint32_t(msg, &offset);
Pack_uint32_t(msg, &length);
}
@@ -198,21 +190,6 @@ void InitMessage(Message* message, uint8_t* buffer, size_t capacity) {
message->status = MESSAGE_STATUS_OK;
}
/*
* The message structure is in the first sizeof(Memory) bytes
* of the buffer
*/
Message* CreateMessage(uint8_t* buffer, size_t buffer_size) {
if (buffer == NULL || buffer_size < sizeof(Message)) return NULL;
Message* message = (Message*)buffer;
message->base = buffer + sizeof(Message);
message->capacity = buffer_size - sizeof(Message);
message->size = 0;
message->read_offset = 0;
message->status = MESSAGE_STATUS_OK;
return message;
}
/*
* Set the message to an empty state
*/

View File

@@ -1,6 +1,6 @@
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#ifndef WIDEVINE_ODK_SRC_SERIALIZATION_BASE_H_
#define WIDEVINE_ODK_SRC_SERIALIZATION_BASE_H_
@@ -61,13 +61,6 @@ void UnpackArray(Message* message, uint8_t* address,
size_t size); /* copy out */
void Unpack_OEMCrypto_Substring(Message* msg, OEMCrypto_Substring* obj);
/*
* Create a message from a buffer. The message structure consumes the first
* sizeof(Message) bytes of the buffer. The caller is responsible for ensuring
* that the buffer remains allocated for the lifetime of the message.
*/
Message* CreateMessage(uint8_t* buffer, size_t buffer_size);
/*
* Initialize a message structure to reference a separate buffer. The caller
* is responsible for ensuring that the buffer remains allocated for the
@@ -90,7 +83,7 @@ size_t GetOffset(Message* message);
size_t SizeOfMessageStruct();
#ifdef __cplusplus
} /* extern "C" */
} // extern "C"
#endif
#endif /* WIDEVINE_ODK_SRC_SERIALIZATION_BASE_H_ */
#endif // WIDEVINE_ODK_SRC_SERIALIZATION_BASE_H_

View File

@@ -0,0 +1,168 @@
// Copyright 2020 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
cc_defaults {
name: "odk_fuzz_library_defaults",
srcs: [
"odk_fuzz_helper.cpp",
],
include_dirs: [
"vendor/widevine/libwvdrmengine/oemcrypto/odk/test",
"vendor/widevine/libwvdrmengine/oemcrypto/odk/include",
"vendor/widevine/libwvdrmengine/oemcrypto/odk/src",
],
}
cc_fuzz {
name: "odk_license_request_fuzz",
srcs: [
"odk_license_request_fuzz.cpp",
],
fuzz_config: {
componentid: 611718,
},
corpus: ["corpus/little_endian_64bit/license_request_corpus/*"],
static_libs: [
"libwv_kdo",
"libwv_odk",
],
defaults: ["odk_fuzz_library_defaults"],
proprietary: true,
}
cc_fuzz {
name: "odk_renewal_request_fuzz",
srcs: [
"odk_renewal_request_fuzz.cpp",
],
fuzz_config: {
componentid: 611718,
},
corpus: ["corpus/little_endian_64bit/renewal_request_corpus/*"],
static_libs: [
"libwv_kdo",
"libwv_odk",
],
defaults: ["odk_fuzz_library_defaults"],
proprietary: true,
}
cc_fuzz {
name: "odk_provisioning_request_fuzz",
srcs: [
"odk_provisioning_request_fuzz.cpp",
],
fuzz_config: {
componentid: 611718,
},
corpus: ["corpus/little_endian_64bit/provisioning_request_corpus/*"],
static_libs: [
"libwv_kdo",
"libwv_odk",
],
defaults: ["odk_fuzz_library_defaults"],
proprietary: true,
}
cc_fuzz {
name: "odk_license_response_fuzz",
srcs: [
"odk_license_response_fuzz.cpp",
],
fuzz_config: {
componentid: 611718,
},
corpus: ["corpus/little_endian_64bit/license_response_corpus/*"],
static_libs: [
"libwv_kdo",
"libwv_odk",
],
defaults: ["odk_fuzz_library_defaults"],
proprietary: true,
}
cc_fuzz {
name: "odk_renewal_response_fuzz",
srcs: [
"odk_renewal_response_fuzz.cpp",
],
fuzz_config: {
componentid: 611718,
},
corpus: ["corpus/little_endian_64bit/renewal_response_corpus/*"],
static_libs: [
"libwv_kdo",
"libwv_odk",
],
defaults: ["odk_fuzz_library_defaults"],
proprietary: true,
}
cc_fuzz {
name: "odk_provisioning_response_fuzz",
srcs: [
"odk_provisioning_response_fuzz.cpp",
],
fuzz_config: {
componentid: 611718,
},
corpus: ["corpus/little_endian_64bit/provisioning_response_corpus/*"],
static_libs: [
"libwv_kdo",
"libwv_odk",
],
defaults: ["odk_fuzz_library_defaults"],
proprietary: true,
}
cc_fuzz {
name: "odk_license_response_fuzz_with_mutator",
srcs: [
"odk_license_response_fuzz_with_mutator.cpp",
],
fuzz_config: {
componentid: 611718,
},
corpus: ["corpus/little_endian_64bit/license_response_corpus/*"],
static_libs: [
"libwv_kdo",
"libwv_odk",
],
defaults: ["odk_fuzz_library_defaults"],
proprietary: true,
}
cc_fuzz {
name: "odk_renewal_response_fuzz_with_mutator",
srcs: [
"odk_renewal_response_fuzz_with_mutator.cpp",
],
fuzz_config: {
componentid: 611718,
},
corpus: ["corpus/little_endian_64bit/renewal_response_corpus/*"],
static_libs: [
"libwv_kdo",
"libwv_odk",
],
defaults: ["odk_fuzz_library_defaults"],
proprietary: true,
}
cc_fuzz {
name: "odk_provisioning_response_fuzz_with_mutator",
srcs: [
"odk_provisioning_response_fuzz_with_mutator.cpp",
],
fuzz_config: {
componentid: 611718,
},
corpus: ["corpus/little_endian_64bit/provisioning_response_corpus/*"],
static_libs: [
"libwv_kdo",
"libwv_odk",
],
defaults: ["odk_fuzz_library_defaults"],
proprietary: true,
}

View File

@@ -0,0 +1,19 @@
# ODK Fuzzing
## Objective
* Run fuzzing on ODK and KDO serialize and deserialize APIs using google
supported fuzzer engines to find security vulnerabilities. Any issues found
by clusterfuzz will be reported to
[odk fuzz buganizer](https://b.corp.google.com/issues?q=componentid:425099%20status:open%20reporter:cluster-fuzz-googleplex@google.com).
## Run fuzz target on local machine
* In order to run fuzz target locally and see code coverage, save binary input
to be tested against fuzz target into a temporary corpus directory and
execute following commands
```shell
$ blaze build --config=asan-fuzzer //your:target
$ blaze-bin/your/target FULL_CORPUS_DIR
```

View File

@@ -0,0 +1,27 @@
// Copyright 2020 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
// ----------------------------------------------------------------
// Builds odk_corpus_generator shared library, which can be used with
// LD_PRELOAD command to generate corpus by intercepting oemcrypto
// unit tests.
// ----------------------------------------------------------------
// Builds libwv_odk.so, The ODK shared Library (libwv_odk) is used
// by the OEMCrypto unit tests to generate corpus for ODK fuzz scrips.
cc_library_shared {
name: "libwv_odk_corpus_generator",
include_dirs: [
"vendor/widevine/libwvdrmengine/oemcrypto/include",
"vendor/widevine/libwvdrmengine/oemcrypto/odk/include",
"vendor/widevine/libwvdrmengine/oemcrypto/odk/test",
],
host_ldlibs: ["-ldl"],
srcs: [
"odk_corpus_generator.c",
"odk_corpus_generator_helper.c",
],
proprietary: true,
owner: "widevine",
}

View File

@@ -0,0 +1,79 @@
# Objective
The Idea behind the corpus generator code is to intercept OEMCrypto unit test
calls to odk APIs using LD_PRELOAD and read the data into corpus files which can
be fed as corpus to fuzzer scripts.
LD_PRELOAD command needs to be run from cdm repository while running oemcrypto
unit tests.
## Get OEMCrypto and Build OEMCrypto unit tests:
* Install Pre-requisites
```shell
$ sudo apt-get install gyp ninja-build
```
* download cdm source code (including ODK & OEMCrypto unit tests):
```shell
$ git clone sso://widevine-internal/cdm
```
* We need to run odk as a dynamic library in order to use LD_PRELOAD, apply
patch from go/wvgerrit/95090 to locally cloned repo which has changes to run
odk as dynamic library:
```shell
$ cd /path/to/cdm/repo
$ git fetch origin 209721cc901745999e08e35466e74f708321267e
$ git cherry-pick FETCH_HEAD
```
* Build OEMCrypto unit tests:
```shell
$ cd /path/to/cdm/repo
$ export PATH_TO_CDM_DIR=..
$ gyp --format=ninja --depth=$(pwd) oemcrypto/oemcrypto_unittests.gyp
$ ninja -C out/Default/
```
## Capture corpus for odk fuzzer by intercepting OEMCrypto unit tests:
When we run LD_PRELOAD command odk_corpus_generator.so gets preloaded before
oemcrypto_unittests and odk_corpus_generator has functions to intercept calls to
ODK request and response APIs. Each call to odk API from oemcrypto_unittests
gets intercepted and input to ODK de serialize response APIs and output from ODK
serialize request APIs is captured in binary format and stored into corpus files
In order to run LD_PRELOAD command, we need to compile corpus generator shared
library and need to preload that before OEMCrypto unit tests run
* Compile shared library
```shell
$ cd /path/to/cdm/repo
$ gyp --format=ninja --depth=$(pwd) oemcrypto/odk/test/fuzzing/corpus_generator/odk_fuzz_corpus_generator.gyp
$ ninja -C out/Default/
```
* Preload the shared library before running OEMCrypto unit tests
```shell
$ cd oemcrypto/odk/test/fuzzing/corpus
$ mkdir license_request_corpus license_response_corpus renewal_request_corpus renewal_response_corpus provisioning_request_corpus provisioning_response_corpus
$ cd /path/to/cdm/repo
$ LD_PRELOAD=out/Default/lib/libodk_corpus_generator.so ./out/Default/oemcrypto_unittests
```
LD_PRELOAD command runs oemcrypto_unittests with odk_corpus_generator as
interceptor. We should see unit tests being executed. The corpus files in binary
format will be captured into `oemcrypto/odk/test/fuzzing/corpus` path. These
files can be used as input corpus for ODK request and response fuzzer scripts.
The generated corpus files can be minimized using go/testcorpus#minimize and
uploaded into google3 repository under following directory under respective
corpus types
`fuzzing/corpus`

View File

@@ -0,0 +1,158 @@
// Copyright 2020 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
// We must define this macro to get RTLD_NEXT definition from <dlfcn.h>
#define _GNU_SOURCE
#include <dlfcn.h>
#include "fuzzing/corpus_generator/odk_corpus_generator_helper.h"
#include "fuzzing/odk_fuzz_structs.h"
#include "odk_structs.h"
OEMCryptoResult ODK_PrepareCoreLicenseRequest(
uint8_t* message, size_t message_length, size_t* core_message_length,
const ODK_NonceValues* nonce_values) {
OEMCryptoResult (*original_function)(uint8_t*, size_t, size_t*,
const ODK_NonceValues*);
original_function = dlsym(RTLD_NEXT, "ODK_PrepareCoreLicenseRequest");
OEMCryptoResult oem_crypto_result = (*original_function)(
message, message_length, core_message_length, nonce_values);
char* file_name = GetFileName("license_request_corpus");
// License Request format expected by fuzzer - [Core License Request]
AppendToFile(file_name, (const char*)message, *core_message_length);
free(file_name);
return oem_crypto_result;
}
OEMCryptoResult ODK_ParseLicense(
const uint8_t* message, size_t message_length, size_t core_message_length,
bool initial_license_load, bool usage_entry_present,
const uint8_t* request_hash, ODK_TimerLimits* timer_limits,
ODK_ClockValues* clock_values, ODK_NonceValues* nonce_values,
ODK_ParsedLicense* parsed_license) {
struct ODK_ParseLicense_Args parse_license_args;
parse_license_args.nonce_values = *nonce_values;
memcpy(parse_license_args.request_hash, request_hash, ODK_SHA256_HASH_SIZE);
parse_license_args.timer_limits = *timer_limits;
parse_license_args.clock_values = *clock_values;
parse_license_args.usage_entry_present = usage_entry_present;
parse_license_args.initial_license_load = initial_license_load;
OEMCryptoResult (*original_function)(
const uint8_t*, size_t, size_t, bool, bool, const uint8_t*,
ODK_TimerLimits*, ODK_ClockValues*, ODK_NonceValues*, ODK_ParsedLicense*);
original_function = dlsym(RTLD_NEXT, "ODK_ParseLicense");
OEMCryptoResult oem_crypto_result = (*original_function)(
message, message_length, core_message_length, initial_license_load,
usage_entry_present, request_hash, timer_limits, clock_values,
nonce_values, parsed_license);
char* file_name = GetFileName("license_response_corpus");
// License Response format expected by fuzzer - [ODK_ParseLicense_Args][Core
// License Response]
AppendToFile(file_name, (const char*)&parse_license_args,
sizeof(struct ODK_ParseLicense_Args));
AppendToFile(file_name, (const char*)message, core_message_length);
free(file_name);
return oem_crypto_result;
}
OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message,
size_t message_length,
size_t* core_message_size,
ODK_NonceValues* nonce_values,
ODK_ClockValues* clock_values,
uint64_t system_time_seconds) {
OEMCryptoResult (*original_function)(
uint8_t*, size_t, size_t*, ODK_NonceValues*, ODK_ClockValues*, uint64_t);
original_function = dlsym(RTLD_NEXT, "ODK_PrepareCoreRenewalRequest");
OEMCryptoResult oem_crypto_result =
(*original_function)(message, message_length, core_message_size,
nonce_values, clock_values, system_time_seconds);
char* file_name = GetFileName("renewal_request_corpus");
// License Request format expected by fuzzer - [ODK_ClockValues][Core
// License Request]
AppendToFile(file_name, (const char*)clock_values, sizeof(ODK_ClockValues));
AppendToFile(file_name, (const char*)message, *core_message_size);
free(file_name);
return oem_crypto_result;
}
OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
size_t core_message_length,
const ODK_NonceValues* nonce_values,
uint64_t system_time,
const ODK_TimerLimits* timer_limits,
ODK_ClockValues* clock_values,
uint64_t* timer_value) {
struct ODK_ParseRenewal_Args parse_renewal_args;
parse_renewal_args.nonce_values = *nonce_values;
parse_renewal_args.clock_values = *clock_values;
parse_renewal_args.timer_limits = *timer_limits;
parse_renewal_args.system_time = system_time;
OEMCryptoResult (*original_function)(
const uint8_t*, size_t, size_t, const ODK_NonceValues*, uint64_t,
const ODK_TimerLimits*, ODK_ClockValues*, uint64_t*);
original_function = dlsym(RTLD_NEXT, "ODK_ParseRenewal");
OEMCryptoResult oem_crypto_result = (*original_function)(
message, message_length, core_message_length, nonce_values, system_time,
timer_limits, clock_values, timer_value);
char* file_name = GetFileName("renewal_response_corpus");
// Renewal Response format expected by fuzzer - [ODK_ParseRenewal_Args][Core
// Renewal Response]
AppendToFile(file_name, (const char*)&parse_renewal_args,
sizeof(struct ODK_ParseRenewal_Args));
AppendToFile(file_name, (const char*)message, core_message_length);
free(file_name);
return oem_crypto_result;
}
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) {
OEMCryptoResult (*original_function)(uint8_t*, size_t, size_t*,
const ODK_NonceValues*, const uint8_t*,
size_t);
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);
char* file_name = GetFileName("provisioning_request_corpus");
// Provisioning Request format expected by fuzzer - [Core Provisioning
// Request]
AppendToFile(file_name, (const char*)message, *core_message_length);
free(file_name);
return oem_crypto_result;
}
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) {
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*);
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);
char* file_name = GetFileName("provisioning_response_corpus");
// Provisioning Response format expected by fuzzer -
// [ODK_ParseProvisioning_Args][Core Provisioning Response]
AppendToFile(file_name, (const char*)&parse_provisioning_args,
sizeof(struct ODK_ParseProvisioning_Args));
AppendToFile(file_name, (const char*)message, core_message_length);
free(file_name);
return oem_crypto_result;
}

View File

@@ -0,0 +1,22 @@
// Copyright 2020 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "fuzzing/corpus_generator/odk_corpus_generator_helper.h"
void AppendToFile(const char* file_name, const char* message,
const size_t message_size) {
FILE* fptr;
if ((fptr = fopen(file_name, "ab")) == NULL) {
printf("Error! opening file %s", file_name);
return;
}
fwrite(message, message_size, 1, fptr);
fclose(fptr);
}
char* GetFileName(const char* directory) {
char* file_name;
file_name = malloc(150);
sprintf(file_name, "%s%s/%d", PATH_TO_CORPUS, directory, rand());
return file_name;
}

View File

@@ -0,0 +1,18 @@
// Copyright 2020 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#ifndef WIDEVINE_ODK_TEST_FUZZING_CORPUS_GENERATOR_ODK_CORPUS_GENERATOR_HELPER_H_
#define WIDEVINE_ODK_TEST_FUZZING_CORPUS_GENERATOR_ODK_CORPUS_GENERATOR_HELPER_H_
#define PATH_TO_CORPUS "./oemcrypto/odk/test/fuzzing/corpus/"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void AppendToFile(const char* file_name, const char* message,
const size_t message_size);
char* GetFileName(const char* directory);
#endif // WIDEVINE_ODK_TEST_FUZZING_CORPUS_GENERATOR_ODK_CORPUS_GENERATOR_HELPER_H_

View File

@@ -0,0 +1,33 @@
# Copyright 2020 Google LLC. All rights reserved. This file and proprietary
# source code may only be used and distributed under the Widevine Master License
# Agreement.
# Reference Link explaining flags for LD_PRELOAD: https://catonmat.net/simple-ld-preload-tutorial-part-two
{
'targets': [
{
'target_name': 'odk_corpus_generator',
'type': 'shared_library',
'cflags_cc': [
'-g3',
'-O0',
'-fno-omit-frame-pointer',
'-Wall',
],
'include_dirs': [
'../../../include',
'../../../test',
'../corpus_generator',
],
'ldflags': [
'-fPIC',
],
'libraries': [
'-ldl',
],
'sources': [
'odk_corpus_generator.c',
],
}
]
}

View File

@@ -0,0 +1,40 @@
# Copyright 2019 Google LLC. All rights reserved. This file and proprietary
# source code may only be used and distributed under the Widevine Master License
# Agreement.
#TODO(b/151858867): Fix File paths
{
'targets': [
{
'target_name': 'odk_fuzz',
'type': 'executable',
'includes': [
'../src/odk.gypi',
'../kdo/oec_util.gypi',
],
'include_dirs': [
'../../include',
'../include',
'../src',
'../kdo/include',
],
'cflags_cc': [
'-std=c++11',
'-g3',
'-O0',
'-fsanitize=fuzzer,address,undefined',
'-fno-omit-frame-pointer',
],
'ldflags': [
'-fPIC',
'-fsanitize=fuzzer,address,undefined',
],
'sources': [
'odk_fuzz.cpp',
],
'dependencies': [
'../../../cdm/cdm.gyp:license_protocol'
],
}
]
}

View File

@@ -0,0 +1,159 @@
// Copyright 2020 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "fuzzing/odk_fuzz_helper.h"
#include "odk.h"
namespace oemcrypto_core_message {
bool convert_byte_to_valid_boolean(const bool* in) {
const char* buf = reinterpret_cast<const char*>(in);
for (int i = 0; i < sizeof(bool); i++) {
if (buf[i]) {
return true;
}
}
return false;
}
void ConvertDataToValidBools(ODK_ParsedLicense* t) {
// Convert boolean flags in parsed_license to valid bytes to
// avoid errors from msan
t->nonce_required = convert_byte_to_valid_boolean(&t->nonce_required);
t->timer_limits.soft_enforce_playback_duration =
convert_byte_to_valid_boolean(
&t->timer_limits.soft_enforce_playback_duration);
t->timer_limits.soft_enforce_rental_duration = convert_byte_to_valid_boolean(
&t->timer_limits.soft_enforce_rental_duration);
}
void ConvertDataToValidBools(ODK_PreparedRenewalRequest* t UNUSED) {}
void ConvertDataToValidBools(ODK_ParsedProvisioning* t UNUSED) {}
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);
}
OEMCryptoResult odk_serialize_RenewalRequest(
const void* in, uint8_t* out, size_t* size,
const ODK_RenewalRequest& core_renewal, ODK_NonceValues* nonce_values) {
ODK_ClockValues clock{};
memcpy(&clock, in, sizeof(ODK_ClockValues));
uint64_t system_time_seconds = core_renewal.playback_time_seconds;
return ODK_PrepareCoreRenewalRequest(out, SIZE_MAX, size, nonce_values,
&clock, system_time_seconds);
}
OEMCryptoResult odk_serialize_ProvisioningRequest(
const void* in UNUSED, uint8_t* out, size_t* size,
const ODK_ProvisioningRequest& core_provisioning,
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());
}
OEMCryptoResult odk_deserialize_LicenseResponse(const uint8_t* message,
size_t core_message_length,
ODK_ParseLicense_Args* a,
ODK_NonceValues* nonce_values,
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),
a->request_hash, &a->timer_limits, &a->clock_values,
nonce_values, parsed_lic);
}
OEMCryptoResult odk_deserialize_RenewalResponse(
const uint8_t* buf, size_t len, ODK_ParseRenewal_Args* a,
ODK_NonceValues* nonce_values, ODK_PreparedRenewalRequest* renewal_msg) {
/* Address Sanitizer doesn't like values other than 0 OR 1 for boolean
* variables. Input from fuzzer can be parsed and any random bytes can be
* assigned to boolean variables. Using the workaround to mitigate sanitizer
* errors in fuzzer code and converting random bytes to 0 OR 1.
* This has no negative security impact*/
a->timer_limits.soft_enforce_playback_duration =
convert_byte_to_valid_boolean(
&a->timer_limits.soft_enforce_playback_duration);
a->timer_limits.soft_enforce_rental_duration = convert_byte_to_valid_boolean(
&a->timer_limits.soft_enforce_rental_duration);
uint64_t timer_value = 0;
OEMCryptoResult err =
ODK_ParseRenewal(buf, SIZE_MAX, len, nonce_values, a->system_time,
&a->timer_limits, &a->clock_values, &timer_value);
const bool is_parse_renewal_response_successful =
err == ODK_SET_TIMER || err == ODK_DISABLE_TIMER ||
err == ODK_TIMER_EXPIRED || err == ODK_STALE_RENEWAL;
if (!is_parse_renewal_response_successful) {
return err;
}
// In order to capture playback_time information which is part of
// renewal_msg and will be later used in kdo_serialize_RenewalResponse in
// odk_kdo method, we call Unpack_ODK_PreparedRenewalRequest private method.
// playback_time cannot be captured from publicly exposed API
// ODK_ParseRenewal.
uint8_t blk[SIZE_OF_MESSAGE_STRUCT];
Message* msg = reinterpret_cast<Message*>(blk);
InitMessage(msg, const_cast<uint8_t*>(buf), len);
SetSize(msg, len);
Unpack_ODK_PreparedRenewalRequest(msg, renewal_msg);
return OEMCrypto_SUCCESS;
}
OEMCryptoResult odk_deserialize_ProvisioningResponse(
const uint8_t* buf, size_t len, ODK_ParseProvisioning_Args* a,
ODK_NonceValues* nonce_values, ODK_ParsedProvisioning* parsed_prov) {
return ODK_ParseProvisioning(buf, SIZE_MAX, len, nonce_values, a->device_id,
a->device_id_length, parsed_prov);
}
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};
std::string core_request_sha_256(
reinterpret_cast<const char*>(args->request_hash), ODK_SHA256_HASH_SIZE);
return serialize::CreateCoreLicenseResponse(
parsed_lic, core_request, core_request_sha_256, oemcrypto_core_message);
}
bool kdo_serialize_RenewalResponse(
const ODK_ParseRenewal_Args* args,
const ODK_PreparedRenewalRequest& renewal_msg,
std::string* oemcrypto_core_message) {
const auto& nonce_values = args->nonce_values;
ODK_RenewalRequest core_request{
nonce_values.api_minor_version, nonce_values.api_major_version,
nonce_values.nonce, nonce_values.session_id, renewal_msg.playback_time};
return serialize::CreateCoreRenewalResponse(
core_request, args->timer_limits.initial_renewal_duration_seconds,
oemcrypto_core_message);
}
bool kdo_serialize_ProvisioningResponse(
const ODK_ParseProvisioning_Args* args,
const ODK_ParsedProvisioning& parsed_prov,
std::string* oemcrypto_core_message) {
const auto& nonce_values = args->nonce_values;
if (args->device_id_length > sizeof(args->device_id)) {
return false;
}
ODK_ProvisioningRequest core_request{
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)};
return serialize::CreateCoreProvisioningResponse(parsed_prov, core_request,
oemcrypto_core_message);
}
} // namespace oemcrypto_core_message

View File

@@ -0,0 +1,205 @@
// Copyright 2020 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#ifndef WIDEVINE_ODK_TEST_FUZZING_ODK_FUZZ_HELPER_H_
#define WIDEVINE_ODK_TEST_FUZZING_ODK_FUZZ_HELPER_H_
#include <memory>
#include <string>
#include "core_message_serialize.h"
#include "fuzzing/odk_fuzz_structs.h"
#include "odk_attributes.h"
#include "odk_serialize.h"
namespace oemcrypto_core_message {
bool convert_byte_to_valid_boolean(const bool* in);
OEMCryptoResult odk_serialize_LicenseRequest(
const void* in, uint8_t* out, size_t* size,
const ODK_LicenseRequest& core_license_request,
const ODK_NonceValues* nonce_values);
OEMCryptoResult odk_serialize_RenewalRequest(
const void* in, uint8_t* out, size_t* size,
const ODK_RenewalRequest& core_renewal, ODK_NonceValues* nonce_values);
OEMCryptoResult odk_serialize_ProvisioningRequest(
const void* in, uint8_t* out, size_t* size,
const ODK_ProvisioningRequest& core_provisioning,
const ODK_NonceValues* nonce_values);
OEMCryptoResult odk_deserialize_LicenseResponse(const uint8_t* message,
size_t core_message_length,
ODK_ParseLicense_Args* a,
ODK_NonceValues* nonce_values,
ODK_ParsedLicense* parsed_lic);
OEMCryptoResult odk_deserialize_RenewalResponse(
const uint8_t* buf, size_t len, ODK_ParseRenewal_Args* a,
ODK_NonceValues* nonce_values, ODK_PreparedRenewalRequest* renewal_msg);
OEMCryptoResult odk_deserialize_ProvisioningResponse(
const uint8_t* buf, size_t len, ODK_ParseProvisioning_Args* a,
ODK_NonceValues* nonce_values, ODK_ParsedProvisioning* parsed_prov);
bool kdo_serialize_LicenseResponse(const ODK_ParseLicense_Args* args,
const ODK_ParsedLicense& parsed_lic,
std::string* oemcrypto_core_message);
bool kdo_serialize_RenewalResponse(
const ODK_ParseRenewal_Args* args,
const ODK_PreparedRenewalRequest& renewal_msg,
std::string* oemcrypto_core_message);
bool kdo_serialize_ProvisioningResponse(
const ODK_ParseProvisioning_Args* args,
const ODK_ParsedProvisioning& parsed_prov,
std::string* oemcrypto_core_message);
// Idea behind having three different functions is:
// Only ODK_ParseLicense structure had fields which needed additional
// procession. Having a single function with templated parameter T was
// failing during compile time because other two structures doesn't have
// fields that need additional processing. Hence to reduce code redundance and
// make us of common FuzzerMutateResponse across three response fuzzers,
// three independent functions were defined and renewal and provisioning
// functions would be empty as no additional processing is needed for them.
void ConvertDataToValidBools(ODK_ParsedLicense* t);
void ConvertDataToValidBools(ODK_PreparedRenewalRequest* t);
void ConvertDataToValidBools(ODK_ParsedProvisioning* t);
// Forward-declare the libFuzzer's mutator callback. Mark it weak so that
// the program links successfully even outside of --config=asan-fuzzer
// (apparently the only config in which LLVM uses our custom mutator).
extern "C" size_t LLVMFuzzerMutate(uint8_t* Data, size_t Size, size_t MaxSize)
__attribute__((weak));
template <typename A, typename T, typename F, typename G>
size_t FuzzerMutateResponse(uint8_t* data, size_t size, size_t max_size,
const F& odk_deserialize_fun,
const G& kdo_serialize_fun) {
const size_t kArgsSize = sizeof(A);
const size_t kCoreResponseSize = sizeof(T);
const size_t kTotalResponseSize = kArgsSize + kCoreResponseSize;
// Deserializing data in order to make sure it deserializes properly.
// Input byte array format: [function arguments][data to parse].
std::shared_ptr<A> _args(new A());
A* args = _args.get();
memcpy(args, data, kArgsSize);
ODK_NonceValues nonce_values = args->nonce_values;
args->nonce_values.api_major_version = ODK_MAJOR_VERSION;
const uint8_t* buf = data + kArgsSize;
T t = {};
OEMCryptoResult result =
odk_deserialize_fun(buf, size - kArgsSize, args, &nonce_values, &t);
// If data doesn't deserialize successfully, We copy random bytes into
// T and serialize using kdo function
// which will create a valid oemcrypto core message using
// nonce and request hash from function args. OEMCrypto core message acts as
// input to odk_kdo.
if (result != OEMCrypto_SUCCESS) {
if (max_size < kTotalResponseSize) {
return 0;
}
// Initialize remaining bytes needed in data to zero.
if (size < kTotalResponseSize) {
memset(data + size, 0, kTotalResponseSize - size);
}
t = {};
memcpy(&t, buf, kCoreResponseSize);
}
// Ask LLVM to run its usual mutations, hopefully giving us interesting
// inputs. We copy deserialized data into pointer data, run mutations
// and copy back the mutated data to args and t
memcpy(data + kArgsSize, &t, kCoreResponseSize);
LLVMFuzzerMutate(data, kTotalResponseSize, kTotalResponseSize);
memcpy(args, data, kArgsSize);
memcpy(&t, data + kArgsSize, kCoreResponseSize);
// Convert boolean flags in parsed message to valid bytes to
// avoid errors from msan. Only needed for parsed license.
ConvertDataToValidBools(&t);
// Serialize the data after mutation.
std::string oemcrypto_core_message;
if (!kdo_serialize_fun(args, t, &oemcrypto_core_message)) {
return 0;
}
// Copy mutated and serialized oemcrypto_core_message to data
// so that it acts as input to odk_kdo function.
memcpy(data + kArgsSize, oemcrypto_core_message.data(),
oemcrypto_core_message.size());
return kArgsSize + oemcrypto_core_message.size();
}
/**
* Template arguments:
* A: struct holding function arguments
* T: odk deserialize output/kdo serialize input structure
* F: odk deserialize function
* G: kdo serialize function
*
* raw bytes -> F deserialize -> struct T -> G serialize -> raw bytes
*/
template <typename A, typename T, typename F, typename G>
void odk_kdo(const F& odk_fun, const G& kdo_fun, const uint8_t* in,
const size_t size, const size_t args_size, uint8_t* out UNUSED) {
T t = {};
// Input byte array format: [function arguments][data to parse]
if (size < args_size) {
return;
}
const uint8_t* buf = in + args_size;
std::shared_ptr<A> _args(new A());
A* args = _args.get();
memcpy(args, in, args_size);
args->nonce_values.api_major_version = ODK_MAJOR_VERSION;
ODK_NonceValues nonce_values = args->nonce_values;
OEMCryptoResult result =
odk_fun(buf, size - args_size, args, &nonce_values, &t);
if (result != OEMCrypto_SUCCESS) {
return;
}
std::string oemcrypto_core_message;
if (!kdo_fun(args, t, &oemcrypto_core_message)) {
return;
}
}
/**
* Template arguments:
* T: kdo deserialize output/odk serialize input structure
* F: kdo deserialize function
* G: odk serialize function
*
* raw bytes -> F deserialize -> struct T -> G serialize -> raw bytes
*/
template <typename T, typename F, typename G>
static void kdo_odk(const F& kdo_fun, const G& odk_fun, const uint8_t* in,
size_t size, const size_t clock_value_size, uint8_t* out) {
if (size <= clock_value_size) {
return;
}
// Input byte array format: [Clock Values][data to parse].
// Only Renewal Request expects clock values to be present.
std::string input(reinterpret_cast<const char*>(in) + clock_value_size,
size - clock_value_size);
T t = {};
if (!kdo_fun(input, &t)) {
return;
}
ODK_NonceValues nonce_values = {t.api_minor_version, t.api_major_version,
t.nonce, t.session_id};
OEMCryptoResult err = odk_fun(in, out, &size, t, &nonce_values);
if (OEMCrypto_SUCCESS != err) {
return;
}
}
} // namespace oemcrypto_core_message
#endif // WIDEVINE_ODK_TEST_FUZZING_ODK_FUZZ_HELPER_H_

View File

@@ -0,0 +1,28 @@
// Copyright 2020 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#ifndef WIDEVINE_ODK_TEST_FUZZING_ODK_FUZZ_STRUCTS_H_
#define WIDEVINE_ODK_TEST_FUZZING_ODK_FUZZ_STRUCTS_H_
#include "odk_structs.h"
struct ODK_ParseLicense_Args {
ODK_NonceValues nonce_values;
uint8_t initial_license_load;
uint8_t usage_entry_present;
uint8_t request_hash[ODK_SHA256_HASH_SIZE];
ODK_TimerLimits timer_limits;
ODK_ClockValues clock_values;
};
struct ODK_ParseRenewal_Args {
ODK_NonceValues nonce_values;
uint64_t system_time;
ODK_TimerLimits timer_limits;
ODK_ClockValues clock_values;
};
struct ODK_ParseProvisioning_Args {
ODK_NonceValues nonce_values;
size_t device_id_length;
uint8_t device_id[64];
};
#endif // WIDEVINE_ODK_TEST_FUZZING_ODK_FUZZ_STRUCTS_H_

View File

@@ -0,0 +1,22 @@
/* Copyright 2020 Google LLC. All rights reserved. This file and proprietary
* source code may only be used and distributed under the Widevine Master
* License Agreement.
*/
#include <vector>
#include "core_message_deserialize.h"
#include "fuzzing/odk_fuzz_helper.h"
namespace oemcrypto_core_message {
using oemcrypto_core_message::deserialize::CoreLicenseRequestFromMessage;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
std::vector<uint8_t> out(size);
const size_t kClockValueSize = 0;
kdo_odk<ODK_LicenseRequest>(CoreLicenseRequestFromMessage,
odk_serialize_LicenseRequest, data, size,
kClockValueSize, out.data());
return 0;
}
} // namespace oemcrypto_core_message

View File

@@ -0,0 +1,20 @@
/* Copyright 2020 Google LLC. All rights reserved. This file and proprietary
* source code may only be used and distributed under the Widevine Master
* License Agreement.
*/
#include <vector>
#include "fuzzing/odk_fuzz_helper.h"
namespace oemcrypto_core_message {
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
const size_t kLicenseResponseArgsSize = sizeof(ODK_ParseLicense_Args);
std::vector<uint8_t> out(size);
odk_kdo<ODK_ParseLicense_Args, ODK_ParsedLicense>(
odk_deserialize_LicenseResponse, kdo_serialize_LicenseResponse, data,
size, kLicenseResponseArgsSize, out.data());
return 0;
}
} // namespace oemcrypto_core_message

View File

@@ -0,0 +1,36 @@
/* Copyright 2020 Google LLC. All rights reserved. This file and proprietary
* source code may only be used and distributed under the Widevine Master
* License Agreement.
*/
#include <vector>
#include "fuzzing/odk_fuzz_helper.h"
namespace oemcrypto_core_message {
// The custom mutator: Ensure that each input can be deserialized properly
// by ODK function after mutation.
extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size,
size_t max_size,
unsigned int seed UNUSED) {
const size_t kLicenseResponseArgsSize = sizeof(ODK_ParseLicense_Args);
if (size < kLicenseResponseArgsSize) {
return 0;
}
// Mutate input data and return mutated input size.
return FuzzerMutateResponse<ODK_ParseLicense_Args, ODK_ParsedLicense>(
data, size, max_size, odk_deserialize_LicenseResponse,
kdo_serialize_LicenseResponse);
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
const size_t kLicenseResponseArgsSize = sizeof(ODK_ParseLicense_Args);
std::vector<uint8_t> out(size);
odk_kdo<ODK_ParseLicense_Args, ODK_ParsedLicense>(
odk_deserialize_LicenseResponse, kdo_serialize_LicenseResponse, data,
size, kLicenseResponseArgsSize, out.data());
return 0;
}
} // namespace oemcrypto_core_message

View File

@@ -0,0 +1,22 @@
/* Copyright 2020 Google LLC. All rights reserved. This file and proprietary
* source code may only be used and distributed under the Widevine Master
* License Agreement.
*/
#include <vector>
#include "core_message_deserialize.h"
#include "fuzzing/odk_fuzz_helper.h"
namespace oemcrypto_core_message {
using oemcrypto_core_message::deserialize::CoreProvisioningRequestFromMessage;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
std::vector<uint8_t> out(size);
const size_t kClockValueSize = 0;
kdo_odk<ODK_ProvisioningRequest>(CoreProvisioningRequestFromMessage,
odk_serialize_ProvisioningRequest, data,
size, kClockValueSize, out.data());
return 0;
}
} // namespace oemcrypto_core_message

View File

@@ -0,0 +1,21 @@
/* Copyright 2020 Google LLC. All rights reserved. This file and proprietary
* source code may only be used and distributed under the Widevine Master
* License Agreement.
*/
#include <vector>
#include "fuzzing/odk_fuzz_helper.h"
namespace oemcrypto_core_message {
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
const size_t kProvisioningResponseArgsSize =
sizeof(ODK_ParseProvisioning_Args);
std::vector<uint8_t> out(size);
odk_kdo<ODK_ParseProvisioning_Args, ODK_ParsedProvisioning>(
odk_deserialize_ProvisioningResponse, kdo_serialize_ProvisioningResponse,
data, size, kProvisioningResponseArgsSize, out.data());
return 0;
}
} // namespace oemcrypto_core_message

View File

@@ -0,0 +1,38 @@
/* Copyright 2020 Google LLC. All rights reserved. This file and proprietary
* source code may only be used and distributed under the Widevine Master
* License Agreement.
*/
#include <vector>
#include "fuzzing/odk_fuzz_helper.h"
namespace oemcrypto_core_message {
// The custom mutator: Ensure that each input can be deserialized properly
// by ODK function after mutation.
extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size,
size_t max_size, unsigned int seed) {
const size_t kProvisioningResponseArgsSize =
sizeof(ODK_ParseProvisioning_Args);
if (size < kProvisioningResponseArgsSize) {
return 0;
}
// Mutate input data and return mutated input size.
return FuzzerMutateResponse<ODK_ParseProvisioning_Args,
ODK_ParsedProvisioning>(
data, size, max_size, odk_deserialize_ProvisioningResponse,
kdo_serialize_ProvisioningResponse);
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
const size_t kProvisioningResponseArgsSize =
sizeof(ODK_ParseProvisioning_Args);
std::vector<uint8_t> out(size);
odk_kdo<ODK_ParseProvisioning_Args, ODK_ParsedProvisioning>(
odk_deserialize_ProvisioningResponse, kdo_serialize_ProvisioningResponse,
data, size, kProvisioningResponseArgsSize, out.data());
return 0;
}
} // namespace oemcrypto_core_message

View File

@@ -0,0 +1,22 @@
/* Copyright 2020 Google LLC. All rights reserved. This file and proprietary
* source code may only be used and distributed under the Widevine Master
* License Agreement.
*/
#include <vector>
#include "core_message_deserialize.h"
#include "fuzzing/odk_fuzz_helper.h"
namespace oemcrypto_core_message {
using oemcrypto_core_message::deserialize::CoreRenewalRequestFromMessage;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
std::vector<uint8_t> out(size);
const size_t kClockValueSize = sizeof(ODK_ClockValues);
kdo_odk<ODK_RenewalRequest>(CoreRenewalRequestFromMessage,
odk_serialize_RenewalRequest, data, size,
kClockValueSize, out.data());
return 0;
}
} // namespace oemcrypto_core_message

View File

@@ -0,0 +1,20 @@
/* Copyright 2020 Google LLC. All rights reserved. This file and proprietary
* source code may only be used and distributed under the Widevine Master
* License Agreement.
*/
#include <vector>
#include "fuzzing/odk_fuzz_helper.h"
namespace oemcrypto_core_message {
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
const size_t kRenewalResponseArgsSize = sizeof(ODK_ParseRenewal_Args);
std::vector<uint8_t> out(size);
odk_kdo<ODK_ParseRenewal_Args, ODK_PreparedRenewalRequest>(
odk_deserialize_RenewalResponse, kdo_serialize_RenewalResponse, data,
size, kRenewalResponseArgsSize, out.data());
return 0;
}
} // namespace oemcrypto_core_message

View File

@@ -0,0 +1,36 @@
/* Copyright 2020 Google LLC. All rights reserved. This file and proprietary
* source code may only be used and distributed under the Widevine Master
* License Agreement.
*/
#include <vector>
#include "fuzzing/odk_fuzz_helper.h"
namespace oemcrypto_core_message {
// The custom mutator: Ensure that each input can be deserialized properly
// by ODK function after mutation.
extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size,
size_t max_size, unsigned int seed) {
const size_t kRenewalResponseArgsSize = sizeof(ODK_ParseRenewal_Args);
if (size < kRenewalResponseArgsSize) {
return 0;
}
// Mutate input data and return mutated input size.
return FuzzerMutateResponse<ODK_ParseRenewal_Args,
ODK_PreparedRenewalRequest>(
data, size, max_size, odk_deserialize_RenewalResponse,
kdo_serialize_RenewalResponse);
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
const size_t kRenewalResponseArgsSize = sizeof(ODK_ParseRenewal_Args);
std::vector<uint8_t> out(size);
odk_kdo<ODK_ParseRenewal_Args, ODK_PreparedRenewalRequest>(
odk_deserialize_RenewalResponse, kdo_serialize_RenewalResponse, data,
size, kRenewalResponseArgsSize, out.data());
return 0;
}
} // namespace oemcrypto_core_message

View File

@@ -0,0 +1,37 @@
// Copyright 2020 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "OEMCryptoCENCCommon.h"
#include "gtest/gtest.h"
#include "odk.h"
#include "third_party/absl/strings/escaping.h"
namespace wvodk_test {
TEST(CoreMessageTest, RenwalRequest) {
std::string oem =
"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst"
"uvwxyzabcdefghijklmnopqrstuvwxyz";
const uint8_t* buf = reinterpret_cast<const uint8_t*>(oem.c_str());
uint8_t* message = const_cast<uint8_t*>(buf);
size_t message_length = 88;
size_t core_message_length = 88;
uint16_t api_minor_version = 16;
uint16_t api_major_version = 16;
uint32_t nonce = 0;
uint32_t timer_status = 2;
uint64_t time = 10;
enum OEMCrypto_Usage_Entry_Status status = kInactiveUsed;
ODK_NonceValues nonce_values{api_minor_version, api_major_version, nonce};
ODK_ClockValues clock_values{time, time, time, time,
time, timer_status, status};
uint64_t system_time_seconds = 100;
EXPECT_EQ(OEMCrypto_SUCCESS,
ODK_PrepareCoreRenewalRequest(message, message_length,
&core_message_length, &nonce_values,
&clock_values, system_time_seconds));
// All messages have at least a five 4-byte fields.
char* m = reinterpret_cast<char*>(message);
VLOG(0) << absl::BytesToHexString(std::string(m, core_message_length));
}
} // namespace wvodk_test

View File

@@ -209,8 +209,10 @@ TEST(OdkTest, SerializeFieldsStress) {
TEST(OdkTest, NullRequestTest) {
size_t core_message_length = 0;
ODK_NonceValues nonce_values{0};
ODK_ClockValues clock_values{0};
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
ODK_ClockValues clock_values;
memset(&clock_values, 0, sizeof(clock_values));
// Assert that nullptr does not cause a core dump.
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_PrepareCoreLicenseRequest(
@@ -250,10 +252,12 @@ TEST(OdkTest, NullResponseTest) {
uint8_t message[message_size] = {0};
size_t core_message_length = message_size;
uint8_t request_hash[ODK_SHA256_HASH_SIZE] = {0};
ODK_TimerLimits timer_limits{0};
ODK_TimerLimits timer_limits;
ODK_ParsedLicense parsed_license;
ODK_NonceValues nonce_values{0};
ODK_ClockValues clock_values{0};
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
ODK_ClockValues clock_values;
memset(&clock_values, 0, sizeof(clock_values));
// Assert that nullptr does not cause a core dump.
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
@@ -322,7 +326,8 @@ TEST(OdkTest, NullResponseTest) {
TEST(OdkTest, PrepareCoreLicenseRequest) {
uint8_t license_message[ODK_LICENSE_REQUEST_SIZE] = {0};
size_t core_message_length = sizeof(license_message);
ODK_NonceValues nonce_values{0};
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));
@@ -331,7 +336,8 @@ TEST(OdkTest, PrepareCoreLicenseRequest) {
TEST(OdkTest, PrepareCoreLicenseRequestSize) {
uint8_t license_message[ODK_LICENSE_REQUEST_SIZE] = {0};
size_t core_message_length = sizeof(license_message);
ODK_NonceValues nonce_values{0};
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
// message length smaller than core message length
size_t core_message_length_invalid = core_message_length + 1;
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
@@ -349,8 +355,10 @@ TEST(OdkTest, PrepareCoreLicenseRequestSize) {
TEST(OdkTest, PrepareCoreRenewalRequest) {
uint8_t renewal_message[ODK_RENEWAL_REQUEST_SIZE] = {0};
size_t core_message_length = sizeof(renewal_message);
ODK_NonceValues nonce_values{0};
ODK_ClockValues clock_values{0};
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
ODK_ClockValues clock_values;
memset(&clock_values, 0, sizeof(clock_values));
constexpr uint64_t system_time_seconds = 10;
EXPECT_EQ(OEMCrypto_SUCCESS,
ODK_PrepareCoreRenewalRequest(
@@ -363,7 +371,8 @@ TEST(OdkTest, PrepareCoreRenewalRequestTimer) {
size_t core_message_length = sizeof(renewal_message);
ODK_NonceValues nonce_values{2, 16, 0, 0};
constexpr uint64_t system_time_seconds = 10;
ODK_ClockValues clock_values_updated{0};
ODK_ClockValues clock_values_updated;
memset(&clock_values_updated, 0, sizeof(clock_values_updated));
// system time smaller than first decrypt time
clock_values_updated.time_of_first_decrypt = system_time_seconds + 1;
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
@@ -383,7 +392,8 @@ TEST(OdkTest, PrepareCoreRenewalRequestTimer) {
TEST(OdkTest, PrepareCoreProvisioningRequest) {
uint8_t provisioning_message[ODK_PROVISIONING_REQUEST_SIZE] = {0};
size_t core_message_length = sizeof(provisioning_message);
ODK_NonceValues nonce_values{0};
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,
@@ -395,7 +405,8 @@ TEST(OdkTest, PrepareCoreProvisioningRequest) {
TEST(OdkTest, PrepareCoreProvisioningRequestDeviceId) {
uint8_t provisioning_message[ODK_PROVISIONING_REQUEST_SIZE] = {0};
size_t core_message_length = sizeof(provisioning_message);
ODK_NonceValues nonce_values{0};
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
uint8_t device_id_invalid[ODK_DEVICE_ID_LEN_MAX + 1] = {0};
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_PrepareCoreProvisioningRequest(
@@ -423,7 +434,8 @@ TEST(OdkTest, RenewalRequestRoundtrip) {
const std::vector<ODK_Field> extra_fields = {
{ODK_UINT64, &playback_time, "playback_time"},
};
ODK_ClockValues clock_values = {0};
ODK_ClockValues clock_values;
memset(&clock_values, 0, sizeof(clock_values));
clock_values.time_of_first_decrypt = playback_start;
auto odk_prepare_func = [&](uint8_t* const buf, size_t* size,
ODK_NonceValues* nonce_values) {
@@ -713,6 +725,17 @@ TEST(OdkSizeTest, ProvisioningRequest) {
EXPECT_EQ(ODK_PROVISIONING_REQUEST_SIZE, core_message_length);
}
// Verify the version string contains the right version numbers.
TEST(OdkTest, CheckReleaseVersion) {
// Here are the version numbers.
std::string expected_version = std::to_string(ODK_MAJOR_VERSION) + "." +
std::to_string(ODK_MINOR_VERSION);
// Here is the version string.
EXPECT_NE(std::string(ODK_RELEASE_DATE).find(expected_version),
std::string::npos)
<< "Version mismatch in odk_structs.h";
}
} // namespace
} // namespace wvodk_test

View File

@@ -1,6 +1,6 @@
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */
/* source code may only be used and distributed under the Widevine Master */
/* License Agreement. */
// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#ifndef WIDEVINE_ODK_TEST_ODK_TEST_HELPER_H_
#define WIDEVINE_ODK_TEST_ODK_TEST_HELPER_H_
@@ -66,7 +66,7 @@ struct ODK_ProvisioningResponseParams {
std::vector<ODK_Field> extra_fields;
};
/* Default values in core_message for testing */
// Default values in core_message for testing
void ODK_SetDefaultCoreFields(ODK_CoreMessage* core_message,
uint32_t message_type);
void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params);
@@ -77,9 +77,9 @@ void ODK_SetDefaultProvisioningResponseParams(
size_t ODK_FieldLength(ODK_FieldType type);
size_t ODK_AllocSize(ODK_FieldType type);
/* Copy ODK_Field to buf */
// Copy ODK_Field to buf
OEMCryptoResult ODK_WriteSingleField(uint8_t* buf, const ODK_Field* field);
/* Load buf to ODK_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,
@@ -89,11 +89,11 @@ void ODK_ExpectEqualBuf(const void* s1, const void* s2, size_t n,
const std::vector<ODK_Field>& fields);
void ODK_ResetOdkFields(std::vector<ODK_Field>* fields);
/* Serialize core_message and extra_fields into buf */
// Serialize core_message and extra_fields into buf
void ODK_BuildMessageBuffer(ODK_CoreMessage* core_message,
const std::vector<ODK_Field>& extra_fields,
uint8_t** buf, uint32_t* buf_size);
} /* namespace wvodk_test */
} // namespace wvodk_test
#endif /* WIDEVINE_ODK_TEST_ODK_TEST_HELPER_H_ */
#endif // WIDEVINE_ODK_TEST_ODK_TEST_HELPER_H_

View File

@@ -35,6 +35,7 @@ TEST(OdkTimerBasicTest, NullTest) {
TEST(OdkTimerBasicTest, Init) {
// Verify that basic initialization sets all of the fields.
ODK_ClockValues clock_values;
memset(&clock_values, 0, sizeof(clock_values));
uint64_t time = 42;
ODK_InitializeClockValues(&clock_values, time);
EXPECT_EQ(clock_values.time_of_license_signed, time);
@@ -50,6 +51,7 @@ TEST(OdkTimerBasicTest, Reload) {
// Verify that reloading clock values uses the same values
// for fields that can be saved, and sets others to 0.
ODK_ClockValues clock_values;
memset(&clock_values, 0, sizeof(clock_values));
uint64_t time = 42u;
uint64_t lic_signed = 1u;
uint64_t first_decrypt = 2u;
@@ -1223,6 +1225,7 @@ TEST_F(ODKUseCase_LimitedDurationLicense, Case5) {
TEST_F(RenewalTest, V15Test) {
const uint32_t key_duration = 25;
ODK_NonceValues nonce_values;
memset(&nonce_values, 0, sizeof(nonce_values));
const uint64_t license_loaded = GetSystemTime(10);
EXPECT_EQ(
ODK_InitializeV15Values(&timer_limits_, &clock_values_, &nonce_values,

View File

@@ -5,13 +5,15 @@
# Override the variables below for the location of various gyp files.
# Alternatively, set the environment variable PATH_TO_CDM_DIR to point to a
# recent version of the source CDM. This *must* be a relative path.
'boringssl_dependency%': '<!(echo $PATH_TO_CDM_DIR)/third_party/boringssl/boringssl.gyp:ssl',
'gtest_dependency%': '<!(echo $PATH_TO_CDM_DIR)/third_party/gmock.gyp:gtest',
'gmock_dependency%': '<!(echo $PATH_TO_CDM_DIR)/third_party/gmock.gyp:gmock',
'gmock_main_dependency%': '<!(echo $PATH_TO_CDM_DIR)/third_party/gmock.gyp:gmock_main',
'oemcrypto_dir%': '.',
'util_dir%': '../util',
'platform_specific_dir%': '<!(echo $PATH_TO_CDM_DIR)/linux/src',
'privacy_crypto_impl%': 'boringssl',
'boringssl_libcrypto_path%': '<!(echo $PATH_TO_CDM_DIR)/third_party/boringssl/boringssl.gyp:crypto',
'boringssl_libssl_path%': '<!(echo $PATH_TO_CDM_DIR)/third_party/boringssl/boringssl.gyp:ssl',
'gtest_dependency': '<!(echo $PATH_TO_CDM_DIR)/third_party/gmock.gyp:gtest',
'gmock_dependency': '<!(echo $PATH_TO_CDM_DIR)/third_party/gmock.gyp:gmock',
'gmock_main_dependency': '<!(echo $PATH_TO_CDM_DIR)/third_party/gmock.gyp:gmock_main',
'oemcrypto_dir': '.',
'util_dir': '../util',
'platform_specific_dir': '<!(echo $PATH_TO_CDM_DIR)/linux/src',
},
'targets': [
{
@@ -30,6 +32,7 @@
'<(util_dir)/test/test_clock.cpp',
],
'includes': [
'../util/libssl_dependency.gypi',
'test/oemcrypto_unittests.gypi',
'ref/oec_ref.gypi',
],
@@ -37,7 +40,6 @@
'-lpthread',
],
'dependencies': [
'<(boringssl_dependency)',
'<(gtest_dependency)',
'<(gmock_dependency)',
],

View File

@@ -33,10 +33,8 @@
# TODO(fredgc) remove these:
'<(oemcrypto_dir)/ref/src/oemcrypto_engine_device_properties.cpp',
],
'dependencies': [
'<(boringssl_dependency)',
],
'includes': [
'../../util/libcrypto_dependency.gypi',
'../odk/src/odk.gypi',
],
}

View File

@@ -23,6 +23,14 @@
#include "oemcrypto_rsa_key_shared.h"
#include "string_conversions.h"
namespace {
// Lower bits in SessionId are actual session id. The rest higher bits are
// session type.
const uint32_t kSessionIdTypeShift = 28;
const uint32_t kSessionIdMask = (1u << kSessionIdTypeShift) - 1u;
} // namespace
namespace wvoec_ref {
// Note: The class CryptoEngine is configured at compile time by compiling in
@@ -64,6 +72,12 @@ SessionId CryptoEngine::OpenSession() {
std::unique_lock<std::mutex> lock(session_table_lock_);
static OEMCrypto_SESSION unique_id = 1;
SessionId id = ++unique_id;
// Check if too many sessions have been opened.
if (SessionTypeBits(id) != 0) {
return 0;
}
// Apply session type to higher bits.
id = (kSessionTypeOEMCrypto << kSessionIdTypeShift) | (id & kSessionIdMask);
sessions_[id] = MakeSession(id);
return id;
}
@@ -102,7 +116,7 @@ int64_t CryptoEngine::MonotonicTime() {
wvcdm::Clock().GetCurrentTime() + offline_time_info_.rollback_offset;
static int64_t then = now;
if (now < then) {
LOGW("Clock rollback detected: %lld seconds", then - now);
LOGW("Clock rollback detected: %ld seconds", then - now);
offline_time_info_.rollback_offset += then - now;
now = then;
}
@@ -216,6 +230,13 @@ OEMCryptoResult CryptoEngine::SetDestination(
max_length = out_description.buffer.clear.address_length;
break;
case OEMCrypto_BufferType_Secure:
if (out_description.buffer.secure.handle_length <
out_description.buffer.secure.offset) {
LOGE("Secure buffer offset too large: %zu < %zu",
out_description.buffer.secure.handle_length,
out_description.buffer.secure.offset);
return OEMCrypto_ERROR_SHORT_BUFFER;
}
destination_ =
reinterpret_cast<uint8_t*>(out_description.buffer.secure.handle) +
out_description.buffer.secure.offset;
@@ -251,4 +272,8 @@ OEMCryptoResult CryptoEngine::SetDestination(
return OEMCrypto_SUCCESS;
}
uint32_t CryptoEngine::SessionTypeBits(SessionId sid) {
return sid >> kSessionIdTypeShift;
}
} // namespace wvoec_ref

View File

@@ -22,8 +22,8 @@
#include "oemcrypto_key_ref.h"
#include "oemcrypto_rsa_key_shared.h"
#include "oemcrypto_session.h"
#include "oemcrypto_usage_table_ref.h"
#include "oemcrypto_types.h"
#include "oemcrypto_usage_table_ref.h"
namespace wvoec_ref {
@@ -41,10 +41,16 @@ typedef struct {
uint8_t padding[16 - (2 * sizeof(time_t)) % 16];
} TimeInfo;
// Session types are higher (32 - kSessionIdTypeShift) bits in SessionId.
typedef enum SessionType {
kSessionTypeOEMCrypto = 0,
kSessionTypeEntitledKey = 1,
} SessionType;
class CryptoEngine {
public:
static const uint32_t kApiVersion = 16;
static const uint32_t kMinorApiVersion = 0;
static const uint32_t kMinorApiVersion = 3;
static const int64_t kTimeInfoUpdateWindowInSeconds = 300;
// This is like a factory method, except we choose which version to use at
@@ -83,9 +89,7 @@ class CryptoEngine {
size_t DeviceRootTokenLength() { return root_of_trust_.DeviceTokenLength(); }
const uint8_t* DeviceRootToken() {
return root_of_trust_.DeviceToken();
}
const uint8_t* DeviceRootToken() { return root_of_trust_.DeviceToken(); }
virtual void Terminate();
@@ -116,9 +120,7 @@ class CryptoEngine {
virtual OEMCrypto_HDCP_Capability config_maximum_hdcp_capability();
// Return true if there might be analog video output enabled.
virtual bool analog_display_active() {
return !config_local_display_only();
}
virtual bool analog_display_active() { return !config_local_display_only(); }
// Return true if there is an analog display, and CGMS A is turned on.
virtual bool cgms_a_active() { return false; }
@@ -222,6 +224,9 @@ class CryptoEngine {
return OEMCrypto_SUCCESS;
}
// Get the session type bits from |sid|.
static uint32_t SessionTypeBits(SessionId sid);
protected:
// System clock, measuring time in seconds, including anti-rollback offset.
int64_t MonotonicTime();

View File

@@ -47,7 +47,7 @@ uint32_t KeyControlBlock::ExtractField(const std::vector<uint8_t>& str,
KeyControlBlock::KeyControlBlock(
const std::vector<uint8_t>& key_control_string) {
if (key_control_string.size() < wvoec::KEY_CONTROL_SIZE) {
LOGE("KCB: BAD Size: %d (not %d)", key_control_string.size(),
LOGE("KCB: BAD Size: %zu (not %zu)", key_control_string.size(),
wvoec::KEY_CONTROL_SIZE);
return;
}

View File

@@ -8,9 +8,9 @@
#include <assert.h>
#include <openssl/cmac.h>
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/mem.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include <stddef.h>
@@ -39,6 +39,9 @@
namespace {
const uint8_t kBakedInCertificateMagicBytes[] = {0xDE, 0xAD, 0xBE, 0xEF};
// Maximum context key length used for performance reasons, not mandated by
// specification.
const size_t kMaxContextKeyLength = 1024 * 1024;
// Return uint32 referenced through a potentially unaligned pointer.
// If the pointer is nullptr, return 0.
@@ -109,6 +112,10 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_OpenSession(
return OEMCrypto_ERROR_TOO_MANY_SESSIONS;
}
SessionId sid = crypto_engine->OpenSession();
if (sid == 0) {
LOGE("OEMCrypto_OpenSession: invalid session id returned.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
*session = (OEMCrypto_SESSION)sid;
return OEMCrypto_SUCCESS;
}
@@ -141,6 +148,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateDerivedKeys(
LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
if (mac_key_context_length > kMaxContextKeyLength ||
enc_key_context_length > kMaxContextKeyLength) {
LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_BUFFER_TOO_LARGE]");
return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
@@ -723,9 +735,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadTestKeybox(const uint8_t* buffer,
if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
crypto_engine->UseTestKeybox(buffer, length);
if (crypto_engine->UseTestKeybox(buffer, length)) {
return OEMCrypto_SUCCESS;
}
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(void) {
if (crypto_engine == nullptr) {
@@ -887,17 +901,6 @@ static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30(
LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// For the reference implementation, the wrapped key and the encrypted
// key are the same size -- just encrypted with different keys.
// We add 32 bytes for a context, 32 for iv, and 32 bytes for a signature.
// Important: This layout must match OEMCrypto_LoadDRMPrivateKey below.
const size_t buffer_size = enc_rsa_key_length + sizeof(WrappedRSAKey);
if (wrapped_rsa_key == nullptr || *wrapped_rsa_key_length < buffer_size) {
*wrapped_rsa_key_length = buffer_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*wrapped_rsa_key_length = buffer_size; // Tell caller how much space we used.
if (!crypto_engine->ValidRootOfTrust()) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
@@ -933,13 +936,7 @@ static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30(
enc_rsa_key_iv, &pkcs8_rsa_key[0])) {
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1];
if (padding > 16) {
// Do not return an error at this point, to avoid a padding oracle attack.
padding = 0;
}
size_t rsa_key_length = enc_rsa_key_length - padding;
if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], rsa_key_length)) {
if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], enc_rsa_key_length)) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): Failed to LoadRSAKey.");
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
@@ -970,6 +967,7 @@ static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30(
LOGE("[_RewrapDeviceRSAKey30(): EncrypteRSAKey failed.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
const size_t buffer_size = enc_rsa_key_length + sizeof(WrappedRSAKey);
// The wrapped keybox must be signed with the same key we verify with. I'll
// pick the server key, so I don't have to modify LoadRSAKey.
unsigned int sig_length = sizeof(wrapped->signature);
@@ -1004,17 +1002,6 @@ static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// For the reference implementation, the wrapped key and the encrypted
// key are the same size -- just encrypted with different keys.
// We add 32 bytes for a context, 32 for iv, and 32 bytes for a signature.
// Important: This layout must match OEMCrypto_LoadDRMPrivateKey below.
const size_t buffer_size = enc_rsa_key_length + sizeof(WrappedRSAKey);
if (wrapped_rsa_key == nullptr || *wrapped_rsa_key_length < buffer_size) {
*wrapped_rsa_key_length = buffer_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*wrapped_rsa_key_length = buffer_size; // Tell caller how much space we used.
if (!crypto_engine->ValidRootOfTrust()) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
@@ -1051,14 +1038,7 @@ static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(
enc_rsa_key_iv, &pkcs8_rsa_key[0])) {
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1];
if (padding > 16) {
// Do not return an error at this point, to avoid a padding oracle attack.
padding = 0;
}
size_t rsa_key_length = enc_rsa_key_length - padding;
if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], rsa_key_length)) {
if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], enc_rsa_key_length)) {
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
@@ -1084,6 +1064,7 @@ static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(
wrapped->iv, wrapped->enc_rsa_key)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
const size_t buffer_size = enc_rsa_key_length + sizeof(WrappedRSAKey);
// The wrapped keybox must be signed with the same key we verify with. I'll
// pick the server key, so I don't have to modify LoadRSAKey.
unsigned int sig_length = sizeof(wrapped->signature);
@@ -1302,6 +1283,12 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(
LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
if (mac_key_context_length > kMaxContextKeyLength ||
enc_key_context_length > kMaxContextKeyLength ||
enc_session_key_length > kMaxContextKeyLength) {
LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_BUFFER_TOO_LARGE]");
return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {

View File

@@ -15,10 +15,10 @@
#include <openssl/aes.h>
#include <openssl/bio.h>
#include <openssl/cmac.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/mem.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
@@ -86,8 +86,7 @@ class ContentKeysContext : public SessionContextKeys {
OEMCrypto_LicenseType type() override { return OEMCrypto_ContentLicense; }
bool SetContentKey(const KeyId& entitlement_id,
const KeyId& content_key_id,
bool SetContentKey(const KeyId& entitlement_id, const KeyId& content_key_id,
const std::vector<uint8_t>& content_key) override;
EntitlementKey* GetEntitlementKey(const KeyId& entitlement_id) override;
@@ -139,8 +138,7 @@ class EntitlementKeysContext : public SessionContextKeys {
Key* FirstKey() override;
void Remove(const KeyId& key_id) override;
void UpdateDuration(const KeyControlBlock& control) override;
bool SetContentKey(const KeyId& entitlement_id,
const KeyId& content_key_id,
bool SetContentKey(const KeyId& entitlement_id, const KeyId& content_key_id,
const std::vector<uint8_t>& content_key) override;
EntitlementKey* GetEntitlementKey(const KeyId& entitlement_id) override;
@@ -210,8 +208,7 @@ SessionContext::SessionContext(CryptoEngine* ce, SessionId sid,
CryptoEngine::kApiVersion, sid);
}
SessionContext::~SessionContext() {
}
SessionContext::~SessionContext() {}
// Internal utility function to derive key using CMAC-128
bool SessionContext::DeriveKey(const std::vector<uint8_t>& key,
@@ -313,7 +310,7 @@ bool SessionContext::RSADeriveKeys(
return false;
}
session_key_.resize(RSA_size(rsa_key()));
int decrypted_size =
const int decrypted_size =
RSA_private_decrypt(enc_session_key.size(), &enc_session_key[0],
&session_key_[0], rsa_key(), RSA_PKCS1_OAEP_PADDING);
if (-1 == decrypted_size) {
@@ -347,7 +344,7 @@ OEMCryptoResult SessionContext::PrepAndSignLicenseRequest(
return OEMCrypto_ERROR_SHORT_BUFFER;
}
if (result != OEMCrypto_SUCCESS) {
LOGE("ODK error: %d", result);
LOGE("ODK error: %d", static_cast<int>(result));
return result;
}
if (message == nullptr || message_length < *core_message_length ||
@@ -366,8 +363,10 @@ OEMCryptoResult SessionContext::PrepAndSignLicenseRequest(
const size_t message_body_length = message_length - *core_message_length;
result = GenerateCertSignature(message_body, message_body_length, signature,
signature_length);
if (result == OEMCrypto_SUCCESS) state_request_signed_ = true;
ODK_InitializeClockValues(&clock_values_, ce_->SystemTime());
if (result == OEMCrypto_SUCCESS) {
state_request_signed_ = true;
result = ODK_InitializeClockValues(&clock_values_, ce_->SystemTime());
}
return result;
}
@@ -395,7 +394,7 @@ OEMCryptoResult SessionContext::PrepAndSignRenewalRequest(
return OEMCrypto_ERROR_SHORT_BUFFER;
}
if (result != OEMCrypto_SUCCESS) {
LOGE("ODK error: %d", result);
LOGE("ODK error: %d", static_cast<int>(result));
return result;
}
if (message == nullptr || message_length < *core_message_length ||
@@ -438,7 +437,7 @@ OEMCryptoResult SessionContext::PrepAndSignProvisioningRequest(
return OEMCrypto_ERROR_SHORT_BUFFER;
}
if (result != OEMCrypto_SUCCESS) {
LOGE("ODK error: %d", result);
LOGE("ODK error: %d", static_cast<int>(result));
return result;
}
if (message == nullptr || message_length == 0 || signature == nullptr) {
@@ -452,7 +451,8 @@ OEMCryptoResult SessionContext::PrepAndSignProvisioningRequest(
result = GenerateCertSignature(message, message_length, signature,
signature_length);
} else {
LOGE("Bad prov method = %d", ce_->config_provisioning_method());
LOGE("Bad prov method = %d",
static_cast<int>(ce_->config_provisioning_method()));
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (result == OEMCrypto_SUCCESS) state_request_signed_ = true;
@@ -508,7 +508,8 @@ size_t SessionContext::ROTSignatureSize() {
return SHA256_DIGEST_LENGTH;
if (ce_->config_provisioning_method() == OEMCrypto_OEMCertificate)
return CertSignatureSize();
LOGE("Bad prov method = %d", ce_->config_provisioning_method());
LOGE("Bad prov method = %d",
static_cast<int>(ce_->config_provisioning_method()));
return 0;
}
@@ -522,7 +523,7 @@ OEMCryptoResult SessionContext::GenerateCertSignature(
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!rsa_key()) {
LOGE("no RSA key set");
LOGE("No RSA key set");
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
if (*signature_length < static_cast<size_t>(RSA_size(rsa_key()))) {
@@ -530,7 +531,7 @@ OEMCryptoResult SessionContext::GenerateCertSignature(
return OEMCrypto_ERROR_SHORT_BUFFER;
}
if (allowed_schemes_ != kSign_RSASSA_PSS) {
LOGE("message signing not allowed");
LOGE("Message signing not allowed");
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
@@ -572,7 +573,7 @@ OEMCryptoResult SessionContext::GenerateRSASignature(
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!rsa_key()) {
LOGE("no RSA key set");
LOGE("No RSA key set");
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
if (*signature_length < static_cast<size_t>(RSA_size(rsa_key()))) {
@@ -592,10 +593,10 @@ OEMCryptoResult SessionContext::GenerateRSASignature(
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
}
// Pad the message with PKCS1 padding, and then encrypt.
int status = RSA_private_encrypt(message_length, message, signature,
const int status = RSA_private_encrypt(message_length, message, signature,
rsa_key(), RSA_PKCS1_PADDING);
if (status < 0) {
LOGE("error in RSA private encrypt. status=%d", status);
LOGE("Error in RSA private encrypt. status = %d", status);
dump_boringssl_error();
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
@@ -675,11 +676,13 @@ OEMCryptoResult SessionContext::CheckStatusOffline(uint32_t nonce,
OEMCryptoResult SessionContext::CheckNonceOrEntry(
const KeyControlBlock& key_control_block) {
switch (key_control_block.control_bits() & wvoec::kControlReplayMask) {
case wvoec::kControlNonceRequired: // Online license. Nonce always required.
case wvoec::kControlNonceRequired: // Online license. Nonce always
// required.
return CheckStatusOnline(key_control_block.nonce(),
key_control_block.control_bits());
break;
case wvoec::kControlNonceOrEntry: // Offline license. Nonce required on first use.
case wvoec::kControlNonceOrEntry: // Offline license. Nonce required on
// first use.
return CheckStatusOffline(key_control_block.nonce(),
key_control_block.control_bits());
break;
@@ -710,7 +713,7 @@ OEMCryptoResult SessionContext::LoadLicense(const uint8_t* message,
usage_entry_present(), license_request_hash_, &timer_limits_,
&clock_values_, &nonce_values_, &parsed_response);
if (result != OEMCrypto_SUCCESS) {
LOGE("ODK Error %d", result);
LOGE("ODK Error %d", static_cast<int>(result));
return result;
}
// Validate message signature
@@ -793,21 +796,21 @@ OEMCryptoResult SessionContext::LoadKeysNoSignature(
message + srm_restriction_data.offset);
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
uint32_t minimum_version = htonl(*reinterpret_cast<const uint32_t*>(
const uint32_t minimum_version = htonl(*reinterpret_cast<const uint32_t*>(
message + srm_restriction_data.offset + 8));
uint16_t current_version = 0;
if (OEMCrypto_SUCCESS != ce_->current_srm_version(&current_version)) {
LOGW("[LoadKeys: SRM Version not available");
srm_requirements_status_ = InvalidSRMVersion;
} else if (current_version < minimum_version) {
LOGW("[LoadKeys: SRM Version is too small %d, required: %d",
LOGW("[LoadKeys: SRM Version is too small %u, required: %u",
current_version, minimum_version);
srm_requirements_status_ = InvalidSRMVersion;
} else if (ce_->srm_blacklisted_device_attached()) {
LOGW("[LoadKeys: SRM blacklisted device attached]");
srm_requirements_status_ = InvalidSRMVersion;
} else {
LOGI("[LoadKeys: SRM Versions is %d, required: %d]", current_version,
LOGI("[LoadKeys: SRM Versions is %u, required: %u]", current_version,
minimum_version);
srm_requirements_status_ = ValidSRMVersion;
}
@@ -842,9 +845,8 @@ OEMCryptoResult SessionContext::LoadKeysNoSignature(
message + key_array[i].key_control_iv.offset,
message + key_array[i].key_control_iv.offset + wvoec::KEY_IV_SIZE);
OEMCryptoResult result =
InstallKey(key_id, enc_key_data, key_data_iv, key_control,
key_control_iv);
OEMCryptoResult result = InstallKey(key_id, enc_key_data, key_data_iv,
key_control, key_control_iv);
if (result != OEMCrypto_SUCCESS) {
status = result;
break;
@@ -863,10 +865,15 @@ OEMCryptoResult SessionContext::LoadKeysNoSignature(
message + enc_mac_keys_iv.offset + wvoec::KEY_IV_SIZE);
if (!UpdateMacKeys(enc_mac_keys_str, enc_mac_key_iv_str)) {
LOGE("Failed to update mac keys.\n");
LOGE("Failed to update mac keys.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
} else {
// If the mac keys are not updated, we will not need them again.
mac_key_server_.resize(0);
mac_key_client_.resize(0);
}
if (usage_entry_) {
OEMCryptoResult result = OEMCrypto_SUCCESS;
switch (usage_entry_status_) {
@@ -882,7 +889,7 @@ OEMCryptoResult SessionContext::LoadKeysNoSignature(
return result;
}
if (!usage_entry_->SetMacKeys(mac_key_server_, mac_key_client_)) {
LOGE("LoadKeys: Usage table can't set keys.\n");
LOGE("LoadKeys: Usage table can't set keys.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
break;
@@ -891,7 +898,7 @@ OEMCryptoResult SessionContext::LoadKeysNoSignature(
return OEMCrypto_ERROR_WRONG_PST;
}
if (!usage_entry_->VerifyMacKeys(mac_key_server_, mac_key_client_)) {
LOGE("LoadKeys: Usage table entry mac keys do not match.\n");
LOGE("LoadKeys: Usage table entry mac keys do not match.");
return OEMCrypto_ERROR_WRONG_KEYS;
}
if (usage_entry_->Inactive()) return OEMCrypto_ERROR_LICENSE_INACTIVE;
@@ -991,11 +998,11 @@ OEMCryptoResult SessionContext::InstallKey(
LOGE("Anti-rollback hardware is required but hardware not present");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
uint8_t minimum_patch_level = (key_control_block.control_bits() &
const uint8_t minimum_patch_level = (key_control_block.control_bits() &
wvoec::kControlSecurityPatchLevelMask) >>
wvoec::kControlSecurityPatchLevelShift;
if (minimum_patch_level > OEMCrypto_Security_Patch_Level()) {
LOGE("[InstallKey(): security patch level: %d. Minimum:%d]",
LOGE("[InstallKey(): security_patch_level = %u, minimum_patch_level = %u]",
OEMCrypto_Security_Patch_Level(), minimum_patch_level);
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
@@ -1026,7 +1033,7 @@ OEMCryptoResult SessionContext::InstallKey(
bool SessionContext::InstallRSAEncryptedKey(
const uint8_t* encrypted_message_key, size_t encrypted_message_key_length) {
encryption_key_.resize(RSA_size(rsa_key()));
int decrypted_size = RSA_private_decrypt(
const int decrypted_size = RSA_private_decrypt(
encrypted_message_key_length, encrypted_message_key, &encryption_key_[0],
rsa_key(), RSA_PKCS1_OAEP_PADDING);
if (-1 == decrypted_size) {
@@ -1054,7 +1061,7 @@ OEMCryptoResult SessionContext::LoadRenewal(const uint8_t* message,
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!ValidateMessage(message, message_length, signature, signature_length)) {
LOGE("signature was invalid");
LOGE("Signature was invalid");
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
}
@@ -1120,6 +1127,10 @@ bool SessionContext::DecryptRSAKey(const uint8_t* enc_rsa_key,
size_t enc_rsa_key_length,
const uint8_t* enc_rsa_key_iv,
uint8_t* pkcs8_rsa_key) {
if (enc_rsa_key_length % AES_BLOCK_SIZE != 0) {
LOGE("[DecryptRSAKey(): bad buffer size]");
return false;
}
// Decrypt rsa key with keybox.
uint8_t iv_buffer[wvoec::KEY_IV_SIZE];
memcpy(iv_buffer, enc_rsa_key_iv, wvoec::KEY_IV_SIZE);
@@ -1134,6 +1145,10 @@ bool SessionContext::EncryptRSAKey(const uint8_t* pkcs8_rsa_key,
size_t enc_rsa_key_length,
const uint8_t* enc_rsa_key_iv,
uint8_t* enc_rsa_key) {
if (enc_rsa_key_length % AES_BLOCK_SIZE != 0) {
LOGE("[EncryptRSAKey(): bad buffer size]");
return false;
}
// Encrypt rsa key with keybox.
uint8_t iv_buffer[wvoec::KEY_IV_SIZE];
memcpy(iv_buffer, enc_rsa_key_iv, wvoec::KEY_IV_SIZE);
@@ -1247,10 +1262,11 @@ OEMCryptoResult SessionContext::Generic_Encrypt(const uint8_t* in_buffer,
const std::vector<uint8_t>& key = current_content_key()->value();
// Set the AES key.
if (static_cast<int>(key.size()) != AES_BLOCK_SIZE) {
LOGE("[Generic_Encrypt(): CONTENT_KEY has wrong size: %d", key.size());
LOGE("[Generic_Encrypt(): CONTENT_KEY has wrong size: %zu", key.size());
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
OEMCryptoResult result = CheckKeyUse("Generic_Encrypt", wvoec::kControlAllowEncrypt,
OEMCryptoResult result =
CheckKeyUse("Generic_Encrypt", wvoec::kControlAllowEncrypt,
OEMCrypto_BufferType_Clear);
if (result != OEMCrypto_SUCCESS) return result;
if (algorithm != OEMCrypto_AES_CBC_128_NO_PADDING) {
@@ -1290,7 +1306,8 @@ OEMCryptoResult SessionContext::Generic_Decrypt(const uint8_t* in_buffer,
LOGE("[Generic_Decrypt(): CONTENT_KEY has wrong size");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
OEMCryptoResult result = CheckKeyUse("Generic_Decrypt", wvoec::kControlAllowDecrypt,
OEMCryptoResult result =
CheckKeyUse("Generic_Decrypt", wvoec::kControlAllowDecrypt,
OEMCrypto_BufferType_Clear);
if (result != OEMCrypto_SUCCESS) return result;
@@ -1332,7 +1349,7 @@ OEMCryptoResult SessionContext::Generic_Sign(const uint8_t* in_buffer,
}
const std::vector<uint8_t>& key = current_content_key()->value();
if (static_cast<int>(key.size()) != SHA256_DIGEST_LENGTH) {
LOGE("[Generic_Sign(): CONTENT_KEY has wrong size; %d", key.size());
LOGE("[Generic_Sign(): CONTENT_KEY has wrong size: %zu", key.size());
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
OEMCryptoResult result = CheckKeyUse("Generic_Sign", wvoec::kControlAllowSign,
@@ -1368,11 +1385,11 @@ OEMCryptoResult SessionContext::Generic_Verify(const uint8_t* in_buffer,
}
const std::vector<uint8_t>& key = current_content_key()->value();
if (static_cast<int>(key.size()) != SHA256_DIGEST_LENGTH) {
LOGE("[Generic_Verify(): CONTENT_KEY has wrong size: %d", key.size());
LOGE("[Generic_Verify(): CONTENT_KEY has wrong size: %zu", key.size());
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
OEMCryptoResult result = CheckKeyUse("Generic_Verify", wvoec::kControlAllowVerify,
OEMCrypto_BufferType_Clear);
OEMCryptoResult result = CheckKeyUse(
"Generic_Verify", wvoec::kControlAllowVerify, OEMCrypto_BufferType_Clear);
if (result != OEMCrypto_SUCCESS) return result;
if (algorithm != OEMCrypto_HMAC_SHA256) {
LOGE("[Generic_Verify(): bad algorithm");
@@ -1521,6 +1538,11 @@ bool SessionContext::DecryptMessage(const std::vector<uint8_t>& key,
LOGE("[DecryptMessage(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return false;
}
if (message.size() % AES_BLOCK_SIZE != 0) {
LOGE("[DecryptMessage(): bad buffer size]");
return false;
}
decrypted->resize(message.size());
uint8_t iv_buffer[16];
memcpy(iv_buffer, &iv[0], 16);
@@ -1558,20 +1580,20 @@ OEMCryptoResult SessionContext::DecryptSamples(
OEMCryptoResult result = ce_->SetDestination(
subsample_dest, subsample_length, subsample.subsample_flags);
if (result != OEMCrypto_SUCCESS) {
LOGE("SetDestination status: %d", result);
LOGE("SetDestination status: %d", static_cast<int>(result));
return result;
}
result = DecryptSubsample(subsample, subsample_source, ce_->destination(),
subsample_dest.type, subsample_iv, pattern);
if (result != OEMCrypto_SUCCESS) {
LOGE("DecryptSubsample status: %d", result);
LOGE("DecryptSubsample status: %d", static_cast<int>(result));
return result;
}
result = ce_->PushDestination(subsample_dest, subsample.subsample_flags);
if (result != OEMCrypto_SUCCESS) {
LOGE("PushDestination status: %d", result);
LOGE("PushDestination status: %d", static_cast<int>(result));
return result;
}
@@ -1630,7 +1652,7 @@ OEMCryptoResult SessionContext::DecryptSubsample(
current_hash_);
if (OEMCrypto_LastSubsample & subsample.subsample_flags) {
if (current_hash_ != given_hash_) {
LOGE("CRC for frame %d is %08x, should be %08x\n",
LOGE("CRC for frame %u is %08x, should be %08x\n",
current_frame_number_, current_hash_, given_hash_);
// Update bad_frame_number_ only if this is the first bad frame.
if (hash_error_ == OEMCrypto_SUCCESS) {
@@ -1666,7 +1688,7 @@ OEMCryptoResult SessionContext::ChooseDecrypt(
// Set the AES key.
if (static_cast<int>(content_key.size()) != AES_BLOCK_SIZE) {
LOGE("[DecryptCTR(): CONTENT_KEY has wrong size: %d", content_key.size());
LOGE("[DecryptCTR(): CONTENT_KEY has wrong size: %zu", content_key.size());
return OEMCrypto_ERROR_DECRYPT_FAILED;
}
const uint8_t* key_u8 = &content_key[0];
@@ -1712,7 +1734,7 @@ OEMCryptoResult SessionContext::PatternDecryptCBC(
const bool skip_block = (pattern_offset >= pattern->encrypt);
pattern_offset = (pattern_offset + 1) % pattern_length;
if (skip_block || (size < AES_BLOCK_SIZE)) {
// If we are decrypting in-place, then this byte is already correct and
// If we are decrypting in-place, then this block is already correct and
// can be skipped.
if (clear_data != cipher_data) {
memcpy(&clear_data[l], &cipher_data[l], size);

View File

@@ -13,8 +13,8 @@
#include <vector>
#include <openssl/aes.h>
#include <openssl/crypto.h>
#include <openssl/hmac.h>
#include <openssl/mem.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
@@ -116,16 +116,18 @@ OEMCryptoResult UsageTableEntry::ReportUsage(const std::vector<uint8_t>& pst,
if (recent_decrypt_) return OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE;
if (pst.size() == 0 || pst.size() > kMaxPSTLength ||
pst.size() != data_.pst_length) {
LOGE("ReportUsage: bad pst length = %d, should be %d.", pst.size(),
LOGE("ReportUsage: bad pst length = %zu, should be %u.", pst.size(),
data_.pst_length);
return OEMCrypto_ERROR_WRONG_PST;
}
if (CRYPTO_memcmp(&pst[0], data_.pst, data_.pst_length)) {
LOGE("ReportUsage: wrong pst %s, should be %s.", wvcdm::b2a_hex(pst).c_str(),
LOGE("ReportUsage: wrong pst %s, should be %s.",
wvcdm::b2a_hex(pst).c_str(),
wvcdm::HexEncode(data_.pst, data_.pst_length).c_str());
return OEMCrypto_ERROR_WRONG_PST;
}
size_t length_needed = wvcdm::Unpacked_PST_Report::report_size(pst.size());
const size_t length_needed =
wvcdm::Unpacked_PST_Report::report_size(pst.size());
if (*buffer_length < length_needed) {
*buffer_length = length_needed;
return OEMCrypto_ERROR_SHORT_BUFFER;
@@ -135,7 +137,7 @@ OEMCryptoResult UsageTableEntry::ReportUsage(const std::vector<uint8_t>& pst,
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
wvcdm::Unpacked_PST_Report pst_report(buffer);
int64_t now = usage_table_->ce_->SystemTime();
const int64_t now = usage_table_->ce_->SystemTime();
pst_report.set_seconds_since_license_received(now -
data_.time_of_license_received);
pst_report.set_seconds_since_first_decrypt(now - data_.time_of_first_decrypt);
@@ -233,7 +235,7 @@ OEMCryptoResult UsageTableEntry::LoadData(CryptoEngine* ce, uint32_t index,
ODK_ClockValues* clock_values) {
if (buffer.size() < SignedEntrySize()) return OEMCrypto_ERROR_SHORT_BUFFER;
if (buffer.size() > SignedEntrySize())
LOGW("LoadUsageTableEntry: buffer is large. %d > %d", buffer.size(),
LOGW("LoadUsageTableEntry: buffer is large. %zu > %zu", buffer.size(),
SignedEntrySize());
std::vector<uint8_t> clear_buffer(buffer.size());
SignedEntryBlock* clear =
@@ -357,10 +359,10 @@ OEMCryptoResult UsageTable::CreateNewUsageEntry(
}
if (!entry) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
if (!usage_entry_number) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
uint32_t index = generation_numbers_.size();
size_t max = ce_->max_usage_table_size();
const size_t index = generation_numbers_.size();
const size_t max = ce_->max_usage_table_size();
if (max > 0 && index >= max) {
LOGE("Too many usage entries: %d/%d", index, max);
LOGE("Too many usage entries: %zu/%zu", index, max);
return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES;
}
UsageTableEntry* new_entry = MakeEntry(index);
@@ -377,7 +379,7 @@ OEMCryptoResult UsageTable::LoadUsageEntry(
uint32_t index, const std::vector<uint8_t>& buffer,
ODK_ClockValues* clock_values) {
if (!header_loaded_) {
LOGE("CreateNewUsageEntry: Header not loaded.");
LOGE("LoadUsageEntry: Header not loaded.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!entry) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
@@ -387,9 +389,9 @@ OEMCryptoResult UsageTable::LoadUsageEntry(
LOGE("LoadUsageEntry: index %d used by other session.", index);
return OEMCrypto_ERROR_INVALID_SESSION;
}
size_t max = ce_->max_usage_table_size();
const size_t max = ce_->max_usage_table_size();
if (max > 0 && index >= max) {
LOGE("Too many usage entries: %d/%d", index, max);
LOGE("Too many usage entries: %u/%zu", index, max);
return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES;
}
std::unique_ptr<UsageTableEntry> new_entry(MakeEntry(index));
@@ -417,7 +419,7 @@ OEMCryptoResult UsageTable::ShrinkUsageTableHeader(
uint32_t new_table_size, uint8_t* header_buffer,
size_t* header_buffer_length) {
if (new_table_size > generation_numbers_.size()) {
LOGE("OEMCrypto_ShrinkUsageTableHeader: %d > %zd.", new_table_size,
LOGE("OEMCrypto_ShrinkUsageTableHeader: %u > %zu", new_table_size,
generation_numbers_.size());
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
@@ -433,7 +435,7 @@ OEMCryptoResult UsageTable::ShrinkUsageTableHeader(
}
for (size_t i = new_table_size; i < sessions_.size(); ++i) {
if (sessions_[i]) {
LOGE("ShrinkUsageTableHeader: session open for %d", i);
LOGE("ShrinkUsageTableHeader: session open for %zu", i);
return OEMCrypto_ERROR_ENTRY_IN_USE;
}
}
@@ -505,8 +507,8 @@ OEMCryptoResult UsageTable::LoadUsageTableHeader(
if (buffer.size() < SignedHeaderSize(0)) return OEMCrypto_ERROR_SHORT_BUFFER;
size_t max = ce_->max_usage_table_size();
if (max > 0 && buffer.size() > SignedHeaderSize(max)) {
LOGE("Header too big: %zd bytes/%zd bytes",
buffer.size(), SignedHeaderSize(max));
LOGE("Header too big: %zu bytes/%zu bytes", buffer.size(),
SignedHeaderSize(max));
return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES;
}
std::vector<uint8_t> clear_buffer(buffer.size());
@@ -567,7 +569,7 @@ OEMCryptoResult UsageTable::LoadUsageTableHeader(
return OEMCrypto_ERROR_SHORT_BUFFER;
}
if (buffer.size() > SignedHeaderSize(clear->count)) {
LOGW("LoadUsageTableHeader: buffer is large. %d > %d", buffer.size(),
LOGW("LoadUsageTableHeader: buffer is large. %zu > %zu", buffer.size(),
SignedHeaderSize(clear->count));
}
@@ -594,12 +596,12 @@ OEMCryptoResult UsageTable::LoadUsageTableHeader(
OEMCryptoResult UsageTable::MoveEntry(UsageTableEntry* entry,
uint32_t new_index) {
if (new_index >= generation_numbers_.size()) {
LOGE("MoveEntry: index beyond end of usage table %d >= %d", new_index,
LOGE("MoveEntry: index beyond end of usage table %u >= %zu", new_index,
generation_numbers_.size());
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (sessions_[new_index]) {
LOGE("MoveEntry: session open for %d", new_index);
LOGE("MoveEntry: session open for %u", new_index);
return OEMCrypto_ERROR_ENTRY_IN_USE;
}
if (!entry) {
@@ -690,7 +692,7 @@ OEMCryptoResult UsageTable::CreateUsageTableHeader(
// Make sure there are no entries that are currently tied to an open session.
for (size_t i = 0; i < sessions_.size(); ++i) {
if (sessions_[i] != nullptr) {
LOGE("CreateUsageTableHeader: index %d used by session.", i);
LOGE("CreateUsageTableHeader: index %zu used by session.", i);
return OEMCrypto_ERROR_INVALID_SESSION;
}
}

View File

@@ -9,6 +9,7 @@
#include <stdint.h>
#include <map>
#include <memory>
#include <string>
#include <vector>

View File

@@ -0,0 +1 @@
(c020:0d112d7ea200;

View File

@@ -0,0 +1 @@
0a4c08001248000000020000101907d9ffde13aa95c122678053362136bdf8408f8276e4c2d87ec52b61aa1b9f646e58734930acebe899b3e464189a14a87202fb02570640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931b76a3a85f046523e10011a09393837363534333231180120002a0c313838363738373430350000

View File

@@ -0,0 +1 @@
0a4c020:0d1190d79fef02570640bd22ef44b2d7e3912250a200

View File

@@ -0,0 +1 @@
0a(c020:0d112d7ea200;

View File

@@ -0,0 +1 @@
0a4c000000200:0101907d9ffde02570640bd22ef44b2d7e3912250a230a1407363534333231180120002a0c313838363738373430350000

View File

@@ -0,0 +1 @@
0a4c000000220:01019dd79fef02570640bd22ef44b2d7e3912250a200

View File

@@ -0,0 +1 @@
0a4c000000200:010197d9ffde02570640bd22ef44b2d7e3912250a230a1407363534333231180120002a0c313838363738373430350000

View File

@@ -0,0 +1 @@
0a4c00000020000101907d9ffde02570640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931b76a3a85f046523e10011a09393837363534333231180120002a0c313838363738373430350000

View File

@@ -0,0 +1 @@
0a4c020:0d112d7e3912250a200;

View File

@@ -0,0 +1 @@
0a4c08001248000000020000101907d9ffde02570640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931b76a3a85f046523e10011a09393837363534333231180120002a0c313838363738373430350000

Some files were not shown because too many files have changed in this diff Show More