coreboot-libre-fam15h-rdimm/3rdparty/chromeec/test/pinweaver.c

2682 lines
82 KiB
C

/* Copyright 2018 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <pinweaver.h>
#include <dcrypto.h>
#include <nvmem_vars.h>
#include <sha256.h>
#include <stdint.h>
#include <string.h>
#include <timer.h>
#include <util.h>
#include <pinweaver_types.h>
#include "test_util.h"
#include <stdlib.h>
struct pw_test_data_t {
union {
struct pw_request_t request;
struct pw_response_t response;
/* Reserve space for the variable length fields. */
uint8_t tpm_buffer_size[PW_MAX_MESSAGE_SIZE];
};
} PW_ALIGN_TO_WRD;
/******************************************************************************/
/* Test data
*/
const int EMPTY_TREE_PATH_LENGTH = 18;
const struct merkle_tree_t EMPTY_TREE = {
{2} /* bits_per_level */,
{6} /* height */,
/* root */
{0x81, 0xaa, 0xe9, 0xde, 0x93, 0xf4, 0xdf, 0x88,
0x18, 0xfa, 0xff, 0xbd, 0xb7, 0x09, 0xc0, 0x86,
0x48, 0xdd, 0xcd, 0x35, 0x00, 0xf2, 0x88, 0xd6,
0x3f, 0xa6, 0x5e, 0x80, 0x10, 0x19, 0x41, 0x17},
/* key derivation nonce. */
{0x75, 0xf8, 0x43, 0xf7, 0x23, 0xbd, 0x2a, 0x0f,
0x8d, 0x34, 0xbf, 0xa6, 0x6d, 0xf9, 0x44, 0x38},
/* hmac_key */
{0x96, 0xc6, 0xb1, 0x64, 0xb6, 0xa7, 0xa8, 0x01,
0xd5, 0x1d, 0x8e, 0x97, 0x24, 0x86, 0xf8, 0x6f,
0xd4, 0x84, 0x0f, 0x95, 0x52, 0x93, 0x8d, 0x7d,
0x00, 0xbb, 0xba, 0xc8, 0xed, 0x7f, 0xa4, 0x7a},
/* wrap_key */
{0x95, 0xc9, 0x0a, 0xd4, 0xb3, 0x61, 0x1b, 0xcf,
0x1b, 0x49, 0x2b, 0xd6, 0x5d, 0xbc, 0x80, 0xa9,
0xf4, 0x83, 0xf2, 0x84, 0xd4, 0x04, 0x57, 0x7f,
0x02, 0xae, 0x37, 0x64, 0xae, 0xda, 0x71, 0x2a},
};
const struct leaf_data_t DEFAULT_LEAF = {
/*pub*/
{
/* label = {0, 1, 2, 3, 0, 1} */
{0x1b1llu},
/* delay_schedule */
{{{5}, {20} }, {{6}, {60} }, {{7}, {300} }, {{8}, {600} },
{{9}, {1800} }, {{10}, {3600} }, {{50}, {PW_BLOCK_ATTEMPTS} },
{{0}, {0} },
{{0}, {0} }, {{0}, {0} }, {{0}, {0} }, {{0}, {0} },
{{0}, {0} }, {{0}, {0} }, {{0}, {0} }, {{0}, {0} }, },
/*timestamp*/
{0, 0},
/* attempt_count */
{0},
/* valid_pcr_criteria */
{{{0, 0}, {0} }, {{0, 0}, {0} } },
},
/*sec*/
{
/* low_entropy_secret */
{0xba, 0xbc, 0x98, 0x9d, 0x97, 0x20, 0xcf, 0xea,
0xaa, 0xbd, 0xb2, 0xe3, 0xe0, 0x2c, 0x5c, 0x55,
0x06, 0x60, 0x93, 0xbd, 0x07, 0xe2, 0xba, 0x92,
0x10, 0x19, 0x24, 0xb1, 0x29, 0x33, 0x5a, 0xe2},
/* high_entropy_secret */
{0xe3, 0x46, 0xe3, 0x62, 0x01, 0x5d, 0xfe, 0x0a,
0xd3, 0x67, 0xd7, 0xef, 0xab, 0x01, 0xad, 0x0e,
0x3a, 0xed, 0xe8, 0x2f, 0x99, 0xd1, 0x2d, 0x13,
0x4d, 0x4e, 0xe4, 0x02, 0xbe, 0x71, 0x8e, 0x40},
/* reset_secret */
{0x8c, 0x33, 0x8c, 0xa7, 0x0f, 0x81, 0xa4, 0xee,
0x24, 0xcd, 0x04, 0x84, 0x9c, 0xa8, 0xfd, 0xdd,
0x14, 0xb0, 0xad, 0xe6, 0xb7, 0x6a, 0x10, 0xfc,
0x03, 0x22, 0xcb, 0x71, 0x31, 0xd3, 0x74, 0xd6},
},
};
const struct leaf_header_t DEFAULT_HEAD = {
{
.minor = PW_LEAF_MINOR_VERSION,
.major = PW_LEAF_MAJOR_VERSION,
},
sizeof(DEFAULT_LEAF.pub),
sizeof(DEFAULT_LEAF.sec),
};
const uint8_t DEFAULT_IV[] = {
0xaa, 0x65, 0x97, 0xc7, 0x02, 0x23, 0xb8, 0xdc,
0xb3, 0x55, 0xca, 0x3a, 0xab, 0xd0, 0x03, 0x90,
};
const uint8_t EMPTY_HMAC[32] = {};
const uint32_t DEFAULT_STORAGE_SEED[8] = {
0xe9e9880b, 0xb2a9fa0e, 0x9dcf22af, 0xc40156d0,
0xca8535dc, 0x748606ee, 0x68f0f627, 0x7df7558a,
};
/* This is not the actual hmac. */
const uint8_t DEFAULT_HMAC[] = {
0x87, 0x7e, 0xe2, 0xb2, 0x60, 0xeb, 0xf3, 0x4b,
0x80, 0x3e, 0xca, 0xcb, 0xe6, 0x24, 0x21, 0x86,
0xd9, 0xe3, 0x91, 0xf7, 0x2d, 0x16, 0x59, 0xd8,
0x0f, 0x37, 0x0a, 0xf4, 0x64, 0x19, 0x44, 0xe7,
};
const uint8_t ROOT_WITH_DEFAULT_HMAC[] = {
0x24, 0xad, 0xe4, 0xad, 0xf2, 0xdc, 0x40, 0x26,
0x15, 0x03, 0x16, 0x6f, 0x3c, 0x32, 0x05, 0x99,
0xf8, 0x25, 0x22, 0x92, 0xb9, 0xc7, 0xcd, 0x18,
0x37, 0xc2, 0xf2, 0x72, 0x31, 0xdd, 0xc4, 0xaf,
};
/* This is not the actual hmac. */
const uint8_t OTHER_HMAC[] = {
0xec, 0x64, 0x73, 0x39, 0xcf, 0x53, 0xb7, 0x08,
0x85, 0x8f, 0xb6, 0x20, 0x25, 0x98, 0x59, 0x97,
0x58, 0x8c, 0x7a, 0x80, 0x10, 0xb4, 0xc1, 0xc8,
0x8a, 0xdf, 0xe3, 0x69, 0x07, 0xd1, 0xc4, 0xdc,
};
const uint8_t ROOT_WITH_OTHER_HMAC[] = {
0xdf, 0xce, 0xf4, 0xba, 0x18, 0xe8, 0xd0, 0x1d,
0xcb, 0x3b, 0x29, 0x41, 0x44, 0x01, 0x6e, 0x72,
0xe3, 0x19, 0x9a, 0x44, 0x62, 0x44, 0x2a, 0xf1,
0xaf, 0x66, 0xb6, 0xf0, 0x61, 0x05, 0x9d, 0xc0,
};
const uint8_t DEFAULT_PCR_DIGEST[] = {
0xdf, 0xce, 0xf4, 0xba, 0x18, 0xe8, 0xd0, 0x1d,
0xcb, 0x3b, 0x29, 0x41, 0x44, 0x01, 0x6e, 0x72,
0xe3, 0x19, 0x9a, 0x44, 0x62, 0x44, 0x2a, 0xf1,
0xaf, 0x66, 0xb6, 0xf0, 0x61, 0x05, 0x9d, 0xc0,
};
/******************************************************************************/
/* Config Variables and defines for Mocks.
*/
struct pw_long_term_storage_t MOCK_pw_long_term_storage;
struct pw_log_storage_t MOCK_pw_log_storage;
int MOCK_getvar_ret = EC_SUCCESS;
int MOCK_setvar_ret = EC_SUCCESS;
const uint8_t *MOCK_rand_bytes_src;
size_t MOCK_rand_bytes_offset;
size_t MOCK_rand_bytes_len;
void (*MOCK_hash_update_cb)(const void *data, size_t len);
static void auth_hash_update_cb(const void *data, size_t len);
const uint8_t *MOCK_hmac;
size_t MOCK_DECRYPTO_init_counter;
size_t MOCK_DECRYPTO_release_counter;
#define MOCK_AES_XOR_BYTE(b) ((uint8_t)(0x77 + (b & 15)))
int MOCK_aes_fail;
int MOCK_appkey_derive_fail;
enum dcrypto_appid MOCK_hwctx_appkey;
#define PW_VALID_PCR_CRITERIA_SIZE \
(sizeof(struct valid_pcr_value_t) * PW_MAX_PCR_CRITERIA_COUNT)
/******************************************************************************/
/* Helper functions
*/
static void convert_response_to_new_version(uint8_t req_type,
struct pw_response_t *response)
{
if (response->header.version == 0) {
if (req_type == PW_TRY_AUTH) {
unsigned char *src = (unsigned char *)
(&response->data.try_auth.reset_secret);
memmove(src + PW_SECRET_SIZE, src,
PW_LEAF_PAYLOAD_SIZE);
memcpy(src, DEFAULT_LEAF.sec.reset_secret,
PW_SECRET_SIZE);
response->header.data_length += PW_SECRET_SIZE;
}
}
}
static int do_request(struct merkle_tree_t *merkle_tree,
struct pw_test_data_t *buf)
{
uint8_t req_type = buf->request.header.type.v;
int ret = pw_handle_request(merkle_tree, &buf->request, &buf->response);
size_t offset = buf->response.header.data_length +
sizeof(buf->response.header);
/* Zero out bytes that won't be sent for testing.*/
memset(buf->tpm_buffer_size + offset, 0,
sizeof(buf->tpm_buffer_size) - offset);
if (buf->request.header.version < PW_PROTOCOL_VERSION)
convert_response_to_new_version(req_type, &buf->response);
return ret;
}
static const char *pw_error_str(int code)
{
switch (code) {
case EC_SUCCESS:
return "EC_SUCCESS";
case EC_ERROR_UNKNOWN:
return "EC_ERROR_UNKNOWN";
case EC_ERROR_UNIMPLEMENTED:
return "EC_ERROR_UNIMPLEMENTED";
case PW_ERR_VERSION_MISMATCH:
return "PW_ERR_VERSION_MISMATCH";
case PW_ERR_LENGTH_INVALID:
return "PW_ERR_LENGTH_INVALID";
case PW_ERR_TYPE_INVALID:
return "PW_ERR_TYPE_INVALID";
case PW_ERR_BITS_PER_LEVEL_INVALID:
return "PW_ERR_BITS_PER_LEVEL_INVALID";
case PW_ERR_HEIGHT_INVALID:
return "PW_ERR_HEIGHT_INVALID";
case PW_ERR_LABEL_INVALID:
return "PW_ERR_LABEL_INVALID";
case PW_ERR_DELAY_SCHEDULE_INVALID:
return "PW_ERR_DELAY_SCHEDULE_INVALID";
case PW_ERR_PATH_AUTH_FAILED:
return "PW_ERR_PATH_AUTH_FAILED";
case PW_ERR_LEAF_VERSION_MISMATCH:
return "PW_ERR_LEAF_VERSION_MISMATCH";
case PW_ERR_HMAC_AUTH_FAILED:
return "PW_ERR_HMAC_AUTH_FAILED";
case PW_ERR_LOWENT_AUTH_FAILED:
return "PW_ERR_LOWENT_AUTH_FAILED";
case PW_ERR_RESET_AUTH_FAILED:
return "PW_ERR_RESET_AUTH_FAILED";
case PW_ERR_CRYPTO_FAILURE:
return "PW_ERR_CRYPTO_FAILURE";
case PW_ERR_RATE_LIMIT_REACHED:
return "PW_ERR_RATE_LIMIT_REACHED";
case PW_ERR_ROOT_NOT_FOUND:
return "PW_ERR_ROOT_NOT_FOUND";
case PW_ERR_NV_EMPTY:
return "PW_ERR_NV_EMPTY";
case PW_ERR_NV_LENGTH_MISMATCH:
return "PW_ERR_NV_LENGTH_MISMATCH";
case PW_ERR_NV_VERSION_MISMATCH:
return "PW_ERR_NV_VERSION_MISMATCH";
default:
return "?";
}
}
/* Pinweaver specific return code check. This prints the string representation
* of the return code instead of just the number.
*/
#define TEST_RET_EQ(n, m) \
do { \
int val1 = n; \
int val2 = m; \
if (val1 != val2) { \
ccprintf("%d: ASSERTION failed: %s (%d) != %s (%d)\n", \
__LINE__, pw_error_str(val1), val1, \
pw_error_str(val2), val2); \
task_dump_trace(); \
return EC_ERROR_UNKNOWN; \
} \
} while (0)
/* Allows mock functions when that don't return success / failure to have
* assertions.
*/
#define TEST_ASRT_NORET(n) \
do { \
if (!(n)) { \
int x = 0;\
ccprintf("%d: ASSERTION failed: %s\n", __LINE__, #n); \
task_dump_trace(); \
x = 1 / x; \
} \
} while (0)
/* For debugging and generating test data. */
void print_array(const uint8_t *data, size_t n) __attribute__ ((unused));
void print_array(const uint8_t *data, size_t n)
{
size_t x;
if (n > 0) {
ccprintf("uint8_t data[] = {");
for (x = 0; x < n - 1; ++x) {
if ((x & 7) != 7)
ccprintf("0x%02x, ", data[x]);
else
ccprintf("0x%02x,\n", data[x]);
}
ccprintf("0x%02x};\n", data[x]);
}
}
/* For exporting structs. This is useful for validating the results of crypto
* operations.
*/
void print_hex(const uint8_t *data, size_t n) __attribute__ ((unused));
void print_hex(const uint8_t *data, size_t n)
{
size_t x;
for (x = 0; x < n; ++x)
ccprintf("%02x ", data[x]);
}
/* Initialize the log.
* For num_operations:
* < 0 only zero out the storage.
* == 0 only initialize the tree
* > 0 cyclically applies operations in the following order:
* insert
* auth failed
* auth success
* remove
* So for num_operations == 4 the complete set of operations will be written to
* the log.
*/
static void setup_storage(int num_operations)
{
MOCK_getvar_ret = EC_SUCCESS;
MOCK_setvar_ret = EC_SUCCESS;
memset(&MOCK_pw_long_term_storage, 0,
sizeof(MOCK_pw_long_term_storage));
memset(&MOCK_pw_log_storage, 0, sizeof(MOCK_pw_log_storage));
if (num_operations < 0)
return;
--num_operations;
store_merkle_tree(&EMPTY_TREE);
while (num_operations > 0) {
--num_operations;
log_insert_leaf(DEFAULT_LEAF.pub.label, ROOT_WITH_DEFAULT_HMAC,
DEFAULT_HMAC);
if (num_operations < 0)
return;
--num_operations;
log_auth(DEFAULT_LEAF.pub.label, ROOT_WITH_OTHER_HMAC,
PW_ERR_LOWENT_AUTH_FAILED,
(struct pw_timestamp_t) {7, 99});
if (num_operations < 0)
return;
--num_operations;
log_auth(DEFAULT_LEAF.pub.label, ROOT_WITH_DEFAULT_HMAC,
EC_SUCCESS,
(struct pw_timestamp_t) {10, 100});
if (num_operations < 0)
return;
--num_operations;
log_remove_leaf(DEFAULT_LEAF.pub.label, EMPTY_TREE.root);
}
}
static void setup_default_empty_path(uint8_t hashes[][PW_HASH_SIZE])
{
uint8_t num_siblings = (1 << EMPTY_TREE.bits_per_level.v) - 1;
const uint8_t level_hashes[5][PW_HASH_SIZE] = {
/* Values for level 5 are all 0 for empty. */
/* SHA256 for level 5, values for level 4. */
{0x38, 0x72, 0x3a, 0x2e, 0x5e, 0x8a, 0x17, 0xaa,
0x79, 0x50, 0xdc, 0x00, 0x82, 0x09, 0x94, 0x4e,
0x89, 0x8f, 0x69, 0xa7, 0xbd, 0x10, 0xa2, 0x3c,
0x83, 0x9d, 0x34, 0x1e, 0x93, 0x5f, 0xd5, 0xca},
/* SHA256 for level 4, values for level 3. */
{0xfe, 0xc1, 0x2b, 0x09, 0x33, 0x31, 0x28, 0x34,
0x79, 0x1f, 0x07, 0x64, 0x1a, 0xed, 0x30, 0x53,
0x11, 0x1f, 0x15, 0x3e, 0x1e, 0x3e, 0xd1, 0xf0,
0xcd, 0x16, 0xcb, 0x39, 0x25, 0xfd, 0x5f, 0x84},
/* SHA256 for level 3, values for level 2. */
{0xb6, 0xd4, 0x9c, 0x89, 0x76, 0x45, 0x9c, 0xe9,
0x9c, 0x0b, 0xad, 0x5d, 0x71, 0xdf, 0x92, 0x77,
0xf6, 0x82, 0x62, 0x63, 0x81, 0x9f, 0xc9, 0x2f,
0x61, 0x9c, 0x29, 0x67, 0x52, 0x37, 0x01, 0x51},
/* SHA256 for level 2, values for level 1. */
{0x87, 0xeb, 0x61, 0x6b, 0x2c, 0x42, 0x07, 0x5e,
0x70, 0x2d, 0x48, 0x49, 0xf2, 0xe0, 0x13, 0x11,
0xc4, 0xe6, 0x98, 0xfa, 0x22, 0x7e, 0x65, 0xc6,
0x66, 0x33, 0x6b, 0xb6, 0xd7, 0xb9, 0x45, 0xfa},
/* SHA256 for level 1, values for level 0. */
{0x80, 0x91, 0x04, 0x3f, 0x6c, 0x29, 0x06, 0x35,
0x86, 0x99, 0x21, 0x88, 0x1f, 0xd9, 0xae, 0xb8,
0x35, 0x94, 0x26, 0x19, 0x64, 0x68, 0x4f, 0x4f,
0x4c, 0x66, 0x13, 0xa9, 0x66, 0x69, 0x25, 0x0e},};
uint8_t hx;
uint8_t kx;
/* Empty first level. */
memset(hashes, 0, num_siblings * PW_HASH_SIZE);
hashes += num_siblings;
for (hx = 1; hx < EMPTY_TREE.height.v; ++hx) {
for (kx = 0; kx < num_siblings; ++kx) {
memcpy(hashes, level_hashes[hx - 1], PW_HASH_SIZE);
++hashes;
}
}
}
static void setup_default_unimported_leaf_data_and_hashes(
const struct leaf_data_t *leaf_data,
const uint8_t hmac[PW_HASH_SIZE],
const struct leaf_header_t *header,
struct unimported_leaf_data_t *data)
{
memcpy(&data->head, header, sizeof(*header));
memcpy(data->hmac, hmac, sizeof(data->hmac));
memcpy(data->iv, DEFAULT_IV, sizeof(DEFAULT_IV));
memcpy(data->payload, &leaf_data->pub, header->pub_len);
DCRYPTO_aes_ctr(data->payload + header->pub_len,
EMPTY_TREE.wrap_key, sizeof(EMPTY_TREE.wrap_key) * 8,
DEFAULT_IV, (const uint8_t *)&leaf_data->sec,
header->sec_len);
setup_default_empty_path((void *)(data->payload + header->pub_len +
header->sec_len));
}
static void setup_reset_tree_defaults(struct merkle_tree_t *merkle_tree,
struct pw_request_t *request)
{
MOCK_DECRYPTO_init_counter = 0;
MOCK_DECRYPTO_release_counter = 0;
memset(merkle_tree, 0, sizeof(*merkle_tree));
memset(&MOCK_pw_long_term_storage, 0,
sizeof(MOCK_pw_long_term_storage));
memset(&MOCK_pw_log_storage, 0, sizeof(MOCK_pw_log_storage));
request->header.version = PW_PROTOCOL_VERSION;
request->header.type.v = PW_RESET_TREE;
request->header.data_length = sizeof(struct pw_request_reset_tree_t);
request->data.reset_tree.bits_per_level.v = 2; /* k = 4 */
request->data.reset_tree.height.v = 6; /* L = 12 */
MOCK_rand_bytes_src = (uint8_t *)EMPTY_TREE.key_derivation_nonce;
MOCK_rand_bytes_offset = 0;
MOCK_rand_bytes_len = sizeof(EMPTY_TREE.key_derivation_nonce);
MOCK_appkey_derive_fail = EC_SUCCESS;
MOCK_setvar_ret = EC_SUCCESS;
}
static void setup_insert_leaf_defaults(struct merkle_tree_t *merkle_tree,
struct pw_request_t *request)
{
MOCK_DECRYPTO_init_counter = 0;
MOCK_DECRYPTO_release_counter = 0;
memcpy(merkle_tree, &EMPTY_TREE, sizeof(EMPTY_TREE));
memset(&MOCK_pw_log_storage, 0, sizeof(MOCK_pw_log_storage));
request->header.version = PW_PROTOCOL_VERSION;
request->header.type.v = PW_INSERT_LEAF;
request->header.data_length = sizeof(struct pw_request_insert_leaf_t) +
get_path_auxiliary_hash_count(&EMPTY_TREE) *
PW_HASH_SIZE;
request->data.insert_leaf.label.v = DEFAULT_LEAF.pub.label.v;
memcpy(&request->data.insert_leaf.delay_schedule,
&DEFAULT_LEAF.pub.delay_schedule,
sizeof(DEFAULT_LEAF.pub.delay_schedule));
memcpy(&request->data.insert_leaf.valid_pcr_criteria,
&DEFAULT_LEAF.pub.valid_pcr_criteria,
sizeof(DEFAULT_LEAF.pub.valid_pcr_criteria));
memcpy(&request->data.insert_leaf.low_entropy_secret,
&DEFAULT_LEAF.sec.low_entropy_secret,
sizeof(DEFAULT_LEAF.sec.low_entropy_secret));
memcpy(&request->data.insert_leaf.high_entropy_secret,
&DEFAULT_LEAF.sec.high_entropy_secret,
sizeof(DEFAULT_LEAF.sec.high_entropy_secret));
memcpy(&request->data.insert_leaf.reset_secret,
&DEFAULT_LEAF.sec.reset_secret,
sizeof(DEFAULT_LEAF.sec.reset_secret));
setup_default_empty_path(request->data.insert_leaf.path_hashes);
MOCK_rand_bytes_src = DEFAULT_IV;
MOCK_rand_bytes_offset = 0;
MOCK_rand_bytes_len = sizeof(DEFAULT_IV);
MOCK_hash_update_cb = 0;
MOCK_hmac = DEFAULT_HMAC;
MOCK_aes_fail = 0;
MOCK_setvar_ret = EC_SUCCESS;
}
static void setup_remove_leaf_defaults(struct merkle_tree_t *merkle_tree,
struct pw_request_t *request)
{
MOCK_DECRYPTO_init_counter = 0;
MOCK_DECRYPTO_release_counter = 0;
memcpy(merkle_tree, &EMPTY_TREE, sizeof(EMPTY_TREE));
memcpy(merkle_tree->root, ROOT_WITH_DEFAULT_HMAC,
sizeof(ROOT_WITH_DEFAULT_HMAC));
memset(&MOCK_pw_log_storage, 0, sizeof(MOCK_pw_log_storage));
request->header.version = PW_PROTOCOL_VERSION;
request->header.type.v = PW_REMOVE_LEAF;
request->header.data_length =
sizeof(struct pw_request_remove_leaf_t) +
get_path_auxiliary_hash_count(&EMPTY_TREE) *
PW_HASH_SIZE;
request->data.remove_leaf.leaf_location = DEFAULT_LEAF.pub.label;
memcpy(request->data.remove_leaf.leaf_hmac, DEFAULT_HMAC,
sizeof(request->data.remove_leaf.leaf_hmac));
setup_default_empty_path(request->data.remove_leaf.path_hashes);
MOCK_setvar_ret = EC_SUCCESS;
}
static void setup_try_auth_defaults_with_leaf(
const struct leaf_data_t *leaf_data,
uint8_t protocol_version,
uint8_t minor_version,
struct merkle_tree_t *merkle_tree,
struct pw_request_t *request)
{
struct leaf_header_t header = DEFAULT_HEAD;
MOCK_DECRYPTO_init_counter = 0;
MOCK_DECRYPTO_release_counter = 0;
memcpy(merkle_tree, &EMPTY_TREE, sizeof(EMPTY_TREE));
if (leaf_data->pub.attempt_count.v != 6 &&
leaf_data->pub.attempt_count.v != 10) {
memcpy(merkle_tree->root, ROOT_WITH_DEFAULT_HMAC,
sizeof(ROOT_WITH_DEFAULT_HMAC));
/* Gets overwritten by auth_hash_update_cb. */
MOCK_hmac = DEFAULT_HMAC;
} else
/* Gets overwritten by auth_hash_update_cb. */
MOCK_hmac = EMPTY_HMAC;
header.leaf_version.minor = minor_version;
memset(&MOCK_pw_log_storage, 0, sizeof(MOCK_pw_log_storage));
request->header.version = protocol_version;
request->header.type.v = PW_TRY_AUTH;
request->header.data_length =
sizeof(struct pw_request_try_auth_t) +
PW_LEAF_PAYLOAD_SIZE +
get_path_auxiliary_hash_count(&EMPTY_TREE) *
PW_HASH_SIZE;
if (minor_version == 0) {
header.pub_len -= PW_VALID_PCR_CRITERIA_SIZE;
request->header.data_length -= PW_VALID_PCR_CRITERIA_SIZE;
}
memcpy(request->data.try_auth.low_entropy_secret,
DEFAULT_LEAF.sec.low_entropy_secret,
sizeof(request->data.try_auth.low_entropy_secret));
setup_default_unimported_leaf_data_and_hashes(
leaf_data, MOCK_hmac, &header,
&request->data.try_auth.unimported_leaf_data);
force_restart_count(0);
force_time((timestamp_t){.val = 0});
MOCK_rand_bytes_src = DEFAULT_IV;
MOCK_rand_bytes_offset = 0;
MOCK_rand_bytes_len = sizeof(DEFAULT_IV);
MOCK_hash_update_cb = auth_hash_update_cb;
MOCK_aes_fail = 0;
MOCK_setvar_ret = EC_SUCCESS;
}
static void setup_try_auth_defaults(struct merkle_tree_t *merkle_tree,
struct pw_request_t *request)
{
setup_try_auth_defaults_with_leaf(&DEFAULT_LEAF, PW_PROTOCOL_VERSION,
PW_LEAF_MINOR_VERSION, merkle_tree,
request);
}
static void setup_reset_auth_defaults(struct merkle_tree_t *merkle_tree,
struct pw_request_t *request)
{
struct leaf_public_data_t *pub =
(void *)request->data.reset_auth.unimported_leaf_data
.payload;
MOCK_DECRYPTO_init_counter = 0;
MOCK_DECRYPTO_release_counter = 0;
memcpy(merkle_tree, &EMPTY_TREE, sizeof(EMPTY_TREE));
memset(&MOCK_pw_log_storage, 0, sizeof(MOCK_pw_log_storage));
request->header.version = PW_PROTOCOL_VERSION;
request->header.type.v = PW_RESET_AUTH;
request->header.data_length =
sizeof(struct pw_request_reset_auth_t) +
PW_LEAF_PAYLOAD_SIZE +
get_path_auxiliary_hash_count(&EMPTY_TREE) *
PW_HASH_SIZE;
memcpy(request->data.reset_auth.reset_secret,
DEFAULT_LEAF.sec.reset_secret,
sizeof(request->data.reset_auth.reset_secret));
setup_default_unimported_leaf_data_and_hashes(
&DEFAULT_LEAF, EMPTY_HMAC, &DEFAULT_HEAD,
&request->data.try_auth.unimported_leaf_data);
pub->attempt_count.v = 6;
MOCK_rand_bytes_src = DEFAULT_IV;
MOCK_rand_bytes_offset = 0;
MOCK_rand_bytes_len = sizeof(DEFAULT_IV);
MOCK_hash_update_cb = auth_hash_update_cb;
MOCK_hmac = EMPTY_HMAC; /* Gets overwritten by auth_hash_update_cb. */
MOCK_aes_fail = 0;
MOCK_setvar_ret = EC_SUCCESS;
}
static void setup_get_log_defaults(struct merkle_tree_t *merkle_tree,
struct pw_request_t *request)
{
MOCK_DECRYPTO_init_counter = 0;
MOCK_DECRYPTO_release_counter = 0;
memcpy(merkle_tree, &EMPTY_TREE, sizeof(*merkle_tree));
request->header.version = PW_PROTOCOL_VERSION;
request->header.type.v = PW_GET_LOG;
request->header.data_length = sizeof(struct pw_request_get_log_t);
/* Chosen not to match any of the root hashes in the log. */
memcpy(request->data.get_log.root, OTHER_HMAC,
sizeof(OTHER_HMAC));
setup_storage(1);
}
static void setup_log_replay_defaults_with_leaf(
const struct leaf_data_t *leaf_data,
struct merkle_tree_t *merkle_tree,
struct pw_request_t *request)
{
MOCK_DECRYPTO_init_counter = 0;
MOCK_DECRYPTO_release_counter = 0;
memcpy(merkle_tree, &EMPTY_TREE, sizeof(*merkle_tree));
if (leaf_data->pub.attempt_count.v != 6 &&
leaf_data->pub.attempt_count.v != 10)
/* Gets overwritten by auth_hash_update_cb. */
MOCK_hmac = DEFAULT_HMAC;
else
/* Gets overwritten by auth_hash_update_cb. */
MOCK_hmac = EMPTY_HMAC;
request->header.version = PW_PROTOCOL_VERSION;
request->header.type.v = PW_LOG_REPLAY;
request->header.data_length =
sizeof(struct pw_request_log_replay_t) +
PW_LEAF_PAYLOAD_SIZE +
get_path_auxiliary_hash_count(&EMPTY_TREE) *
PW_HASH_SIZE;
memcpy(request->data.log_replay.log_root, ROOT_WITH_DEFAULT_HMAC,
sizeof(ROOT_WITH_DEFAULT_HMAC));
setup_default_unimported_leaf_data_and_hashes(
leaf_data, MOCK_hmac, &DEFAULT_HEAD,
&request->data.try_auth.unimported_leaf_data);
MOCK_hash_update_cb = auth_hash_update_cb;
setup_storage(4);
}
static void setup_log_replay_defaults(struct merkle_tree_t *merkle_tree,
struct pw_request_t *request)
{
setup_log_replay_defaults_with_leaf(&DEFAULT_LEAF, merkle_tree,
request);
}
/* Increases the length of the pub and cipher_text by 4 each. */
static void setup_mock_future_version(
struct unimported_leaf_data_t *unimported_leaf_data,
uint16_t *req_length)
{
uint8_t *start = unimported_leaf_data->payload;
const uint8_t size_increase = 4;
const uint16_t cipher_text_offset = unimported_leaf_data->head.pub_len;
const uint16_t hashes_offset = cipher_text_offset +
unimported_leaf_data->head.sec_len;
/* Shift hashes by 8*/
memmove(start + hashes_offset + size_increase * 2,
start + hashes_offset,
get_path_auxiliary_hash_count(&EMPTY_TREE) *
PW_HASH_SIZE);
/* Shift cipher_text by 4*/
memmove(start + cipher_text_offset + size_increase,
start + cipher_text_offset,
unimported_leaf_data->head.sec_len);
++unimported_leaf_data->head.leaf_version.minor;
unimported_leaf_data->head.pub_len += size_increase;
unimported_leaf_data->head.sec_len += size_increase;
*req_length += size_increase * 2;
}
static int test_handle_short_msg(struct merkle_tree_t *merkle_tree,
struct pw_test_data_t *buf,
const uint8_t root[PW_HASH_SIZE])
{
int ret = do_request(merkle_tree, buf);
TEST_RET_EQ(buf->response.header.result_code, ret);
TEST_ASSERT(buf->response.header.version == PW_PROTOCOL_VERSION);
TEST_ASSERT(buf->response.header.data_length == 0);
TEST_ASSERT_ARRAY_EQ(buf->response.header.root, root, PW_HASH_SIZE);
TEST_ASSERT_ARRAY_EQ(buf->response.header.root, merkle_tree->root,
PW_HASH_SIZE);
return ret;
}
/* Changes MOCK_hmac in a deterministic way based on the contents of the data
* with the goal of making it easier to catch bugs in the handling of try_auth
* and reset_auth requests.
*/
static void auth_hash_update_cb(const void *data, size_t len)
{
const struct leaf_data_t *leaf_data = data;
if (len != sizeof(leaf_data->pub) && len != sizeof(leaf_data->pub) + 4)
return;
switch (leaf_data->pub.attempt_count.v) {
case 10:
case 6:
MOCK_hmac = EMPTY_HMAC;
break;
case 16:
MOCK_hmac = OTHER_HMAC;
break;
default:
MOCK_hmac = DEFAULT_HMAC;
break;
}
}
/******************************************************************************/
/* Mock implementations of TPM functionality.
*/
void get_storage_seed(void *buf, size_t *len)
{
*len = *len < sizeof(DEFAULT_STORAGE_SEED) ? *len :
sizeof(DEFAULT_STORAGE_SEED);
memcpy(buf, DEFAULT_STORAGE_SEED, *len);
}
uint8_t get_current_pcr_digest(const uint8_t bitmask[2],
uint8_t sha256_of_selected_pcr[32])
{
memcpy(sha256_of_selected_pcr, DEFAULT_PCR_DIGEST, 32);
return 0;
}
/******************************************************************************/
/* Mock implementations of nvmem_vars functionality.
*/
const struct tuple *getvar(const uint8_t *key, uint8_t key_len)
{
struct tuple *var = NULL;
size_t i;
const struct {
size_t key_len;
const void *key;
size_t val_size;
const void *val;
} vars[] = {
{sizeof(PW_TREE_VAR) - 1, PW_TREE_VAR,
sizeof(MOCK_pw_long_term_storage), &MOCK_pw_long_term_storage},
{sizeof(PW_LOG_VAR0) - 1, PW_LOG_VAR0,
sizeof(MOCK_pw_log_storage), &MOCK_pw_log_storage},
};
if (!key || !key_len)
return NULL;
if (MOCK_getvar_ret != EC_SUCCESS)
return NULL;
for (i = 0; i < ARRAY_SIZE(vars); i++) {
if ((key_len != vars[i].key_len) ||
memcmp(key, vars[i].key, key_len)) {
continue;
}
var = malloc(sizeof(struct tuple) + key_len + vars[i].val_size);
var->flags = 0;
var->val_len = vars[i].val_size;
memcpy(var->data_ + var->key_len, vars[i].val, var->val_len);
break;
}
return var;
}
void freevar(const struct tuple *var)
{
if (!var)
return;
/* This typecast is OK because we know that 'var' came from malloc. */
free((void *)var);
}
const uint8_t *tuple_val(const struct tuple *tpl)
{
return tpl->data_ + tpl->key_len;
}
int setvar(const uint8_t *key, uint8_t key_len, const uint8_t *val,
uint8_t val_len)
{
if (MOCK_setvar_ret != EC_SUCCESS)
return MOCK_setvar_ret;
if (key_len == (sizeof(PW_TREE_VAR) - 1) &&
memcmp(key, PW_TREE_VAR, (sizeof(PW_TREE_VAR) - 1)) == 0) {
TEST_ASSERT(val_len == sizeof(MOCK_pw_long_term_storage));
memcpy(&MOCK_pw_long_term_storage, val, val_len);
return EC_SUCCESS;
} else if (key_len == (sizeof(PW_LOG_VAR0) - 1) &&
memcmp(key, PW_LOG_VAR0, (sizeof(PW_LOG_VAR0) - 1)) == 0) {
TEST_ASSERT(val_len == sizeof(struct pw_log_storage_t));
memcpy(&MOCK_pw_log_storage, val, val_len);
return EC_SUCCESS;
} else
return EC_ERROR_UNKNOWN;
}
/******************************************************************************/
/* Mock implementations of TRNG functionality.
*/
void rand_bytes(void *buffer, size_t len)
{
if (!MOCK_rand_bytes_src)
return;
TEST_ASRT_NORET(len <= MOCK_rand_bytes_len - MOCK_rand_bytes_offset);
memcpy(buffer, MOCK_rand_bytes_src + MOCK_rand_bytes_offset, len);
MOCK_rand_bytes_offset += len;
if (MOCK_rand_bytes_len == MOCK_rand_bytes_offset)
MOCK_rand_bytes_offset = 0;
}
/******************************************************************************/
/* Mock implementations of Dcrypto functionality.
*/
void HASH_update(struct HASH_CTX *ctx, const void *data, size_t len)
{
if (MOCK_hash_update_cb)
MOCK_hash_update_cb(data, len);
if (ctx)
SHA256_update(ctx, data, len);
}
uint8_t *HASH_final(struct HASH_CTX *ctx)
{
++MOCK_DECRYPTO_release_counter;
return SHA256_final(ctx);
}
void DCRYPTO_SHA256_init(LITE_SHA256_CTX *ctx, uint32_t sw_required)
{
SHA256_init(ctx);
++MOCK_DECRYPTO_init_counter;
}
void DCRYPTO_HMAC_SHA256_init(LITE_HMAC_CTX *ctx, const void *key,
unsigned int len)
{
TEST_ASRT_NORET(len == sizeof(EMPTY_TREE.hmac_key));
TEST_ASRT_NORET(memcmp(key, EMPTY_TREE.hmac_key,
sizeof(EMPTY_TREE.hmac_key)) == 0);
SHA256_init(&ctx->hash);
++MOCK_DECRYPTO_init_counter;
}
const uint8_t *DCRYPTO_HMAC_final(LITE_HMAC_CTX *ctx)
{
++MOCK_DECRYPTO_release_counter;
return MOCK_hmac;
}
/* Perform a symmetric transformation of the data to simulate AES without
* requiring a full AES-CTR implementation.
*
* 1 for success 0 for fail
*/
int DCRYPTO_aes_ctr(uint8_t *out, const uint8_t *key, uint32_t key_bits,
const uint8_t *iv, const uint8_t *in, size_t in_len)
{
size_t x;
if (MOCK_aes_fail) {
--MOCK_aes_fail;
return 0;
}
TEST_ASSERT(key_bits == 256);
TEST_ASSERT_ARRAY_EQ(key, EMPTY_TREE.wrap_key,
sizeof(EMPTY_TREE.wrap_key));
TEST_ASSERT_ARRAY_EQ(iv, DEFAULT_IV, sizeof(DEFAULT_IV));
TEST_ASSERT(in_len == sizeof(struct leaf_sensitive_data_t));
for (x = 0; x < in_len; ++x)
out[x] = MOCK_AES_XOR_BYTE(x) ^ in[x];
return 1;
}
/* 1 for success 0 for fail*/
int DCRYPTO_appkey_init(enum dcrypto_appid appid, struct APPKEY_CTX *ctx)
{
MOCK_hwctx_appkey = appid;
return 1;
}
void DCRYPTO_appkey_finish(struct APPKEY_CTX *ctx)
{
MOCK_hwctx_appkey = 0;
}
/* 1 for success 0 for fail*/
int DCRYPTO_appkey_derive(enum dcrypto_appid appid, const uint32_t input[8],
uint32_t output[8])
{
TEST_ASSERT(appid == PINWEAVER);
TEST_ASSERT(MOCK_hwctx_appkey == appid);
if (MOCK_appkey_derive_fail != EC_SUCCESS)
return 0;
if (input[6] ^ DEFAULT_STORAGE_SEED[6])
memcpy(output, EMPTY_TREE.hmac_key,
sizeof(EMPTY_TREE.hmac_key));
else
memcpy(output, EMPTY_TREE.wrap_key,
sizeof(EMPTY_TREE.wrap_key));
return 1;
}
/******************************************************************************/
/* Reusable test cases.
*/
static int check_dcrypto_mutex_usage(void)
{
if (MOCK_DECRYPTO_init_counter == MOCK_DECRYPTO_release_counter)
return EC_SUCCESS;
ccprintf("ASSERTION failed: DCRYPTO init(%d) != DCRYPTO release(%d)\n",
MOCK_DECRYPTO_init_counter, MOCK_DECRYPTO_release_counter);
return EC_ERROR_UNKNOWN;
}
static int invalid_length_with_leaf_head(
size_t head_offset,
void (*defaults)(struct merkle_tree_t *, struct pw_request_t *))
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
struct leaf_header_t *req_head = (void *)&buf + head_offset;
uint8_t old_root[PW_HASH_SIZE];
defaults(&merkle_tree, &buf.request);
memcpy(old_root, merkle_tree.root, sizeof(old_root));
buf.request.header.data_length = 0;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, old_root),
PW_ERR_LENGTH_INVALID);
defaults(&merkle_tree, &buf.request);
++buf.request.header.data_length;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, old_root),
PW_ERR_LENGTH_INVALID);
defaults(&merkle_tree, &buf.request);
++req_head->pub_len;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, old_root),
PW_ERR_LENGTH_INVALID);
defaults(&merkle_tree, &buf.request);
++req_head->leaf_version.minor;
--req_head->pub_len;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, old_root),
PW_ERR_LENGTH_INVALID);
return check_dcrypto_mutex_usage();
}
/******************************************************************************/
/* Basic operation test cases.
*/
static int get_path_auxiliary_hash_count_test(void)
{
struct merkle_tree_t merkle_tree;
memcpy(&merkle_tree, &EMPTY_TREE, sizeof(merkle_tree));
TEST_ASSERT(get_path_auxiliary_hash_count(&merkle_tree) ==
EMPTY_TREE_PATH_LENGTH);
return EC_SUCCESS;
}
static int compute_hash_test(void)
{
const uint8_t hashes[4][PW_HASH_SIZE] = {
{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
};
const struct {
struct index_t index;
uint8_t result[PW_HASH_SIZE];
} test_cases[] = {
{{0},
{0xd5, 0xd9, 0x25, 0xb6, 0xa9, 0x90, 0x24, 0x12,
0x39, 0x0e, 0xfa, 0xd4, 0x8d, 0x55, 0x45, 0xf3,
0x23, 0x6c, 0x6d, 0xff, 0xcc, 0xc8, 0xe1, 0x39,
0xc7, 0xc3, 0x25, 0xf0, 0xd2, 0xa8, 0xf2, 0x0c}
},
{{1},
{0x64, 0x3e, 0x56, 0xbc, 0xb9, 0xda, 0x18, 0xaf,
0xa0, 0x8c, 0x1f, 0xf8, 0x5e, 0xba, 0x58, 0xd0,
0xe1, 0x99, 0x61, 0xe0, 0xe2, 0x12, 0xe9, 0x14,
0xb5, 0x33, 0x46, 0x35, 0x52, 0x1e, 0xaf, 0x91}
},
{{3},
{0xd0, 0x90, 0xc7, 0x3d, 0x12, 0xfb, 0xbc, 0xbc,
0x78, 0xcc, 0xbe, 0x58, 0x21, 0x14, 0xcf, 0x38,
0x68, 0x49, 0x20, 0xe9, 0x61, 0xcb, 0x35, 0xc4,
0x95, 0xb0, 0x14, 0x5a, 0x35, 0x43, 0x3e, 0x73}
},
};
uint8_t result[PW_HASH_SIZE];
size_t x;
for (x = 0; x < ARRAY_SIZE(test_cases); ++x) {
compute_hash(hashes, 3, test_cases[x].index, hashes[3], result);
TEST_ASSERT_ARRAY_EQ(result, test_cases[x].result,
sizeof(result));
}
return EC_SUCCESS;
}
/******************************************************************************/
/* Header validation test cases.
*/
static int handle_request_version_mismatch(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_reset_tree_defaults(&merkle_tree, &buf.request);
buf.request.header.version = PW_PROTOCOL_VERSION + 1;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_HMAC),
PW_ERR_VERSION_MISMATCH);
return EC_SUCCESS;
}
static int handle_request_invalid_type(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
memcpy(&merkle_tree, &EMPTY_TREE, sizeof(merkle_tree));
memset(&buf.response, 0x77, sizeof(buf.response));
buf.request.header.version = PW_PROTOCOL_VERSION;
buf.request.header.type.v = PW_MT_INVALID;
buf.request.header.data_length = 0;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root),
PW_ERR_TYPE_INVALID);
return EC_SUCCESS;
}
/******************************************************************************/
/* Reset Tree test cases.
*/
static int handle_reset_tree_invalid_length(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_reset_tree_defaults(&merkle_tree, &buf.request);
++buf.request.header.data_length;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_HMAC),
PW_ERR_LENGTH_INVALID);
return check_dcrypto_mutex_usage();
}
static int handle_reset_tree_bits_per_level_invalid(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_reset_tree_defaults(&merkle_tree, &buf.request);
/* Test lower bound. */
buf.request.data.reset_tree.bits_per_level.v = BITS_PER_LEVEL_MIN - 1;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root),
PW_ERR_BITS_PER_LEVEL_INVALID);
setup_reset_tree_defaults(&merkle_tree, &buf.request);
/* Test upper bound. */
buf.request.data.reset_tree.bits_per_level.v = BITS_PER_LEVEL_MAX + 1;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_HMAC),
PW_ERR_BITS_PER_LEVEL_INVALID);
return check_dcrypto_mutex_usage();
}
static int handle_reset_tree_height_invalid(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_reset_tree_defaults(&merkle_tree, &buf.request);
/* Test lower bound. */
buf.request.data.reset_tree.height.v = HEIGHT_MIN - 1;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root),
PW_ERR_HEIGHT_INVALID);
setup_reset_tree_defaults(&merkle_tree, &buf.request);
/* Test upper bound. */
buf.request.data.reset_tree.height.v =
HEIGHT_MAX(buf.request.data.reset_tree
.bits_per_level.v) + 1;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_HMAC),
PW_ERR_HEIGHT_INVALID);
return check_dcrypto_mutex_usage();
}
static int handle_reset_tree_crypto_failure(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_reset_tree_defaults(&merkle_tree, &buf.request);
/* Test lower bound. */
MOCK_appkey_derive_fail = PW_ERR_CRYPTO_FAILURE;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_HMAC),
PW_ERR_CRYPTO_FAILURE);
return check_dcrypto_mutex_usage();
}
static int handle_reset_tree_nv_fail(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_reset_tree_defaults(&merkle_tree, &buf.request);
MOCK_setvar_ret = PW_ERR_NV_LENGTH_MISMATCH;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root),
PW_ERR_NV_LENGTH_MISMATCH);
return EC_SUCCESS;
}
static int handle_reset_tree_success(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_reset_tree_defaults(&merkle_tree, &buf.request);
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root),
EC_SUCCESS);
TEST_ASSERT_ARRAY_EQ((uint8_t *)&merkle_tree, (uint8_t *)&EMPTY_TREE,
sizeof(EMPTY_TREE));
TEST_ASSERT(MOCK_pw_long_term_storage.storage_version ==
PW_STORAGE_VERSION);
TEST_ASSERT(MOCK_pw_long_term_storage.bits_per_level.v ==
EMPTY_TREE.bits_per_level.v);
TEST_ASSERT(MOCK_pw_long_term_storage.height.v ==
EMPTY_TREE.height.v);
TEST_ASSERT_ARRAY_EQ(MOCK_pw_long_term_storage.key_derivation_nonce,
EMPTY_TREE.key_derivation_nonce,
sizeof(EMPTY_TREE.key_derivation_nonce));
TEST_ASSERT(MOCK_pw_log_storage.storage_version == PW_STORAGE_VERSION);
TEST_ASSERT(MOCK_pw_log_storage.entries[0].type.v == PW_RESET_TREE);
TEST_ASSERT_ARRAY_EQ(MOCK_pw_log_storage.entries[0].root,
EMPTY_TREE.root, sizeof(EMPTY_TREE.root));
return check_dcrypto_mutex_usage();
}
/******************************************************************************/
/* Insert leaf test cases.
*/
static int handle_insert_leaf_invalid_length(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_insert_leaf_defaults(&merkle_tree, &buf.request);
++buf.request.header.data_length;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root),
PW_ERR_LENGTH_INVALID);
return check_dcrypto_mutex_usage();
}
static int handle_insert_leaf_label_invalid(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_insert_leaf_defaults(&merkle_tree, &buf.request);
buf.request.data.insert_leaf.label.v |= 0x030000;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root),
PW_ERR_LABEL_INVALID);
return check_dcrypto_mutex_usage();
}
static int handle_insert_leaf_delay_schedule_invalid(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
struct delay_schedule_entry_t (*ds)[PW_SCHED_COUNT] =
&buf.request.data.insert_leaf.delay_schedule;
setup_insert_leaf_defaults(&merkle_tree, &buf.request);
/* Non-increasing attempt_count. */
(*ds)[1].attempt_count.v = 0;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root),
PW_ERR_DELAY_SCHEDULE_INVALID);
setup_insert_leaf_defaults(&merkle_tree, &buf.request);
/* Non-increasing time_diff. */
(*ds)[1].time_diff.v = 0;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root),
PW_ERR_DELAY_SCHEDULE_INVALID);
setup_insert_leaf_defaults(&merkle_tree, &buf.request);
/* attempt_count noise. */
(*ds)[14].attempt_count.v = 99;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root),
PW_ERR_DELAY_SCHEDULE_INVALID);
setup_insert_leaf_defaults(&merkle_tree, &buf.request);
/* time_diff noise. */
(*ds)[14].time_diff.v = 99;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root),
PW_ERR_DELAY_SCHEDULE_INVALID);
setup_insert_leaf_defaults(&merkle_tree, &buf.request);
/* Empty delay_schedule. */
memset(&(*ds)[0], 0, sizeof(*ds));
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root),
PW_ERR_DELAY_SCHEDULE_INVALID);
return check_dcrypto_mutex_usage();
}
static int handle_insert_leaf_path_auth_failed(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_insert_leaf_defaults(&merkle_tree, &buf.request);
buf.request.data.insert_leaf.path_hashes[0][0] ^= 0xff;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root),
PW_ERR_PATH_AUTH_FAILED);
return check_dcrypto_mutex_usage();
}
static int handle_insert_leaf_crypto_failure(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_insert_leaf_defaults(&merkle_tree, &buf.request);
MOCK_aes_fail = 1;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root),
PW_ERR_CRYPTO_FAILURE);
return check_dcrypto_mutex_usage();
}
static int handle_insert_leaf_nv_fail(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_insert_leaf_defaults(&merkle_tree, &buf.request);
MOCK_setvar_ret = PW_ERR_NV_LENGTH_MISMATCH;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root),
PW_ERR_NV_LENGTH_MISMATCH);
return EC_SUCCESS;
}
static int handle_insert_leaf_success(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
size_t x;
const uint8_t *plain_text = (const uint8_t *)&DEFAULT_LEAF.sec;
struct wrapped_leaf_data_t *wrapped_leaf_data =
(void *)&buf.response.data.insert_leaf
.unimported_leaf_data;
setup_insert_leaf_defaults(&merkle_tree, &buf.request);
TEST_RET_EQ(do_request(&merkle_tree, &buf), EC_SUCCESS);
TEST_ASSERT(buf.response.header.version == PW_PROTOCOL_VERSION);
TEST_ASSERT(buf.response.header.data_length ==
sizeof(buf.response.data.insert_leaf) +
PW_LEAF_PAYLOAD_SIZE);
TEST_RET_EQ(buf.response.header.result_code, EC_SUCCESS);
TEST_ASSERT_ARRAY_EQ(buf.response.header.root, ROOT_WITH_DEFAULT_HMAC,
sizeof(ROOT_WITH_DEFAULT_HMAC));
TEST_ASSERT_ARRAY_EQ(buf.response.header.root, merkle_tree.root,
PW_HASH_SIZE);
TEST_ASSERT_ARRAY_EQ(
buf.response.data.insert_leaf.unimported_leaf_data.hmac,
DEFAULT_HMAC, sizeof(DEFAULT_HMAC));
TEST_ASSERT_ARRAY_EQ(
(uint8_t *)&wrapped_leaf_data->pub,
(uint8_t *)&DEFAULT_LEAF.pub, sizeof(DEFAULT_LEAF.pub));
for (x = 0; x < sizeof(DEFAULT_LEAF.sec); ++x)
TEST_ASSERT(plain_text[x] ==
(wrapped_leaf_data->cipher_text[x] ^
MOCK_AES_XOR_BYTE(x)));
TEST_ASSERT(MOCK_pw_log_storage.entries[0].type.v == PW_INSERT_LEAF);
TEST_ASSERT(MOCK_pw_log_storage.entries[0].label.v ==
DEFAULT_LEAF.pub.label.v);
TEST_ASSERT_ARRAY_EQ(MOCK_pw_log_storage.entries[0].root,
ROOT_WITH_DEFAULT_HMAC,
sizeof(ROOT_WITH_DEFAULT_HMAC));
TEST_ASSERT_ARRAY_EQ(MOCK_pw_log_storage.entries[0].leaf_hmac,
DEFAULT_HMAC,
sizeof(DEFAULT_HMAC));
return check_dcrypto_mutex_usage();
}
static int handle_insert_leaf_old_protocol_success(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
size_t x;
int hash_count;
unsigned char *src;
const uint8_t *plain_text = (const uint8_t *)&DEFAULT_LEAF.sec;
struct wrapped_leaf_data_t *wrapped_leaf_data =
(void *)&buf.response.data.insert_leaf
.unimported_leaf_data;
setup_insert_leaf_defaults(&merkle_tree, &buf.request);
// Make changes to simulate the protocol 0 request.
buf.request.header.version = 0;
hash_count =
get_path_auxiliary_hash_count(&merkle_tree);
src = (unsigned char *)
(&buf.request.data.insert_leaf.valid_pcr_criteria);
memmove(src, src + PW_VALID_PCR_CRITERIA_SIZE,
hash_count * PW_HASH_SIZE);
buf.request.header.data_length -= PW_VALID_PCR_CRITERIA_SIZE;
TEST_RET_EQ(do_request(&merkle_tree, &buf), EC_SUCCESS);
TEST_ASSERT(buf.response.header.version == 0);
TEST_ASSERT(buf.response.header.data_length ==
sizeof(buf.response.data.insert_leaf) +
PW_LEAF_PAYLOAD_SIZE);
TEST_RET_EQ(buf.response.header.result_code, EC_SUCCESS);
TEST_ASSERT_ARRAY_EQ(buf.response.header.root, ROOT_WITH_DEFAULT_HMAC,
sizeof(ROOT_WITH_DEFAULT_HMAC));
TEST_ASSERT_ARRAY_EQ(buf.response.header.root, merkle_tree.root,
PW_HASH_SIZE);
TEST_ASSERT_ARRAY_EQ(
buf.response.data.insert_leaf.unimported_leaf_data.hmac,
DEFAULT_HMAC, sizeof(DEFAULT_HMAC));
TEST_ASSERT_ARRAY_EQ(
(uint8_t *)&wrapped_leaf_data->pub,
(uint8_t *)&DEFAULT_LEAF.pub, sizeof(DEFAULT_LEAF.pub));
for (x = 0; x < sizeof(DEFAULT_LEAF.sec); ++x)
TEST_ASSERT(plain_text[x] ==
(wrapped_leaf_data->cipher_text[x] ^
MOCK_AES_XOR_BYTE(x)));
TEST_ASSERT(MOCK_pw_log_storage.entries[0].type.v == PW_INSERT_LEAF);
TEST_ASSERT(MOCK_pw_log_storage.entries[0].label.v ==
DEFAULT_LEAF.pub.label.v);
TEST_ASSERT_ARRAY_EQ(MOCK_pw_log_storage.entries[0].root,
ROOT_WITH_DEFAULT_HMAC,
sizeof(ROOT_WITH_DEFAULT_HMAC));
TEST_ASSERT_ARRAY_EQ(MOCK_pw_log_storage.entries[0].leaf_hmac,
DEFAULT_HMAC,
sizeof(DEFAULT_HMAC));
return check_dcrypto_mutex_usage();
}
/******************************************************************************/
/* Remove leaf test cases.
*/
static int handle_remove_leaf_invalid_length(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_remove_leaf_defaults(&merkle_tree, &buf.request);
++buf.request.header.data_length;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf,
ROOT_WITH_DEFAULT_HMAC),
PW_ERR_LENGTH_INVALID);
return check_dcrypto_mutex_usage();
}
static int handle_remove_leaf_label_invalid(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_remove_leaf_defaults(&merkle_tree, &buf.request);
buf.request.data.remove_leaf.leaf_location.v |= 0x030000;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf,
ROOT_WITH_DEFAULT_HMAC),
PW_ERR_LABEL_INVALID);
return check_dcrypto_mutex_usage();
}
static int handle_remove_leaf_path_auth_failed(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_remove_leaf_defaults(&merkle_tree, &buf.request);
buf.request.data.remove_leaf.path_hashes[0][0] ^= 0xff;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf,
ROOT_WITH_DEFAULT_HMAC),
PW_ERR_PATH_AUTH_FAILED);
return check_dcrypto_mutex_usage();
}
static int handle_remove_leaf_nv_fail(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_remove_leaf_defaults(&merkle_tree, &buf.request);
MOCK_setvar_ret = PW_ERR_NV_LENGTH_MISMATCH;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root),
PW_ERR_NV_LENGTH_MISMATCH);
return EC_SUCCESS;
}
static int handle_remove_leaf_success(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_remove_leaf_defaults(&merkle_tree, &buf.request);
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root),
EC_SUCCESS);
TEST_ASSERT(MOCK_pw_log_storage.entries[0].type.v ==
PW_REMOVE_LEAF);
TEST_ASSERT(MOCK_pw_log_storage.entries[0].label.v ==
DEFAULT_LEAF.pub.label.v);
TEST_ASSERT_ARRAY_EQ(MOCK_pw_log_storage.entries[0].root,
EMPTY_TREE.root, sizeof(EMPTY_TREE.root));
return check_dcrypto_mutex_usage();
}
/******************************************************************************/
/* Try auth test cases.
*/
static int handle_try_auth_invalid_length(void)
{
return invalid_length_with_leaf_head(
(size_t)&((struct pw_request_t *)0)->data.try_auth
.unimported_leaf_data.head,
setup_try_auth_defaults);
}
static int handle_try_auth_leaf_version_mismatch(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
struct leaf_header_t *req_head =
&buf.request.data.try_auth.unimported_leaf_data.head;
setup_try_auth_defaults(&merkle_tree, &buf.request);
++req_head->leaf_version.major;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf,
ROOT_WITH_DEFAULT_HMAC),
PW_ERR_LEAF_VERSION_MISMATCH);
return check_dcrypto_mutex_usage();
}
static int handle_try_auth_label_invalid(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
struct leaf_data_t leaf_data;
memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(DEFAULT_LEAF));
leaf_data.pub.label.v |= 0x030000;
setup_try_auth_defaults_with_leaf(&leaf_data, PW_PROTOCOL_VERSION,
PW_LEAF_MINOR_VERSION, &merkle_tree,
&buf.request);
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf,
ROOT_WITH_DEFAULT_HMAC),
PW_ERR_LABEL_INVALID);
return check_dcrypto_mutex_usage();
}
static int handle_try_auth_path_auth_failed(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
uint8_t (*path_hashes)[32] =
(void *)buf.request.data.try_auth.unimported_leaf_data
.payload +
sizeof(struct leaf_public_data_t) +
sizeof(struct leaf_sensitive_data_t);
setup_try_auth_defaults(&merkle_tree, &buf.request);
(*path_hashes)[0] ^= 0xff;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf,
ROOT_WITH_DEFAULT_HMAC),
PW_ERR_PATH_AUTH_FAILED);
return check_dcrypto_mutex_usage();
}
static int handle_try_auth_hmac_auth_failed(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_try_auth_defaults(&merkle_tree, &buf.request);
MOCK_hash_update_cb = 0;
MOCK_hmac = EMPTY_TREE.root;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf,
ROOT_WITH_DEFAULT_HMAC),
PW_ERR_HMAC_AUTH_FAILED);
return check_dcrypto_mutex_usage();
}
static int handle_try_auth_crypto_failure(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_try_auth_defaults(&merkle_tree, &buf.request);
MOCK_aes_fail = 1;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf,
ROOT_WITH_DEFAULT_HMAC),
PW_ERR_CRYPTO_FAILURE);
return check_dcrypto_mutex_usage();
}
static int check_try_auth_rate_limit_reached_response(
struct merkle_tree_t *merkle_tree,
struct pw_test_data_t *buf,
const struct time_diff_t seconds_to_wait)
{
uint8_t old_root[PW_HASH_SIZE];
memcpy(old_root, merkle_tree->root, sizeof(old_root));
TEST_RET_EQ(do_request(merkle_tree, buf), PW_ERR_RATE_LIMIT_REACHED);
TEST_ASSERT(buf->response.header.version == PW_PROTOCOL_VERSION);
TEST_ASSERT(buf->response.header.data_length ==
sizeof(struct pw_response_try_auth_t) +
PW_LEAF_PAYLOAD_SIZE);
TEST_RET_EQ(buf->response.header.result_code,
PW_ERR_RATE_LIMIT_REACHED);
TEST_ASSERT_ARRAY_EQ(buf->response.header.root, old_root,
sizeof(old_root));
TEST_ASSERT_ARRAY_EQ(buf->response.header.root, merkle_tree->root,
sizeof(merkle_tree->root));
TEST_ASSERT(buf->response.data.try_auth.seconds_to_wait.v ==
seconds_to_wait.v);
TEST_ASSERT_MEMSET(buf->response.data.try_auth.high_entropy_secret,
0, PW_SECRET_SIZE);
TEST_ASSERT_MEMSET((uint8_t *)&buf->response.data.try_auth
.unimported_leaf_data, 0,
sizeof(buf->response.data.try_auth
.unimported_leaf_data) + PW_LEAF_PAYLOAD_SIZE);
return check_dcrypto_mutex_usage();
}
static int handle_try_auth_rate_limit_reached(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
struct leaf_data_t leaf_data = {};
/* Test PW_BLOCK_ATTEMPTS. */
memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(DEFAULT_LEAF));
leaf_data.pub.attempt_count.v = 51;
force_restart_count(1);
force_time((timestamp_t){.val = 7200llu * SECOND});
setup_try_auth_defaults_with_leaf(&leaf_data, PW_PROTOCOL_VERSION,
PW_LEAF_MINOR_VERSION, &merkle_tree,
&buf.request);
TEST_RET_EQ(check_try_auth_rate_limit_reached_response(
&merkle_tree, &buf,
(const struct time_diff_t){PW_BLOCK_ATTEMPTS}),
EC_SUCCESS);
memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(DEFAULT_LEAF));
memset(leaf_data.pub.delay_schedule, 0,
sizeof(leaf_data.pub.delay_schedule));
leaf_data.pub.delay_schedule[0].attempt_count.v = 5;
leaf_data.pub.delay_schedule[0].time_diff.v = PW_BLOCK_ATTEMPTS;
leaf_data.pub.attempt_count.v = 6;
force_restart_count(1);
force_time((timestamp_t){.val = 7200llu * SECOND});
setup_try_auth_defaults_with_leaf(&leaf_data, PW_PROTOCOL_VERSION,
PW_LEAF_MINOR_VERSION, &merkle_tree,
&buf.request);
TEST_RET_EQ(check_try_auth_rate_limit_reached_response(
&merkle_tree, &buf,
(const struct time_diff_t){PW_BLOCK_ATTEMPTS}),
EC_SUCCESS);
memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(DEFAULT_LEAF));
memset(leaf_data.pub.delay_schedule, 0,
sizeof(leaf_data.pub.delay_schedule));
leaf_data.pub.delay_schedule[0].attempt_count.v = 5;
leaf_data.pub.delay_schedule[0].time_diff.v = PW_BLOCK_ATTEMPTS;
leaf_data.pub.attempt_count.v = 6;
force_restart_count(1);
force_time((timestamp_t){.val = 7200llu * SECOND});
setup_try_auth_defaults_with_leaf(&leaf_data, PW_PROTOCOL_VERSION,
PW_LEAF_MINOR_VERSION, &merkle_tree,
&buf.request);
TEST_RET_EQ(check_try_auth_rate_limit_reached_response(
&merkle_tree, &buf,
(const struct time_diff_t){PW_BLOCK_ATTEMPTS}),
EC_SUCCESS);
/* Test same boot_count case. */
memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(DEFAULT_LEAF));
leaf_data.pub.attempt_count.v = 10;
leaf_data.pub.timestamp.boot_count = 0;
leaf_data.pub.timestamp.timer_value = 7200llu;
setup_try_auth_defaults_with_leaf(&leaf_data, PW_PROTOCOL_VERSION,
PW_LEAF_MINOR_VERSION, &merkle_tree,
&buf.request);
force_restart_count(0);
force_time((timestamp_t){.val = (leaf_data.pub.timestamp.timer_value +
3599llu) * SECOND});
TEST_RET_EQ(check_try_auth_rate_limit_reached_response(
&merkle_tree, &buf, (const struct time_diff_t){1}),
EC_SUCCESS);
/* Test boot_count + 1 case. */
memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(DEFAULT_LEAF));
leaf_data.pub.attempt_count.v = 10;
leaf_data.pub.timestamp.boot_count = 0;
leaf_data.pub.timestamp.timer_value = 7200llu;
setup_try_auth_defaults_with_leaf(&leaf_data, PW_PROTOCOL_VERSION,
PW_LEAF_MINOR_VERSION, &merkle_tree,
&buf.request);
force_restart_count(1);
force_time((timestamp_t){.val = 3599llu * SECOND});
TEST_RET_EQ(check_try_auth_rate_limit_reached_response(
&merkle_tree, &buf, (const struct time_diff_t){1}),
EC_SUCCESS);
return check_dcrypto_mutex_usage();
}
static int handle_try_auth_nv_fail(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_try_auth_defaults(&merkle_tree, &buf.request);
force_restart_count(0);
force_time((timestamp_t){.val = 65 * SECOND});
MOCK_setvar_ret = PW_ERR_NV_LENGTH_MISMATCH;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root),
PW_ERR_NV_LENGTH_MISMATCH);
return EC_SUCCESS;
}
static int handle_try_auth_lowent_auth_failed(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
struct leaf_data_t leaf_data = {};
struct leaf_public_data_t *pub =
(void *)buf.response.data.try_auth.unimported_leaf_data
.payload;
struct leaf_sensitive_data_t sec = {};
uint8_t *resp_cipher_text = (void *)pub + sizeof(*pub);
memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(DEFAULT_LEAF));
leaf_data.pub.attempt_count.v = 5;
leaf_data.sec.low_entropy_secret[
sizeof(leaf_data.sec.low_entropy_secret) - 1] =
~leaf_data.sec.low_entropy_secret[
sizeof(leaf_data.sec.low_entropy_secret) - 1];
setup_try_auth_defaults_with_leaf(&leaf_data, PW_PROTOCOL_VERSION,
PW_LEAF_MINOR_VERSION, &merkle_tree,
&buf.request);
force_restart_count(1);
force_time((timestamp_t){.val = (65ull * SECOND)});
TEST_RET_EQ(do_request(&merkle_tree, &buf), PW_ERR_LOWENT_AUTH_FAILED);
TEST_ASSERT(buf.response.header.version == PW_PROTOCOL_VERSION);
TEST_ASSERT(buf.response.header.data_length ==
sizeof(struct pw_response_try_auth_t) +
PW_LEAF_PAYLOAD_SIZE);
TEST_RET_EQ(buf.response.header.result_code, PW_ERR_LOWENT_AUTH_FAILED);
TEST_ASSERT_ARRAY_EQ(buf.response.header.root, EMPTY_TREE.root,
sizeof(EMPTY_TREE.root));
TEST_ASSERT_ARRAY_EQ(buf.response.header.root, merkle_tree.root,
sizeof(merkle_tree.root));
TEST_ASSERT_ARRAY_EQ(
buf.response.data.try_auth.unimported_leaf_data.hmac,
EMPTY_HMAC, sizeof(EMPTY_HMAC));
TEST_ASSERT_ARRAY_EQ(buf.response.data.try_auth.unimported_leaf_data.iv,
DEFAULT_IV, sizeof(DEFAULT_IV));
DCRYPTO_aes_ctr((uint8_t *)&sec, EMPTY_TREE.wrap_key,
sizeof(EMPTY_TREE.wrap_key) * 8, DEFAULT_IV,
resp_cipher_text, sizeof(sec));
TEST_ASSERT(pub->label.v == leaf_data.pub.label.v);
TEST_ASSERT_ARRAY_EQ(
(uint8_t *)&pub->delay_schedule,
(uint8_t *)&leaf_data.pub.delay_schedule,
sizeof(leaf_data.pub.delay_schedule));
TEST_ASSERT_ARRAY_EQ((uint8_t *)&sec, (uint8_t *)&leaf_data.sec,
sizeof(leaf_data.sec));
TEST_ASSERT(pub->attempt_count.v == leaf_data.pub.attempt_count.v + 1);
TEST_ASSERT(pub->timestamp.boot_count == 1);
TEST_ASSERT_MEMSET(buf.response.data.try_auth.high_entropy_secret,
0, PW_SECRET_SIZE);
/* A threshold of 100 is used since some time will pass after
* force_time() is called.
*/
TEST_ASSERT(pub->timestamp.timer_value - 65ull < 100);
/* Validate the log entry for a failed auth attempt. */
TEST_ASSERT(MOCK_pw_log_storage.entries[0].type.v == PW_TRY_AUTH);
TEST_ASSERT(MOCK_pw_log_storage.entries[0].label.v ==
DEFAULT_LEAF.pub.label.v);
TEST_ASSERT(MOCK_pw_log_storage.entries[0].return_code ==
PW_ERR_LOWENT_AUTH_FAILED);
TEST_ASSERT(MOCK_pw_log_storage.entries[0].timestamp.boot_count ==
pub->timestamp.boot_count);
TEST_ASSERT(MOCK_pw_log_storage.entries[0].timestamp.timer_value ==
pub->timestamp.timer_value);
TEST_ASSERT_ARRAY_EQ(MOCK_pw_log_storage.entries[0].root,
EMPTY_TREE.root,
sizeof(EMPTY_TREE.root));
return check_dcrypto_mutex_usage();
}
static int handle_try_auth_pcr_mismatch(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
struct leaf_data_t leaf_data = {};
/* Test same boot_count case. */
memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(leaf_data));
leaf_data.pub.attempt_count.v = 6;
leaf_data.pub.valid_pcr_criteria[0].bitmask[0] = 1;
memset(leaf_data.pub.valid_pcr_criteria[0].digest, 0, 32);
setup_try_auth_defaults_with_leaf(&leaf_data, PW_PROTOCOL_VERSION,
PW_LEAF_MINOR_VERSION, &merkle_tree,
&buf.request);
force_restart_count(0);
force_time((timestamp_t){.val = 65 * SECOND});
TEST_RET_EQ(do_request(&merkle_tree, &buf), PW_ERR_PCR_NOT_MATCH);
return check_dcrypto_mutex_usage();
}
static int try_auth_success(uint8_t protocol_version,
uint8_t minor_version)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
struct leaf_data_t leaf_data = {};
struct leaf_public_data_t *pub =
(void *)buf.response.data.try_auth.unimported_leaf_data
.payload;
struct leaf_sensitive_data_t sec = {};
uint8_t *resp_cipher_text = (void *)pub + sizeof(*pub);
/* Test same boot_count case. */
memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(leaf_data));
leaf_data.pub.attempt_count.v = 6;
leaf_data.pub.valid_pcr_criteria[0].bitmask[0] = 1;
memcpy(leaf_data.pub.valid_pcr_criteria[0].digest,
DEFAULT_PCR_DIGEST, 32);
setup_try_auth_defaults_with_leaf(&leaf_data, protocol_version,
minor_version, &merkle_tree,
&buf.request);
force_restart_count(0);
force_time((timestamp_t){.val = 65 * SECOND});
TEST_RET_EQ(do_request(&merkle_tree, &buf), EC_SUCCESS);
TEST_ASSERT(buf.response.header.version == protocol_version);
TEST_ASSERT(buf.response.header.data_length ==
sizeof(struct pw_response_try_auth_t) +
PW_LEAF_PAYLOAD_SIZE);
TEST_RET_EQ(buf.response.header.result_code, EC_SUCCESS);
TEST_ASSERT_ARRAY_EQ(buf.response.header.root, ROOT_WITH_DEFAULT_HMAC,
sizeof(ROOT_WITH_DEFAULT_HMAC));
TEST_ASSERT_ARRAY_EQ(buf.response.header.root, merkle_tree.root,
sizeof(merkle_tree.root));
TEST_ASSERT_ARRAY_EQ(
buf.response.data.try_auth.unimported_leaf_data.hmac,
DEFAULT_HMAC, sizeof(DEFAULT_HMAC));
TEST_ASSERT_ARRAY_EQ(buf.response.data.try_auth.unimported_leaf_data.iv,
DEFAULT_IV, sizeof(DEFAULT_IV));
DCRYPTO_aes_ctr((uint8_t *)&sec, EMPTY_TREE.wrap_key,
sizeof(EMPTY_TREE.wrap_key) * 8, DEFAULT_IV,
resp_cipher_text, sizeof(sec));
TEST_ASSERT(pub->label.v == leaf_data.pub.label.v);
TEST_ASSERT_ARRAY_EQ(
(uint8_t *)&pub->delay_schedule,
(uint8_t *)&leaf_data.pub.delay_schedule,
sizeof(leaf_data.pub.delay_schedule));
if (protocol_version == PW_PROTOCOL_VERSION) {
TEST_ASSERT_ARRAY_EQ((uint8_t *)&sec,
(uint8_t *)&DEFAULT_LEAF.sec,
sizeof(DEFAULT_LEAF.sec));
}
TEST_ASSERT(pub->attempt_count.v == 0);
TEST_ASSERT_ARRAY_EQ(buf.response.data.try_auth.high_entropy_secret,
DEFAULT_LEAF.sec.high_entropy_secret,
sizeof(DEFAULT_LEAF.sec.high_entropy_secret));
TEST_ASSERT_ARRAY_EQ(buf.response.data.try_auth.reset_secret,
DEFAULT_LEAF.sec.reset_secret,
sizeof(DEFAULT_LEAF.sec.reset_secret));
/* Validate the log entry on success. */
TEST_ASSERT(MOCK_pw_log_storage.entries[0].type.v == PW_TRY_AUTH);
TEST_ASSERT(MOCK_pw_log_storage.entries[0].label.v ==
DEFAULT_LEAF.pub.label.v);
TEST_ASSERT(MOCK_pw_log_storage.entries[0].return_code == EC_SUCCESS);
TEST_ASSERT(MOCK_pw_log_storage.entries[0].timestamp.boot_count ==
pub->timestamp.boot_count);
TEST_ASSERT(MOCK_pw_log_storage.entries[0].timestamp.timer_value ==
pub->timestamp.timer_value);
TEST_ASSERT_ARRAY_EQ(MOCK_pw_log_storage.entries[0].root,
ROOT_WITH_DEFAULT_HMAC,
sizeof(ROOT_WITH_DEFAULT_HMAC));
/* Test boot_count + 1 case. */
leaf_data.pub.attempt_count.v = 6;
leaf_data.pub.timestamp.boot_count = 0;
leaf_data.pub.timestamp.timer_value = 7200llu;
setup_try_auth_defaults_with_leaf(&leaf_data, protocol_version,
minor_version, &merkle_tree,
&buf.request);
force_restart_count(1);
force_time((timestamp_t){.val = 65llu * SECOND});
TEST_RET_EQ(do_request(&merkle_tree, &buf), EC_SUCCESS);
TEST_ASSERT(buf.response.header.version == protocol_version);
TEST_ASSERT(buf.response.header.data_length ==
sizeof(struct pw_response_try_auth_t) +
PW_LEAF_PAYLOAD_SIZE);
TEST_RET_EQ(buf.response.header.result_code, EC_SUCCESS);
TEST_ASSERT_ARRAY_EQ(buf.response.header.root, ROOT_WITH_DEFAULT_HMAC,
sizeof(ROOT_WITH_DEFAULT_HMAC));
TEST_ASSERT_ARRAY_EQ(buf.response.header.root, merkle_tree.root,
sizeof(merkle_tree.root));
TEST_ASSERT_ARRAY_EQ(
buf.response.data.try_auth.unimported_leaf_data.hmac,
DEFAULT_HMAC, sizeof(DEFAULT_HMAC));
TEST_ASSERT_ARRAY_EQ(buf.response.data.try_auth.unimported_leaf_data.iv,
DEFAULT_IV, sizeof(DEFAULT_IV));
DCRYPTO_aes_ctr((uint8_t *)&sec, EMPTY_TREE.wrap_key,
sizeof(EMPTY_TREE.wrap_key) * 8, DEFAULT_IV,
resp_cipher_text, sizeof(sec));
TEST_ASSERT(pub->label.v == leaf_data.pub.label.v);
TEST_ASSERT_ARRAY_EQ(
(uint8_t *)&pub->delay_schedule,
(uint8_t *)&leaf_data.pub.delay_schedule,
sizeof(leaf_data.pub.delay_schedule));
if (protocol_version == PW_PROTOCOL_VERSION) {
TEST_ASSERT_ARRAY_EQ((uint8_t *)&sec,
(uint8_t *)&DEFAULT_LEAF.sec,
sizeof(DEFAULT_LEAF.sec));
}
TEST_ASSERT(pub->attempt_count.v == 0);
TEST_ASSERT_ARRAY_EQ(buf.response.data.try_auth.high_entropy_secret,
DEFAULT_LEAF.sec.high_entropy_secret,
sizeof(DEFAULT_LEAF.sec.high_entropy_secret));
return check_dcrypto_mutex_usage();
}
static int handle_try_auth_success(void)
{
return try_auth_success(PW_PROTOCOL_VERSION, PW_LEAF_MINOR_VERSION);
}
static int handle_try_auth_old_protocol_old_leaf_success(void)
{
return try_auth_success(0, 0);
}
static int handle_try_auth_old_protocol_new_leaf_success(void)
{
return try_auth_success(0, PW_LEAF_MINOR_VERSION);
}
/******************************************************************************/
/* Reset auth test cases.
*/
static int handle_reset_auth_invalid_length(void)
{
return invalid_length_with_leaf_head(
(size_t)&((struct pw_request_t *)0)->data.reset_auth
.unimported_leaf_data.head,
setup_reset_auth_defaults);
}
static int handle_reset_auth_label_invalid(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
struct leaf_public_data_t *pub =
(void *)buf.request.data.reset_auth.unimported_leaf_data
.payload;
setup_reset_auth_defaults(&merkle_tree, &buf.request);
pub->label.v |= 0x030000;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root),
PW_ERR_LABEL_INVALID);
return check_dcrypto_mutex_usage();
}
static int handle_reset_auth_path_auth_failed(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
uint8_t (*path_hashes)[32] =
(void *)buf.request.data.reset_auth.unimported_leaf_data
.payload +
sizeof(struct leaf_public_data_t) +
sizeof(struct leaf_sensitive_data_t);
setup_reset_auth_defaults(&merkle_tree, &buf.request);
(*path_hashes)[0] ^= 0xff;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root),
PW_ERR_PATH_AUTH_FAILED);
return check_dcrypto_mutex_usage();
}
static int handle_reset_auth_hmac_auth_failed(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_reset_auth_defaults(&merkle_tree, &buf.request);
MOCK_hash_update_cb = 0;
MOCK_hmac = EMPTY_TREE.root;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root),
PW_ERR_HMAC_AUTH_FAILED);
return check_dcrypto_mutex_usage();
}
static int handle_reset_auth_crypto_failure(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_reset_auth_defaults(&merkle_tree, &buf.request);
MOCK_aes_fail = 1;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root),
PW_ERR_CRYPTO_FAILURE);
return check_dcrypto_mutex_usage();
}
static int handle_reset_auth_reset_auth_failed(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_reset_auth_defaults(&merkle_tree, &buf.request);
buf.request.data.reset_auth.reset_secret[0] ^= 0xff;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root),
PW_ERR_RESET_AUTH_FAILED);
return check_dcrypto_mutex_usage();
}
static int handle_reset_auth_nv_fail(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_reset_auth_defaults(&merkle_tree, &buf.request);
MOCK_setvar_ret = PW_ERR_NV_LENGTH_MISMATCH;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root),
PW_ERR_NV_LENGTH_MISMATCH);
return EC_SUCCESS;
}
static int handle_reset_auth_success(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
struct leaf_public_data_t *pub =
(void *)buf.response.data.reset_auth
.unimported_leaf_data.payload;
struct leaf_sensitive_data_t sec = {};
uint8_t *resp_cipher_text = (void *)pub + sizeof(*pub);
setup_reset_auth_defaults(&merkle_tree, &buf.request);
TEST_RET_EQ(do_request(&merkle_tree, &buf), EC_SUCCESS);
TEST_ASSERT(buf.response.header.version == PW_PROTOCOL_VERSION);
TEST_ASSERT(buf.response.header.data_length ==
sizeof(struct pw_response_reset_auth_t) +
PW_LEAF_PAYLOAD_SIZE);
TEST_RET_EQ(buf.response.header.result_code, EC_SUCCESS);
TEST_ASSERT_ARRAY_EQ(buf.response.header.root, ROOT_WITH_DEFAULT_HMAC,
sizeof(ROOT_WITH_DEFAULT_HMAC));
TEST_ASSERT_ARRAY_EQ(buf.response.header.root, merkle_tree.root,
sizeof(merkle_tree.root));
TEST_ASSERT_ARRAY_EQ(
buf.response.data.reset_auth.high_entropy_secret,
DEFAULT_LEAF.sec.high_entropy_secret,
sizeof(DEFAULT_LEAF.sec.high_entropy_secret));
TEST_ASSERT_ARRAY_EQ(
buf.response.data.reset_auth.unimported_leaf_data.hmac,
DEFAULT_HMAC, sizeof(DEFAULT_HMAC));
TEST_ASSERT_ARRAY_EQ(
buf.response.data.reset_auth.unimported_leaf_data.iv,
DEFAULT_IV, sizeof(DEFAULT_IV));
DCRYPTO_aes_ctr((uint8_t *)&sec, EMPTY_TREE.wrap_key,
sizeof(EMPTY_TREE.wrap_key) * 8, DEFAULT_IV,
resp_cipher_text, sizeof(sec));
TEST_ASSERT(pub->label.v == DEFAULT_LEAF.pub.label.v);
TEST_ASSERT_ARRAY_EQ(
(const uint8_t *)&pub->delay_schedule,
(const uint8_t *)&DEFAULT_LEAF.pub.delay_schedule,
sizeof(DEFAULT_LEAF.pub.delay_schedule));
TEST_ASSERT_ARRAY_EQ((uint8_t *)&sec, (uint8_t *)&DEFAULT_LEAF.sec,
sizeof(DEFAULT_LEAF.sec));
TEST_ASSERT(pub->attempt_count.v == 0);
/* Validate the log entry on success. */
TEST_ASSERT(MOCK_pw_log_storage.entries[0].type.v == PW_TRY_AUTH);
TEST_ASSERT(MOCK_pw_log_storage.entries[0].label.v ==
DEFAULT_LEAF.pub.label.v);
TEST_ASSERT(MOCK_pw_log_storage.entries[0].return_code == EC_SUCCESS);
TEST_ASSERT(MOCK_pw_log_storage.entries[0].timestamp.boot_count ==
pub->timestamp.boot_count);
TEST_ASSERT(MOCK_pw_log_storage.entries[0].timestamp.timer_value ==
pub->timestamp.timer_value);
TEST_ASSERT_ARRAY_EQ(MOCK_pw_log_storage.entries[0].root,
ROOT_WITH_DEFAULT_HMAC,
sizeof(ROOT_WITH_DEFAULT_HMAC));
/* Test with different minor version and struct lengths. */
setup_reset_auth_defaults(&merkle_tree, &buf.request);
setup_mock_future_version(
&buf.request.data.reset_auth.unimported_leaf_data,
&buf.request.header.data_length);
TEST_RET_EQ(do_request(&merkle_tree, &buf), EC_SUCCESS);
TEST_ASSERT(buf.response.header.version == PW_PROTOCOL_VERSION);
TEST_ASSERT(buf.response.header.data_length ==
sizeof(struct pw_response_reset_auth_t) +
PW_LEAF_PAYLOAD_SIZE);
TEST_RET_EQ(buf.response.header.result_code, EC_SUCCESS);
TEST_ASSERT_ARRAY_EQ(buf.response.header.root, ROOT_WITH_DEFAULT_HMAC,
sizeof(ROOT_WITH_DEFAULT_HMAC));
TEST_ASSERT_ARRAY_EQ(buf.response.header.root, merkle_tree.root,
sizeof(merkle_tree.root));
TEST_ASSERT_ARRAY_EQ(
buf.response.data.reset_auth.high_entropy_secret,
DEFAULT_LEAF.sec.high_entropy_secret,
sizeof(DEFAULT_LEAF.sec.high_entropy_secret));
TEST_ASSERT_ARRAY_EQ(
buf.response.data.reset_auth.unimported_leaf_data.hmac,
DEFAULT_HMAC, sizeof(DEFAULT_HMAC));
TEST_ASSERT_ARRAY_EQ(
buf.response.data.reset_auth.unimported_leaf_data.iv,
DEFAULT_IV, sizeof(DEFAULT_IV));
DCRYPTO_aes_ctr((uint8_t *)&sec, EMPTY_TREE.wrap_key,
sizeof(EMPTY_TREE.wrap_key) * 8, DEFAULT_IV,
resp_cipher_text, sizeof(sec));
TEST_ASSERT(pub->label.v == DEFAULT_LEAF.pub.label.v);
TEST_ASSERT_ARRAY_EQ(
(const uint8_t *)&pub->delay_schedule,
(const uint8_t *)&DEFAULT_LEAF.pub.delay_schedule,
sizeof(DEFAULT_LEAF.pub.delay_schedule));
TEST_ASSERT_ARRAY_EQ((uint8_t *)&sec, (uint8_t *)&DEFAULT_LEAF.sec,
sizeof(DEFAULT_LEAF.sec));
TEST_ASSERT(pub->attempt_count.v == 0);
/* Validate the log entry on success. */
TEST_ASSERT(MOCK_pw_log_storage.entries[0].type.v == PW_TRY_AUTH);
TEST_ASSERT(MOCK_pw_log_storage.entries[0].label.v ==
DEFAULT_LEAF.pub.label.v);
TEST_ASSERT(MOCK_pw_log_storage.entries[0].return_code == EC_SUCCESS);
TEST_ASSERT(MOCK_pw_log_storage.entries[0].timestamp.boot_count ==
pub->timestamp.boot_count);
TEST_ASSERT(MOCK_pw_log_storage.entries[0].timestamp.timer_value ==
pub->timestamp.timer_value);
TEST_ASSERT_ARRAY_EQ(MOCK_pw_log_storage.entries[0].root,
ROOT_WITH_DEFAULT_HMAC,
sizeof(ROOT_WITH_DEFAULT_HMAC));
return check_dcrypto_mutex_usage();
}
/******************************************************************************/
/* Get log test cases.
*/
static int handle_get_log_invalid_length(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_get_log_defaults(&merkle_tree, &buf.request);
++buf.request.header.data_length;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root),
PW_ERR_LENGTH_INVALID);
return check_dcrypto_mutex_usage();
}
static int handle_get_log_nv_fail(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_get_log_defaults(&merkle_tree, &buf.request);
MOCK_getvar_ret = PW_ERR_NV_EMPTY;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root),
PW_ERR_NV_EMPTY);
return check_dcrypto_mutex_usage();
}
static int handle_get_log_success(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
const struct pw_get_log_entry_t (*view)[PW_LOG_ENTRY_COUNT] =
(void *)buf.response.data.get_log;
setup_get_log_defaults(&merkle_tree, &buf.request);
setup_storage(4);
TEST_RET_EQ(do_request(&merkle_tree, &buf), EC_SUCCESS);
TEST_ASSERT_ARRAY_EQ(buf.response.header.root, EMPTY_TREE.root,
sizeof(EMPTY_TREE.root));
TEST_ASSERT_ARRAY_EQ(buf.response.header.root, merkle_tree.root,
sizeof(merkle_tree.root));
TEST_ASSERT(buf.response.header.version == PW_PROTOCOL_VERSION);
TEST_ASSERT(buf.response.header.data_length ==
sizeof(struct pw_get_log_entry_t) * PW_LOG_ENTRY_COUNT);
TEST_RET_EQ(buf.response.header.result_code, EC_SUCCESS);
TEST_ASSERT(buf.response.header.version == PW_PROTOCOL_VERSION);
TEST_ASSERT((*view)[0].type.v == PW_REMOVE_LEAF);
TEST_ASSERT((*view)[0].label.v == DEFAULT_LEAF.pub.label.v);
TEST_ASSERT_ARRAY_EQ((*view)[0].root, EMPTY_TREE.root,
sizeof(EMPTY_TREE.root));
TEST_ASSERT((*view)[1].type.v == PW_TRY_AUTH);
TEST_ASSERT((*view)[1].label.v == DEFAULT_LEAF.pub.label.v);
TEST_ASSERT((*view)[1].return_code == EC_SUCCESS);
TEST_ASSERT((*view)[1].timestamp.boot_count == 10);
TEST_ASSERT((*view)[1].timestamp.timer_value == 100);
TEST_ASSERT_ARRAY_EQ((*view)[1].root, ROOT_WITH_DEFAULT_HMAC,
sizeof(ROOT_WITH_DEFAULT_HMAC));
setup_get_log_defaults(&merkle_tree, &buf.request);
setup_storage(2);
TEST_RET_EQ(do_request(&merkle_tree, &buf), EC_SUCCESS);
TEST_ASSERT((*view)[0].type.v == PW_TRY_AUTH);
TEST_ASSERT((*view)[0].label.v == DEFAULT_LEAF.pub.label.v);
TEST_ASSERT((*view)[0].return_code == PW_ERR_LOWENT_AUTH_FAILED);
TEST_ASSERT((*view)[0].timestamp.boot_count == 7);
TEST_ASSERT((*view)[0].timestamp.timer_value == 99);
TEST_ASSERT_ARRAY_EQ((*view)[0].root, ROOT_WITH_OTHER_HMAC,
sizeof(ROOT_WITH_OTHER_HMAC));
TEST_ASSERT((*view)[1].type.v == PW_INSERT_LEAF);
TEST_ASSERT((*view)[1].label.v == DEFAULT_LEAF.pub.label.v);
TEST_ASSERT_ARRAY_EQ((*view)[1].root, ROOT_WITH_DEFAULT_HMAC,
sizeof(ROOT_WITH_DEFAULT_HMAC));
TEST_ASSERT_ARRAY_EQ((*view)[1].leaf_hmac, DEFAULT_HMAC,
sizeof(DEFAULT_HMAC));
setup_get_log_defaults(&merkle_tree, &buf.request);
setup_storage(0);
TEST_RET_EQ(do_request(&merkle_tree, &buf), EC_SUCCESS);
TEST_ASSERT((*view)[0].type.v == PW_RESET_TREE);
TEST_ASSERT_ARRAY_EQ((*view)[0].root, EMPTY_TREE.root,
sizeof(EMPTY_TREE.root));
return check_dcrypto_mutex_usage();
}
/******************************************************************************/
/* Log replay test cases.
*/
static int handle_log_replay_invalid_length(void)
{
return invalid_length_with_leaf_head(
(size_t)&((struct pw_request_t *)0)->data.log_replay
.unimported_leaf_data.head,
setup_log_replay_defaults);
}
static int handle_log_replay_nv_fail(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_log_replay_defaults(&merkle_tree, &buf.request);
MOCK_getvar_ret = PW_ERR_NV_EMPTY;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root),
PW_ERR_NV_EMPTY);
return check_dcrypto_mutex_usage();
}
static int handle_log_replay_root_not_found(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_log_replay_defaults(&merkle_tree, &buf.request);
memcpy(buf.request.data.log_replay.log_root, DEFAULT_HMAC,
sizeof(DEFAULT_HMAC));
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root),
PW_ERR_ROOT_NOT_FOUND);
return check_dcrypto_mutex_usage();
}
static int handle_log_replay_type_invalid(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
setup_log_replay_defaults(&merkle_tree, &buf.request);
memcpy(buf.request.data.log_replay.log_root, EMPTY_TREE.root,
sizeof(EMPTY_TREE.root));
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root),
PW_ERR_TYPE_INVALID);
return check_dcrypto_mutex_usage();
}
static int handle_log_replay_hmac_auth_failed(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
struct leaf_data_t leaf_data = {};
memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(leaf_data));
leaf_data.pub.attempt_count.v = 7;
setup_log_replay_defaults_with_leaf(&leaf_data, &merkle_tree,
&buf.request);
memcpy(buf.request.data.log_replay.unimported_leaf_data.hmac,
EMPTY_HMAC, sizeof(EMPTY_HMAC));
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root),
PW_ERR_HMAC_AUTH_FAILED);
return check_dcrypto_mutex_usage();
}
static int handle_log_replay_crypto_failure(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
struct leaf_data_t leaf_data = {};
memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(leaf_data));
leaf_data.pub.attempt_count.v = 7;
setup_log_replay_defaults_with_leaf(&leaf_data, &merkle_tree,
&buf.request);
MOCK_aes_fail = 1;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root),
PW_ERR_CRYPTO_FAILURE);
return check_dcrypto_mutex_usage();
}
static int handle_log_replay_label_invalid(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
struct leaf_data_t leaf_data = {};
memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(leaf_data));
leaf_data.pub.label.v = 0;
setup_log_replay_defaults_with_leaf(&leaf_data, &merkle_tree,
&buf.request);
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root),
PW_ERR_LABEL_INVALID);
return check_dcrypto_mutex_usage();
}
static int handle_log_replay_path_auth_failed(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
uint8_t (*path_hashes)[32] =
(void *)buf.request.data.log_replay.unimported_leaf_data
.payload +
sizeof(struct leaf_public_data_t) +
sizeof(struct leaf_sensitive_data_t);
setup_log_replay_defaults(&merkle_tree, &buf.request);
(*path_hashes)[0] ^= 0xff;
TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root),
PW_ERR_PATH_AUTH_FAILED);
return check_dcrypto_mutex_usage();
}
static int handle_log_replay_success(void)
{
struct merkle_tree_t merkle_tree;
struct pw_test_data_t buf;
struct leaf_data_t leaf_data = {};
struct leaf_public_data_t *pub =
(void *)buf.response.data.log_replay
.unimported_leaf_data.payload;
struct leaf_sensitive_data_t sec = {};
uint8_t *resp_cipher_text = (void *)pub + sizeof(*pub);
/*
* Test for auth success.
*/
setup_log_replay_defaults(&merkle_tree, &buf.request);
TEST_RET_EQ(do_request(&merkle_tree, &buf), EC_SUCCESS);
TEST_ASSERT(buf.response.header.version == PW_PROTOCOL_VERSION);
TEST_ASSERT(buf.response.header.data_length ==
sizeof(struct pw_response_log_replay_t) +
PW_LEAF_PAYLOAD_SIZE);
TEST_RET_EQ(buf.response.header.result_code, EC_SUCCESS);
TEST_ASSERT_ARRAY_EQ(buf.response.header.root, EMPTY_TREE.root,
sizeof(EMPTY_TREE.root));
TEST_ASSERT_ARRAY_EQ(buf.response.header.root, merkle_tree.root,
sizeof(merkle_tree.root));
TEST_ASSERT_ARRAY_EQ(
buf.response.data.log_replay.unimported_leaf_data.hmac,
DEFAULT_HMAC, sizeof(DEFAULT_HMAC));
TEST_ASSERT_ARRAY_EQ(
buf.response.data.log_replay.unimported_leaf_data.iv,
DEFAULT_IV, sizeof(DEFAULT_IV));
DCRYPTO_aes_ctr((uint8_t *)&sec, EMPTY_TREE.wrap_key,
sizeof(EMPTY_TREE.wrap_key) * 8, DEFAULT_IV,
resp_cipher_text, sizeof(sec));
TEST_ASSERT(pub->label.v == DEFAULT_LEAF.pub.label.v);
TEST_ASSERT_ARRAY_EQ(
(const uint8_t *)&pub->delay_schedule,
(const uint8_t *)&DEFAULT_LEAF.pub.delay_schedule,
sizeof(DEFAULT_LEAF.pub.delay_schedule));
TEST_ASSERT_ARRAY_EQ((uint8_t *)&sec, (uint8_t *)&DEFAULT_LEAF.sec,
sizeof(DEFAULT_LEAF.sec));
TEST_ASSERT(pub->attempt_count.v == 0);
TEST_ASSERT(pub->timestamp.boot_count == 10);
TEST_ASSERT(pub->timestamp.timer_value == 100);
/*
* Test for auth failed.
*/
memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(leaf_data));
leaf_data.pub.attempt_count.v = 15;
setup_log_replay_defaults_with_leaf(&leaf_data, &merkle_tree,
&buf.request);
memcpy(buf.request.data.log_replay.log_root, ROOT_WITH_OTHER_HMAC,
sizeof(ROOT_WITH_OTHER_HMAC));
setup_storage(2);
TEST_RET_EQ(do_request(&merkle_tree, &buf), EC_SUCCESS);
TEST_ASSERT(buf.response.header.version == PW_PROTOCOL_VERSION);
TEST_ASSERT(buf.response.header.data_length ==
sizeof(struct pw_response_log_replay_t) +
PW_LEAF_PAYLOAD_SIZE);
TEST_RET_EQ(buf.response.header.result_code, EC_SUCCESS);
TEST_ASSERT_ARRAY_EQ(buf.response.header.root, EMPTY_TREE.root,
sizeof(EMPTY_TREE.root));
TEST_ASSERT_ARRAY_EQ(buf.response.header.root, merkle_tree.root,
sizeof(merkle_tree.root));
TEST_ASSERT_ARRAY_EQ(
buf.response.data.log_replay.unimported_leaf_data.hmac,
OTHER_HMAC, sizeof(OTHER_HMAC));
TEST_ASSERT_ARRAY_EQ(
buf.response.data.log_replay.unimported_leaf_data.iv,
DEFAULT_IV, sizeof(DEFAULT_IV));
DCRYPTO_aes_ctr((uint8_t *)&sec, EMPTY_TREE.wrap_key,
sizeof(EMPTY_TREE.wrap_key) * 8, DEFAULT_IV,
resp_cipher_text, sizeof(sec));
TEST_ASSERT(pub->label.v == DEFAULT_LEAF.pub.label.v);
TEST_ASSERT_ARRAY_EQ(
(const uint8_t *)&pub->delay_schedule,
(const uint8_t *)&DEFAULT_LEAF.pub.delay_schedule,
sizeof(DEFAULT_LEAF.pub.delay_schedule));
TEST_ASSERT_ARRAY_EQ((uint8_t *)&sec, (uint8_t *)&DEFAULT_LEAF.sec,
sizeof(DEFAULT_LEAF.sec));
TEST_ASSERT(pub->attempt_count.v == 16);
TEST_ASSERT(pub->timestamp.boot_count == 7);
TEST_ASSERT(pub->timestamp.timer_value == 99);
return check_dcrypto_mutex_usage();
}
/******************************************************************************/
/* Main test function. Encapsulates the test cases..
*/
void run_test(void)
{
test_reset();
/* Test basic operations. */
RUN_TEST(get_path_auxiliary_hash_count_test);
RUN_TEST(compute_hash_test);
/* Test header validation. */
RUN_TEST(handle_request_version_mismatch);
RUN_TEST(handle_request_invalid_type);
/* Test reset tree. */
RUN_TEST(handle_reset_tree_invalid_length);
RUN_TEST(handle_reset_tree_bits_per_level_invalid);
RUN_TEST(handle_reset_tree_height_invalid);
RUN_TEST(handle_reset_tree_crypto_failure);
RUN_TEST(handle_reset_tree_nv_fail);
RUN_TEST(handle_reset_tree_success);
/* Test insert leaf. */
RUN_TEST(handle_insert_leaf_invalid_length);
RUN_TEST(handle_insert_leaf_label_invalid);
RUN_TEST(handle_insert_leaf_delay_schedule_invalid);
RUN_TEST(handle_insert_leaf_path_auth_failed);
RUN_TEST(handle_insert_leaf_crypto_failure);
RUN_TEST(handle_insert_leaf_nv_fail);
RUN_TEST(handle_insert_leaf_success);
RUN_TEST(handle_insert_leaf_old_protocol_success);
/* Test remove leaf. */
RUN_TEST(handle_remove_leaf_invalid_length);
RUN_TEST(handle_remove_leaf_label_invalid);
RUN_TEST(handle_remove_leaf_path_auth_failed);
RUN_TEST(handle_remove_leaf_nv_fail);
RUN_TEST(handle_remove_leaf_success);
/* Test try auth. */
RUN_TEST(handle_try_auth_invalid_length);
RUN_TEST(handle_try_auth_leaf_version_mismatch);
RUN_TEST(handle_try_auth_label_invalid);
RUN_TEST(handle_try_auth_path_auth_failed);
RUN_TEST(handle_try_auth_hmac_auth_failed);
RUN_TEST(handle_try_auth_crypto_failure);
RUN_TEST(handle_try_auth_rate_limit_reached);
RUN_TEST(handle_try_auth_nv_fail);
RUN_TEST(handle_try_auth_lowent_auth_failed);
RUN_TEST(handle_try_auth_pcr_mismatch);
RUN_TEST(handle_try_auth_success);
RUN_TEST(handle_try_auth_old_protocol_old_leaf_success);
RUN_TEST(handle_try_auth_old_protocol_new_leaf_success);
/* Test reset auth. */
RUN_TEST(handle_reset_auth_invalid_length);
RUN_TEST(handle_reset_auth_label_invalid);
RUN_TEST(handle_reset_auth_path_auth_failed);
RUN_TEST(handle_reset_auth_hmac_auth_failed);
RUN_TEST(handle_reset_auth_crypto_failure);
RUN_TEST(handle_reset_auth_reset_auth_failed);
RUN_TEST(handle_reset_auth_nv_fail);
RUN_TEST(handle_reset_auth_success);
/* Test get log. */
RUN_TEST(handle_get_log_invalid_length);
RUN_TEST(handle_get_log_nv_fail);
RUN_TEST(handle_get_log_success);
/* Test log replay. */
RUN_TEST(handle_log_replay_invalid_length);
RUN_TEST(handle_log_replay_nv_fail);
RUN_TEST(handle_log_replay_root_not_found);
RUN_TEST(handle_log_replay_type_invalid);
RUN_TEST(handle_log_replay_hmac_auth_failed);
RUN_TEST(handle_log_replay_crypto_failure);
RUN_TEST(handle_log_replay_label_invalid);
RUN_TEST(handle_log_replay_path_auth_failed);
RUN_TEST(handle_log_replay_success);
test_print_result();
}