xref: /btstack/test/mesh/provisioning_device_test.cpp (revision cc528b9d66cd63ff4662ca3aba554b3ddf559fb2)
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 "btstack_memory.h"
41 #include "mesh/gatt-service/mesh_provisioning_service_server.h"
42 #include "hci_dump.h"
43 #include "hci_dump_posix_fs.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 #include "mock.h"
54 
55 static void CHECK_EQUAL_ARRAY(const char * name, uint8_t * expected, uint8_t * actual, int size){
56     int i;
57     for (i=0; i<size; i++){
58         if (expected[i] != actual[i]) {
59             printf("%s: offset %u wrong\n", name, i);
60             printf("expected: "); printf_hexdump(expected, size);
61             printf("actual:   "); printf_hexdump(actual, size);
62         }
63         BYTES_EQUAL(expected[i], actual[i]);
64     }
65 }
66 
67 const static uint8_t device_uuid[] = { 0x00, 0x1B, 0xDC, 0x08, 0x10, 0x21, 0x0B, 0x0E, 0x0A, 0x0C, 0x00, 0x0B, 0x0E, 0x0A, 0x0C, 0x00 };
68 
69 // pb-adv mock for testing
70 
71 static btstack_packet_handler_t pb_adv_packet_handler;
72 
73 static uint8_t * pdu_data;
74 static uint16_t  pdu_size;
75 
76 /**
77  * Initialize Provisioning Bearer using Advertisement Bearer
78  * @param DeviceUUID
79  */
80 void pb_adv_init(void){}
81 void pb_gatt_init(void){}
82 
83 /**
84  * Close Link
85  * @param con_handle
86  * @param reason 0 = success, 1 = timeout, 2 = fail
87  */
88 void pb_gatt_close_link(hci_con_handle_t con_handle, uint8_t reason){
89     UNUSED(con_handle);
90     UNUSED(reason);
91 }
92 void pb_adv_close_link(hci_con_handle_t con_handle, uint8_t reason){
93     UNUSED(con_handle);
94     UNUSED(reason);
95 }
96 
97 
98 /**
99  * Register listener for Provisioning PDUs and MESH_PBV_ADV_SEND_COMPLETE
100  */
101 void pb_adv_register_device_packet_handler(btstack_packet_handler_t packet_handler){
102     pb_adv_packet_handler = packet_handler;
103 }
104 
105 void pb_gatt_register_packet_handler(btstack_packet_handler_t packet_handler){
106     UNUSED(packet_handler);
107 }
108 /**
109  * Send Provisioning PDU
110  */
111 void pb_adv_send_pdu(uint16_t pb_transport_cid, const uint8_t * pdu, uint16_t size){
112     UNUSED(pb_transport_cid);
113     pdu_data = (uint8_t*) pdu;
114     pdu_size = size;
115     // dump_data((uint8_t*)pdu,size);
116     // printf_hexdump(pdu, size);
117 }
118 void pb_gatt_send_pdu(uint16_t con_handle, const uint8_t * pdu, uint16_t _pdu_size){
119     UNUSED(con_handle);
120     UNUSED(pdu);
121     UNUSED(_pdu_size);
122 }
123 
124 uint16_t mesh_network_key_get_free_index(void){
125     return 0;
126 }
127 
128 static mesh_network_key_t network_key;
129 extern "C" mesh_network_key_t * btstack_memory_mesh_network_key_get(void){
130     return &network_key;
131 }
132 
133 static void perform_crypto_operations(void){
134     int more = 1;
135     while (more){
136         more = mock_process_hci_cmd();
137     }
138 }
139 
140 static void send_prov_pdu(const uint8_t * packet, uint16_t size){
141     pb_adv_packet_handler(PROVISIONING_DATA_PACKET, 0, (uint8_t*) packet, size);
142     perform_crypto_operations();
143 }
144 
145 static void pb_adv_emit_pdu_sent(uint8_t status){
146     uint8_t event[] = { HCI_EVENT_MESH_META, 2, MESH_SUBEVENT_PB_TRANSPORT_PDU_SENT, status};
147     pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event));
148 }
149 
150 static int scan_hex_byte(const char * byte_string){
151     int upper_nibble = nibble_for_char(*byte_string++);
152     if (upper_nibble < 0) return -1;
153     int lower_nibble = nibble_for_char(*byte_string);
154     if (lower_nibble < 0) return -1;
155     return (upper_nibble << 4) | lower_nibble;
156 }
157 
158 static int btstack_parse_hex(const char * string, uint16_t len, uint8_t * buffer){
159     int i;
160     for (i = 0; i < len; i++) {
161         int single_byte = scan_hex_byte(string);
162         if (single_byte < 0) return 0;
163         string += 2;
164         buffer[i] = (uint8_t)single_byte;
165         // don't check seperator after last byte
166         if (i == len - 1) {
167             return 1;
168         }
169         // optional seperator
170         char separator = *string;
171         if (separator == ':' && separator == '-' && separator == ' ') {
172             string++;
173         }
174     }
175     return 1;
176 }
177 
178 // void pb_gatt_close_link(hci_con_handle_t con_handle, uint8_t reason){
179 // }
180 
181 static uint8_t      prov_static_oob_data[16];
182 static const char * prov_static_oob_string = "00000000000000000102030405060708";
183 
184 TEST_GROUP(Provisioning){
185     void setup(void){
186         mock_init();
187         for (unsigned int i = 0 ; i < 4 ; i ++){
188             printf("rand: %08x\n", rand());
189         }
190         btstack_crypto_init();
191         provisioning_device_init();
192         mesh_node_set_device_uuid(device_uuid);
193         btstack_parse_hex(prov_static_oob_string, 16, prov_static_oob_data);
194         provisioning_device_set_static_oob(16, prov_static_oob_data);
195         provisioning_device_set_output_oob_actions(0x08, 0x08);
196         provisioning_device_set_input_oob_actions(0x08, 0x08);
197         perform_crypto_operations();
198     }
199 };
200 
201 uint8_t prov_invite[] = { 0x00, 0x00 };
202 uint8_t prov_capabilities[] = { 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x08, 0x00, 0x08, 0x08, 0x00, 0x08, };
203 uint8_t prov_start[] = { 0x02, 0x00, 0x00, 0x02, 0x00, 0x01 };
204 uint8_t prov_public_key[] = { 0x03,
205                               0x8E, 0x9D, 0xEE, 0x76, 0x17, 0x67, 0x4A, 0xCD, 0xBE, 0xA5, 0x4D, 0xCD, 0xAB, 0x7E, 0xA3, 0x83,
206                               0x26, 0xF6, 0x87, 0x22, 0x7F, 0x97, 0xE7, 0xC4, 0xEE, 0xF5, 0x2F, 0x7C, 0x80, 0x5A, 0xEB, 0x2A,
207                               0x59, 0x46, 0x99, 0xDF, 0x60, 0x54, 0x53, 0x47, 0x48, 0xF8, 0xA1, 0x99, 0xF0, 0x02, 0xE7, 0x23,
208                               0x2C, 0x52, 0x9C, 0xBA, 0x0F, 0x54, 0x94, 0x1F, 0xE4, 0xB7, 0x02, 0x89, 0x9E, 0x03, 0xFA, 0x43 };
209 uint8_t prov_confirm[] = { 0x05,
210                            0x5F, 0xDE, 0x98, 0x35, 0x7F, 0x0B, 0xA2, 0xB2, 0x94, 0x72, 0x03, 0xD6, 0x82, 0x57, 0xF0, 0x6E };
211 uint8_t prov_random[]  = { 0x06, 0xC2, 0xE1, 0xF1, 0xF9, 0x7D, 0x3F, 0x9E, 0xCF, 0xE6, 0x73, 0xB8, 0x5C, 0x2E, 0x97, 0x4A, 0x25, };
212 uint8_t prov_data[] = {
213     0x07,
214     0x85, 0x66, 0xac, 0x46, 0x37, 0x34, 0x86, 0xe1, 0x3e, 0x4c, 0x13, 0x52, 0xd0, 0x6d, 0x34, 0x7d,
215     0xce, 0xf1, 0xd1, 0x7d, 0xbd, 0xbe, 0xcc, 0x99, 0xc3,
216     0x93, 0x87, 0xfc, 0xb0, 0x72, 0x0f, 0xd8, 0x8d };
217 uint8_t prov_complete[] = { 0x08, };
218 
219 TEST(Provisioning, Prov1){
220     // send prov inviate
221     send_prov_pdu(prov_invite, sizeof(prov_invite));
222     // check for prov cap
223     CHECK_EQUAL_ARRAY("prov_capabilities", prov_capabilities, pdu_data, sizeof(prov_capabilities));
224     pb_adv_emit_pdu_sent(0);
225     // send prov start
226     send_prov_pdu(prov_start, sizeof(prov_start));
227     // send public key
228     send_prov_pdu(prov_public_key, sizeof(prov_public_key));
229     // check for public key
230     CHECK_EQUAL_ARRAY("prov_public_key", prov_public_key, pdu_data, sizeof(prov_public_key));
231     pb_adv_emit_pdu_sent(0);
232     // send prov confirm
233     send_prov_pdu(prov_confirm, sizeof(prov_confirm));
234     // check for prov confirm
235     CHECK_EQUAL_ARRAY("prov_confirm", prov_confirm, pdu_data, sizeof(prov_confirm));
236     pb_adv_emit_pdu_sent(0);
237     // send prov random
238     send_prov_pdu(prov_random, sizeof(prov_random));
239     // check for prov random
240     CHECK_EQUAL_ARRAY("prov_random", prov_random, pdu_data, sizeof(prov_random));
241     pb_adv_emit_pdu_sent(0);
242     // send prov data
243     send_prov_pdu(prov_data, sizeof(prov_data));
244     // check prov complete
245     CHECK_EQUAL_ARRAY("prov_complete", prov_complete, pdu_data, sizeof(prov_complete));
246     pb_adv_emit_pdu_sent(0);
247 }
248 
249 int main (int argc, const char * argv[]){
250     // log into file using HCI_DUMP_PACKETLOGGER format
251     const char * log_path = "hci_dump.pklg";
252     hci_dump_posix_fs_open(log_path, HCI_DUMP_PACKETLOGGER);
253     hci_dump_init(hci_dump_posix_fs_get_instance());
254     printf("Packet Log: %s\n", log_path);
255 
256     return CommandLineTestRunner::RunAllTests(argc, argv);
257 }
258