summaryrefslogtreecommitdiff
path: root/test/pinweaver.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/pinweaver.c')
-rw-r--r--test/pinweaver.c1739
1 files changed, 1739 insertions, 0 deletions
diff --git a/test/pinweaver.c b/test/pinweaver.c
new file mode 100644
index 0000000000..16c40ec9aa
--- /dev/null
+++ b/test/pinweaver.c
@@ -0,0 +1,1739 @@
+/* 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 <sha256.h>
+#include <stdint.h>
+#include <string.h>
+#include <timer.h>
+#include <util.h>
+#include <pinweaver_types.h>
+
+#include "test_util.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];
+ };
+};
+
+/******************************************************************************/
+/* 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},
+ },
+ /*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,
+};
+
+/******************************************************************************/
+/* Config Variables and defines for Mocks.
+ */
+
+uint32_t MOCK_restart_count;
+
+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;
+
+/******************************************************************************/
+/* Helper functions
+ */
+static int do_request(struct merkle_tree_t *merkle_tree,
+ struct pw_test_data_t *buf)
+{
+ 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);
+ 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";
+ 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]);
+}
+
+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],
+ struct unimported_leaf_data_t *data)
+{
+ memcpy(&data->head, &DEFAULT_HEAD, sizeof(DEFAULT_HEAD));
+ memcpy(data->hmac, hmac, sizeof(data->hmac));
+ memcpy(data->iv, DEFAULT_IV, sizeof(DEFAULT_IV));
+ memcpy(data->payload, &leaf_data->pub, sizeof(leaf_data->pub));
+ DCRYPTO_aes_ctr(data->payload + sizeof(leaf_data->pub),
+ EMPTY_TREE.wrap_key, sizeof(EMPTY_TREE.wrap_key) * 8,
+ DEFAULT_IV, (const uint8_t *)&leaf_data->sec,
+ sizeof(leaf_data->sec));
+ setup_default_empty_path((void *)(data->payload + DEFAULT_HEAD.pub_len +
+ DEFAULT_HEAD.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));
+
+ 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;
+}
+
+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));
+
+ 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.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;
+}
+
+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));
+
+ 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);
+}
+
+static void setup_try_auth_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(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;
+
+ request->header.version = PW_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;
+
+ 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,
+ &request->data.try_auth.unimported_leaf_data);
+
+ MOCK_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;
+}
+
+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, 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));
+
+ 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,
+ &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;
+}
+
+/* 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;
+ default:
+ MOCK_hmac = DEFAULT_HMAC;
+ break;
+ }
+}
+
+/******************************************************************************/
+/* Mock implementations of TPM, TRNG, and Dcrypto functionality.
+ */
+
+uint32_t get_restart_count(void)
+{
+ return MOCK_restart_count;
+}
+
+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);
+}
+
+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;
+}
+
+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_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));
+
+ 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_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)));
+
+ 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_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);
+
+ 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, &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;
+ MOCK_restart_count = 1;
+ force_time((timestamp_t){.val = 7200llu * SECOND});
+ setup_try_auth_defaults_with_leaf(&leaf_data, &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;
+ MOCK_restart_count = 1;
+ force_time((timestamp_t){.val = 7200llu * SECOND});
+ setup_try_auth_defaults_with_leaf(&leaf_data, &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, &merkle_tree,
+ &buf.request);
+ MOCK_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, &merkle_tree,
+ &buf.request);
+ MOCK_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_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, &merkle_tree,
+ &buf.request);
+ MOCK_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);
+ return check_dcrypto_mutex_usage();
+}
+
+static int handle_try_auth_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.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;
+ setup_try_auth_defaults_with_leaf(&leaf_data, &merkle_tree,
+ &buf.request);
+ MOCK_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 == 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, 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));
+ 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 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, &merkle_tree,
+ &buf.request);
+ MOCK_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 == 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, 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));
+ 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();
+}
+
+/******************************************************************************/
+/* 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_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);
+
+ /* 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);
+ 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_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_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_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_lowent_auth_failed);
+ RUN_TEST(handle_try_auth_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_success);
+
+ test_print_result();
+}