1 /*
2 * Copyright (c) 2024 Nordic Semiconductor
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Proxy Solicitation test
7 */
8
9 #include "mesh_test.h"
10 #include "mesh/access.h"
11 #include "mesh/settings.h"
12 #include "mesh/net.h"
13 #include "mesh/crypto.h"
14 #include "mesh/proxy.h"
15 #include <string.h>
16 #include <zephyr/logging/log.h>
17 #include <zephyr/sys/byteorder.h>
18 #include <zephyr/bluetooth/uuid.h>
19
20 LOG_MODULE_REGISTER(test_proxy_sol, LOG_LEVEL_INF);
21
22 #define WAIT_TIME 60 /*seconds*/
23 #define SEM_TIMEOUT 6 /*seconds*/
24 #define BEACON_TYPE_NET_ID 0
25 #define BEACON_TYPE_PRIVATE_NET_ID 2
26 #define BEACON_NET_ID_LEN 20
27 #define OTHER_ADV_TYPES_LEN 28
28
29 static struct bt_mesh_prov prov;
30 static struct bt_mesh_cfg_cli cfg_cli;
31 static struct bt_mesh_priv_beacon_cli priv_beacon_cli;
32 static struct bt_mesh_od_priv_proxy_cli od_priv_proxy_cli;
33 static struct k_sem beacon_sem;
34
35 static const struct bt_mesh_test_cfg tester_cfg = {
36 .addr = 0x0001,
37 .dev_key = {0x01},
38 };
39 static const struct bt_mesh_test_cfg iut_cfg = {
40 .addr = 0x0002,
41 .dev_key = {0x02},
42 };
43
44 static struct bt_mesh_model models[] = {
45 BT_MESH_MODEL_CFG_SRV,
46 BT_MESH_MODEL_CFG_CLI(&cfg_cli),
47 BT_MESH_MODEL_PRIV_BEACON_SRV,
48 BT_MESH_MODEL_PRIV_BEACON_CLI(&priv_beacon_cli),
49 BT_MESH_MODEL_OD_PRIV_PROXY_SRV,
50 BT_MESH_MODEL_OD_PRIV_PROXY_CLI(&od_priv_proxy_cli)
51 };
52
53 static struct bt_mesh_elem elems[] = {
54 BT_MESH_ELEM(0, models, BT_MESH_MODEL_NONE),
55 };
56
57 static const struct bt_mesh_comp comp = {
58 .cid = TEST_VND_COMPANY_ID,
59 .vid = 0xaaaa,
60 .pid = 0xbbbb,
61 .elem = elems,
62 .elem_count = ARRAY_SIZE(elems),
63 };
64
is_tester_address(void)65 static bool is_tester_address(void)
66 {
67 return bt_mesh_primary_addr() == tester_cfg.addr;
68 }
69
proxy_adv_type_get(uint8_t adv_type,struct net_buf_simple * buf)70 static uint8_t proxy_adv_type_get(uint8_t adv_type, struct net_buf_simple *buf)
71 {
72 uint8_t type;
73 uint8_t len = buf->len;
74
75 if (adv_type != BT_GAP_ADV_TYPE_ADV_IND || len < 12) {
76 return 0xFF;
77 }
78
79 (void)net_buf_simple_pull_mem(buf, 11);
80 type = net_buf_simple_pull_u8(buf);
81
82 if (len != ((type == BEACON_TYPE_NET_ID) ? BEACON_NET_ID_LEN : OTHER_ADV_TYPES_LEN)) {
83 return 0xFF;
84 }
85
86 return type;
87 }
88
scan_recv(const struct bt_le_scan_recv_info * info,struct net_buf_simple * ad)89 static void scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *ad)
90 {
91 uint8_t type = proxy_adv_type_get(info->adv_type, ad);
92
93 if (is_tester_address() && type == BEACON_TYPE_PRIVATE_NET_ID) {
94 k_sem_give(&beacon_sem);
95 }
96 }
97
98 static struct bt_le_scan_cb scan_cb = {
99 .recv = scan_recv,
100 };
101
tester_configure(void)102 static void tester_configure(void)
103 {
104 uint8_t err, status;
105
106 k_sem_init(&beacon_sem, 0, 1);
107 bt_le_scan_cb_register(&scan_cb);
108
109 bt_mesh_test_cfg_set(NULL, WAIT_TIME);
110 bt_mesh_device_setup(&prov, &comp);
111
112 ASSERT_OK_MSG(bt_mesh_provision(test_net_key, 0, 0, 0, tester_cfg.addr, tester_cfg.dev_key),
113 "Node failed to provision");
114
115 err = bt_mesh_cfg_cli_app_key_add(0, tester_cfg.addr, 0, 0, test_app_key, &status);
116 if (err || status) {
117 FAIL("AppKey add failed (err %d, status %u)", err, status);
118 }
119 }
120
iut_configure(void)121 static void iut_configure(void)
122 {
123 uint8_t err, status;
124
125 bt_mesh_test_cfg_set(NULL, WAIT_TIME);
126 bt_mesh_device_setup(&prov, &comp);
127
128 /* Configurations stored in flash during immediate_replay_attack */
129 if (!bt_mesh_is_provisioned()) {
130 ASSERT_OK_MSG(
131 bt_mesh_provision(test_net_key, 0, 0, 0, iut_cfg.addr, iut_cfg.dev_key),
132 "Node failed to provision");
133
134 err = bt_mesh_cfg_cli_app_key_add(0, iut_cfg.addr, 0, 0, test_app_key, &status);
135 if (err || status) {
136 FAIL("AppKey add failed (err %d, status %u)", err, status);
137 }
138 err = bt_mesh_cfg_cli_gatt_proxy_set(0, iut_cfg.addr, BT_MESH_GATT_PROXY_DISABLED,
139 &status);
140 if (err || status) {
141 FAIL("Proxy state disable failed (err %d, status %u)", err, status);
142 }
143 err = bt_mesh_priv_beacon_cli_gatt_proxy_set(0, iut_cfg.addr,
144 BT_MESH_GATT_PROXY_DISABLED, &status);
145 if (err || status) {
146 FAIL("Private proxy state disable failed (err %d, status %u)", err, status);
147 }
148 err = bt_mesh_od_priv_proxy_cli_set(0, iut_cfg.addr, BT_MESH_FEATURE_ENABLED,
149 &status);
150 if (err || !status) {
151 FAIL("On-Demand Private Proxy enable failed (err %d, status %u)", err,
152 status);
153 }
154 }
155 }
156
sol_fixed_pdu_create(struct bt_mesh_subnet * sub,struct net_buf_simple * pdu)157 static void sol_fixed_pdu_create(struct bt_mesh_subnet *sub, struct net_buf_simple *pdu)
158 {
159 uint32_t fixed_seq_n = 2;
160
161 net_buf_simple_add_u8(pdu, sub->keys[SUBNET_KEY_TX_IDX(sub)].msg.nid);
162 net_buf_simple_add_u8(pdu, 0x80);
163 net_buf_simple_add_le24(pdu, sys_cpu_to_be24(fixed_seq_n));
164 net_buf_simple_add_le16(pdu, sys_cpu_to_be16(bt_mesh_primary_addr()));
165 net_buf_simple_add_le16(pdu, 0x0000);
166
167 ASSERT_OK(bt_mesh_net_encrypt(&sub->keys[SUBNET_KEY_TX_IDX(sub)].msg.enc, pdu, 0,
168 BT_MESH_NONCE_SOLICITATION));
169
170 ASSERT_OK(bt_mesh_net_obfuscate(pdu->data, 0,
171 &sub->keys[SUBNET_KEY_TX_IDX(sub)].msg.privacy));
172
173 net_buf_simple_push_u8(pdu, 0);
174 net_buf_simple_push_le16(pdu, BT_UUID_MESH_PROXY_SOLICITATION_VAL);
175 }
176
sol_fixed_pdu_send(void)177 static int sol_fixed_pdu_send(void)
178 {
179 NET_BUF_SIMPLE_DEFINE(pdu, 20);
180 net_buf_simple_init(&pdu, 3);
181
182 struct bt_mesh_subnet *sub = bt_mesh_subnet_find(NULL, NULL);
183
184 uint16_t adv_int = BT_MESH_TRANSMIT_INT(CONFIG_BT_MESH_SOL_ADV_XMIT);
185
186 sol_fixed_pdu_create(sub, &pdu);
187
188 struct bt_data ad[] = {
189 BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
190 BT_DATA_BYTES(BT_DATA_UUID16_ALL,
191 BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_SOLICITATION_VAL)),
192 BT_DATA(BT_DATA_SVC_DATA16, pdu.data, pdu.size),
193 };
194
195 return bt_mesh_adv_bt_data_send(CONFIG_BT_MESH_SOL_ADV_XMIT, adv_int, ad, 3);
196 }
197
test_tester_beacon_rcvd(void)198 static void test_tester_beacon_rcvd(void)
199 {
200 tester_configure();
201
202 /* Check that no beacons are currently being picked up by the scanner */
203 ASSERT_EQUAL(-EAGAIN, k_sem_take(&beacon_sem, K_SECONDS(SEM_TIMEOUT)));
204
205 ASSERT_OK(bt_mesh_proxy_solicit(0));
206
207 ASSERT_OK_MSG(k_sem_take(&beacon_sem, K_SECONDS(SEM_TIMEOUT)),
208 "No beacon (proxy advs) reveiced.");
209
210 PASS();
211 }
212
test_tester_immediate_replay_attack(void)213 static void test_tester_immediate_replay_attack(void)
214 {
215 tester_configure();
216
217 /* Check that no beacons are currently being picked up by the scanner */
218 ASSERT_EQUAL(-EAGAIN, k_sem_take(&beacon_sem, K_SECONDS(SEM_TIMEOUT)));
219
220 /* Send initial solicitation PDU with fixed sequence number */
221 ASSERT_OK(sol_fixed_pdu_send());
222
223 ASSERT_OK_MSG(k_sem_take(&beacon_sem, K_SECONDS(SEM_TIMEOUT)),
224 "No beacon (proxy advs) reveiced.");
225 k_sem_reset(&beacon_sem);
226
227 /* Wait for iut proxy advs to time out */
228 k_sleep(K_MSEC(200));
229 ASSERT_EQUAL(-EAGAIN, k_sem_take(&beacon_sem, K_SECONDS(SEM_TIMEOUT)));
230
231 /* Replay attack */
232 ASSERT_OK(sol_fixed_pdu_send());
233
234 ASSERT_EQUAL(-EAGAIN, k_sem_take(&beacon_sem, K_SECONDS(SEM_TIMEOUT)));
235
236 PASS();
237 }
238
test_tester_power_replay_attack(void)239 static void test_tester_power_replay_attack(void)
240 {
241 tester_configure();
242
243 /* Check that no beacons are currently being picked up by the scanner */
244 ASSERT_EQUAL(-EAGAIN, k_sem_take(&beacon_sem, K_SECONDS(SEM_TIMEOUT)));
245
246 /* Replay attack, using standard api, starting with sseq = 0 < fixed sseq */
247 for (size_t i = 0; i < 3; i++) {
248 k_sleep(K_MSEC(100));
249 ASSERT_OK(bt_mesh_proxy_solicit(0));
250 }
251
252 ASSERT_EQUAL(-EAGAIN, k_sem_take(&beacon_sem, K_SECONDS(SEM_TIMEOUT)));
253
254 /* Send a sol pdu with sseq = 3 > fixed sseq (2) */
255 ASSERT_OK(bt_mesh_proxy_solicit(0));
256 ASSERT_OK_MSG(k_sem_take(&beacon_sem, K_SECONDS(SEM_TIMEOUT)),
257 "No beacon (proxy advs) reveiced.");
258
259 PASS();
260 }
261
test_iut_beacon_send(void)262 static void test_iut_beacon_send(void)
263 {
264 iut_configure();
265 k_sleep(K_SECONDS(3 * SEM_TIMEOUT));
266
267 PASS();
268 }
269
test_iut_immediate_replay_attack(void)270 static void test_iut_immediate_replay_attack(void)
271 {
272 iut_configure();
273 k_sleep(K_SECONDS(5 * SEM_TIMEOUT));
274
275 PASS();
276 }
277
test_iut_power_replay_attack(void)278 static void test_iut_power_replay_attack(void)
279 {
280 iut_configure();
281 k_sleep(K_SECONDS(4 * SEM_TIMEOUT));
282
283 PASS();
284 }
285
286 #define TEST_CASE(role, name, description) \
287 { \
288 .test_id = "proxy_sol_" #role "_" #name, \
289 .test_descr = description, \
290 .test_tick_f = bt_mesh_test_timeout, \
291 .test_main_f = test_##role##_##name, \
292 }
293
294 static const struct bst_test_instance test_proxy_sol[] = {
295
296 TEST_CASE(tester, beacon_rcvd, "Check for beacon after solicitation"),
297 TEST_CASE(tester, immediate_replay_attack, "Perform replay attack immediately"),
298 TEST_CASE(tester, power_replay_attack, "Perform replay attack after power cycle of iut"),
299
300 TEST_CASE(iut, beacon_send, "Respond with beacon after solicitation"),
301 TEST_CASE(iut, immediate_replay_attack, "Device is under immediate replay attack"),
302 TEST_CASE(iut, power_replay_attack, "Device is under power cycle replay attack"),
303
304 BSTEST_END_MARKER};
305
test_proxy_sol_install(struct bst_test_list * tests)306 struct bst_test_list *test_proxy_sol_install(struct bst_test_list *tests)
307 {
308 tests = bst_add_tests(tests, test_proxy_sol);
309 return tests;
310 }
311