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