xref: /btstack/test/mesh/provisioning_device_test.cpp (revision d6915e6f98e8539dd9caf390100fc4903f0449ac)
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 "mesh/pb_adv.h"
43 #include "mesh/pb_gatt.h"
44 #include "mesh/mesh_node.h"
45 #include "ble/gatt-service/mesh_provisioning_service_server.h"
46 #include "provisioning.h"
47 #include "provisioning_device.h"
48 #include "hci_dump.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 
144 static mesh_network_key_t network_key;
145 extern "C" mesh_network_key_t * btstack_memory_mesh_network_key_get(void){
146     return &network_key;
147 }
148 
149 static void perform_crypto_operations(void){
150     int more = 1;
151     while (more){
152         more = mock_process_hci_cmd();
153     }
154 }
155 
156 static void send_prov_pdu(const uint8_t * packet, uint16_t size){
157     pb_adv_packet_handler(PROVISIONING_DATA_PACKET, 0, (uint8_t*) packet, size);
158     perform_crypto_operations();
159 }
160 
161 static void pb_adv_emit_pdu_sent(uint8_t status){
162     uint8_t event[] = { HCI_EVENT_MESH_META, 2, MESH_SUBEVENT_PB_TRANSPORT_PDU_SENT, status};
163     pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event));
164 }
165 
166 static int scan_hex_byte(const char * byte_string){
167     int upper_nibble = nibble_for_char(*byte_string++);
168     if (upper_nibble < 0) return -1;
169     int lower_nibble = nibble_for_char(*byte_string);
170     if (lower_nibble < 0) return -1;
171     return (upper_nibble << 4) | lower_nibble;
172 }
173 
174 static int btstack_parse_hex(const char * string, uint16_t len, uint8_t * buffer){
175     int i;
176     for (i = 0; i < len; i++) {
177         int single_byte = scan_hex_byte(string);
178         if (single_byte < 0) return 0;
179         string += 2;
180         buffer[i] = (uint8_t)single_byte;
181         // don't check seperator after last byte
182         if (i == len - 1) {
183             return 1;
184         }
185         // optional seperator
186         char separator = *string;
187         if (separator == ':' && separator == '-' && separator == ' ') {
188             string++;
189         }
190     }
191     return 1;
192 }
193 
194 // void pb_gatt_close_link(hci_con_handle_t con_handle, uint8_t reason){
195 // }
196 
197 static uint8_t      prov_static_oob_data[16];
198 static const char * prov_static_oob_string = "00000000000000000102030405060708";
199 
200 TEST_GROUP(Provisioning){
201     void setup(void){
202         btstack_crypto_init();
203         provisioning_device_init();
204         mesh_node_set_device_uuid(device_uuid);
205         btstack_parse_hex(prov_static_oob_string, 16, prov_static_oob_data);
206         provisioning_device_set_static_oob(16, prov_static_oob_data);
207         provisioning_device_set_output_oob_actions(0x08, 0x08);
208         provisioning_device_set_input_oob_actions(0x08, 0x08);
209         perform_crypto_operations();
210     }
211 };
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, 0x02, 0x00, 0x01 };
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, 0x80, 0x4d, 0xdc, 0x3b, 0xba, 0x60, 0xd5, 0x93, 0x5b, 0x56, 0xef, 0xb5, 0xcb, 0x59, 0x31, 0xfa, };
222 uint8_t prov_random[]  = { 0x06, 0x9b, 0x4d, 0x39, 0xf6, 0xf7, 0xe8, 0xa1, 0x05, 0xd3, 0xfe, 0xed, 0xa5, 0xd5, 0xf3, 0xd9, 0xe4, };
223 uint8_t prov_data[] = {
224     0x07,
225     0x85, 0x66, 0xac, 0x46, 0x37, 0x34, 0x86, 0xe1, 0x3e, 0x4c, 0x13, 0x52, 0xd0, 0x6d, 0x34, 0x7d,
226     0xce, 0xf1, 0xd1, 0x7d, 0xbd, 0xbe, 0xcc, 0x99, 0xc3,
227     0x93, 0x87, 0xfc, 0xb0, 0x72, 0x0f, 0xd8, 0x8d };
228 uint8_t prov_complete[] = { 0x08, };
229 
230 TEST(Provisioning, Prov1){
231     // send prov inviate
232     send_prov_pdu(prov_invite, sizeof(prov_invite));
233     // check for prov cap
234     CHECK_EQUAL_ARRAY(prov_capabilities, pdu_data, sizeof(prov_capabilities));
235     pb_adv_emit_pdu_sent(0);
236     // send prov start
237     send_prov_pdu(prov_start, sizeof(prov_start));
238     // send public key
239     send_prov_pdu(prov_public_key, sizeof(prov_public_key));
240     // check for public key
241     CHECK_EQUAL_ARRAY(prov_public_key, pdu_data, sizeof(prov_public_key));
242     pb_adv_emit_pdu_sent(0);
243     // send prov confirm
244     send_prov_pdu(prov_confirm, sizeof(prov_confirm));
245     // check for prov confirm
246     CHECK_EQUAL_ARRAY(prov_confirm, pdu_data, sizeof(prov_confirm));
247     pb_adv_emit_pdu_sent(0);
248     // send prov random
249     send_prov_pdu(prov_random, sizeof(prov_random));
250     // check for prov random
251     CHECK_EQUAL_ARRAY(prov_random, pdu_data, sizeof(prov_random));
252     pb_adv_emit_pdu_sent(0);
253     // send prov data
254     send_prov_pdu(prov_data, sizeof(prov_data));
255     // check prov complete
256     CHECK_EQUAL_ARRAY(prov_complete, pdu_data, sizeof(prov_complete));
257     pb_adv_emit_pdu_sent(0);
258 }
259 
260 int main (int argc, const char * argv[]){
261     hci_dump_open("hci_dump.pklg", HCI_DUMP_PACKETLOGGER);
262     return CommandLineTestRunner::RunAllTests(argc, argv);
263 }
264