feat(ble): Add security related tests.

* Add security related tests to verify behavior when trying to read
  a GATT characteristic from our peripheral with and without client
  auto security request/retry.
This commit is contained in:
Pete Johanson 2024-01-03 16:55:26 -08:00
parent bc7b4b56bd
commit 69f962fab2
13 changed files with 148 additions and 19 deletions

View File

@ -34,6 +34,14 @@ if [ -z "$BLE_TESTS_NO_CENTRAL_BUILD" ]; then
fi
cp build/tests/ble/private_central/zephyr/zephyr.exe "${BSIM_OUT_PATH}/bin/ble_test_private_central.exe"
if ! [ -e build/tests/ble/no_auto_sec_central ]; then
west build -d build/tests/ble/no_auto_sec_central -b nrf52_bsim tests/ble/central -- -DCONFIG_BT_ATT_RETRY_ON_SEC_ERR=n > /dev/null 2>&1
else
west build -d build/tests/ble/no_auto_sec_central
fi
cp build/tests/ble/no_auto_sec_central/zephyr/zephyr.exe "${BSIM_OUT_PATH}/bin/ble_test_no_auto_sec_central.exe"
fi
testcases=$(find $path -name nrf52_bsim.keymap -exec dirname \{\} \;)

View File

@ -522,14 +522,6 @@ static void split_central_process_connection(struct bt_conn *conn) {
LOG_DBG("Current security for connection: %d", bt_conn_get_security(conn));
#if !IS_ENABLED(CONFIG_BT_GATT_AUTO_SEC_REQ)
err = bt_conn_set_security(conn, BT_SECURITY_L2);
if (err) {
LOG_ERR("Failed to set security (reason %d)", err);
return;
}
#endif // !IS_ENABLED(CONFIG_BT_GATT_AUTO_SEC_REQ)
struct peripheral_slot *slot = peripheral_slot_for_conn(conn);
if (slot == NULL) {
LOG_ERR("No peripheral state found for connection");

View File

@ -40,6 +40,10 @@ LOG_MODULE_REGISTER(ble_central, 4);
static bool disconnect_and_reconnect = false;
static bool clear_bond_on_disconnect = false;
static bool halt_after_bonding = false;
static bool read_hid_report_on_connect = false;
static bool skip_set_security_on_connect = false;
static bool skip_discovery_on_connect = false;
static bool read_directly_on_discovery = false;
static int32_t wait_on_start = 0;
static void ble_central_native_posix_options(void) {
@ -59,6 +63,26 @@ static void ble_central_native_posix_options(void) {
.type = 'b',
.dest = (void *)&clear_bond_on_disconnect,
.descript = "Clear bonds on disconnect and reconnect"},
{.is_switch = true,
.option = "skip_set_security_on_connect",
.type = 'b',
.dest = (void *)&skip_set_security_on_connect,
.descript = "Skip set security level after connecting"},
{.is_switch = true,
.option = "read_hid_report_on_connect",
.type = 'b',
.dest = (void *)&read_hid_report_on_connect,
.descript = "Read the peripheral HID report after connecting"},
{.is_switch = true,
.option = "skip_discovery_on_connect",
.type = 'b',
.dest = (void *)&skip_discovery_on_connect,
.descript = "Skip GATT characteristic discovery after connecting"},
{.is_switch = true,
.option = "read_directly_on_discovery",
.type = 'b',
.dest = (void *)&read_directly_on_discovery,
.descript = "Read HIDS report after GATT characteristic discovery"},
{.option = "wait_on_start",
.name = "milliseconds",
.type = 'u',
@ -94,6 +118,16 @@ static uint8_t notify_func(struct bt_conn *conn, struct bt_gatt_subscribe_params
return BT_GATT_ITER_CONTINUE;
}
static struct bt_gatt_read_params read_params;
static const struct bt_uuid_16 hids_uuid = BT_UUID_INIT_16(BT_UUID_HIDS_REPORT_VAL);
static uint8_t read_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_read_params *params,
const void *data, uint16_t length) {
LOG_DBG("Read err: %d, length %d", err, length);
return BT_GATT_ITER_CONTINUE;
}
static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr,
struct bt_gatt_discover_params *params) {
int err;
@ -117,15 +151,24 @@ static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *at
LOG_DBG("[Discover failed] (err %d)", err);
}
} else if (!bt_uuid_cmp(discover_params.uuid, BT_UUID_HIDS_REPORT)) {
memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid));
discover_params.uuid = &uuid.uuid;
discover_params.start_handle = attr->handle + 2;
discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
subscribe_params.value_handle = bt_gatt_attr_value_handle(attr);
if (read_directly_on_discovery) {
read_params.single.handle = bt_gatt_attr_value_handle(attr);
read_params.single.offset = 0;
read_params.handle_count = 1;
read_params.func = read_cb;
err = bt_gatt_discover(conn, &discover_params);
if (err) {
LOG_DBG("[Discover failed] (err %d)", err);
bt_gatt_read(conn, &read_params);
} else {
memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid));
discover_params.uuid = &uuid.uuid;
discover_params.start_handle = attr->handle + 2;
discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
subscribe_params.value_handle = bt_gatt_attr_value_handle(attr);
err = bt_gatt_discover(conn, &discover_params);
if (err) {
LOG_DBG("[Discover failed] (err %d)", err);
}
}
} else {
subscribe_params.notify = notify_func;
@ -278,12 +321,23 @@ static void connected(struct bt_conn *conn, uint8_t conn_err) {
LOG_DBG("[Connected]: %s", addr);
if (conn == default_conn) {
if (bt_conn_get_security(conn) >= BT_SECURITY_L2) {
if (bt_conn_get_security(conn) >= BT_SECURITY_L2 && !skip_discovery_on_connect) {
LOG_DBG("[Discovering characteristics for the connection]");
discover_conn(conn);
} else {
} else if (!skip_set_security_on_connect) {
LOG_DBG("[Setting the security for the connection]");
bt_conn_set_security(conn, BT_SECURITY_L2);
}
if (read_hid_report_on_connect) {
read_params.func = read_cb;
read_params.handle_count = 0;
read_params.by_uuid.start_handle = 0x0001;
read_params.by_uuid.end_handle = 0xFFFF;
read_params.by_uuid.uuid = &hids_uuid.uuid;
bt_gatt_read(conn, &read_params);
}
}
}
@ -313,7 +367,7 @@ static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_
first_connect = false;
if (do_disconnect) {
k_work_reschedule(&disconnect_work, K_MSEC(500));
} else {
} else if (!skip_discovery_on_connect) {
discover_conn(conn);
}
}

View File

@ -0,0 +1 @@
./ble_test_central.exe -d=2 -skip_set_security_on_connect -read_hid_report_on_connect -skip_discovery_on_connect

View File

@ -0,0 +1 @@
s/^d_02: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9] .{19}//p

