Skip to content

Commit 2b91ebe

Browse files
alxelaxcfriedt
authored andcommitted
test: Bluetooth: Mesh: test replay attack on ble mesh rpc
The test checks the resistance of ble mesh stack to replay attack. Replay protection cache shall store seqAuth last frames. Device shall filter out such messages on the transport layer. Power on\off sequence shouldn't impact that since replay protection cache is stored in settings subsystem. Signed-off-by: Aleksandr Khromykh <[email protected]>
1 parent 4b5cd92 commit 2b91ebe

File tree

8 files changed

+305
-9
lines changed

8 files changed

+305
-9
lines changed

tests/bluetooth/bsim_bt/bsim_test_mesh/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ if(CONFIG_SETTINGS)
2121
target_sources(app PRIVATE
2222
src/settings_test_backend.c
2323
src/test_persistence.c
24+
src/test_replay_cache.c
2425
)
2526
else()
2627
target_sources(app PRIVATE

tests/bluetooth/bsim_bt/bsim_test_mesh/prj_pst.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,6 @@ CONFIG_BT_MESH_PROV_DEVICE=y
4848
CONFIG_BT_MESH_CDB=y
4949
CONFIG_BT_MESH_CDB_NODE_COUNT=3
5050
CONFIG_BT_MESH_GATT_PROXY=y
51+
CONFIG_BT_MESH_TX_SEG_RETRANS_COUNT=1
5152

5253
CONFIG_BT_MESH_DEBUG=y

tests/bluetooth/bsim_bt/bsim_test_mesh/src/main.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#if defined(CONFIG_SETTINGS)
1111
extern struct bst_test_list *test_persistence_install(struct bst_test_list *tests);
12+
extern struct bst_test_list *test_rpc_install(struct bst_test_list *tests);
1213
#else
1314
extern struct bst_test_list *test_transport_install(struct bst_test_list *tests);
1415
extern struct bst_test_list *test_friendship_install(struct bst_test_list *tests);
@@ -20,6 +21,7 @@ extern struct bst_test_list *test_scanner_install(struct bst_test_list *test);
2021
bst_test_install_t test_installers[] = {
2122
#if defined(CONFIG_SETTINGS)
2223
test_persistence_install,
24+
test_rpc_install,
2325
#else
2426
test_transport_install,
2527
test_friendship_install,

tests/bluetooth/bsim_bt/bsim_test_mesh/src/mesh_test.c

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@ static K_MEM_SLAB_DEFINE(msg_pool, sizeof(struct bt_mesh_test_msg),
2020
static K_QUEUE_DEFINE(recv);
2121
struct bt_mesh_test_stats test_stats;
2222
struct bt_mesh_msg_ctx test_send_ctx;
23+
static void (*ra_cb)(uint8_t *, size_t);
2324

2425
static int msg_rx(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx,
2526
struct net_buf_simple *buf)
2627
{
27-
size_t len = buf->len + BT_MESH_MODEL_OP_LEN(TEST_MSG_OP);
28+
size_t len = buf->len + BT_MESH_MODEL_OP_LEN(TEST_MSG_OP_1);
2829
static uint8_t prev_seq;
2930
struct bt_mesh_test_msg *msg;
3031
uint8_t seq = 0;
@@ -69,8 +70,25 @@ static int msg_rx(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx,
6970
return 0;
7071
}
7172

73+
static int ra_rx(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx,
74+
struct net_buf_simple *buf)
75+
{
76+
LOG_INF("\tlen: %d bytes", buf->len);
77+
LOG_INF("\tsrc: 0x%04x", ctx->addr);
78+
LOG_INF("\tdst: 0x%04x", ctx->recv_dst);
79+
LOG_INF("\tttl: %u", ctx->recv_ttl);
80+
LOG_INF("\trssi: %d", ctx->recv_rssi);
81+
82+
if (ra_cb) {
83+
ra_cb(net_buf_simple_pull_mem(buf, buf->len), buf->len);
84+
}
85+
86+
return 0;
87+
}
88+
7289
static const struct bt_mesh_model_op model_op[] = {
73-
{ TEST_MSG_OP, 0, msg_rx },
90+
{ TEST_MSG_OP_1, 0, msg_rx },
91+
{ TEST_MSG_OP_2, 0, ra_rx },
7492
};
7593

7694
int __weak test_model_pub_update(struct bt_mesh_model *mod)
@@ -164,8 +182,16 @@ static void bt_enabled(void)
164182
return;
165183
}
166184

185+
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
186+
LOG_INF("Loading stored settings");
187+
settings_load();
188+
}
189+
167190
err = bt_mesh_provision(test_net_key, 0, 0, 0, cfg->addr, cfg->dev_key);
168-
if (err) {
191+
if (err == -EALREADY) {
192+
LOG_INF("Using stored settings");
193+
return;
194+
} else if (err) {
169195
FAIL("Provisioning failed (err %d)", err);
170196
return;
171197
}
@@ -327,15 +353,15 @@ int bt_mesh_test_send_async(uint16_t addr, size_t len,
327353
test_send_ctx.send_rel = (flags & FORCE_SEGMENTATION);
328354
test_send_ctx.send_ttl = BT_MESH_TTL_DEFAULT;
329355

330-
BT_MESH_MODEL_BUF_DEFINE(buf, TEST_MSG_OP, BT_MESH_TX_SDU_MAX);
331-
bt_mesh_model_msg_init(&buf, TEST_MSG_OP);
356+
BT_MESH_MODEL_BUF_DEFINE(buf, TEST_MSG_OP_1, BT_MESH_TX_SDU_MAX);
357+
bt_mesh_model_msg_init(&buf, TEST_MSG_OP_1);
332358

333-
if (len > BT_MESH_MODEL_OP_LEN(TEST_MSG_OP)) {
359+
if (len > BT_MESH_MODEL_OP_LEN(TEST_MSG_OP_1)) {
334360
net_buf_simple_add_u8(&buf, count);
335361
}
336362

337363
/* Subtract the length of the opcode and the sequence ID */
338-
for (int i = 1; i < len - BT_MESH_MODEL_OP_LEN(TEST_MSG_OP); i++) {
364+
for (int i = 1; i < len - BT_MESH_MODEL_OP_LEN(TEST_MSG_OP_1); i++) {
339365
net_buf_simple_add_u8(&buf, i);
340366
}
341367

@@ -395,3 +421,32 @@ int bt_mesh_test_send(uint16_t addr, size_t len,
395421

396422
return 0;
397423
}
424+
425+
int bt_mesh_test_send_ra(uint16_t addr, uint8_t *data, size_t len,
426+
const struct bt_mesh_send_cb *send_cb,
427+
void *cb_data)
428+
{
429+
int err;
430+
431+
test_send_ctx.addr = addr;
432+
test_send_ctx.send_rel = 0;
433+
test_send_ctx.send_ttl = BT_MESH_TTL_DEFAULT;
434+
435+
BT_MESH_MODEL_BUF_DEFINE(buf, TEST_MSG_OP_2, BT_MESH_TX_SDU_MAX);
436+
bt_mesh_model_msg_init(&buf, TEST_MSG_OP_2);
437+
438+
net_buf_simple_add_mem(&buf, data, len);
439+
440+
err = bt_mesh_model_send(test_model, &test_send_ctx, &buf, send_cb, cb_data);
441+
if (err) {
442+
LOG_ERR("bt_mesh_model_send failed (err: %d)", err);
443+
return err;
444+
}
445+
446+
return 0;
447+
}
448+
449+
void bt_mesh_test_ra_cb_setup(void (*cb)(uint8_t *, size_t))
450+
{
451+
ra_cb = cb;
452+
}

tests/bluetooth/bsim_bt/bsim_test_mesh/src/mesh_test.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
#include <bluetooth/mesh.h>
2727

2828
#define TEST_MOD_ID 0x8888
29-
#define TEST_MSG_OP BT_MESH_MODEL_OP_1(0x0f)
29+
#define TEST_MSG_OP_1 BT_MESH_MODEL_OP_1(0x0f)
30+
#define TEST_MSG_OP_2 BT_MESH_MODEL_OP_1(0x10)
3031

3132
#define TEST_VND_COMPANY_ID 0x1234
3233
#define TEST_VND_MOD_ID 0x5678
@@ -120,4 +121,8 @@ int bt_mesh_test_send_async(uint16_t addr, size_t len,
120121
enum bt_mesh_test_send_flags flags,
121122
const struct bt_mesh_send_cb *send_cb,
122123
void *cb_data);
124+
int bt_mesh_test_send_ra(uint16_t addr, uint8_t *data, size_t len,
125+
const struct bt_mesh_send_cb *send_cb,
126+
void *cb_data);
127+
void bt_mesh_test_ra_cb_setup(void (*cb)(uint8_t *, size_t));
123128
#endif /* ZEPHYR_TESTS_BLUETOOTH_BSIM_BT_BSIM_TEST_MESH_MESH_TEST_H_ */

tests/bluetooth/bsim_bt/bsim_test_mesh/src/test_persistence.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ static void test_args_parse(int argc, char *argv[])
207207
},
208208
};
209209

210-
bs_args_parse_all_cmd_line(argc, argv, &args_struct);
210+
bs_args_parse_all_cmd_line(argc, argv, args_struct);
211211
}
212212

213213
static void check_mod_pub_params(struct bt_mesh_cfg_mod_pub *expected,
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
/*
2+
* Copyright (c) 2021 Nordic Semiconductor
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#include "mesh_test.h"
7+
#include "settings_test_backend.h"
8+
#include "mesh/mesh.h"
9+
#include "mesh/net.h"
10+
11+
#define LOG_MODULE_NAME test_rpc
12+
13+
#include <logging/log.h>
14+
LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF);
15+
16+
#define WAIT_TIME 60 /*seconds*/
17+
#define TEST_DATA_WAITING_TIME 5 /* seconds */
18+
#define TEST_DATA_SIZE 20
19+
20+
static const struct bt_mesh_test_cfg tx_cfg = {
21+
.addr = 0x0001,
22+
.dev_key = { 0x01 },
23+
};
24+
static const struct bt_mesh_test_cfg rx_cfg = {
25+
.addr = 0x0002,
26+
.dev_key = { 0x02 },
27+
};
28+
29+
static uint8_t test_data[TEST_DATA_SIZE];
30+
static uint8_t rx_cnt;
31+
static bool is_tx_succeeded;
32+
33+
static void test_tx_init(void)
34+
{
35+
bt_mesh_test_cfg_set(&tx_cfg, WAIT_TIME);
36+
}
37+
38+
static void test_rx_init(void)
39+
{
40+
bt_mesh_test_cfg_set(&rx_cfg, WAIT_TIME);
41+
}
42+
43+
static void tx_started(uint16_t dur, int err, void *data)
44+
{
45+
if (err) {
46+
FAIL("Couldn't start sending (err: %d)", err);
47+
}
48+
49+
LOG_INF("Sending started");
50+
}
51+
52+
static void tx_ended(int err, void *data)
53+
{
54+
struct k_sem *sem = data;
55+
56+
if (err) {
57+
is_tx_succeeded = false;
58+
LOG_INF("Sending failed (%d)", err);
59+
} else {
60+
is_tx_succeeded = true;
61+
LOG_INF("Sending succeeded");
62+
}
63+
64+
k_sem_give(sem);
65+
}
66+
67+
static void rx_ended(uint8_t *data, size_t len)
68+
{
69+
memset(test_data, rx_cnt++, sizeof(test_data));
70+
71+
if (memcmp(test_data, data, len)) {
72+
FAIL("Unexpected rx data");
73+
}
74+
75+
LOG_INF("Receiving succeeded");
76+
}
77+
78+
static void test_tx_immediate_replay_attack(void)
79+
{
80+
settings_test_backend_clear();
81+
bt_mesh_test_setup();
82+
83+
static const struct bt_mesh_send_cb send_cb = {
84+
.start = tx_started,
85+
.end = tx_ended,
86+
};
87+
struct k_sem sem;
88+
89+
k_sem_init(&sem, 0, 1);
90+
91+
uint32_t seq = bt_mesh.seq;
92+
93+
for (int i = 0; i < 3; i++) {
94+
is_tx_succeeded = false;
95+
96+
memset(test_data, i, sizeof(test_data));
97+
ASSERT_OK(bt_mesh_test_send_ra(rx_cfg.addr, test_data,
98+
sizeof(test_data), &send_cb, &sem));
99+
100+
if (k_sem_take(&sem, K_SECONDS(TEST_DATA_WAITING_TIME))) {
101+
LOG_ERR("Send timed out");
102+
}
103+
104+
ASSERT_TRUE(is_tx_succeeded);
105+
}
106+
107+
bt_mesh.seq = seq;
108+
109+
for (int i = 0; i < 3; i++) {
110+
is_tx_succeeded = true;
111+
112+
memset(test_data, i, sizeof(test_data));
113+
ASSERT_OK(bt_mesh_test_send_ra(rx_cfg.addr, test_data,
114+
sizeof(test_data), &send_cb, &sem));
115+
116+
if (k_sem_take(&sem, K_SECONDS(TEST_DATA_WAITING_TIME))) {
117+
LOG_ERR("Send timed out");
118+
}
119+
120+
ASSERT_TRUE(!is_tx_succeeded);
121+
}
122+
123+
PASS();
124+
}
125+
126+
static void test_rx_immediate_replay_attack(void)
127+
{
128+
settings_test_backend_clear();
129+
bt_mesh_test_setup();
130+
bt_mesh_test_ra_cb_setup(rx_ended);
131+
132+
k_sleep(K_SECONDS(6 * TEST_DATA_WAITING_TIME));
133+
134+
ASSERT_TRUE(rx_cnt == 3, "Device didn't receive expected data");
135+
136+
PASS();
137+
}
138+
139+
static void test_tx_power_replay_attack(void)
140+
{
141+
settings_test_backend_clear();
142+
bt_mesh_test_setup();
143+
144+
static const struct bt_mesh_send_cb send_cb = {
145+
.start = tx_started,
146+
.end = tx_ended,
147+
};
148+
struct k_sem sem;
149+
150+
k_sem_init(&sem, 0, 1);
151+
152+
for (int i = 0; i < 3; i++) {
153+
is_tx_succeeded = true;
154+
155+
memset(test_data, i, sizeof(test_data));
156+
ASSERT_OK(bt_mesh_test_send_ra(rx_cfg.addr, test_data,
157+
sizeof(test_data), &send_cb, &sem));
158+
159+
if (k_sem_take(&sem, K_SECONDS(TEST_DATA_WAITING_TIME))) {
160+
LOG_ERR("Send timed out");
161+
}
162+
163+
ASSERT_TRUE(!is_tx_succeeded);
164+
}
165+
166+
for (int i = 0; i < 3; i++) {
167+
is_tx_succeeded = false;
168+
169+
memset(test_data, i, sizeof(test_data));
170+
ASSERT_OK(bt_mesh_test_send_ra(rx_cfg.addr, test_data,
171+
sizeof(test_data), &send_cb, &sem));
172+
173+
if (k_sem_take(&sem, K_SECONDS(TEST_DATA_WAITING_TIME))) {
174+
LOG_ERR("Send timed out");
175+
}
176+
177+
ASSERT_TRUE(is_tx_succeeded);
178+
}
179+
180+
PASS();
181+
}
182+
183+
static void test_rx_power_replay_attack(void)
184+
{
185+
bt_mesh_test_setup();
186+
bt_mesh_test_ra_cb_setup(rx_ended);
187+
188+
k_sleep(K_SECONDS(6 * TEST_DATA_WAITING_TIME));
189+
190+
ASSERT_TRUE(rx_cnt == 3, "Device didn't receive expected data");
191+
192+
PASS();
193+
}
194+
195+
#define TEST_CASE(role, name, description) \
196+
{ \
197+
.test_id = "rpc_" #role "_" #name, \
198+
.test_descr = description, \
199+
.test_post_init_f = test_##role##_init, \
200+
.test_tick_f = bt_mesh_test_timeout, \
201+
.test_main_f = test_##role##_##name, \
202+
}
203+
204+
static const struct bst_test_instance test_rpc[] = {
205+
TEST_CASE(tx, immediate_replay_attack, "RPC: perform replay attack immediately"),
206+
TEST_CASE(tx, power_replay_attack, "RPC: perform replay attack after power cycle"),
207+
208+
TEST_CASE(rx, immediate_replay_attack, "RPC: device under immediate attack"),
209+
TEST_CASE(rx, power_replay_attack, "RPC: device under power cycle reply attack"),
210+
BSTEST_END_MARKER
211+
};
212+
213+
struct bst_test_list *test_rpc_install(struct bst_test_list *tests)
214+
{
215+
tests = bst_add_tests(tests, test_rpc);
216+
return tests;
217+
}

0 commit comments

Comments
 (0)