Update to v16.1 documentation and ODK library
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
156
oemcrypto/odk/include/OEMCryptoCENCCommon.h
Normal file
156
oemcrypto/odk/include/OEMCryptoCENCCommon.h
Normal file
@@ -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 <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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_
|
||||
@@ -48,7 +48,7 @@
|
||||
#define ODK_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#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:
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#define ODK_STRUCTS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#define ODK_STRUCTS_PRIV_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "OEMCryptoCENCCommon.h"
|
||||
#include "odk_structs.h"
|
||||
|
||||
typedef enum {
|
||||
@@ -9,6 +9,40 @@
|
||||
|
||||
#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) {
|
||||
if (clock_values == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "OEMCryptoCENCCommon.h"
|
||||
#include "odk_assert.h"
|
||||
#include "odk_overflow.h"
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ extern "C" {
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "OEMCryptoCENCCommon.h"
|
||||
|
||||
#define SIZE_OF_MESSAGE_STRUCT 64
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "OEMCryptoCENCCommon.h"
|
||||
#include "odk.h"
|
||||
#include "odk_serialize.h"
|
||||
#include "oec_util.h"
|
||||
|
||||
@@ -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<uint8_t*>(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<uint8_t*>(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<OEMCrypto_Substring*>(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<ODK_Field> 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<char*>(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 <typename T, typename F, typename G>
|
||||
void ValidateResponse(uint32_t message_type,
|
||||
std::vector<ODK_Field>& 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<ODK_Field> 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_LicenseRequest>(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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -87,10 +87,12 @@ std::string a2bs_hex(const std::string& byte) {
|
||||
}
|
||||
|
||||
std::string b2a_hex(const std::vector<uint8_t>& 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<const uint8_t*>(byte.data()),
|
||||
byte.length());
|
||||
}
|
||||
@@ -251,7 +253,7 @@ std::vector<uint8_t> 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');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user