xref: /btstack/test/mesh/provisioning_device_test.cpp (revision 1b464e99afd70ddaf6b75be1ba7cc563a5f5dfd8)
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/gatt-service/mesh_provisioning_service_server.h"
43 #include "hci_dump.h"
44 #include "mesh/mesh_node.h"
45 #include "mesh/pb_adv.h"
46 #include "mesh/pb_gatt.h"
47 #include "mesh/provisioning.h"
48 #include "mesh/provisioning_device.h"
49 
50 #include "CppUTest/TestHarness.h"
51 #include "CppUTest/CommandLineTestRunner.h"
52 
53 static void CHECK_EQUAL_ARRAY(uint8_t * expected, uint8_t * actual, int size){
54     int i;
55     for (i=0; i<size; i++){
56         if (expected[i] != actual[i]) {
57             printf("offset %u wrong\n", i);
58             printf("expected: "); printf_hexdump(expected, size);
59             printf("actual:   "); printf_hexdump(actual, size);
60         }
61         BYTES_EQUAL(expected[i], actual[i]);
62     }
63 }
64 
65 void dump_data(uint8_t * buffer, uint16_t size){
66     static int data_counter = 1;
67     char var_name[80];
68     sprintf(var_name, "test_data_%02u", data_counter);
69     printf("uint8_t %s[] = { ", var_name);
70     for (int i = 0; i < size ; i++){
71         if ((i % 16) == 0) printf("\n    ");
72         printf ("0x%02x, ", buffer[i]);
73     }
74     printf("};\n");
75     data_counter++;
76 }
77 
78 int parse_hex(uint8_t * buffer, const char * hex_string){
79     int len = 0;
80     while (*hex_string){
81         if (*hex_string == ' '){
82             hex_string++;
83             continue;
84         }
85         int high_nibble = nibble_for_char(*hex_string++);
86         int low_nibble = nibble_for_char(*hex_string++);
87         *buffer++ = (high_nibble << 4) | low_nibble;
88         len++;
89     }
90     return len;
91 }
92 
93 // returns if anything was done
94 extern "C" int mock_process_hci_cmd(void);
95 
96 const static uint8_t device_uuid[] = { 0x00, 0x1B, 0xDC, 0x08, 0x10, 0x21, 0x0B, 0x0E, 0x0A, 0x0C, 0x00, 0x0B, 0x0E, 0x0A, 0x0C, 0x00 };
97 
98 // pb-adv mock for testing
99 
100 static btstack_packet_handler_t pb_adv_packet_handler;
101 
102 static uint8_t * pdu_data;
103 static uint16_t  pdu_size;
104 
105 /**
106  * Initialize Provisioning Bearer using Advertisement Bearer
107  * @param DeviceUUID
108  */
109 void pb_adv_init(void){}
110 void pb_gatt_init(void){}
111 
112 /**
113  * Close Link
114  * @param con_handle
115  * @param reason 0 = success, 1 = timeout, 2 = fail
116  */
117 void pb_gatt_close_link(hci_con_handle_t con_handle, uint8_t reason){}
118 void pb_adv_close_link(hci_con_handle_t con_handle, uint8_t reason){}
119 
120 
121 /**
122  * Register listener for Provisioning PDUs and MESH_PBV_ADV_SEND_COMPLETE
123  */
124 void pb_adv_register_packet_handler(btstack_packet_handler_t packet_handler){
125     pb_adv_packet_handler = packet_handler;
126 }
127 
128 void pb_gatt_register_packet_handler(btstack_packet_handler_t packet_handler){
129     UNUSED(packet_handler);
130 }
131 /**
132  * Send Provisioning PDU
133  */
134 void pb_adv_send_pdu(uint16_t pb_transport_cid, const uint8_t * pdu, uint16_t size){
135     UNUSED(pb_transport_cid);
136     pdu_data = (uint8_t*) pdu;
137     pdu_size = size;
138     // dump_data((uint8_t*)pdu,size);
139     // printf_hexdump(pdu, size);
140 }
141 void pb_gatt_send_pdu(uint16_t con_handle, const uint8_t * pdu, uint16_t pdu_size){}
142 
143 uint16_t mesh_network_key_get_free_index(void){
144     return 0;
145 }
146 
147 static mesh_network_key_t network_key;
148 extern "C" mesh_network_key_t * btstack_memory_mesh_network_key_get(void){
149     return &network_key;
150 }
151 
152 static void perform_crypto_operations(void){
153     int more = 1;
154     while (more){
155         more = mock_process_hci_cmd();
156     }
157 }
158 
159 static void send_prov_pdu(const uint8_t * packet, uint16_t size){
160     pb_adv_packet_handler(PROVISIONING_DATA_PACKET, 0, (uint8_t*) packet, size);
161     perform_crypto_operations();
162 }
163 
164 static void pb_adv_emit_pdu_sent(uint8_t status){
165     uint8_t event[] = { HCI_EVENT_MESH_META, 2, MESH_SUBEVENT_PB_TRANSPORT_PDU_SENT, status};
166     pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event));
167 }
168 
169 static int scan_hex_byte(const char * byte_string){
170     int upper_nibble = nibble_for_char(*byte_string++);
171     if (upper_nibble < 0) return -1;
172     int lower_nibble = nibble_for_char(*byte_string);
173     if (lower_nibble < 0) return -1;
174     return (upper_nibble << 4) | lower_nibble;
175 }
176 
177 static int btstack_parse_hex(const char * string, uint16_t len, uint8_t * buffer){
178     int i;
179     for (i = 0; i < len; i++) {
180         int single_byte = scan_hex_byte(string);
181         if (single_byte < 0) return 0;
182         string += 2;
183         buffer[i] = (uint8_t)single_byte;
184         // don't check seperator after last byte
185         if (i == len - 1) {
186             return 1;
187         }
188         // optional seperator
189         char separator = *string;
190         if (separator == ':' && separator == '-' && separator == ' ') {
191             string++;
192         }
193     }
194     return 1;
195 }
196 
197 // void pb_gatt_close_link(hci_con_handle_t con_handle, uint8_t reason){
198 // }
199 
200 static uint8_t      prov_static_oob_data[16];
201 static const char * prov_static_oob_string = "00000000000000000102030405060708";
202 
203 TEST_GROUP(Provisioning){
204     void setup(void){
205         btstack_crypto_init();
206         provisioning_device_init();
207         mesh_node_set_device_uuid(device_uuid);
208         btstack_parse_hex(prov_static_oob_string, 16, prov_static_oob_data);
209         provisioning_device_set_static_oob(16, prov_static_oob_data);
210         provisioning_device_set_output_oob_actions(0x08, 0x08);
211         provisioning_device_set_input_oob_actions(0x08, 0x08);
212         perform_crypto_operations();
213     }
214 };
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, 0x02, 0x00, 0x01 };
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, 0x80, 0x4d, 0xdc, 0x3b, 0xba, 0x60, 0xd5, 0x93, 0x5b, 0x56, 0xef, 0xb5, 0xcb, 0x59, 0x31, 0xfa, };
225 uint8_t prov_random[]  = { 0x06, 0x9b, 0x4d, 0x39, 0xf6, 0xf7, 0xe8, 0xa1, 0x05, 0xd3, 0xfe, 0xed, 0xa5, 0xd5, 0xf3, 0xd9, 0xe4, };
226 uint8_t prov_data[] = {
227     0x07,
228     0x85, 0x66, 0xac, 0x46, 0x37, 0x34, 0x86, 0xe1, 0x3e, 0x4c, 0x13, 0x52, 0xd0, 0x6d, 0x34, 0x7d,
229     0xce, 0xf1, 0xd1, 0x7d, 0xbd, 0xbe, 0xcc, 0x99, 0xc3,
230     0x93, 0x87, 0xfc, 0xb0, 0x72, 0x0f, 0xd8, 0x8d };
231 uint8_t prov_complete[] = { 0x08, };
232 
233 TEST(Provisioning, Prov1){
234     // send prov inviate
235     send_prov_pdu(prov_invite, sizeof(prov_invite));
236     // check for prov cap
237     CHECK_EQUAL_ARRAY(prov_capabilities, pdu_data, sizeof(prov_capabilities));
238     pb_adv_emit_pdu_sent(0);
239     // send prov start
240     send_prov_pdu(prov_start, sizeof(prov_start));
241     // send public key
242     send_prov_pdu(prov_public_key, sizeof(prov_public_key));
243     // check for public key
244     CHECK_EQUAL_ARRAY(prov_public_key, pdu_data, sizeof(prov_public_key));
245     pb_adv_emit_pdu_sent(0);
246     // send prov confirm
247     send_prov_pdu(prov_confirm, sizeof(prov_confirm));
248     // check for prov confirm
249     CHECK_EQUAL_ARRAY(prov_confirm, pdu_data, sizeof(prov_confirm));
250     pb_adv_emit_pdu_sent(0);
251     // send prov random
252     send_prov_pdu(prov_random, sizeof(prov_random));
253     // check for prov random
254     CHECK_EQUAL_ARRAY(prov_random, pdu_data, sizeof(prov_random));
255     pb_adv_emit_pdu_sent(0);
256     // send prov data
257     send_prov_pdu(prov_data, sizeof(prov_data));
258     // check prov complete
259     CHECK_EQUAL_ARRAY(prov_complete, pdu_data, sizeof(prov_complete));
260     pb_adv_emit_pdu_sent(0);
261 }
262 
263 int main (int argc, const char * argv[]){
264     hci_dump_open("hci_dump.pklg", HCI_DUMP_PACKETLOGGER);
265     return CommandLineTestRunner::RunAllTests(argc, argv);
266 }
267