Skip to content

Commit a8b928a

Browse files
committed
nimble/ll: Add unit tests for CS DRBG
The BT specification provides sample data that can be used to test the correctness of a CS DRBG implementation.
1 parent 0307f73 commit a8b928a

File tree

4 files changed

+375
-0
lines changed

4 files changed

+375
-0
lines changed

nimble/controller/pkg.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,14 @@ pkg.deps:
4242
- nimble
4343
- nimble/transport
4444

45+
pkg.deps.TEST:
46+
- "@apache-mynewt-core/crypto/mbedtls"
47+
4548
pkg.init:
4649
ble_ll_init:
4750
- $before:ble_transport_hs_init
4851
- $before:ble_transport_ll_init
52+
53+
pkg.cflags.TEST:
54+
- -Irepos/mbedtls/include
55+
- -Irepos/include/mbedtls
Lines changed: 362 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,362 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#include <stdint.h>
21+
#include <controller/ble_ll_utils.h>
22+
#include <testutil/testutil.h>
23+
#include "ble_ll_cs_drbg_priv.h"
24+
25+
static void
26+
ble_ll_cs_drbg_e_test(void)
27+
{
28+
uint8_t key[16] = { 0 };
29+
uint8_t data[16] = { 0 };
30+
uint8_t out[16] = { 0 };
31+
uint8_t expected_out[16] = { 0 };
32+
33+
/* Sample data from BT spec Vol 6, Part C, 1.1 Encrypt Command
34+
* Swap because the copy-pasted strings are in leftmost (MSO) to rightmost
35+
* (LSO) orientation.
36+
*/
37+
swap_buf(key,
38+
(uint8_t[16]){ 0x4C, 0x68, 0x38, 0x41, 0x39, 0xF5, 0x74, 0xD8,
39+
0x36, 0xBC, 0xF3, 0x4E, 0x9D, 0xFB, 0x01, 0xBF },
40+
16);
41+
42+
swap_buf(data,
43+
(uint8_t[16]){ 0x02, 0x13, 0x24, 0x35, 0x46, 0x57, 0x68, 0x79,
44+
0xac, 0xbd, 0xce, 0xdf, 0xe0, 0xf1, 0x02, 0x13 },
45+
16);
46+
47+
swap_buf(expected_out,
48+
(uint8_t[16]){ 0x99, 0xad, 0x1b, 0x52, 0x26, 0xa3, 0x7e, 0x3e,
49+
0x05, 0x8e, 0x3b, 0x8e, 0x27, 0xc2, 0xc6, 0x66 },
50+
16);
51+
52+
ble_ll_cs_drbg_e(key, data, out);
53+
TEST_ASSERT(memcmp(out, expected_out, sizeof(out)) == 0);
54+
}
55+
56+
static void
57+
ble_ll_cs_drbg_f7_test(void)
58+
{
59+
uint8_t v_s[80];
60+
uint8_t k[16];
61+
uint8_t k2[16] = { 0 };
62+
uint8_t x[16] = { 0 };
63+
uint8_t expected_k2[16] = { 0 };
64+
uint8_t expected_x[16] = { 0 };
65+
66+
/* Sample data from BT spec Vol 6, Part C, 7. Deterministic
67+
* random bit generator sample data.
68+
* Swap because the copy-pasted strings are in leftmost (MSO)
69+
* to rightmost (LSO) orientation.
70+
*/
71+
swap_buf(k,
72+
(uint8_t[16]){ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
73+
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F },
74+
16);
75+
76+
swap_buf(v_s,
77+
(uint8_t[80]){
78+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28,
80+
0x00, 0x00, 0x00, 0x20, 0xE1, 0x0B, 0xC2, 0x8A, 0x0B, 0xFD,
81+
0xDF, 0xE9, 0x3E, 0x7F, 0x51, 0x86, 0xE0, 0xCA, 0x0B, 0x3B,
82+
0x9F, 0xF4, 0x77, 0xC1, 0x86, 0x73, 0x84, 0x0D, 0xC9, 0x80,
83+
0xDE, 0xDF, 0x98, 0x82, 0xED, 0x44, 0x64, 0xA6, 0x74, 0x96,
84+
0x78, 0x68, 0xF1, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
85+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
86+
80);
87+
88+
swap_buf(expected_k2,
89+
(uint8_t[16]){ 0x8B, 0x2B, 0x06, 0xDC, 0x52, 0x2D, 0x3E, 0x0A,
90+
0xF0, 0xA5, 0x0C, 0xAF, 0x48, 0x10, 0xE0, 0x35 },
91+
16);
92+
93+
TEST_ASSERT(ble_ll_cs_drbg_f7(k, v_s, sizeof(v_s), k2) == 0);
94+
TEST_ASSERT(memcmp(k2, expected_k2, sizeof(k2)) == 0);
95+
96+
v_s[76] = 0x01;
97+
swap_buf(expected_x,
98+
(uint8_t[16]){ 0xA3, 0x4F, 0xBE, 0x57, 0xF8, 0xF9, 0x7E, 0x34,
99+
0x9D, 0x15, 0xA3, 0x76, 0x79, 0x60, 0x74, 0x64 },
100+
16);
101+
102+
TEST_ASSERT(ble_ll_cs_drbg_f7(k, v_s, sizeof(v_s), x) == 0);
103+
TEST_ASSERT(memcmp(x, expected_x, sizeof(x)) == 0);
104+
}
105+
106+
static void
107+
ble_ll_cs_drbg_f8_test(void)
108+
{
109+
uint8_t input_bit_string[40] = { 0 };
110+
uint8_t expected_sm[32] = { 0 };
111+
uint8_t sm[32] = { 0 };
112+
113+
/* Sample data from BT spec Vol 6, Part C, 7. Deterministic
114+
* random bit generator sample data.
115+
* Swap because the copy-pasted strings are in leftmost (MSO)
116+
* to rightmost (LSO) orientation.
117+
*/
118+
119+
/* 320-bit input bit string created from concatenated vectors
120+
* CS_IV || CS_IN || CS_PV
121+
*/
122+
swap_buf(input_bit_string,
123+
(uint8_t[40]){ 0xE1, 0x0B, 0xC2, 0x8A, 0x0B, 0xFD, 0xDF, 0xE9,
124+
0x3E, 0x7F, 0x51, 0x86, 0xE0, 0xCA, 0x0B, 0x3B,
125+
0x9F, 0xF4, 0x77, 0xC1, 0x86, 0x73, 0x84, 0x0D,
126+
0xC9, 0x80, 0xDE, 0xDF, 0x98, 0x82, 0xED, 0x44,
127+
0x64, 0xA6, 0x74, 0x96, 0x78, 0x68, 0xF1, 0x43 },
128+
40);
129+
130+
swap_buf(expected_sm,
131+
(uint8_t[32]){ 0xB6, 0x02, 0xB1, 0xB2, 0x8C, 0x6F, 0x0A, 0x3D,
132+
0xDA, 0xE6, 0x37, 0xB4, 0x84, 0x25, 0x08, 0x7D,
133+
0xDC, 0x18, 0x8C, 0x89, 0xA1, 0xB0, 0xCD, 0xFD,
134+
0xA1, 0xE8, 0xFC, 0x66, 0xC9, 0x99, 0x97, 0x50 },
135+
32);
136+
137+
TEST_ASSERT(ble_ll_cs_drbg_f8(input_bit_string, sm) == 0);
138+
TEST_ASSERT(memcmp(sm, expected_sm, sizeof(sm)) == 0);
139+
}
140+
141+
static void
142+
ble_ll_cs_drbg_f9_test(void)
143+
{
144+
uint8_t sm[32] = { 0 };
145+
uint8_t k[16] = { 0 };
146+
uint8_t v[16] = { 0 };
147+
uint8_t expected_k[16] = { 0 };
148+
uint8_t expected_v[16] = { 0 };
149+
150+
/* First call to f9 from instantiation function h9,
151+
* K and V vectors filled with zeros.
152+
*
153+
* Sample data from BT spec Vol 6, Part C, 7. Deterministic
154+
* random bit generator sample data.
155+
* Swap because the copy-pasted strings are in leftmost (MSO)
156+
* to rightmost (LSO) orientation.
157+
*/
158+
159+
swap_buf(sm, (uint8_t[32]){ 0xB6, 0x02, 0xB1, 0xB2, 0x8C, 0x6F, 0x0A, 0x3D,
160+
0xDA, 0xE6, 0x37, 0xB4, 0x84, 0x25, 0x08, 0x7D,
161+
0xDC, 0x18, 0x8C, 0x89, 0xA1, 0xB0, 0xCD, 0xFD,
162+
0xA1, 0xE8, 0xFC, 0x66, 0xC9, 0x99, 0x97, 0x50 },
163+
32);
164+
165+
swap_buf(expected_k,
166+
(uint8_t[16]){ 0xEE, 0xE0, 0x4D, 0x7C, 0x76, 0x11, 0x3A, 0x5C,
167+
0xEC, 0x99, 0x2A, 0xE3, 0x20, 0xC2, 0x4D, 0x27 },
168+
16);
169+
170+
swap_buf(expected_v,
171+
(uint8_t[16]){ 0xDF, 0x90, 0x56, 0x47, 0xC1, 0x06, 0x6E, 0x6F,
172+
0x52, 0xC0, 0x3E, 0xDF, 0xB8, 0x2B, 0x69, 0x28 },
173+
16);
174+
175+
TEST_ASSERT(ble_ll_cs_drbg_f9(sm, k, v) == 0);
176+
TEST_ASSERT(memcmp(k, expected_k, sizeof(k)) == 0);
177+
TEST_ASSERT(memcmp(v, expected_v, sizeof(v)) == 0);
178+
}
179+
180+
static void
181+
cs_drbg_init(struct ble_ll_cs_drbg_ctx *ctx)
182+
{
183+
memset(ctx, 0, sizeof(*ctx));
184+
185+
/* CS_IV = CS_IV_P || CS_IV_C */
186+
swap_buf(ctx->iv,
187+
(uint8_t[16]){ 0xE1, 0x0B, 0xC2, 0x8A, 0x0B, 0xFD, 0xDF, 0xE9,
188+
0x3E, 0x7F, 0x51, 0x86, 0xE0, 0xCA, 0x0B, 0x3B },
189+
16);
190+
191+
/* CS_IN = CS_IN_P || CS_IN_C */
192+
swap_buf(ctx->in,
193+
(uint8_t[8]){ 0x9F, 0xF4, 0x77, 0xC1, 0x86, 0x73, 0x84, 0x0D }, 8);
194+
195+
/* CS_PV = CS_PV_P || CS_PV_C */
196+
swap_buf(ctx->pv,
197+
(uint8_t[16]){ 0xC9, 0x80, 0xDE, 0xDF, 0x98, 0x82, 0xED, 0x44,
198+
0x64, 0xA6, 0x74, 0x96, 0x78, 0x68, 0xF1, 0x43 },
199+
16);
200+
201+
ble_ll_cs_drbg_init(ctx);
202+
}
203+
204+
static void
205+
ble_ll_cs_drbg_rand_test(void)
206+
{
207+
struct ble_ll_cs_drbg_ctx ctx;
208+
uint8_t output[20] = { 0 };
209+
uint8_t expected_output[20] = { 0 };
210+
211+
/* Test if subsequent drgb generator calls returns expected bit sequences. */
212+
213+
cs_drbg_init(&ctx);
214+
215+
/* First round - request full 128-bit batch */
216+
swap_buf(expected_output,
217+
(uint8_t[16]){ 0x79, 0x74, 0x1F, 0xD1, 0x8F, 0x57, 0x7B, 0x45,
218+
0xD0, 0x9A, 0x66, 0x5A, 0x7F, 0x1F, 0x28, 0x58 },
219+
16);
220+
221+
TEST_ASSERT(ble_ll_cs_drbg_rand(&ctx, 0x00, BLE_LL_CS_DRBG_HOP_CHAN_NON_MODE0,
222+
output, 16) == 0);
223+
TEST_ASSERT(memcmp(output, expected_output, 16) == 0);
224+
}
225+
226+
static void
227+
ble_ll_cs_drbg_chan_selection_3b_test(void)
228+
{
229+
struct ble_ll_cs_drbg_ctx ctx;
230+
uint8_t filtered_channels[72] = { 0 };
231+
uint8_t shuffled_channels[72] = { 0 };
232+
uint8_t expected_shuffled_channels[19] = { 0 };
233+
234+
cs_drbg_init(&ctx);
235+
236+
memcpy(filtered_channels,
237+
(uint8_t[19]){ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
238+
17, 18, 19, 20 },
239+
19);
240+
241+
memcpy(expected_shuffled_channels,
242+
(uint8_t[19]){ 11, 7, 14, 18, 9, 19, 10, 8, 5, 2, 4, 15, 16, 13, 12,
243+
6, 17, 20, 3 },
244+
19);
245+
assert(ble_ll_cs_drbg_shuffle_cr1(&ctx, 0x00, BLE_LL_CS_DRBG_HOP_CHAN_MODE0,
246+
filtered_channels, shuffled_channels, 19) == 0);
247+
assert(memcmp(shuffled_channels, expected_shuffled_channels, 19) == 0);
248+
249+
memcpy(expected_shuffled_channels,
250+
(uint8_t[19]){ 6, 12, 5, 10, 3, 2, 18, 17, 16, 8, 11, 7, 19, 4, 13,
251+
20, 9, 15, 14 },
252+
19);
253+
assert(ble_ll_cs_drbg_shuffle_cr1(&ctx, 0x03, BLE_LL_CS_DRBG_HOP_CHAN_NON_MODE0,
254+
filtered_channels, shuffled_channels, 19) == 0);
255+
assert(memcmp(shuffled_channels, expected_shuffled_channels, 19) == 0);
256+
}
257+
258+
static void
259+
ble_ll_cs_drbg_generate_aa_test(void)
260+
{
261+
struct ble_ll_cs_drbg_ctx ctx;
262+
uint32_t initiator_aa;
263+
uint32_t reflector_aa;
264+
uint32_t expected_initiator_aa;
265+
uint32_t expected_reflector_aa;
266+
267+
cs_drbg_init(&ctx);
268+
269+
/* Step 0 */
270+
assert(ble_ll_cs_drbg_generate_aa(&ctx, 0, &initiator_aa, &reflector_aa) == 0);
271+
expected_initiator_aa = get_be32((uint8_t[4]){ 0x6C, 0x37, 0x6A, 0xB8 });
272+
expected_reflector_aa = get_be32((uint8_t[4]){ 0xF0, 0x79, 0xBC, 0x3A });
273+
assert(initiator_aa == expected_initiator_aa);
274+
assert(reflector_aa == expected_reflector_aa);
275+
276+
/* Step 1 */
277+
assert(ble_ll_cs_drbg_generate_aa(&ctx, 1, &initiator_aa, &reflector_aa) == 0);
278+
expected_initiator_aa = get_be32((uint8_t[4]){ 0x01, 0x1C, 0xAE, 0x4E });
279+
expected_reflector_aa = get_be32((uint8_t[4]){ 0xD0, 0x6A, 0xCD, 0xDA });
280+
assert(initiator_aa == expected_initiator_aa);
281+
assert(reflector_aa == expected_reflector_aa);
282+
283+
/* Step 2 */
284+
assert(ble_ll_cs_drbg_generate_aa(&ctx, 2, &initiator_aa, &reflector_aa) == 0);
285+
expected_initiator_aa = get_be32((uint8_t[4]){ 0x64, 0x06, 0x12, 0x14 });
286+
expected_reflector_aa = get_be32((uint8_t[4]){ 0x28, 0x94, 0x2F, 0x38 });
287+
assert(initiator_aa == expected_initiator_aa);
288+
assert(reflector_aa == expected_reflector_aa);
289+
290+
/* Step 14 */
291+
assert(ble_ll_cs_drbg_generate_aa(&ctx, 14, &initiator_aa, &reflector_aa) == 0);
292+
expected_initiator_aa = get_be32((uint8_t[4]){ 0xF7, 0x21, 0x97, 0x86 });
293+
expected_reflector_aa = get_be32((uint8_t[4]){ 0x57, 0x17, 0x64, 0x70 });
294+
assert(initiator_aa == expected_initiator_aa);
295+
assert(reflector_aa == expected_reflector_aa);
296+
}
297+
298+
static void
299+
ble_ll_cs_drbg_rand_marker_position_test(void)
300+
{
301+
uint8_t position1;
302+
uint8_t position2;
303+
struct ble_ll_cs_drbg_ctx ctx;
304+
305+
cs_drbg_init(&ctx);
306+
307+
/* Step 9 */
308+
assert(ble_ll_cs_drbg_rand_marker_position(&ctx, 9, BLE_LL_CS_RTT_32_BIT_SOUNDING_SEQUENCE,
309+
&position1, &position2) == 0);
310+
assert(position1 == 12 && position2 == 0xFF);
311+
312+
assert(ble_ll_cs_drbg_rand_marker_position(&ctx, 9, BLE_LL_CS_RTT_32_BIT_SOUNDING_SEQUENCE,
313+
&position1, &position2) == 0);
314+
assert(position1 == 4 && position2 == 0xFF);
315+
316+
/* Step 14 */
317+
assert(ble_ll_cs_drbg_rand_marker_position(&ctx, 14, BLE_LL_CS_RTT_32_BIT_SOUNDING_SEQUENCE,
318+
&position1, &position2) == 0);
319+
assert(position1 == 8 && position2 == 0xFF);
320+
321+
assert(ble_ll_cs_drbg_rand_marker_position(&ctx, 14, BLE_LL_CS_RTT_32_BIT_SOUNDING_SEQUENCE,
322+
&position1, &position2) == 0);
323+
assert(position1 == 11 && position2 == 0xFF);
324+
}
325+
326+
static void
327+
ble_ll_cs_drbg_rand_marker_selection_test(void)
328+
{
329+
uint8_t marker_selection;
330+
struct ble_ll_cs_drbg_ctx ctx;
331+
332+
cs_drbg_init(&ctx);
333+
334+
/* Step 9 */
335+
assert(ble_ll_cs_drbg_rand_marker_selection(&ctx, 0x09, &marker_selection) == 0);
336+
assert(marker_selection == 0x00);
337+
338+
assert(ble_ll_cs_drbg_rand_marker_selection(&ctx, 0x09, &marker_selection) == 0);
339+
assert(marker_selection == 0x80);
340+
341+
memset(ctx.t_cache, 0, sizeof(ctx.t_cache));
342+
343+
/* Step 14 */
344+
assert(ble_ll_cs_drbg_rand_marker_selection(&ctx, 14, &marker_selection) == 0);
345+
assert(marker_selection == 0x80);
346+
347+
assert(ble_ll_cs_drbg_rand_marker_selection(&ctx, 14, &marker_selection) == 0);
348+
assert(marker_selection == 0x80);
349+
}
350+
351+
TEST_SUITE(ble_ll_cs_drbg_test_suite)
352+
{
353+
ble_ll_cs_drbg_e_test();
354+
ble_ll_cs_drbg_f7_test();
355+
ble_ll_cs_drbg_f8_test();
356+
ble_ll_cs_drbg_f9_test();
357+
ble_ll_cs_drbg_rand_test();
358+
ble_ll_cs_drbg_chan_selection_3b_test();
359+
ble_ll_cs_drbg_generate_aa_test();
360+
ble_ll_cs_drbg_rand_marker_position_test();
361+
ble_ll_cs_drbg_rand_marker_selection_test();
362+
}

nimble/controller/test/src/ble_ll_test.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ TEST_SUITE_DECL(ble_ll_crypto_test_suite);
2727
TEST_SUITE_DECL(ble_ll_csa2_test_suite);
2828
TEST_SUITE_DECL(ble_ll_isoal_test_suite);
2929
TEST_SUITE_DECL(ble_ll_iso_test_suite);
30+
TEST_SUITE_DECL(ble_ll_cs_drbg_test_suite);
3031

3132
int
3233
main(int argc, char **argv)
@@ -36,6 +37,7 @@ main(int argc, char **argv)
3637
ble_ll_csa2_test_suite();
3738
ble_ll_isoal_test_suite();
3839
ble_ll_iso_test_suite();
40+
ble_ll_cs_drbg_test_suite();
3941

4042
return tu_any_failed;
4143
}

0 commit comments

Comments
 (0)