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