xref: /btstack/test/mesh/provisioning_device_test.cpp (revision 8936a14384360a1b771ab2f993f6a6ac0346f02d)
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 "btstack.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 static mesh_network_key_t network_key;
144 mesh_network_key_t * btstack_memory_mesh_network_key_get(void){
145     return &network_key;
146 }
147 
148 static void perform_crypto_operations(void){
149     int more = 1;
150     while (more){
151         more = mock_process_hci_cmd();
152     }
153 }
154 
155 static void send_prov_pdu(const uint8_t * packet, uint16_t size){
156     pb_adv_packet_handler(PROVISIONING_DATA_PACKET, 0, (uint8_t*) packet, size);
157     perform_crypto_operations();
158 }
159 
160 static void pb_adv_emit_pdu_sent(uint8_t status){
161     uint8_t event[] = { HCI_EVENT_MESH_META, 2, MESH_SUBEVENT_PB_TRANSPORT_PDU_SENT, status};
162     pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event));
163 }
164 
165 static int scan_hex_byte(const char * byte_string){
166     int upper_nibble = nibble_for_char(*byte_string++);
167     if (upper_nibble < 0) return -1;
168     int lower_nibble = nibble_for_char(*byte_string);
169     if (lower_nibble < 0) return -1;
170     return (upper_nibble << 4) | lower_nibble;
171 }
172 
173 static int btstack_parse_hex(const char * string, uint16_t len, uint8_t * buffer){
174     int i;
175     for (i = 0; i < len; i++) {
176         int single_byte = scan_hex_byte(string);
177         if (single_byte < 0) return 0;
178         string += 2;
179         buffer[i] = (uint8_t)single_byte;
180         // don't check seperator after last byte
181         if (i == len - 1) {
182             return 1;
183         }
184         // optional seperator
185         char separator = *string;
186         if (separator == ':' && separator == '-' && separator == ' ') {
187             string++;
188         }
189     }
190     return 1;
191 }
192 
193 // void pb_gatt_close_link(hci_con_handle_t con_handle, uint8_t reason){
194 // }
195 
196 static uint8_t      prov_static_oob_data[16];
197 static const char * prov_static_oob_string = "00000000000000000102030405060708";
198 
199 TEST_GROUP(Provisioning){
200     void setup(void){
201         btstack_crypto_init();
202         provisioning_device_init();
203         mesh_node_set_device_uuid(device_uuid);
204         btstack_parse_hex(prov_static_oob_string, 16, prov_static_oob_data);
205         provisioning_device_set_static_oob(16, prov_static_oob_data);
206         provisioning_device_set_output_oob_actions(0x08, 0x08);
207         provisioning_device_set_input_oob_actions(0x08, 0x08);
208         perform_crypto_operations();
209     }
210 };
211 
212 uint8_t prov_invite[] = { 0x00, 0x00 };
213 uint8_t prov_capabilities[] = { 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x08, 0x00, 0x08, 0x08, 0x00, 0x08, };
214 uint8_t prov_start[] = { 0x02, 0x00, 0x00, 0x02, 0x00, 0x01 };
215 uint8_t prov_public_key[] = { 0x03,
216     0xf0, 0xc8, 0x63, 0xf8, 0xe5, 0x55, 0x11, 0x4b, 0xf4, 0x88, 0x2c, 0xc7, 0x87, 0xb9, 0x5c, 0x27,
217     0x2a, 0x7f, 0xe4, 0xdc, 0xdd, 0xf1, 0x92, 0x2f, 0x4f, 0x18, 0xa4, 0x94, 0xe1, 0xc3, 0x57, 0xa1,
218     0xa6, 0xc3, 0x2d, 0x07, 0xbe, 0xb5, 0x76, 0xab, 0x60, 0x10, 0x68, 0x06, 0x8f, 0x0a, 0x9e, 0x01,
219     0x60, 0xc3, 0xa1, 0x41, 0x19, 0xf5, 0xd4, 0x26, 0xa7, 0x95, 0x5d, 0xa3, 0xe6, 0xed, 0x3e, 0x81, };
220 uint8_t prov_confirm[] = { 0x05, 0x80, 0x4d, 0xdc, 0x3b, 0xba, 0x60, 0xd5, 0x93, 0x5b, 0x56, 0xef, 0xb5, 0xcb, 0x59, 0x31, 0xfa, };
221 uint8_t prov_random[]  = { 0x06, 0x9b, 0x4d, 0x39, 0xf6, 0xf7, 0xe8, 0xa1, 0x05, 0xd3, 0xfe, 0xed, 0xa5, 0xd5, 0xf3, 0xd9, 0xe4, };
222 uint8_t prov_data[] = {
223     0x07,
224     0x85, 0x66, 0xac, 0x46, 0x37, 0x34, 0x86, 0xe1, 0x3e, 0x4c, 0x13, 0x52, 0xd0, 0x6d, 0x34, 0x7d,
225     0xce, 0xf1, 0xd1, 0x7d, 0xbd, 0xbe, 0xcc, 0x99, 0xc3,
226     0x93, 0x87, 0xfc, 0xb0, 0x72, 0x0f, 0xd8, 0x8d };
227 uint8_t prov_complete[] = { 0x08, };
228 
229 TEST(Provisioning, Prov1){
230     // send prov inviate
231     send_prov_pdu(prov_invite, sizeof(prov_invite));
232     // check for prov cap
233     CHECK_EQUAL_ARRAY(prov_capabilities, pdu_data, sizeof(prov_capabilities));
234     pb_adv_emit_pdu_sent(0);
235     // send prov start
236     send_prov_pdu(prov_start, sizeof(prov_start));
237     // send public key
238     send_prov_pdu(prov_public_key, sizeof(prov_public_key));
239     // check for public key
240     CHECK_EQUAL_ARRAY(prov_public_key, pdu_data, sizeof(prov_public_key));
241     pb_adv_emit_pdu_sent(0);
242     // send prov confirm
243     send_prov_pdu(prov_confirm, sizeof(prov_confirm));
244     // check for prov confirm
245     CHECK_EQUAL_ARRAY(prov_confirm, pdu_data, sizeof(prov_confirm));
246     pb_adv_emit_pdu_sent(0);
247     // send prov random
248     send_prov_pdu(prov_random, sizeof(prov_random));
249     // check for prov random
250     CHECK_EQUAL_ARRAY(prov_random, pdu_data, sizeof(prov_random));
251     pb_adv_emit_pdu_sent(0);
252     // send prov data
253     send_prov_pdu(prov_data, sizeof(prov_data));
254     // check prov complete
255     CHECK_EQUAL_ARRAY(prov_complete, pdu_data, sizeof(prov_complete));
256     pb_adv_emit_pdu_sent(0);
257 }
258 
259 int main (int argc, const char * argv[]){
260     hci_dump_open("hci_dump.pklg", HCI_DUMP_PACKETLOGGER);
261     return CommandLineTestRunner::RunAllTests(argc, argv);
262 }
263