xref: /btstack/test/mesh/provisioning_provisioner_test.cpp (revision 339c5cba8125d2aacb0a9cbf2e14fb5117d68419)
1 /*
2  * Copyright (C) 2017 BlueKitchen GmbH
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holders nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  * 4. Any redistribution, use, or modification is done solely for
17  *    personal benefit and not for any commercial purpose or for
18  *    monetary gain.
19  *
20  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Please inquire about commercial licensing options at
34  * [email protected]
35  *
36  */
37 
38 #include <stdint.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include "ble/mesh/pb_adv.h"
43 #include "provisioning_provisioner.h"
44 #include "btstack.h"
45 
46 #include "CppUTest/TestHarness.h"
47 #include "CppUTest/CommandLineTestRunner.h"
48 
49 static void CHECK_EQUAL_ARRAY(uint8_t * expected, uint8_t * actual, int size){
50     int i;
51     for (i=0; i<size; i++){
52         if (expected[i] != actual[i]) {
53             printf("offset %u wrong\n", i);
54             printf("expected: "); printf_hexdump(expected, size);
55             printf("actual:   "); printf_hexdump(actual, size);
56         }
57         BYTES_EQUAL(expected[i], actual[i]);
58     }
59 }
60 
61 static void dump_data(uint8_t * buffer, uint16_t size){
62     static int data_counter = 1;
63     char var_name[80];
64     sprintf(var_name, "test_data_%02u", data_counter);
65     printf("uint8_t %s[] = { ", var_name);
66     for (int i = 0; i < size ; i++){
67         if ((i % 16) == 0) printf("\n    ");
68         printf ("0x%02x, ", buffer[i]);
69     }
70     printf("};\n");
71     data_counter++;
72 }
73 
74 static int parse_hex(uint8_t * buffer, const char * hex_string){
75     int len = 0;
76     while (*hex_string){
77         if (*hex_string == ' '){
78             hex_string++;
79             continue;
80         }
81         int high_nibble = nibble_for_char(*hex_string++);
82         int low_nibble = nibble_for_char(*hex_string++);
83         *buffer++ = (high_nibble << 4) | low_nibble;
84         len++;
85     }
86     return len;
87 }
88 
89 // returns if anything was done
90 extern "C" int mock_process_hci_cmd(void);
91 
92 // pb-adv mock for testing
93 
94 static btstack_packet_handler_t pb_adv_packet_handler;
95 
96 static uint8_t * pdu_data;
97 static uint16_t  pdu_size;
98 
99 static void pb_adv_emit_link_open(uint8_t status, uint16_t pb_adv_cid){
100     uint8_t event[7] = { HCI_EVENT_MESH_META, 5, MESH_PB_TRANSPORT_LINK_OPEN, status};
101     little_endian_store_16(event, 4, pb_adv_cid);
102     event[6] = PB_TYPE_ADV;
103     pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event));
104 }
105 
106 static void pb_adv_emit_pdu_sent(uint8_t status){
107     uint8_t event[] = { HCI_EVENT_MESH_META, 2, MESH_PB_TRANSPORT_PDU_SENT, status};
108     pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event));
109 }
110 
111 void pb_adv_init(const uint8_t * device_uuid){
112     printf("pb_adv_init\n");
113 }
114 
115 void pb_adv_close_link(uint16_t pb_adv_cid, uint8_t reason){
116 }
117 
118 void pb_adv_register_packet_handler(btstack_packet_handler_t packet_handler){
119     pb_adv_packet_handler = packet_handler;
120 }
121 
122 void pb_adv_send_pdu(uint16_t pb_transport_cid, const uint8_t * pdu, uint16_t size){
123     UNUSED(pb_transport_cid);
124     pdu_data = (uint8_t*) pdu;
125     pdu_size = size;
126     // dump_data((uint8_t*)pdu,size);
127     // printf_hexdump(pdu, size);
128 }
129 
130 uint16_t pb_adv_create_link(const uint8_t * device_uuid){
131     // just simluate opened
132     pb_adv_emit_link_open(0, 1);
133     return 1;
134 }
135 
136 //
137 static void perform_crypto_operations(void){
138     int more = 1;
139     while (more){
140         more = mock_process_hci_cmd();
141     }
142 }
143 
144 static void send_prov_pdu(const uint8_t * packet, uint16_t size){
145     pb_adv_packet_handler(PROVISIONING_DATA_PACKET, 0, (uint8_t*) packet, size);
146     perform_crypto_operations();
147 }
148 
149 
150 static int scan_hex_byte(const char * byte_string){
151     int upper_nibble = nibble_for_char(*byte_string++);
152     if (upper_nibble < 0) return -1;
153     int lower_nibble = nibble_for_char(*byte_string);
154     if (lower_nibble < 0) return -1;
155     return (upper_nibble << 4) | lower_nibble;
156 }
157 
158 static int btstack_parse_hex(const char * string, uint16_t len, uint8_t * buffer){
159     int i;
160     for (i = 0; i < len; i++) {
161         int single_byte = scan_hex_byte(string);
162         if (single_byte < 0) return 0;
163         string += 2;
164         buffer[i] = (uint8_t)single_byte;
165         // don't check seperator after last byte
166         if (i == len - 1) {
167             return 1;
168         }
169         // optional seperator
170         char separator = *string;
171         if (separator == ':' && separator == '-' && separator == ' ') {
172             string++;
173         }
174     }
175     return 1;
176 }
177 
178 static uint8_t      prov_static_oob_data[16];
179 static const char * prov_static_oob_string = "00000000000000000102030405060708";
180 
181 static void provisioning_handle_pdu(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
182     if (packet_type != HCI_EVENT_PACKET) return;
183     switch(packet[0]){
184         case HCI_EVENT_MESH_META:
185             switch(packet[2]){
186                 case MESH_PB_PROV_CAPABILITIES:
187                     printf("Provisioner capabilities\n");
188                     provisioning_provisioner_select_authentication_method(1, 0, 0, 0, 0, 0);
189                     break;
190                 default:
191                     break;
192             }
193         default:
194             break;
195     }
196 }
197 
198 TEST_GROUP(Provisioning){
199     void setup(void){
200         btstack_crypto_init();
201         provisioning_provisioner_init();
202         btstack_parse_hex(prov_static_oob_string, 16, prov_static_oob_data);
203         provisioning_provisioner_register_packet_handler(&provisioning_handle_pdu);
204         // provisioning_device_set_static_oob(16, prov_static_oob_data);
205         // provisioning_device_set_output_oob_actions(0x08, 0x08);
206         // provisioning_device_set_input_oob_actions(0x08, 0x08);
207         perform_crypto_operations();
208     }
209 };
210 
211 const static uint8_t device_uuid[] = { 0x00, 0x1B, 0xDC, 0x08, 0x10, 0x21, 0x0B, 0x0E, 0x0A, 0x0C, 0x00, 0x0B, 0x0E, 0x0A, 0x0C, 0x00 };
212 
213 uint8_t prov_invite[] = { 0x00, 0x00 };
214 uint8_t prov_capabilities[] = { 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x08, 0x00, 0x08, 0x08, 0x00, 0x08, };
215 uint8_t prov_start[] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 };
216 uint8_t prov_public_key[] = { 0x03,
217     0xf0, 0xc8, 0x63, 0xf8, 0xe5, 0x55, 0x11, 0x4b, 0xf4, 0x88, 0x2c, 0xc7, 0x87, 0xb9, 0x5c, 0x27,
218     0x2a, 0x7f, 0xe4, 0xdc, 0xdd, 0xf1, 0x92, 0x2f, 0x4f, 0x18, 0xa4, 0x94, 0xe1, 0xc3, 0x57, 0xa1,
219     0xa6, 0xc3, 0x2d, 0x07, 0xbe, 0xb5, 0x76, 0xab, 0x60, 0x10, 0x68, 0x06, 0x8f, 0x0a, 0x9e, 0x01,
220     0x60, 0xc3, 0xa1, 0x41, 0x19, 0xf5, 0xd4, 0x26, 0xa7, 0x95, 0x5d, 0xa3, 0xe6, 0xed, 0x3e, 0x81, };
221 uint8_t prov_confirm[] = {   0x05, 0x3d, 0x0d, 0x55, 0xc4, 0x83, 0xb9, 0x49, 0x6f, 0xab, 0x05, 0xdd, 0xb2, 0x3b, 0x5b, 0xc2, 0x9d};
222 uint8_t prov_random[]  = {   0x06, 0xe9, 0xc5, 0xf1, 0xb0, 0xc4, 0x15, 0x8a, 0xe5, 0x9b, 0x4d, 0x39, 0xf6, 0xf7, 0xe8, 0xa1, 0x05};
223 uint8_t prov_data[] = {
224     0x07, 0x47, 0x1a, 0x19, 0xcc, 0x17, 0x5c, 0xd0, 0xe8, 0x10, 0x3c, 0x85,
225     0x0a, 0x36, 0x10, 0x07, 0x35, 0x17, 0x41, 0x6a, 0xc3, 0x1e, 0x07, 0xe7,
226     0x90, 0x77, 0x3b, 0xab, 0xbb, 0x40, 0x37, 0x75, 0xb7
227 };
228 uint8_t prov_complete[] = { 0x08, };
229 
230 static void expect_packet(const char * packet_name, const uint8_t * packet_data, uint16_t packet_len){
231     printf("Expect '%s'\n", packet_name);
232     CHECK(pdu_data != NULL);
233     CHECK_EQUAL_ARRAY((uint8_t*)packet_data, pdu_data, packet_len);
234 }
235 
236 #define EXPECT_PACKET(packet) expect_packet(#packet, packet, sizeof(packet))
237 
238 TEST(Provisioning, Prov1){
239     // simulate unprovisioned device beacon
240     provisioning_provisioner_start_provisioning(device_uuid);
241     // wait for prov invite
242     EXPECT_PACKET(prov_invite);
243     pb_adv_emit_pdu_sent(0);
244     // send capabilities
245     send_prov_pdu(prov_capabilities, sizeof(prov_capabilities));
246     // wait for start
247     EXPECT_PACKET(prov_start);
248     pb_adv_emit_pdu_sent(0);
249     // wait for public key
250     EXPECT_PACKET(prov_public_key);
251     pb_adv_emit_pdu_sent(0);
252     // send public key
253     send_prov_pdu(prov_public_key, sizeof(prov_public_key));
254     // wait for confirm
255     EXPECT_PACKET(prov_confirm);
256     pb_adv_emit_pdu_sent(0);
257     // send prov confirm
258     send_prov_pdu(prov_confirm, sizeof(prov_confirm));
259     // wait for random
260     CHECK_EQUAL_ARRAY(prov_random, pdu_data, sizeof(prov_random));
261     pb_adv_emit_pdu_sent(0);
262     // send prov random
263     send_prov_pdu(prov_random, sizeof(prov_random));
264     // wait for prov data
265     EXPECT_PACKET(prov_data);
266     pb_adv_emit_pdu_sent(0);
267     // send prov complete
268     send_prov_pdu(prov_complete, sizeof(prov_complete));
269 }
270 
271 int main (int argc, const char * argv[]){
272     hci_dump_open("hci_dump.pklg", HCI_DUMP_PACKETLOGGER);
273     return CommandLineTestRunner::RunAllTests(argc, argv);
274 }
275