/* * Copyright (c) 2022 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include "mocks/keys_help_utils.h" #include "mocks/rpa.h" #include "testing_common_defs.h" #include #include #include #include DEFINE_FFF_GLOBALS; /* This LUT contains different combinations of ID, Address and key type. * Item in this list will be used to fill keys pool. */ static const struct id_addr_type testing_id_addr_type_lut[] = { {BT_ADDR_ID_1, BT_ADDR_LE_1, BT_KEYS_PERIPH_LTK}, {BT_ADDR_ID_1, BT_RPA_ADDR_LE_1, BT_KEYS_PERIPH_LTK}, {BT_ADDR_ID_1, BT_RPA_ADDR_LE_2, BT_KEYS_IRK}, {BT_ADDR_ID_1, BT_ADDR_LE_3, BT_KEYS_IRK}, {BT_ADDR_ID_2, BT_ADDR_LE_1, BT_KEYS_LTK}, {BT_ADDR_ID_2, BT_RPA_ADDR_LE_3, BT_KEYS_IRK}, {BT_ADDR_ID_2, BT_RPA_ADDR_LE_4, BT_KEYS_IRK}, {BT_ADDR_ID_2, BT_ADDR_LE_2, BT_KEYS_LOCAL_CSRK}, {BT_ADDR_ID_3, BT_ADDR_LE_1, BT_KEYS_REMOTE_CSRK}, {BT_ADDR_ID_3, BT_ADDR_LE_2, BT_KEYS_LTK_P256}, {BT_ADDR_ID_4, BT_ADDR_LE_1, BT_KEYS_ALL}}; /* Global iterator to iterate over the ID, Address and type LUT */ static uint8_t params_it; /* Pointer to the current set of testing parameters */ static struct id_addr_type const *current_params_vector; /* This list will hold returned references while filling keys pool */ static struct bt_keys *returned_keys_refs[CONFIG_BT_MAX_PAIRED]; BUILD_ASSERT(ARRAY_SIZE(testing_id_addr_type_lut) == CONFIG_BT_MAX_PAIRED); BUILD_ASSERT(ARRAY_SIZE(testing_id_addr_type_lut) == ARRAY_SIZE(returned_keys_refs)); /* Check if a Bluetooth LE random address is resolvable private address. */ #define BT_ADDR_IS_RPA(a) (((a)->val[5] & 0xc0) == 0x40) static bool check_if_addr_is_rpa(const bt_addr_le_t *addr) { if (addr->type != BT_ADDR_LE_RANDOM) { return false; } return BT_ADDR_IS_RPA(&addr->a); } static bool bt_rpa_irk_matches_unreachable_custom_fake(const uint8_t irk[16], const bt_addr_t *addr) { zassert_unreachable("Unexpected call to 'bt_rpa_irk_matches()' occurred"); return true; } static bool bt_rpa_irk_matches_custom_fake(const uint8_t irk[16], const bt_addr_t *addr) { if (irk[0] != (params_it) && bt_addr_eq(¤t_params_vector->addr->a, addr)) { return false; } return true; } static void *empty_list_ts_setup(void) { clear_key_pool(); return NULL; } ZTEST_SUITE(bt_keys_find_irk_initially_empty_list, NULL, empty_list_ts_setup, NULL, NULL, NULL); /* * Find a non-existing key reference for ID and Address of type 'BT_KEYS_IRK' * * Constraints: * - Empty keys pool list * * Expected behaviour: * - A NULL value is returned */ ZTEST(bt_keys_find_irk_initially_empty_list, test_find_non_existing_key_reference) { uint8_t id; const bt_addr_le_t *addr; struct bt_keys *returned_ref; struct id_addr_type const *params_vector; for (size_t i = 0; i < ARRAY_SIZE(testing_id_addr_type_lut); i++) { params_vector = &testing_id_addr_type_lut[i]; id = params_vector->id; addr = params_vector->addr; returned_ref = bt_keys_find_irk(id, addr); zassert_true(returned_ref == NULL, "bt_keys_find_irk() returned a non-valid reference"); } } static void rpa_resolving_ts_setup(void *f) { clear_key_pool(); int rv = fill_key_pool_by_id_addr_type( testing_id_addr_type_lut, ARRAY_SIZE(testing_id_addr_type_lut), returned_keys_refs); zassert_true(rv == 0, "Failed to fill keys pool list, error code %d", -rv); /* Set the index to the IRK value to recognize row index during bt_rpa_irk_matches() * callback */ for (size_t it = 0; it < ARRAY_SIZE(returned_keys_refs); it++) { returned_keys_refs[it]->irk.val[0] = it; } RPA_FFF_FAKES_LIST(RESET_FAKE); } ZTEST_SUITE(bt_keys_find_irk_rpa_resolving, NULL, NULL, rpa_resolving_ts_setup, NULL, NULL); /* * Try to resolve an RPA address using IRK by finding an existing key reference for ID and Address * of type 'BT_KEYS_IRK'. Matching the address with existing IRKs fails. * * Constraints: * - Full keys pool list * - IRK value and device address don't match * * Expected behaviour: * - A NULL value is returned */ ZTEST(bt_keys_find_irk_rpa_resolving, test_resolving_rpa_address_by_irk_but_matching_fails) { uint8_t id; const bt_addr_le_t *addr; struct bt_keys *returned_ref; struct id_addr_type const *params_vector; bt_rpa_irk_matches_fake.return_val = false; for (size_t i = 0; i < ARRAY_SIZE(testing_id_addr_type_lut); i++) { params_vector = &testing_id_addr_type_lut[i]; id = params_vector->id; addr = params_vector->addr; returned_ref = bt_keys_find_irk(id, addr); zassert_true(returned_ref == NULL, "bt_keys_find_irk() returned a non-valid reference"); } } /* * Try to resolve an RPA address using IRK by finding an existing key reference for ID and Address * of type 'BT_KEYS_IRK'. Matching the address with existing IRKs fails. * * Constraints: * - Full keys pool list * - IRK value and device address match * * Expected behaviour: * - A valid reference value is returned */ ZTEST(bt_keys_find_irk_rpa_resolving, test_resolving_rpa_address_by_irk_and_matching_succeeds) { int type; uint8_t id; const bt_addr_le_t *addr; struct id_addr_type const *params_vector; struct bt_keys *returned_ref, *expected_key_ref; bt_rpa_irk_matches_fake.custom_fake = bt_rpa_irk_matches_custom_fake; for (size_t it = 0; it < ARRAY_SIZE(testing_id_addr_type_lut); it++) { params_vector = &testing_id_addr_type_lut[it]; type = params_vector->type; id = params_vector->id; addr = params_vector->addr; /* Set global variables to be used within bt_rpa_irk_matches_custom_fake() */ params_it = it; current_params_vector = params_vector; expected_key_ref = returned_keys_refs[it]; /* * Try to resolve the current testing vector address. * Address will be considered resolvable if: * - The current testing vector address is an RPA * - The current testing vector key type is an IRK */ returned_ref = bt_keys_find_irk(id, addr); if (check_if_addr_is_rpa(addr) && (type & BT_KEYS_IRK)) { zassert_true(returned_ref != NULL, "bt_keys_find_irk() returned a NULL reference %d", it); zassert_equal_ptr(returned_ref, expected_key_ref, "bt_keys_find_irk() returned unexpected reference"); /* Check if address has been stored */ zassert_mem_equal(&returned_ref->irk.rpa, &addr->a, sizeof(bt_addr_t), "Incorrect address was stored by 'bt_keys_find_irk()'"); } else { zassert_true(returned_ref == NULL, "bt_keys_find_irk() returned a non-valid reference %d", it); } } } static void *no_resolving_ts_setup(void) { int type; const bt_addr_le_t *addr; struct id_addr_type const *params_vector; clear_key_pool(); int rv = fill_key_pool_by_id_addr_type( testing_id_addr_type_lut, ARRAY_SIZE(testing_id_addr_type_lut), returned_keys_refs); zassert_true(rv == 0, "Failed to fill keys pool list, error code %d", -rv); /* Set the index to the IRK value to recognize row index during bt_rpa_irk_matches() * callback */ for (size_t it = 0; it < ARRAY_SIZE(returned_keys_refs); it++) { returned_keys_refs[it]->irk.val[0] = it; } /* Copy the address as if was previously resolved using IRK */ for (size_t it = 0; it < ARRAY_SIZE(returned_keys_refs); it++) { params_vector = &testing_id_addr_type_lut[it]; type = params_vector->type; addr = params_vector->addr; if (check_if_addr_is_rpa(addr) && (type & BT_KEYS_IRK)) { bt_addr_copy(&returned_keys_refs[it]->irk.rpa, &addr->a); } } return NULL; } ZTEST_SUITE(bt_keys_find_irk_no_resolving, NULL, no_resolving_ts_setup, NULL, NULL, NULL); /* * Find an existing key reference for ID and Address of type 'BT_KEYS_IRK' * while the address has been resolved previously using the IRK * * Constraints: * - Full keys pool list * - IRK address and device address match * * Expected behaviour: * - A valid reference value is returned */ ZTEST(bt_keys_find_irk_no_resolving, test_find_key_of_previously_resolved_address) { int type; uint8_t id; const bt_addr_le_t *addr; struct id_addr_type const *params_vector; struct bt_keys *returned_ref, *expected_key_ref; for (size_t it = 0; it < ARRAY_SIZE(testing_id_addr_type_lut); it++) { params_vector = &testing_id_addr_type_lut[it]; type = params_vector->type; id = params_vector->id; addr = params_vector->addr; /* Set global variables to be used within bt_rpa_irk_matches_custom_fake() */ params_it = it; current_params_vector = params_vector; /* * Now, as the address under test should have been resolved before, * bt_rpa_irk_matches() isn't expected to be called for an RPA. * * But, for other records, which won't be resolved, a call to bt_rpa_irk_matches() * is expected simulating the attempt to resolve it */ if (check_if_addr_is_rpa(addr) && (type & BT_KEYS_IRK)) { bt_rpa_irk_matches_fake.custom_fake = bt_rpa_irk_matches_unreachable_custom_fake; } else { bt_rpa_irk_matches_fake.custom_fake = bt_rpa_irk_matches_custom_fake; } expected_key_ref = returned_keys_refs[it]; returned_ref = bt_keys_find_irk(id, addr); if (check_if_addr_is_rpa(addr) && (type & BT_KEYS_IRK)) { zassert_true(returned_ref != NULL, "bt_keys_find_irk() returned a NULL reference"); zassert_equal_ptr(returned_ref, expected_key_ref, "bt_keys_find_irk() returned unexpected reference"); /* Check if address has been stored */ zassert_mem_equal(&returned_ref->irk.rpa, &addr->a, sizeof(bt_addr_t), "Incorrect address was stored by 'bt_keys_find_irk()'"); } else { zassert_true(returned_ref == NULL, "bt_keys_find_irk() returned a non-valid reference"); } } }