Skip to content

Commit acfe688

Browse files
theob-projhedberg
authored andcommitted
Bluetooth: Tests: Encrypted Advertising Data test
Add a new BabbleSim test that use the sample data from the Supplement to the Bluetooth Core Specification to validate the Encrypted Advertising Data feature implementation. Signed-off-by: Théo Battrel <[email protected]>
1 parent a693b9b commit acfe688

File tree

11 files changed

+600
-0
lines changed

11 files changed

+600
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
cmake_minimum_required(VERSION 3.20.0)
4+
5+
if(NOT DEFINED ENV{BSIM_COMPONENTS_PATH})
6+
message(FATAL_ERROR "This test requires the BabbleSim simulator. Please set \
7+
the environment variable BSIM_COMPONENTS_PATH to point to its \
8+
components folder. More information can be found in \
9+
https://babblesim.github.io/folder_structure_and_env.html")
10+
endif()
11+
12+
find_package(Zephyr HINTS $ENV{ZEPHYR_BASE})
13+
project(bsim_test_ead_css_sample_data)
14+
15+
target_sources(app PRIVATE
16+
src/main.c
17+
src/common.c
18+
src/central.c
19+
src/peripheral.c
20+
)
21+
22+
zephyr_include_directories(
23+
$ENV{BSIM_COMPONENTS_PATH}/libUtilv1/src/
24+
$ENV{BSIM_COMPONENTS_PATH}/libPhyComv1/src/
25+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
CONFIG_BT=y
2+
CONFIG_BT_CENTRAL=y
3+
CONFIG_BT_PERIPHERAL=y
4+
CONFIG_BT_DEVICE_NAME="EAD CSS Sample Data"
5+
6+
CONFIG_BT_SMP=y
7+
CONFIG_BT_EXT_ADV=y
8+
9+
CONFIG_BT_EAD=y
10+
11+
CONFIG_LOG=y
12+
CONFIG_BT_EAD_LOG_LEVEL_DBG=y
13+
14+
CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=191
15+
CONFIG_BT_CTLR_SCAN_DATA_LEN_MAX=191
16+
17+
CONFIG_BT_TESTING=y
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/* Copyright (c) 2023 Nordic Semiconductor ASA
2+
* SPDX-License-Identifier: Apache-2.0
3+
*/
4+
5+
#include "common.h"
6+
7+
extern const struct test_sample_data *sample_data;
8+
9+
extern int data_set;
10+
11+
static bool data_parse_cb(struct bt_data *data, void *user_data)
12+
{
13+
if (data->type == BT_DATA_ENCRYPTED_AD_DATA) {
14+
int err;
15+
uint8_t decrypted_payload[sample_data->size_ad_data];
16+
struct net_buf_simple decrypted_buf;
17+
size_t decrypted_data_size = BT_EAD_DECRYPTED_PAYLOAD_SIZE(data->data_len);
18+
19+
if (decrypted_data_size != sample_data->size_ad_data) {
20+
LOG_ERR("Size of decrypted data: %d", decrypted_data_size);
21+
LOG_ERR("Size of sample data: %d", sample_data->size_ad_data);
22+
FAIL("Computed size of data does not match the size of the data from the "
23+
"sample. (data set %d)\n",
24+
data_set);
25+
}
26+
27+
if (memcmp(sample_data->randomizer_little_endian, data->data,
28+
BT_EAD_RANDOMIZER_SIZE) != 0) {
29+
LOG_ERR("Received Randomizer: %s",
30+
bt_hex(data->data, BT_EAD_RANDOMIZER_SIZE));
31+
LOG_ERR("Expected Randomizer from sample: %s",
32+
bt_hex(sample_data->randomizer_little_endian,
33+
BT_EAD_RANDOMIZER_SIZE));
34+
FAIL("Received Randomizer does not match the expected one.\n");
35+
}
36+
37+
net_buf_simple_init_with_data(&decrypted_buf, decrypted_payload,
38+
decrypted_data_size);
39+
40+
err = bt_ead_decrypt(sample_data->session_key, sample_data->iv, data->data,
41+
data->data_len, decrypted_buf.data);
42+
if (err != 0) {
43+
FAIL("Error during decryption.\n");
44+
} else if (memcmp(decrypted_buf.data, sample_data->ad_data, decrypted_data_size)) {
45+
LOG_HEXDUMP_ERR(decrypted_buf.data, decrypted_data_size,
46+
"Decrypted data from bt_ead_decrypt:");
47+
LOG_HEXDUMP_ERR(sample_data->ad_data, sample_data->size_ad_data,
48+
"Expected data from sample:");
49+
FAIL("Decrypted AD data does not match expected sample data. (data set "
50+
"%d)\n",
51+
data_set);
52+
}
53+
54+
LOG_HEXDUMP_DBG(decrypted_buf.data, decrypted_data_size, "Raw decrypted data: ");
55+
56+
bt_data_parse(&decrypted_buf, &data_parse_cb, NULL);
57+
58+
PASS("Central test passed. (data set %d)\n", data_set);
59+
60+
return false;
61+
}
62+
63+
LOG_DBG("Parsed data:");
64+
LOG_DBG("len : %d", data->data_len);
65+
LOG_DBG("type: 0x%02x", data->type);
66+
LOG_HEXDUMP_DBG(data->data, data->data_len, "data:");
67+
68+
return true;
69+
}
70+
71+
static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
72+
struct net_buf_simple *ad)
73+
{
74+
char addr_str[BT_ADDR_LE_STR_LEN];
75+
76+
bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
77+
78+
LOG_DBG("Device found: %s (RSSI %d)", addr_str, rssi);
79+
80+
bt_data_parse(ad, &data_parse_cb, NULL);
81+
}
82+
83+
static void start_scan(void)
84+
{
85+
int err;
86+
87+
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
88+
if (err) {
89+
FAIL("Scanning failed to start (err %d)\n", err);
90+
}
91+
92+
LOG_DBG("Scanning successfully started");
93+
}
94+
95+
void test_central(void)
96+
{
97+
int err;
98+
99+
LOG_DBG("Central device. (data set %d)", data_set);
100+
101+
err = bt_enable(NULL);
102+
if (err) {
103+
FAIL("Bluetooth init failed (err %d)\n", err);
104+
}
105+
106+
LOG_DBG("Bluetooth initialized");
107+
108+
start_scan();
109+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/* Copyright (c) 2023 Nordic Semiconductor ASA
2+
* SPDX-License-Identifier: Apache-2.0
3+
*/
4+
5+
#include "common.h"
6+
7+
#include "bs_cmd_line.h"
8+
9+
#define SAMPLE_DATA_SET_SIZE 2
10+
static const struct test_sample_data *sample_data_set[] = {
11+
&sample_data_1,
12+
&sample_data_2,
13+
};
14+
BUILD_ASSERT(ARRAY_SIZE(sample_data_set) == SAMPLE_DATA_SET_SIZE);
15+
16+
const struct test_sample_data *sample_data;
17+
18+
int data_set;
19+
20+
void test_args_parse(int argc, char *argv[])
21+
{
22+
bs_args_struct_t args_struct[] = {
23+
{
24+
.dest = &data_set,
25+
.type = 'i',
26+
.name = "{1, 2}",
27+
.option = "data-set",
28+
.descript = "Sample data set ID",
29+
},
30+
};
31+
32+
bs_args_parse_all_cmd_line(argc, argv, args_struct);
33+
34+
if (data_set < 1 || data_set > SAMPLE_DATA_SET_SIZE) {
35+
data_set = 1;
36+
}
37+
38+
sample_data = sample_data_set[data_set - 1];
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/* Copyright (c) 2023 Nordic Semiconductor ASA
2+
* SPDX-License-Identifier: Apache-2.0
3+
*/
4+
5+
#include <zephyr/kernel.h>
6+
7+
#include <zephyr/bluetooth/ead.h>
8+
#include <zephyr/bluetooth/bluetooth.h>
9+
10+
#include <zephyr/logging/log.h>
11+
12+
#include "common/bt_str.h"
13+
14+
#include "bs_tracing.h"
15+
#include "bstests.h"
16+
17+
/**
18+
* @brief Encrypt and authenticate the given advertising data.
19+
*
20+
* This is the same function as @ref bt_ead_encrypt except this one adds the @p
21+
* randomizer parameter to let the user set the randomizer value.
22+
*
23+
* @note This function should only be used for testing purposes, it is only
24+
* available when @kconfig{CONFIG_BT_TESTING} is enabled.
25+
*
26+
* @param[in] session_key Key of @ref BT_EAD_KEY_SIZE bytes used for the
27+
* encryption.
28+
* @param[in] iv Initialisation Vector used to generate the nonce. It must be
29+
* changed each time the Session Key changes.
30+
* @param[in] randomizer Randomizer value used to generate the nonce. The value
31+
* is also placed in front of the encrypted advertising data.
32+
* @param[in] payload Advertising Data to encrypt. Can be multiple advertising
33+
* structures that are concatenated.
34+
* @param[in] payload_size Size of the Advertising Data to encrypt.
35+
* @param[out] encrypted_payload Encrypted Ad Data including the Randomizer and
36+
* the MIC. Size must be at least @ref BT_EAD_RANDOMIZER_SIZE + @p
37+
* payload_size + @ref BT_EAD_MIC_SIZE. Use @ref
38+
* BT_EAD_ENCRYPTED_PAYLOAD_SIZE to get the right size.
39+
*
40+
* @retval 0 Data have been correctly encrypted and authenticated.
41+
* @retval -EIO Error occurred during the encryption or the authentication.
42+
* @retval -EINVAL One of the argument is a NULL pointer.
43+
*/
44+
int bt_test_ead_encrypt(const uint8_t session_key[BT_EAD_KEY_SIZE],
45+
const uint8_t iv[BT_EAD_IV_SIZE],
46+
const uint8_t randomizer[BT_EAD_RANDOMIZER_SIZE], const uint8_t *payload,
47+
size_t payload_size, uint8_t *encrypted_payload);
48+
49+
#define FAIL(...) \
50+
do { \
51+
bst_result = Failed; \
52+
bs_trace_error_time_line(__VA_ARGS__); \
53+
} while (0)
54+
55+
#define PASS(...) \
56+
do { \
57+
bst_result = Passed; \
58+
bs_trace_info_time(1, __VA_ARGS__); \
59+
} while (0)
60+
61+
extern enum bst_result_t bst_result;
62+
63+
#define CREATE_FLAG(flag) static atomic_t flag = (atomic_t) false
64+
#define SET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) true)
65+
#define GET_FLAG(flag) (bool)atomic_get(&flag)
66+
#define UNSET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) false)
67+
#define WAIT_FOR_FLAG(flag) \
68+
while (!(bool)atomic_get(&flag)) { \
69+
(void)k_sleep(K_MSEC(1)); \
70+
}
71+
72+
LOG_MODULE_DECLARE(bt_bsim_ead_sample_data, CONFIG_BT_EAD_LOG_LEVEL);
73+
74+
struct test_sample_data {
75+
const uint8_t session_key[BT_EAD_KEY_SIZE];
76+
const uint8_t iv[BT_EAD_IV_SIZE];
77+
const uint8_t randomizer_little_endian[BT_EAD_RANDOMIZER_SIZE];
78+
const uint8_t *ad_data;
79+
const size_t size_ad_data;
80+
const uint8_t *ead;
81+
const size_t size_ead;
82+
};
83+
84+
/* Encrypted Advertising Data Set 1 (ref: Supplement to the Bluetooth Core
85+
* Specification v11, Part A, 2.3.1)
86+
*/
87+
88+
#define SIZE_SAMPLE_AD_DATA_1 20
89+
static const uint8_t sample_ad_data_1[] = {0x0F, 0x09, 0x53, 0x68, 0x6F, 0x72, 0x74,
90+
0x20, 0x4D, 0x69, 0x6E, 0x69, 0x2D, 0x42,
91+
0x75, 0x73, 0x03, 0x19, 0x0A, 0x8C};
92+
BUILD_ASSERT(sizeof(sample_ad_data_1) == SIZE_SAMPLE_AD_DATA_1);
93+
94+
#define SIZE_SAMPLE_EAD_1 29
95+
static const uint8_t sample_ead_1[] = {
96+
0x18, 0xE1, 0x57, 0xCA, 0xDE, 0x74, 0xE4, 0xDC, 0xAF, 0xDC, 0x51, 0xC7, 0x28, 0x28, 0x10,
97+
0xC2, 0x21, 0x7F, 0x0E, 0x4C, 0xEF, 0x43, 0x43, 0x18, 0x1F, 0xBA, 0x00, 0x69, 0xCC,
98+
};
99+
BUILD_ASSERT(sizeof(sample_ead_1) == SIZE_SAMPLE_EAD_1);
100+
101+
static const struct test_sample_data sample_data_1 = {
102+
.session_key = {0x57, 0xA9, 0xDA, 0x12, 0xD1, 0x2E, 0x6E, 0x13, 0x1E, 0x20, 0x61, 0x2A,
103+
0xD1, 0x0A, 0x6A, 0x19},
104+
.iv = {0x9E, 0x7A, 0x00, 0xEF, 0xB1, 0x7A, 0xE7, 0x46},
105+
.randomizer_little_endian = {0x18, 0xE1, 0x57, 0xCA, 0xDE},
106+
.ad_data = sample_ad_data_1,
107+
.size_ad_data = SIZE_SAMPLE_AD_DATA_1,
108+
.ead = sample_ead_1,
109+
.size_ead = SIZE_SAMPLE_EAD_1,
110+
};
111+
112+
/* Encrypted Advertising Data Set 2 (ref: Supplement to the Bluetooth Core
113+
* Specification v11, Part A, 2.3.2)
114+
*/
115+
116+
#define SIZE_SAMPLE_AD_DATA_2 20
117+
static const uint8_t sample_ad_data_2[] = {0x0F, 0x09, 0x53, 0x68, 0x6F, 0x72, 0x74,
118+
0x20, 0x4D, 0x69, 0x6E, 0x69, 0x2D, 0x42,
119+
0x75, 0x73, 0x03, 0x19, 0x0A, 0x8C};
120+
BUILD_ASSERT(sizeof(sample_ad_data_2) == SIZE_SAMPLE_AD_DATA_2);
121+
122+
#define SIZE_SAMPLE_EAD_2 29
123+
static const uint8_t sample_ead_2[] = {0x8d, 0x1c, 0x97, 0x6e, 0x7a, 0x35, 0x44, 0x40, 0x76, 0x12,
124+
0x57, 0x88, 0xc2, 0x38, 0xa5, 0x8e, 0x8b, 0xd9, 0xcf, 0xf0,
125+
0xde, 0xfe, 0x25, 0x1a, 0x8e, 0x72, 0x75, 0x45, 0x4c};
126+
BUILD_ASSERT(sizeof(sample_ead_2) == SIZE_SAMPLE_EAD_2);
127+
128+
static const struct test_sample_data sample_data_2 = {
129+
.session_key = {0x57, 0xA9, 0xDA, 0x12, 0xD1, 0x2E, 0x6E, 0x13, 0x1E, 0x20, 0x61, 0x2A,
130+
0xD1, 0x0A, 0x6A, 0x19},
131+
.iv = {0x9E, 0x7A, 0x00, 0xEF, 0xB1, 0x7A, 0xE7, 0x46},
132+
.randomizer_little_endian = {0x8D, 0x1C, 0x97, 0x6E, 0x7A},
133+
.ad_data = sample_ad_data_2,
134+
.size_ad_data = SIZE_SAMPLE_AD_DATA_2,
135+
.ead = sample_ead_2,
136+
.size_ead = SIZE_SAMPLE_EAD_2,
137+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/* Copyright (c) 2023 Nordic Semiconductor ASA
2+
* SPDX-License-Identifier: Apache-2.0
3+
*/
4+
5+
#include "bs_types.h"
6+
#include "bs_tracing.h"
7+
#include "bstests.h"
8+
9+
#include <zephyr/logging/log.h>
10+
LOG_MODULE_REGISTER(bt_bsim_ead_sample_data, CONFIG_BT_EAD_LOG_LEVEL);
11+
12+
extern enum bst_result_t bst_result;
13+
14+
#define WAIT_TIME_S 20
15+
#define WAIT_TIME (WAIT_TIME_S * 1e6)
16+
17+
extern void test_central(void);
18+
extern void test_peripheral(void);
19+
extern void test_args_parse(int argc, char *argv[]);
20+
21+
void test_tick(bs_time_t HW_device_time)
22+
{
23+
if (bst_result != Passed) {
24+
bst_result = Failed;
25+
bs_trace_error_time_line("Test failed (not passed after %d seconds)\n",
26+
WAIT_TIME_S);
27+
}
28+
}
29+
30+
static void test_ead_sample_data_init(void)
31+
{
32+
bst_ticker_set_next_tick_absolute(WAIT_TIME);
33+
bst_result = In_progress;
34+
}
35+
36+
static const struct bst_test_instance test_def[] = {
37+
{
38+
.test_id = "central",
39+
.test_descr = "Central device",
40+
.test_post_init_f = test_ead_sample_data_init,
41+
.test_tick_f = test_tick,
42+
.test_main_f = test_central,
43+
.test_args_f = test_args_parse,
44+
},
45+
{
46+
.test_id = "peripheral",
47+
.test_descr = "Peripheral device",
48+
.test_post_init_f = test_ead_sample_data_init,
49+
.test_tick_f = test_tick,
50+
.test_main_f = test_peripheral,
51+
.test_args_f = test_args_parse,
52+
},
53+
BSTEST_END_MARKER};
54+
55+
struct bst_test_list *test_encrypted_ad_data_install(struct bst_test_list *tests)
56+
{
57+
return bst_add_tests(tests, test_def);
58+
}
59+
60+
bst_test_install_t test_installers[] = {test_encrypted_ad_data_install, NULL};
61+
62+
void main(void)
63+
{
64+
bst_main();
65+
}

0 commit comments

Comments
 (0)