Update to v16.1 documentation and ODK library

This commit is contained in:
Fred Gylys-Colwell
2019-12-13 11:12:54 -08:00
parent 2f232e2939
commit 5b9580a351
19 changed files with 390 additions and 87 deletions

View 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_

View File

@@ -48,7 +48,7 @@
#define ODK_H_ #define ODK_H_
#include <stdint.h> #include <stdint.h>
#include "OEMCryptoCENC.h" #include "OEMCryptoCENCCommon.h"
#include "odk_structs.h" #include "odk_structs.h"
#ifdef __cplusplus #ifdef __cplusplus
@@ -400,6 +400,41 @@ OEMCryptoResult ODK_InitializeV15Values(ODK_TimerLimits* timer_limits,
uint32_t key_duration, uint32_t key_duration,
uint64_t system_time_seconds); 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 * ODK_ParseLicense
* *
@@ -514,6 +549,8 @@ OEMCryptoResult ODK_ParseLicense(
* allowed. * allowed.
* ODK_TIMER_EXPIRED: Set timer as diabled. Playback is not allowed. * ODK_TIMER_EXPIRED: Set timer as diabled. Playback is not allowed.
* ODK_UNSUPPORTED_API * ODK_UNSUPPORTED_API
* ODK_STALE_RENEWAL: This renewal is not the most recently signed. It is
* rejected.
* OEMCrypto_ERROR_INVALID_NONCE * OEMCrypto_ERROR_INVALID_NONCE
* *
* Version: * Version:

View File

@@ -8,7 +8,7 @@
#define ODK_STRUCTS_H_ #define ODK_STRUCTS_H_
#include <stdint.h> #include <stdint.h>
#include "OEMCryptoCENC.h" #include "OEMCryptoCENCCommon.h"
#define ODK_MAX_NUM_KEYS 32 #define ODK_MAX_NUM_KEYS 32
#define ODK_DEVICE_ID_LEN_MAX 64 #define ODK_DEVICE_ID_LEN_MAX 64
@@ -71,6 +71,7 @@ typedef struct {
uint64_t time_of_license_signed; uint64_t time_of_license_signed;
uint64_t time_of_first_decrypt; uint64_t time_of_first_decrypt;
uint64_t time_of_last_decrypt; uint64_t time_of_last_decrypt;
uint64_t time_of_renewal_request;
uint64_t time_when_timer_expires; uint64_t time_when_timer_expires;
uint32_t timer_status; uint32_t timer_status;
enum OEMCrypto_Usage_Entry_Status status; enum OEMCrypto_Usage_Entry_Status status;

View File

@@ -103,10 +103,11 @@ static OEMCryptoResult ODK_ParseResponse(const uint8_t* buf,
} }
if (nonce_values) { if (nonce_values) {
/* always verify nonce_values for Renewal and Provisioning responses */
if (nonce_values->api_version != core_message->nonce_values.api_version || if (nonce_values->api_version != core_message->nonce_values.api_version ||
nonce_values->nonce != core_message->nonce_values.nonce || nonce_values->nonce != core_message->nonce_values.nonce ||
nonce_values->session_id != core_message->nonce_values.session_id) { 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, size_t core_message_length,
bool initial_license_load, bool initial_license_load,
bool usage_entry_present, bool usage_entry_present,
const uint8_t request_hash[ODK_SHA256_HASH_SIZE], const uint8_t* request_hash,
ODK_TimerLimits* timer_limits, ODK_TimerLimits* timer_limits,
ODK_ClockValues* clock_values, ODK_ClockValues* clock_values,
ODK_NonceValues* nonce_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, message, message_length, ODK_License_Response_Type, NULL,
&license_response.core_message); &license_response.core_message);
if (err) { if (err != OEMCrypto_SUCCESS) {
return err; return err;
} }
@@ -208,10 +209,8 @@ OEMCryptoResult ODK_ParseLicense(const uint8_t* message, size_t message_length,
return ODK_ERROR_CORE_MESSAGE; return ODK_ERROR_CORE_MESSAGE;
} }
if (usage_entry_present) { if (usage_entry_present && parsed_license->pst.length == 0) {
nonce_values->nonce = license_response.core_message.nonce_values.nonce; return ODK_ERROR_CORE_MESSAGE;
nonce_values->session_id = license_response.core_message.nonce_values.session_id;
return err;
} }
return err; return err;

View File

@@ -8,7 +8,7 @@
#define ODK_STRUCTS_PRIV_H_ #define ODK_STRUCTS_PRIV_H_
#include <stdint.h> #include <stdint.h>
#include "OEMCryptoCENC.h" #include "OEMCryptoCENCCommon.h"
#include "odk_structs.h" #include "odk_structs.h"
typedef enum { typedef enum {

View File

@@ -9,8 +9,42 @@
#include "odk.h" #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, 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; if (clock_values == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT;
clock_values->time_of_license_signed = system_time_seconds; clock_values->time_of_license_signed = system_time_seconds;
clock_values->time_of_first_decrypt = 0; clock_values->time_of_first_decrypt = 0;
@@ -64,7 +98,8 @@ uint32_t ODK_AttemptFirstPlayback(uint64_t system_time_seconds,
* session. */ * session. */
if (clock_values->status == kUnused) { if (clock_values->status == kUnused) {
/* If the rental clock has expired, the license has expired. */ /* 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; clock_values->timer_status = ODK_TIMER_EXPIRED;
return 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; clock_values->time_of_last_decrypt = system_time_seconds;
return OEMCrypto_SUCCESS; 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;
}

View File

@@ -10,7 +10,7 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include "OEMCryptoCENC.h" #include "OEMCryptoCENCCommon.h"
#include "odk_assert.h" #include "odk_assert.h"
#include "odk_overflow.h" #include "odk_overflow.h"

View File

@@ -14,7 +14,7 @@ extern "C" {
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "OEMCryptoCENC.h" #include "OEMCryptoCENCCommon.h"
#define SIZE_OF_MESSAGE_STRUCT 64 #define SIZE_OF_MESSAGE_STRUCT 64

View File

@@ -12,7 +12,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include "OEMCryptoCENC.h" #include "OEMCryptoCENCCommon.h"
#include "odk.h" #include "odk.h"
#include "odk_serialize.h" #include "odk_serialize.h"
#include "oec_util.h" #include "oec_util.h"

View File

@@ -36,7 +36,9 @@ size_t ODK_FieldLength(ODK_FieldType type) {
case ODK_SUBSTRING: case ODK_SUBSTRING:
return sizeof(uint32_t) + sizeof(uint32_t); return sizeof(uint32_t) + sizeof(uint32_t);
case ODK_DEVICEID: case ODK_DEVICEID:
return DEVICE_ID_MAX; return ODK_DEVICE_ID_LEN_MAX;
case ODK_HASH:
return ODK_SHA256_HASH_SIZE;
default: default:
return SIZE_MAX; return SIZE_MAX;
} }
@@ -51,7 +53,7 @@ size_t ODK_AllocSize(ODK_FieldType type) {
OEMCryptoResult ODK_WriteSingleField(uint8_t* const buf, OEMCryptoResult ODK_WriteSingleField(uint8_t* const buf,
const ODK_Field* const field) { const ODK_Field* const field) {
if (!field || !field->value) { if (!buf || !field || !field->value) {
return ODK_ERROR_CORE_MESSAGE; return ODK_ERROR_CORE_MESSAGE;
} }
switch (field->type) { switch (field->type) {
@@ -73,9 +75,12 @@ OEMCryptoResult ODK_WriteSingleField(uint8_t* const buf,
memcpy(buf + sizeof(off), &len, sizeof(len)); memcpy(buf + sizeof(off), &len, sizeof(len));
break; 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); const uint8_t* const id = static_cast<uint8_t*>(field->value);
memcpy(buf, id, DEVICE_ID_MAX); memcpy(buf, id, field_len);
break; break;
} }
default: default:
@@ -112,9 +117,11 @@ OEMCryptoResult ODK_ReadSingleField(const uint8_t* const buf,
s->length = be32toh(len); s->length = be32toh(len);
break; 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); uint8_t* const id = static_cast<uint8_t*>(field->value);
memcpy(id, buf, DEVICE_ID_MAX); memcpy(id, buf, field_len);
break; break;
} }
default: 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); 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) { void expect_eq_buf(const void* s1, const void* s2, size_t n) {
if (memcmp(s1, s2, n)) { if (memcmp(s1, s2, n)) {
const void* buffers[] = {s1, s2}; const void* buffers[] = {s1, s2};
@@ -222,6 +206,7 @@ void ValidateRequest(uint32_t message_type,
uint32_t api_version = 16; uint32_t api_version = 16;
uint32_t nonce = 0xdeadbeef; uint32_t nonce = 0xdeadbeef;
uint32_t session_id = 0xcafebabe; uint32_t session_id = 0xcafebabe;
ODK_NonceValues nonce_values{api_version, nonce, session_id};
std::vector<ODK_Field> total_fields = { std::vector<ODK_Field> total_fields = {
{ODK_UINT32, &message_type}, {ODK_UINT32, &message_size}, {ODK_UINT32, &message_type}, {ODK_UINT32, &message_size},
{ODK_UINT32, &api_version}, {ODK_UINT32, &nonce}, {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](); uint8_t* buf2 = new uint8_t[message_size]();
size_t bytes_written = message_size; size_t bytes_written = message_size;
EXPECT_EQ( EXPECT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_SUCCESS, odk_prepare_func(buf, &bytes_written, &nonce_values));
odk_prepare_func(buf, &bytes_written, api_version, nonce, session_id));
EXPECT_EQ(bytes_written, message_size); EXPECT_EQ(bytes_written, message_size);
EXPECT_EQ(OEMCrypto_SUCCESS, ODK_IterFields(ODK_WRITE, buf2, SIZE_MAX, 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), std::string oemcrypto_core_message(reinterpret_cast<char*>(buf),
message_size); message_size);
EXPECT_TRUE(kdo_parse_func(oemcrypto_core_message, &t)); 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, EXPECT_EQ(OEMCrypto_SUCCESS,
odk_prepare_func(buf2, &bytes_written, t.api_version, t.nonce, odk_prepare_func(buf2, &bytes_written, &nonce_values));
t.session_id));
EXPECT_EQ(bytes_written, message_size); EXPECT_EQ(bytes_written, message_size);
expect_eq_buf(buf, buf2, message_size); expect_eq_buf(buf, buf2, message_size);
@@ -264,6 +250,12 @@ void ValidateRequest(uint32_t message_type,
delete[] buf2; delete[] buf2;
} }
/**
* Template arguments:
* T: kdo input struct
* F: odk deserializer
* G: kdo serializer
*/
template <typename T, typename F, typename G> template <typename T, typename F, typename G>
void ValidateResponse(uint32_t message_type, void ValidateResponse(uint32_t message_type,
std::vector<ODK_Field>& extra_fields, std::vector<ODK_Field>& extra_fields,
@@ -310,8 +302,9 @@ void ValidateResponse(uint32_t message_type,
bytes_written - bytes_read == header_size); bytes_written - bytes_read == header_size);
// parse buf with odk // parse buf with odk
ODK_NonceValues nonce_values{api_version, nonce, session_id};
EXPECT_EQ(OEMCrypto_SUCCESS, 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 // serialize odk output to oemcrypto_core_message
std::string oemcrypto_core_message; std::string oemcrypto_core_message;
@@ -377,14 +370,11 @@ TEST(OdkTest, SerializeFieldsStress) {
delete[] buf2; delete[] buf2;
} }
#if 0 // TODO(b/144233698): fix this.
TEST(OdkTest, LicenseRequest) { TEST(OdkTest, LicenseRequest) {
std::vector<ODK_Field> empty; std::vector<ODK_Field> empty;
auto odk_prepare_func = [&](uint8_t* const buf, size_t* size, auto odk_prepare_func = [&](uint8_t* const buf, size_t* size,
uint32_t api_version, uint32_t nonce, ODK_NonceValues* nonce_values) {
uint32_t session_id) { return ODK_PrepareCoreLicenseRequest(buf, SIZE_MAX, size, nonce_values);
return ODK_PrepareCoreLicenseRequest(buf, SIZE_MAX, size, api_version,
nonce, session_id);
}; };
auto kdo_parse_func = ParseLicenseRequest; auto kdo_parse_func = ParseLicenseRequest;
ValidateRequest<ODK_LicenseRequest>(ODK_License_Request_Type, empty, ValidateRequest<ODK_LicenseRequest>(ODK_License_Request_Type, empty,
@@ -398,11 +388,9 @@ TEST(OdkTest, RenewalRequest) {
}; };
ODK_ClockValues clock_values = {0}; ODK_ClockValues clock_values = {0};
auto odk_prepare_func = [&](uint8_t* const buf, size_t* size, auto odk_prepare_func = [&](uint8_t* const buf, size_t* size,
uint32_t api_version, uint32_t nonce, const ODK_NonceValues* nonce_values) {
uint32_t session_id) { return ODK_PrepareCoreRenewalRequest(buf, SIZE_MAX, size, nonce_values,
return ODK_PrepareCoreRenewalRequest(buf, SIZE_MAX, size, api_version, &clock_values, system_time_seconds);
nonce, session_id, &clock_values,
system_time_seconds);
}; };
auto kdo_parse_func = [&](const std::string& oemcrypto_core_message, auto kdo_parse_func = [&](const std::string& oemcrypto_core_message,
ODK_RenewalRequest* core_renewal_request) { ODK_RenewalRequest* core_renewal_request) {
@@ -425,11 +413,9 @@ TEST(OdkTest, ProvisionRequest) {
{ODK_DEVICEID, device_id}, {ODK_DEVICEID, device_id},
}; };
auto odk_prepare_func = [&](uint8_t* const buf, size_t* size, auto odk_prepare_func = [&](uint8_t* const buf, size_t* size,
uint32_t api_version, uint32_t nonce, const ODK_NonceValues* nonce_values) {
uint32_t session_id) { return ODK_PrepareCoreProvisioningRequest(buf, SIZE_MAX, size, nonce_values,
return ODK_PrepareCoreProvisioningRequest(buf, SIZE_MAX, size, api_version, device_id, device_id_length);
nonce, session_id, device_id,
device_id_length);
}; };
auto kdo_parse_func = auto kdo_parse_func =
[&](const std::string& oemcrypto_core_message, [&](const std::string& oemcrypto_core_message,
@@ -466,6 +452,9 @@ TEST(OdkTest, LicenseResponse) {
.renewal_playback_duration_seconds = 13, .renewal_playback_duration_seconds = 13,
.license_duration_seconds = 14, .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_length = 3,
.key_array = .key_array =
{ {
@@ -510,6 +499,7 @@ TEST(OdkTest, LicenseResponse) {
{ODK_UINT64, {ODK_UINT64,
&parsed_license.timer_limits.renewal_playback_duration_seconds}, &parsed_license.timer_limits.renewal_playback_duration_seconds},
{ODK_UINT64, &parsed_license.timer_limits.license_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_UINT32, &parsed_license.key_array_length},
{ODK_SUBSTRING, &parsed_license.key_array[0].key_id}, {ODK_SUBSTRING, &parsed_license.key_array[0].key_id},
{ODK_SUBSTRING, &parsed_license.key_array[0].key_data_iv}, {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}, {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, auto odk_parse_func = [&](const uint8_t* buf, size_t size,
uint32_t api_version, uint32_t nonce, ODK_NonceValues* nonce_values) {
uint32_t session_id) { return ODK_ParseLicense(buf, size + 128, size, 1, 0, request_hash, nullptr,
return ODK_ParseLicense(buf, size + 128, api_version, nonce, session_id, 0, nullptr, nonce_values, &parsed_license);
0, &parsed_license);
}; };
auto kdo_prepare_func = [&](const ODK_LicenseRequest& core_request, auto kdo_prepare_func = [&](const ODK_LicenseRequest& core_request,
std::string* oemcrypto_core_message) { std::string* oemcrypto_core_message) {
@@ -571,10 +562,9 @@ TEST(OdkTest, RenewalResponse) {
}; };
auto odk_parse_func = [&](const uint8_t* buf, size_t size, auto odk_parse_func = [&](const uint8_t* buf, size_t size,
uint32_t api_version, uint32_t nonce, ODK_NonceValues* nonce_values) {
uint32_t session_id) {
OEMCryptoResult err = 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); &timer_limits, &clock_values, &playback_timer);
EXPECT_EQ(ODK_SET_TIMER, err); EXPECT_EQ(ODK_SET_TIMER, err);
@@ -617,14 +607,13 @@ TEST(OdkTest, ProvisionResponse) {
}; };
auto odk_parse_func = [&](const uint8_t* buf, size_t size, auto odk_parse_func = [&](const uint8_t* buf, size_t size,
uint32_t api_version, uint32_t nonce, ODK_NonceValues* nonce_values) {
uint32_t session_id) {
// restore device id because it is not part of parsed_response // restore device id because it is not part of parsed_response
device_id_length = DEVICE_ID_MAX / 2; device_id_length = DEVICE_ID_MAX / 2;
memset(device_id, 0xff, device_id_length); memset(device_id, 0xff, device_id_length);
OEMCryptoResult err = OEMCryptoResult err =
ODK_ParseProvisioning(buf, size + 16, api_version, nonce, session_id, ODK_ParseProvisioning(buf, size + 16, size, nonce_values, device_id,
device_id, device_id_length, &parsed_response); device_id_length, &parsed_response);
return err; return err;
}; };
auto kdo_prepare_func = [&](ODK_ProvisioningRequest& core_request, auto kdo_prepare_func = [&](ODK_ProvisioningRequest& core_request,
@@ -646,10 +635,10 @@ TEST(OdkSizeTest, LicenseRequest) {
uint32_t api_version = 0; uint32_t api_version = 0;
uint32_t nonce = 0; uint32_t nonce = 0;
uint32_t session_id = 0; uint32_t session_id = 0;
ODK_NonceValues nonce_values{api_version, nonce, session_id};
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
ODK_PrepareCoreLicenseRequest(message, message_length, ODK_PrepareCoreLicenseRequest(message, message_length,
&core_message_length, api_version, &core_message_length, &nonce_values));
nonce, session_id));
// All messages have at least a five 4-byte fields. // All messages have at least a five 4-byte fields.
size_t minimum_message_size = 5 * 4; size_t minimum_message_size = 5 * 4;
EXPECT_GE(core_message_length, minimum_message_size); EXPECT_GE(core_message_length, minimum_message_size);
@@ -665,10 +654,11 @@ TEST(OdkSizeTest, RenewalRequest) {
ODK_ClockValues clock_values = {}; ODK_ClockValues clock_values = {};
clock_values.time_of_first_decrypt = 10; clock_values.time_of_first_decrypt = 10;
uint64_t system_time_seconds = 15; uint64_t system_time_seconds = 15;
ODK_NonceValues nonce_values{api_version, nonce, session_id};
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
ODK_PrepareCoreRenewalRequest( ODK_PrepareCoreRenewalRequest(message, message_length,
message, message_length, &core_message_length, api_version, &core_message_length, &nonce_values,
nonce, session_id, &clock_values, system_time_seconds)); &clock_values, system_time_seconds));
// All messages have at least a five 4-byte fields. // All messages have at least a five 4-byte fields.
size_t minimum_message_size = 5 * 4; size_t minimum_message_size = 5 * 4;
EXPECT_GE(core_message_length, minimum_message_size); EXPECT_GE(core_message_length, minimum_message_size);
@@ -683,12 +673,12 @@ TEST(OdkSizeTest, ProvisioningRequest) {
uint32_t session_id = 0; uint32_t session_id = 0;
uint8_t* device_id = nullptr; uint8_t* device_id = nullptr;
uint32_t device_id_length = 0; uint32_t device_id_length = 0;
ODK_NonceValues nonce_values{api_version, nonce, session_id};
EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
ODK_PrepareCoreProvisioningRequest( ODK_PrepareCoreProvisioningRequest(
message, message_length, &core_message_length, api_version, message, message_length, &core_message_length, &nonce_values,
nonce, session_id, nullptr, device_id_length)); nullptr, device_id_length));
// All messages have at least a five 4-byte fields. // All messages have at least a five 4-byte fields.
size_t minimum_message_size = 5 * 4; size_t minimum_message_size = 5 * 4;
EXPECT_GE(core_message_length, minimum_message_size); EXPECT_GE(core_message_length, minimum_message_size);
} }
#endif

View File

@@ -7,7 +7,7 @@
#ifndef ODK_TEST_H_ #ifndef ODK_TEST_H_
#define ODK_TEST_H_ #define ODK_TEST_H_
#include "OEMCryptoCENC.h" #include "OEMCryptoCENCCommon.h"
typedef enum { typedef enum {
ODK_License_Request_Type = 1, ODK_License_Request_Type = 1,
@@ -23,6 +23,7 @@ typedef enum {
ODK_UINT64, ODK_UINT64,
ODK_SUBSTRING, ODK_SUBSTRING,
ODK_DEVICEID, ODK_DEVICEID,
ODK_HASH,
ODK_NUMTYPES, ODK_NUMTYPES,
} ODK_FieldType; } ODK_FieldType;

View File

@@ -87,10 +87,12 @@ std::string a2bs_hex(const std::string& byte) {
} }
std::string b2a_hex(const std::vector<uint8_t>& 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) { std::string b2a_hex(const std::string& byte) {
if (byte.empty()) return "";
return HexEncode(reinterpret_cast<const uint8_t*>(byte.data()), return HexEncode(reinterpret_cast<const uint8_t*>(byte.data()),
byte.length()); 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) { std::string HexEncode(const uint8_t* in_buffer, unsigned int size) {
static const char kHexChars[] = "0123456789ABCDEF"; static const char kHexChars[] = "0123456789ABCDEF";
if (size == 0) return "";
// Each input byte creates two output hex characters. // Each input byte creates two output hex characters.
std::string out_buffer(size * 2, '\0'); std::string out_buffer(size * 2, '\0');