xref: /btstack/test/mesh/provisioning_provisioner_test.cpp (revision 870b3bb0eb047cc259e24bfdf3c381905c2195ad)
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 void pb_gatt_init(const uint8_t * device_uuid){}
113 
114 void pb_adv_close_link(uint16_t pb_adv_cid, uint8_t reason){}
115 
116 void pb_adv_register_packet_handler(btstack_packet_handler_t packet_handler){
117     pb_adv_packet_handler = packet_handler;
118 }
119 
120 void pb_gatt_register_packet_handler(btstack_packet_handler_t packet_handler){
121     UNUSED(packet_handler);
122 }
123 
124 void pb_adv_send_pdu(uint16_t pb_transport_cid, const uint8_t * pdu, uint16_t size){
125     UNUSED(pb_transport_cid);
126     pdu_data = (uint8_t*) pdu;
127     pdu_size = size;
128     // dump_data((uint8_t*)pdu,size);
129     // printf_hexdump(pdu, size);
130 }
131 void pb_gatt_send_pdu(uint16_t con_handle, const uint8_t * pdu, uint16_t pdu_size){}
132 
133 uint16_t pb_adv_create_link(const uint8_t * device_uuid){
134     // just simluate opened
135     pb_adv_emit_link_open(0, 1);
136     return 1;
137 }
138 
139 //
140 static void perform_crypto_operations(void){
141     int more = 1;
142     while (more){
143         more = mock_process_hci_cmd();
144     }
145 }
146 
147 static void send_prov_pdu(const uint8_t * packet, uint16_t size){
148     pb_adv_packet_handler(PROVISIONING_DATA_PACKET, 0, (uint8_t*) packet, size);
149     perform_crypto_operations();
150 }
151 
152 
153 static int scan_hex_byte(const char * byte_string){
154     int upper_nibble = nibble_for_char(*byte_string++);
155     if (upper_nibble < 0) return -1;
156     int lower_nibble = nibble_for_char(*byte_string);
157     if (lower_nibble < 0) return -1;
158     return (upper_nibble << 4) | lower_nibble;
159 }
160 
161 static int btstack_parse_hex(const char * string, uint16_t len, uint8_t * buffer){
162     int i;
163     for (i = 0; i < len; i++) {
164         int single_byte = scan_hex_byte(string);
165         if (single_byte < 0) return 0;
166         string += 2;
167         buffer[i] = (uint8_t)single_byte;
168         // don't check seperator after last byte
169         if (i == len - 1) {
170             return 1;
171         }
172         // optional seperator
173         char separator = *string;
174         if (separator == ':' && separator == '-' && separator == ' ') {
175             string++;
176         }
177     }
178     return 1;
179 }
180 
181 static uint8_t      prov_static_oob_data[16];
182 static const char * prov_static_oob_string = "00000000000000000102030405060708";
183 
184 static void provisioning_handle_pdu(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
185     if (packet_type != HCI_EVENT_PACKET) return;
186     switch(packet[0]){
187         case HCI_EVENT_MESH_META:
188             switch(packet[2]){
189                 case MESH_PB_PROV_CAPABILITIES:
190                     printf("Provisioner capabilities\n");
191                     provisioning_provisioner_select_authentication_method(1, 0, 0, 0, 0, 0);
192                     break;
193                 default:
194                     break;
195             }
196         default:
197             break;
198     }
199 }
200 
201 TEST_GROUP(Provisioning){
202     void setup(void){
203         btstack_crypto_init();
204         provisioning_provisioner_init();
205         btstack_parse_hex(prov_static_oob_string, 16, prov_static_oob_data);
206         provisioning_provisioner_register_packet_handler(&provisioning_handle_pdu);
207         // provisioning_device_set_static_oob(16, prov_static_oob_data);
208         // provisioning_device_set_output_oob_actions(0x08, 0x08);
209         // provisioning_device_set_input_oob_actions(0x08, 0x08);
210         perform_crypto_operations();
211     }
212 };
213 
214 const static uint8_t device_uuid[] = { 0x00, 0x1B, 0xDC, 0x08, 0x10, 0x21, 0x0B, 0x0E, 0x0A, 0x0C, 0x00, 0x0B, 0x0E, 0x0A, 0x0C, 0x00 };
215 
216 uint8_t prov_invite[] = { 0x00, 0x00 };
217 uint8_t prov_capabilities[] = { 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x08, 0x00, 0x08, 0x08, 0x00, 0x08, };
218 uint8_t prov_start[] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 };
219 uint8_t prov_public_key[] = { 0x03,
220     0xf0, 0xc8, 0x63, 0xf8, 0xe5, 0x55, 0x11, 0x4b, 0xf4, 0x88, 0x2c, 0xc7, 0x87, 0xb9, 0x5c, 0x27,
221     0x2a, 0x7f, 0xe4, 0xdc, 0xdd, 0xf1, 0x92, 0x2f, 0x4f, 0x18, 0xa4, 0x94, 0xe1, 0xc3, 0x57, 0xa1,
222     0xa6, 0xc3, 0x2d, 0x07, 0xbe, 0xb5, 0x76, 0xab, 0x60, 0x10, 0x68, 0x06, 0x8f, 0x0a, 0x9e, 0x01,
223     0x60, 0xc3, 0xa1, 0x41, 0x19, 0xf5, 0xd4, 0x26, 0xa7, 0x95, 0x5d, 0xa3, 0xe6, 0xed, 0x3e, 0x81, };
224 uint8_t prov_confirm[] = {   0x05, 0x3d, 0x0d, 0x55, 0xc4, 0x83, 0xb9, 0x49, 0x6f, 0xab, 0x05, 0xdd, 0xb2, 0x3b, 0x5b, 0xc2, 0x9d};
225 uint8_t prov_random[]  = {   0x06, 0xe9, 0xc5, 0xf1, 0xb0, 0xc4, 0x15, 0x8a, 0xe5, 0x9b, 0x4d, 0x39, 0xf6, 0xf7, 0xe8, 0xa1, 0x05};
226 uint8_t prov_data[] = {
227     0x07, 0x47, 0x1a, 0x19, 0xcc, 0x17, 0x5c, 0xd0, 0xe8, 0x10, 0x3c, 0x85,
228     0x0a, 0x36, 0x10, 0x07, 0x35, 0x17, 0x41, 0x6a, 0xc3, 0x1e, 0x07, 0xe7,
229     0x90, 0x77, 0x3b, 0xab, 0xbb, 0x40, 0x37, 0x75, 0xb7
230 };
231 uint8_t prov_complete[] = { 0x08, };
232 
233 static void expect_packet(const char * packet_name, const uint8_t * packet_data, uint16_t packet_len){
234     printf("Expect '%s'\n", packet_name);
235     CHECK(pdu_data != NULL);
236     CHECK_EQUAL_ARRAY((uint8_t*)packet_data, pdu_data, packet_len);
237 }
238 
239 #define EXPECT_PACKET(packet) expect_packet(#packet, packet, sizeof(packet))
240 
241 TEST(Provisioning, Prov1){
242     // simulate unprovisioned device beacon
243     provisioning_provisioner_start_provisioning(device_uuid);
244     // wait for prov invite
245     EXPECT_PACKET(prov_invite);
246     pb_adv_emit_pdu_sent(0);
247     // send capabilities
248     send_prov_pdu(prov_capabilities, sizeof(prov_capabilities));
249     // wait for start
250     EXPECT_PACKET(prov_start);
251     pb_adv_emit_pdu_sent(0);
252     // wait for public key
253     EXPECT_PACKET(prov_public_key);
254     pb_adv_emit_pdu_sent(0);
255     // send public key
256     send_prov_pdu(prov_public_key, sizeof(prov_public_key));
257     // wait for confirm
258     EXPECT_PACKET(prov_confirm);
259     pb_adv_emit_pdu_sent(0);
260     // send prov confirm
261     send_prov_pdu(prov_confirm, sizeof(prov_confirm));
262     // wait for random
263     CHECK_EQUAL_ARRAY(prov_random, pdu_data, sizeof(prov_random));
264     pb_adv_emit_pdu_sent(0);
265     // send prov random
266     send_prov_pdu(prov_random, sizeof(prov_random));
267     // wait for prov data
268     EXPECT_PACKET(prov_data);
269     pb_adv_emit_pdu_sent(0);
270     // send prov complete
271     send_prov_pdu(prov_complete, sizeof(prov_complete));
272 }
273 
274 int main (int argc, const char * argv[]){
275     hci_dump_open("hci_dump.pklg", HCI_DUMP_PACKETLOGGER);
276     return CommandLineTestRunner::RunAllTests(argc, argv);
277 }
278