View File

@ -0,0 +1,24 @@
#include <behaviors.dtsi>
#include <dt-bindings/zmk/bt.h>
#include <dt-bindings/zmk/keys.h>
#include <dt-bindings/zmk/kscan_mock.h>
&kscan {
events =
<ZMK_MOCK_PRESS(0,0,10000)
ZMK_MOCK_RELEASE(0,0,2000)
ZMK_MOCK_PRESS(0,1,100)
ZMK_MOCK_RELEASE(0,1,1000)>;
};
/ {
keymap {
compatible = "zmk,keymap";
default_layer {
bindings = <
&kp A &kp B
&bt BT_SEL 0 &bt BT_SEL 1>;
};
};
};

View File

@ -0,0 +1,13 @@
<wrn> bt_id: No static addresses stored in controller
<dbg> ble_central: _posix_zephyr_main: [Bluetooth initialized]
<dbg> ble_central: start_scan: [Scanning successfully started]
<dbg> ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59
<dbg> ble_central: eir_found: [AD]: 9 data_len 0
<dbg> ble_central: eir_found: [AD]: 25 data_len 2
<dbg> ble_central: eir_found: [AD]: 1 data_len 1
<dbg> ble_central: eir_found: [AD]: 2 data_len 4
<dbg> ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random)
<dbg> ble_central: pairing_complete: Pairing complete
<dbg> ble_central: read_cb: Read err: 0, length 8
<dbg> ble_central: read_cb: Read err: 0, length 12
<dbg> ble_central: read_cb: Read err: 10, length 0

View File

@ -0,0 +1 @@
./ble_test_no_auto_sec_central.exe -d=2 -skip_set_security_on_connect -read_hid_report_on_connect -skip_discovery_on_connect

View File

@ -0,0 +1 @@
s/^d_02: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9] .{19}//p

View File

@ -0,0 +1,24 @@
#include <behaviors.dtsi>
#include <dt-bindings/zmk/bt.h>
#include <dt-bindings/zmk/keys.h>
#include <dt-bindings/zmk/kscan_mock.h>
&kscan {
events =
<ZMK_MOCK_PRESS(0,0,10000)
ZMK_MOCK_RELEASE(0,0,2000)
ZMK_MOCK_PRESS(0,1,100)
ZMK_MOCK_RELEASE(0,1,1000)>;
};
/ {
keymap {
compatible = "zmk,keymap";
default_layer {
bindings = <
&kp A &kp B
&bt BT_SEL 0 &bt BT_SEL 1>;
};
};
};

View File

@ -0,0 +1,10 @@
<wrn> bt_id: No static addresses stored in controller
<dbg> ble_central: _posix_zephyr_main: [Bluetooth initialized]
<dbg> ble_central: start_scan: [Scanning successfully started]
<dbg> ble_central: device_found: [DEVICE]: ED:3B:20:15:18:12 (random), AD evt type 0, AD data len 15, RSSI -59
<dbg> ble_central: eir_found: [AD]: 9 data_len 0
<dbg> ble_central: eir_found: [AD]: 25 data_len 2
<dbg> ble_central: eir_found: [AD]: 1 data_len 1
<dbg> ble_central: eir_found: [AD]: 2 data_len 4
<dbg> ble_central: connected: [Connected]: ED:3B:20:15:18:12 (random)
<dbg> ble_central: read_cb: Read err: 15, length 0