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