diff --git a/docs/License_Duration_and_Renewal.pdf b/docs/License_Duration_and_Renewal.pdf index c8ac6ad..ef6dca5 100644 Binary files a/docs/License_Duration_and_Renewal.pdf and b/docs/License_Duration_and_Renewal.pdf differ diff --git a/docs/WidevineModularDRMSecurityIntegrationGuideforCENC_v16.pdf b/docs/WidevineModularDRMSecurityIntegrationGuideforCENC_v16.pdf index 2ec854a..6894bd8 100644 Binary files a/docs/WidevineModularDRMSecurityIntegrationGuideforCENC_v16.pdf and b/docs/WidevineModularDRMSecurityIntegrationGuideforCENC_v16.pdf differ diff --git a/docs/Widevine_Core_Message_Serialization.pdf b/docs/Widevine_Core_Message_Serialization.pdf index a4240a8..9b7af8b 100644 Binary files a/docs/Widevine_Core_Message_Serialization.pdf and b/docs/Widevine_Core_Message_Serialization.pdf differ diff --git a/docs/Widevine_Modular_DRM_Version_16_Delta.pdf b/docs/Widevine_Modular_DRM_Version_16_Delta.pdf index 34d33e3..b97af8d 100644 Binary files a/docs/Widevine_Modular_DRM_Version_16_Delta.pdf and b/docs/Widevine_Modular_DRM_Version_16_Delta.pdf differ diff --git a/oemcrypto/odk/include/OEMCryptoCENCCommon.h b/oemcrypto/odk/include/OEMCryptoCENCCommon.h new file mode 100644 index 0000000..d9a29ce --- /dev/null +++ b/oemcrypto/odk/include/OEMCryptoCENCCommon.h @@ -0,0 +1,156 @@ +// 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 + * + * Common structures and error codes between WV servers and OEMCrypto. + * + *********************************************************************/ + +#ifndef OEMCRYPTO_CENC_COMMON_H_ +#define OEMCRYPTO_CENC_COMMON_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint32_t OEMCrypto_SESSION; + +// clang-format off +typedef enum OEMCryptoResult { + OEMCrypto_SUCCESS = 0, + OEMCrypto_ERROR_INIT_FAILED = 1, + OEMCrypto_ERROR_TERMINATE_FAILED = 2, + OEMCrypto_ERROR_OPEN_FAILURE = 3, + OEMCrypto_ERROR_CLOSE_FAILURE = 4, + OEMCrypto_ERROR_ENTER_SECURE_PLAYBACK_FAILED = 5, // deprecated + OEMCrypto_ERROR_EXIT_SECURE_PLAYBACK_FAILED = 6, // deprecated + OEMCrypto_ERROR_SHORT_BUFFER = 7, + OEMCrypto_ERROR_NO_DEVICE_KEY = 8, // no keybox device key. + OEMCrypto_ERROR_NO_ASSET_KEY = 9, + OEMCrypto_ERROR_KEYBOX_INVALID = 10, + OEMCrypto_ERROR_NO_KEYDATA = 11, + OEMCrypto_ERROR_NO_CW = 12, + OEMCrypto_ERROR_DECRYPT_FAILED = 13, + OEMCrypto_ERROR_WRITE_KEYBOX = 14, + OEMCrypto_ERROR_WRAP_KEYBOX = 15, + OEMCrypto_ERROR_BAD_MAGIC = 16, + OEMCrypto_ERROR_BAD_CRC = 17, + OEMCrypto_ERROR_NO_DEVICEID = 18, + OEMCrypto_ERROR_RNG_FAILED = 19, + OEMCrypto_ERROR_RNG_NOT_SUPPORTED = 20, + OEMCrypto_ERROR_SETUP = 21, + OEMCrypto_ERROR_OPEN_SESSION_FAILED = 22, + OEMCrypto_ERROR_CLOSE_SESSION_FAILED = 23, + OEMCrypto_ERROR_INVALID_SESSION = 24, + OEMCrypto_ERROR_NOT_IMPLEMENTED = 25, + OEMCrypto_ERROR_NO_CONTENT_KEY = 26, + OEMCrypto_ERROR_CONTROL_INVALID = 27, + OEMCrypto_ERROR_UNKNOWN_FAILURE = 28, + OEMCrypto_ERROR_INVALID_CONTEXT = 29, + OEMCrypto_ERROR_SIGNATURE_FAILURE = 30, + OEMCrypto_ERROR_TOO_MANY_SESSIONS = 31, + OEMCrypto_ERROR_INVALID_NONCE = 32, + OEMCrypto_ERROR_TOO_MANY_KEYS = 33, + OEMCrypto_ERROR_DEVICE_NOT_RSA_PROVISIONED = 34, + OEMCrypto_ERROR_INVALID_RSA_KEY = 35, + OEMCrypto_ERROR_KEY_EXPIRED = 36, + OEMCrypto_ERROR_INSUFFICIENT_RESOURCES = 37, + OEMCrypto_ERROR_INSUFFICIENT_HDCP = 38, + OEMCrypto_ERROR_BUFFER_TOO_LARGE = 39, + OEMCrypto_WARNING_GENERATION_SKEW = 40, // Warning, not an error. + OEMCrypto_ERROR_GENERATION_SKEW = 41, + OEMCrypto_LOCAL_DISPLAY_ONLY = 42, // Info, not an error. + OEMCrypto_ERROR_ANALOG_OUTPUT = 43, + OEMCrypto_ERROR_WRONG_PST = 44, + OEMCrypto_ERROR_WRONG_KEYS = 45, + OEMCrypto_ERROR_MISSING_MASTER = 46, + OEMCrypto_ERROR_LICENSE_INACTIVE = 47, + OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE = 48, + OEMCrypto_ERROR_ENTRY_IN_USE = 49, + OEMCrypto_ERROR_USAGE_TABLE_UNRECOVERABLE = 50, // Reserved. Do not use. + OEMCrypto_KEY_NOT_LOADED = 51, // obsolete. use error 26. + OEMCrypto_KEY_NOT_ENTITLED = 52, + OEMCrypto_ERROR_BAD_HASH = 53, + OEMCrypto_ERROR_OUTPUT_TOO_LARGE = 54, + OEMCrypto_ERROR_SESSION_LOST_STATE = 55, + OEMCrypto_ERROR_SYSTEM_INVALIDATED = 56, + OEMCrypto_ERROR_LICENSE_RELOAD = 57, + OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES = 58, + OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION = 59, + /* ODK return values */ + ODK_ERROR_BASE = 1000, + ODK_ERROR_CORE_MESSAGE = ODK_ERROR_BASE, + ODK_SET_TIMER = ODK_ERROR_BASE + 1, + ODK_DISABLE_TIMER = ODK_ERROR_BASE + 2, + ODK_TIMER_EXPIRED = ODK_ERROR_BASE + 3, + ODK_UNSUPPORTED_API = ODK_ERROR_BASE + 4, + ODK_STALE_RENEWAL = ODK_ERROR_BASE + 5, +} OEMCryptoResult; +// clang-format on + +/* + * OEMCrypto_Usage_Entry_Status. + * Valid values for status in the usage table. + */ +typedef enum OEMCrypto_Usage_Entry_Status { + kUnused = 0, + kActive = 1, + kInactive = 2, // Deprecated. Used kInactiveUsed or kInactiveUnused. + kInactiveUsed = 3, + kInactiveUnused = 4, +} OEMCrypto_Usage_Entry_Status; + +/* + * 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. + */ +typedef struct { + size_t offset; + 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 + * 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 + * key_data field. + * 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 + * key_control field. + * 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 + * by the caller of OEMCrypto_LoadKeys(). + */ +typedef struct { + OEMCrypto_Substring key_id; + OEMCrypto_Substring key_data_iv; + OEMCrypto_Substring key_data; + OEMCrypto_Substring key_control_iv; + OEMCrypto_Substring key_control; +} OEMCrypto_KeyObject; + +#ifdef __cplusplus +} +#endif + +#endif // OEMCRYPTO_CENC_COMMON_H_ diff --git a/oemcrypto/odk/include/odk.h b/oemcrypto/odk/include/odk.h index 51c3d86..b89c2b2 100644 --- a/oemcrypto/odk/include/odk.h +++ b/oemcrypto/odk/include/odk.h @@ -48,7 +48,7 @@ #define ODK_H_ #include -#include "OEMCryptoCENC.h" +#include "OEMCryptoCENCCommon.h" #include "odk_structs.h" #ifdef __cplusplus @@ -400,6 +400,41 @@ 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 the renewal is + * accepted. The field nonce_values.api_level is verified to be 15. + * + * 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 + * described in the document "License Duration and Renewal". + * [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 + * allowed. + * ODK_TIMER_EXPIRED: Set timer as disabled. Playback is not allowed. + * + * Version: + * This method is new in version 16 of the API. + */ +OEMCryptoResult ODK_RefreshV15Values(const ODK_TimerLimits* timer_limits, + ODK_ClockValues* clock_values, + const ODK_NonceValues* nonce_values, + uint64_t system_time_seconds, + uint64_t* timer_value); + /* * ODK_ParseLicense * @@ -514,6 +549,8 @@ OEMCryptoResult ODK_ParseLicense( * allowed. * ODK_TIMER_EXPIRED: Set timer as diabled. 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 * * Version: diff --git a/oemcrypto/odk/include/odk_structs.h b/oemcrypto/odk/include/odk_structs.h index 82f971c..8085a47 100644 --- a/oemcrypto/odk/include/odk_structs.h +++ b/oemcrypto/odk/include/odk_structs.h @@ -8,7 +8,7 @@ #define ODK_STRUCTS_H_ #include -#include "OEMCryptoCENC.h" +#include "OEMCryptoCENCCommon.h" #define ODK_MAX_NUM_KEYS 32 #define ODK_DEVICE_ID_LEN_MAX 64 @@ -71,6 +71,7 @@ typedef struct { uint64_t time_of_license_signed; uint64_t time_of_first_decrypt; uint64_t time_of_last_decrypt; + uint64_t time_of_renewal_request; uint64_t time_when_timer_expires; uint32_t timer_status; enum OEMCrypto_Usage_Entry_Status status; diff --git a/oemcrypto/odk/src/odk.c b/oemcrypto/odk/src/odk.c index c62f642..92cb8ca 100644 --- a/oemcrypto/odk/src/odk.c +++ b/oemcrypto/odk/src/odk.c @@ -103,10 +103,11 @@ static OEMCryptoResult ODK_ParseResponse(const uint8_t* buf, } if (nonce_values) { + /* always verify nonce_values for Renewal and Provisioning responses */ if (nonce_values->api_version != core_message->nonce_values.api_version || nonce_values->nonce != core_message->nonce_values.nonce || nonce_values->session_id != core_message->nonce_values.session_id) { - return ODK_ERROR_CORE_MESSAGE; + return OEMCrypto_ERROR_INVALID_NONCE; } } @@ -168,7 +169,7 @@ OEMCryptoResult ODK_ParseLicense(const uint8_t* message, size_t message_length, size_t core_message_length, bool initial_license_load, bool usage_entry_present, - const uint8_t request_hash[ODK_SHA256_HASH_SIZE], + const uint8_t* request_hash, ODK_TimerLimits* timer_limits, ODK_ClockValues* clock_values, ODK_NonceValues* nonce_values, @@ -183,7 +184,7 @@ OEMCryptoResult ODK_ParseLicense(const uint8_t* message, size_t message_length, message, message_length, ODK_License_Response_Type, NULL, &license_response.core_message); - if (err) { + if (err != OEMCrypto_SUCCESS) { return err; } @@ -208,10 +209,8 @@ OEMCryptoResult ODK_ParseLicense(const uint8_t* message, size_t message_length, return ODK_ERROR_CORE_MESSAGE; } - if (usage_entry_present) { - nonce_values->nonce = license_response.core_message.nonce_values.nonce; - nonce_values->session_id = license_response.core_message.nonce_values.session_id; - return err; + if (usage_entry_present && parsed_license->pst.length == 0) { + return ODK_ERROR_CORE_MESSAGE; } return err; diff --git a/oemcrypto/odk/include/odk_assert.h b/oemcrypto/odk/src/odk_assert.h similarity index 100% rename from oemcrypto/odk/include/odk_assert.h rename to oemcrypto/odk/src/odk_assert.h diff --git a/oemcrypto/odk/include/odk_overflow.h b/oemcrypto/odk/src/odk_overflow.h similarity index 100% rename from oemcrypto/odk/include/odk_overflow.h rename to oemcrypto/odk/src/odk_overflow.h diff --git a/oemcrypto/odk/include/odk_serialize.h b/oemcrypto/odk/src/odk_serialize.h similarity index 100% rename from oemcrypto/odk/include/odk_serialize.h rename to oemcrypto/odk/src/odk_serialize.h diff --git a/oemcrypto/odk/include/odk_structs_priv.h b/oemcrypto/odk/src/odk_structs_priv.h similarity index 97% rename from oemcrypto/odk/include/odk_structs_priv.h rename to oemcrypto/odk/src/odk_structs_priv.h index 52776cb..8b3ee35 100644 --- a/oemcrypto/odk/include/odk_structs_priv.h +++ b/oemcrypto/odk/src/odk_structs_priv.h @@ -8,7 +8,7 @@ #define ODK_STRUCTS_PRIV_H_ #include -#include "OEMCryptoCENC.h" +#include "OEMCryptoCENCCommon.h" #include "odk_structs.h" typedef enum { diff --git a/oemcrypto/odk/src/odk_timer.c b/oemcrypto/odk/src/odk_timer.c index 622c50b..ebe829f 100644 --- a/oemcrypto/odk/src/odk_timer.c +++ b/oemcrypto/odk/src/odk_timer.c @@ -9,8 +9,42 @@ #include "odk.h" +OEMCryptoResult ODK_InitializeSessionValues(ODK_TimerLimits* timer_limits, + ODK_ClockValues* clock_values, + ODK_NonceValues* nonce_values, + uint32_t api_version, + uint32_t session_id) { + if (clock_values == NULL || clock_values == NULL || nonce_values == NULL) + return OEMCrypto_ERROR_INVALID_CONTEXT; + timer_limits->soft_expiry = false; + timer_limits->earliest_playback_start_seconds = 0; + timer_limits->latest_playback_start_seconds = 0; + timer_limits->initial_playback_duration_seconds = 0; + timer_limits->renewal_playback_duration_seconds = 0; + timer_limits->license_duration_seconds = 0; + + clock_values->time_of_license_signed = 0; + clock_values->time_of_first_decrypt = 0; + clock_values->time_of_last_decrypt = 0; + clock_values->time_when_timer_expires = 0; + clock_values->timer_status = 0; + clock_values->status = kUnused; + + nonce_values->api_version = api_version; + nonce_values->nonce = 0; + nonce_values->session_id = session_id; + + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult ODK_SetNonceValues(ODK_NonceValues* nonce_values, + uint32_t nonce) { + nonce_values->nonce = nonce; + return OEMCrypto_SUCCESS; +} + OEMCryptoResult ODK_InitializeClockValues(ODK_ClockValues* clock_values, - uint64_t system_time_seconds) { + uint64_t system_time_seconds) { if (clock_values == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; clock_values->time_of_license_signed = system_time_seconds; clock_values->time_of_first_decrypt = 0; @@ -64,7 +98,8 @@ uint32_t ODK_AttemptFirstPlayback(uint64_t system_time_seconds, * session. */ if (clock_values->status == kUnused) { /* If the rental clock has expired, the license has expired. */ - if (rental_time > timer_limits->latest_playback_start_seconds) { + if (rental_time > timer_limits->latest_playback_start_seconds && + timer_limits->latest_playback_start_seconds > 0) { clock_values->timer_status = ODK_TIMER_EXPIRED; return ODK_TIMER_EXPIRED; } @@ -161,3 +196,85 @@ OEMCryptoResult ODK_UpdateLastPlaybackTime(uint64_t system_time_seconds, clock_values->time_of_last_decrypt = system_time_seconds; return OEMCrypto_SUCCESS; } + +OEMCryptoResult ODK_DeactivateUsageEntry(ODK_ClockValues* clock_values) { + if (clock_values == NULL) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + if (clock_values->status == kUnused) { + clock_values->status = kInactiveUnused; + } else if (clock_values->status == kActive) { + clock_values->status = kInactiveUsed; + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult ODK_InitializeV15Values(ODK_TimerLimits* timer_limits, + ODK_ClockValues* clock_values, + ODK_NonceValues* nonce_values, + uint32_t key_duration, + uint64_t system_time_seconds) { + if (clock_values == NULL || clock_values == NULL || nonce_values == NULL) + return OEMCrypto_ERROR_INVALID_CONTEXT; + timer_limits->soft_expiry = false; + timer_limits->earliest_playback_start_seconds = 0; + timer_limits->latest_playback_start_seconds = 0; + timer_limits->initial_playback_duration_seconds = key_duration; + timer_limits->renewal_playback_duration_seconds = key_duration; + timer_limits->license_duration_seconds = 0; + nonce_values->api_version = 15; + if (key_duration > 0) { + clock_values->time_when_timer_expires = system_time_seconds + key_duration; + } else { + clock_values->time_when_timer_expires = 0; + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult ODK_RefreshV15Values(const ODK_TimerLimits* timer_limits, + ODK_ClockValues* clock_values, + const ODK_NonceValues* nonce_values, + uint64_t system_time_seconds, + uint64_t* timer_value) { + if (timer_limits == NULL || clock_values == NULL || nonce_values == NULL) + return OEMCrypto_ERROR_INVALID_CONTEXT; + if (nonce_values->api_version != 15) return OEMCrypto_ERROR_INVALID_NONCE; + if (clock_values->status > kActive) { + clock_values->timer_status = ODK_TIMER_EXPIRED; + return ODK_TIMER_EXPIRED; + } + /* If this is before the license was signed, something is odd. Return an + * error. */ + if (system_time_seconds < clock_values->time_of_license_signed) + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + + /* All times are relative to when the license was signed. */ + const uint64_t rental_time = + system_time_seconds - clock_values->time_of_license_signed; + + /* The timer should be limited by the renewal playback duration. This is + * similar to code in AttemptFirstPlayback, above, except we use the + * renewal_playback_duration here, and we do not change clock_values->status. + */ + uint64_t time_left = timer_limits->renewal_playback_duration_seconds; + /* If there is a license duration, it also limits the timer. Remember, a + * limit of 0 means no limit, or infinite. */ + if (timer_limits->license_duration_seconds > 0) { + if (timer_limits->license_duration_seconds < rental_time) { + clock_values->timer_status = ODK_TIMER_EXPIRED; + return ODK_TIMER_EXPIRED; + } + if (timer_limits->license_duration_seconds - rental_time < time_left || + time_left == 0) { + time_left = timer_limits->license_duration_seconds - rental_time; + } + } + if (time_left == 0 || timer_limits->soft_expiry) { /* Unlimited. */ + clock_values->time_when_timer_expires = 0; + clock_values->timer_status = ODK_DISABLE_TIMER; + return ODK_DISABLE_TIMER; + } + /* Set timer to limit playback. */ + if (timer_value) *timer_value = time_left; + clock_values->time_when_timer_expires = system_time_seconds + time_left; + clock_values->timer_status = ODK_SET_TIMER; + return ODK_SET_TIMER; +} diff --git a/oemcrypto/odk/src/serialization_base.c b/oemcrypto/odk/src/serialization_base.c index 7058899..60cc473 100644 --- a/oemcrypto/odk/src/serialization_base.c +++ b/oemcrypto/odk/src/serialization_base.c @@ -10,7 +10,7 @@ #include #include -#include "OEMCryptoCENC.h" +#include "OEMCryptoCENCCommon.h" #include "odk_assert.h" #include "odk_overflow.h" diff --git a/oemcrypto/odk/include/serialization_base.h b/oemcrypto/odk/src/serialization_base.h similarity index 98% rename from oemcrypto/odk/include/serialization_base.h rename to oemcrypto/odk/src/serialization_base.h index a447aba..cc1a3d1 100644 --- a/oemcrypto/odk/include/serialization_base.h +++ b/oemcrypto/odk/src/serialization_base.h @@ -14,7 +14,7 @@ extern "C" { #include #include -#include "OEMCryptoCENC.h" +#include "OEMCryptoCENCCommon.h" #define SIZE_OF_MESSAGE_STRUCT 64 diff --git a/oemcrypto/odk/test/odk_fuzz.cpp b/oemcrypto/odk/test/odk_fuzz.cpp index c849da2..1ad80b7 100644 --- a/oemcrypto/odk/test/odk_fuzz.cpp +++ b/oemcrypto/odk/test/odk_fuzz.cpp @@ -12,7 +12,7 @@ #include #include -#include "OEMCryptoCENC.h" +#include "OEMCryptoCENCCommon.h" #include "odk.h" #include "odk_serialize.h" #include "oec_util.h" diff --git a/oemcrypto/odk/test/odk_test.cpp b/oemcrypto/odk/test/odk_test.cpp index 52a37d1..4b9c5fa 100644 --- a/oemcrypto/odk/test/odk_test.cpp +++ b/oemcrypto/odk/test/odk_test.cpp @@ -36,7 +36,9 @@ size_t ODK_FieldLength(ODK_FieldType type) { case ODK_SUBSTRING: return sizeof(uint32_t) + sizeof(uint32_t); case ODK_DEVICEID: - return DEVICE_ID_MAX; + return ODK_DEVICE_ID_LEN_MAX; + case ODK_HASH: + return ODK_SHA256_HASH_SIZE; default: return SIZE_MAX; } @@ -51,7 +53,7 @@ size_t ODK_AllocSize(ODK_FieldType type) { OEMCryptoResult ODK_WriteSingleField(uint8_t* const buf, const ODK_Field* const field) { - if (!field || !field->value) { + if (!buf || !field || !field->value) { return ODK_ERROR_CORE_MESSAGE; } switch (field->type) { @@ -73,9 +75,12 @@ OEMCryptoResult ODK_WriteSingleField(uint8_t* const buf, memcpy(buf + sizeof(off), &len, sizeof(len)); break; } - case ODK_DEVICEID: { + case ODK_DEVICEID: + case ODK_HASH: { + const size_t field_len = ODK_FieldLength(field->type); const uint8_t* const id = static_cast(field->value); - memcpy(buf, id, DEVICE_ID_MAX); + memcpy(buf, id, field_len); + break; } default: @@ -112,9 +117,11 @@ OEMCryptoResult ODK_ReadSingleField(const uint8_t* const buf, s->length = be32toh(len); break; } - case ODK_DEVICEID: { + case ODK_DEVICEID: + case ODK_HASH: { + const size_t field_len = ODK_FieldLength(field->type); uint8_t* const id = static_cast(field->value); - memcpy(id, buf, DEVICE_ID_MAX); + memcpy(id, buf, field_len); break; } default: @@ -174,29 +181,6 @@ OEMCryptoResult ODK_WriteFields(uint8_t* const buf, const size_t size_in, return ODK_IterFields(ODK_WRITE, buf, size_in, size_out, fields); } -OEMCryptoResult ODK_ValidateSubstrings(const size_t size, const size_t n, - const ODK_Field* const fields) { - if (!fields) { - return ODK_ERROR_CORE_MESSAGE; - } - size_t off = 0; - for (size_t i = 0; i < n; i++) { - if (fields[i].type != ODK_SUBSTRING) { - continue; - } - if (!fields[i].value) { - return ODK_ERROR_CORE_MESSAGE; - } - size_t end = 0; - OEMCrypto_Substring* s = static_cast(fields[i].value); - if (s->offset > size || - __builtin_add_overflow(s->offset, s->length, &end) || end > size) { - return ODK_ERROR_CORE_MESSAGE; - } - } - return OEMCrypto_SUCCESS; -} - void expect_eq_buf(const void* s1, const void* s2, size_t n) { if (memcmp(s1, s2, n)) { const void* buffers[] = {s1, s2}; @@ -222,6 +206,7 @@ void ValidateRequest(uint32_t message_type, uint32_t api_version = 16; uint32_t nonce = 0xdeadbeef; uint32_t session_id = 0xcafebabe; + ODK_NonceValues nonce_values{api_version, nonce, session_id}; std::vector total_fields = { {ODK_UINT32, &message_type}, {ODK_UINT32, &message_size}, {ODK_UINT32, &api_version}, {ODK_UINT32, &nonce}, @@ -238,9 +223,8 @@ void ValidateRequest(uint32_t message_type, uint8_t* buf2 = new uint8_t[message_size](); size_t bytes_written = message_size; - EXPECT_EQ( - OEMCrypto_SUCCESS, - odk_prepare_func(buf, &bytes_written, api_version, nonce, session_id)); + EXPECT_EQ(OEMCrypto_SUCCESS, + odk_prepare_func(buf, &bytes_written, &nonce_values)); EXPECT_EQ(bytes_written, message_size); EXPECT_EQ(OEMCrypto_SUCCESS, ODK_IterFields(ODK_WRITE, buf2, SIZE_MAX, @@ -254,9 +238,11 @@ void ValidateRequest(uint32_t message_type, std::string oemcrypto_core_message(reinterpret_cast(buf), message_size); EXPECT_TRUE(kdo_parse_func(oemcrypto_core_message, &t)); + nonce_values.api_version = t.api_version; + nonce_values.nonce = t.nonce; + nonce_values.session_id = t.session_id; EXPECT_EQ(OEMCrypto_SUCCESS, - odk_prepare_func(buf2, &bytes_written, t.api_version, t.nonce, - t.session_id)); + odk_prepare_func(buf2, &bytes_written, &nonce_values)); EXPECT_EQ(bytes_written, message_size); expect_eq_buf(buf, buf2, message_size); @@ -264,6 +250,12 @@ void ValidateRequest(uint32_t message_type, delete[] buf2; } +/** + * Template arguments: + * T: kdo input struct + * F: odk deserializer + * G: kdo serializer + */ template void ValidateResponse(uint32_t message_type, std::vector& extra_fields, @@ -310,8 +302,9 @@ void ValidateResponse(uint32_t message_type, bytes_written - bytes_read == header_size); // parse buf with odk + ODK_NonceValues nonce_values{api_version, nonce, session_id}; EXPECT_EQ(OEMCrypto_SUCCESS, - odk_parse_func(buf, bytes_written, api_version, nonce, session_id)); + odk_parse_func(buf, bytes_written, &nonce_values)); // serialize odk output to oemcrypto_core_message std::string oemcrypto_core_message; @@ -377,14 +370,11 @@ TEST(OdkTest, SerializeFieldsStress) { delete[] buf2; } -#if 0 // TODO(b/144233698): fix this. TEST(OdkTest, LicenseRequest) { std::vector empty; auto odk_prepare_func = [&](uint8_t* const buf, size_t* size, - uint32_t api_version, uint32_t nonce, - uint32_t session_id) { - return ODK_PrepareCoreLicenseRequest(buf, SIZE_MAX, size, api_version, - nonce, session_id); + ODK_NonceValues* nonce_values) { + return ODK_PrepareCoreLicenseRequest(buf, SIZE_MAX, size, nonce_values); }; auto kdo_parse_func = ParseLicenseRequest; ValidateRequest(ODK_License_Request_Type, empty, @@ -398,11 +388,9 @@ TEST(OdkTest, RenewalRequest) { }; ODK_ClockValues clock_values = {0}; auto odk_prepare_func = [&](uint8_t* const buf, size_t* size, - uint32_t api_version, uint32_t nonce, - uint32_t session_id) { - return ODK_PrepareCoreRenewalRequest(buf, SIZE_MAX, size, api_version, - nonce, session_id, &clock_values, - system_time_seconds); + const ODK_NonceValues* nonce_values) { + return ODK_PrepareCoreRenewalRequest(buf, SIZE_MAX, size, nonce_values, + &clock_values, system_time_seconds); }; auto kdo_parse_func = [&](const std::string& oemcrypto_core_message, ODK_RenewalRequest* core_renewal_request) { @@ -425,11 +413,9 @@ TEST(OdkTest, ProvisionRequest) { {ODK_DEVICEID, device_id}, }; auto odk_prepare_func = [&](uint8_t* const buf, size_t* size, - uint32_t api_version, uint32_t nonce, - uint32_t session_id) { - return ODK_PrepareCoreProvisioningRequest(buf, SIZE_MAX, size, api_version, - nonce, session_id, device_id, - device_id_length); + const ODK_NonceValues* nonce_values) { + return ODK_PrepareCoreProvisioningRequest(buf, SIZE_MAX, size, nonce_values, + device_id, device_id_length); }; auto kdo_parse_func = [&](const std::string& oemcrypto_core_message, @@ -466,6 +452,9 @@ TEST(OdkTest, LicenseResponse) { .renewal_playback_duration_seconds = 13, .license_duration_seconds = 14, }, + .request_hash = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}, .key_array_length = 3, .key_array = { @@ -510,6 +499,7 @@ TEST(OdkTest, LicenseResponse) { {ODK_UINT64, &parsed_license.timer_limits.renewal_playback_duration_seconds}, {ODK_UINT64, &parsed_license.timer_limits.license_duration_seconds}, + {ODK_HASH, &parsed_license.request_hash}, {ODK_UINT32, &parsed_license.key_array_length}, {ODK_SUBSTRING, &parsed_license.key_array[0].key_id}, {ODK_SUBSTRING, &parsed_license.key_array[0].key_data_iv}, @@ -528,11 +518,12 @@ TEST(OdkTest, LicenseResponse) { {ODK_SUBSTRING, &parsed_license.key_array[2].key_control}, }; + uint8_t request_hash[ODK_SHA256_HASH_SIZE] = {}; + memcpy(request_hash, parsed_license.request_hash, ODK_SHA256_HASH_SIZE); auto odk_parse_func = [&](const uint8_t* buf, size_t size, - uint32_t api_version, uint32_t nonce, - uint32_t session_id) { - return ODK_ParseLicense(buf, size + 128, api_version, nonce, session_id, 0, - 0, &parsed_license); + ODK_NonceValues* nonce_values) { + return ODK_ParseLicense(buf, size + 128, size, 1, 0, request_hash, nullptr, + nullptr, nonce_values, &parsed_license); }; auto kdo_prepare_func = [&](const ODK_LicenseRequest& core_request, std::string* oemcrypto_core_message) { @@ -571,10 +562,9 @@ TEST(OdkTest, RenewalResponse) { }; auto odk_parse_func = [&](const uint8_t* buf, size_t size, - uint32_t api_version, uint32_t nonce, - uint32_t session_id) { + ODK_NonceValues* nonce_values) { OEMCryptoResult err = - ODK_ParseRenewal(buf, size, api_version, nonce, session_id, system_time, + ODK_ParseRenewal(buf, size, size, nonce_values, system_time, &timer_limits, &clock_values, &playback_timer); EXPECT_EQ(ODK_SET_TIMER, err); @@ -617,14 +607,13 @@ TEST(OdkTest, ProvisionResponse) { }; auto odk_parse_func = [&](const uint8_t* buf, size_t size, - uint32_t api_version, uint32_t nonce, - uint32_t session_id) { + ODK_NonceValues* nonce_values) { // restore device id because it is not part of parsed_response device_id_length = DEVICE_ID_MAX / 2; memset(device_id, 0xff, device_id_length); OEMCryptoResult err = - ODK_ParseProvisioning(buf, size + 16, api_version, nonce, session_id, - device_id, device_id_length, &parsed_response); + ODK_ParseProvisioning(buf, size + 16, size, nonce_values, device_id, + device_id_length, &parsed_response); return err; }; auto kdo_prepare_func = [&](ODK_ProvisioningRequest& core_request, @@ -646,10 +635,10 @@ TEST(OdkSizeTest, LicenseRequest) { uint32_t api_version = 0; uint32_t nonce = 0; uint32_t session_id = 0; + ODK_NonceValues nonce_values{api_version, nonce, session_id}; EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, ODK_PrepareCoreLicenseRequest(message, message_length, - &core_message_length, api_version, - nonce, session_id)); + &core_message_length, &nonce_values)); // All messages have at least a five 4-byte fields. size_t minimum_message_size = 5 * 4; EXPECT_GE(core_message_length, minimum_message_size); @@ -665,10 +654,11 @@ TEST(OdkSizeTest, RenewalRequest) { ODK_ClockValues clock_values = {}; clock_values.time_of_first_decrypt = 10; uint64_t system_time_seconds = 15; + ODK_NonceValues nonce_values{api_version, nonce, session_id}; EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, - ODK_PrepareCoreRenewalRequest( - message, message_length, &core_message_length, api_version, - nonce, session_id, &clock_values, system_time_seconds)); + 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. size_t minimum_message_size = 5 * 4; EXPECT_GE(core_message_length, minimum_message_size); @@ -683,12 +673,12 @@ TEST(OdkSizeTest, ProvisioningRequest) { uint32_t session_id = 0; uint8_t* device_id = nullptr; uint32_t device_id_length = 0; + ODK_NonceValues nonce_values{api_version, nonce, session_id}; EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, ODK_PrepareCoreProvisioningRequest( - message, message_length, &core_message_length, api_version, - nonce, session_id, nullptr, device_id_length)); + message, message_length, &core_message_length, &nonce_values, + nullptr, device_id_length)); // All messages have at least a five 4-byte fields. size_t minimum_message_size = 5 * 4; EXPECT_GE(core_message_length, minimum_message_size); } -#endif diff --git a/oemcrypto/odk/test/odk_test.h b/oemcrypto/odk/test/odk_test.h index edbbdaa..a8114a1 100644 --- a/oemcrypto/odk/test/odk_test.h +++ b/oemcrypto/odk/test/odk_test.h @@ -7,7 +7,7 @@ #ifndef ODK_TEST_H_ #define ODK_TEST_H_ -#include "OEMCryptoCENC.h" +#include "OEMCryptoCENCCommon.h" typedef enum { ODK_License_Request_Type = 1, @@ -23,6 +23,7 @@ typedef enum { ODK_UINT64, ODK_SUBSTRING, ODK_DEVICEID, + ODK_HASH, ODK_NUMTYPES, } ODK_FieldType; diff --git a/util/src/string_conversions.cpp b/util/src/string_conversions.cpp index 828b92f..b9b4979 100644 --- a/util/src/string_conversions.cpp +++ b/util/src/string_conversions.cpp @@ -87,10 +87,12 @@ std::string a2bs_hex(const std::string& byte) { } std::string b2a_hex(const std::vector& byte) { - return HexEncode(&byte[0], byte.size()); + if (byte.empty()) return ""; + return HexEncode(byte.data(), byte.size()); } std::string b2a_hex(const std::string& byte) { + if (byte.empty()) return ""; return HexEncode(reinterpret_cast(byte.data()), byte.length()); } @@ -251,7 +253,7 @@ std::vector Base64SafeDecode(const std::string& b64_input) { std::string HexEncode(const uint8_t* in_buffer, unsigned int size) { static const char kHexChars[] = "0123456789ABCDEF"; - + if (size == 0) return ""; // Each input byte creates two output hex characters. std::string out_buffer(size * 2, '\0');