xref: /btstack/test/mesh/provisioning_provisioner_test.cpp (revision 42c5c5581b83a00e2c1de42e4fe687a30b9efa5a)
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/gatt-service/mesh_provisioning_service_server.h"
45 #include "mesh/provisioning.h"
46 #include "mesh/provisioning_provisioner.h"
47 #include "hci_dump.h"
48 #include "hci_dump_posix_fs.h"
49 #include "mock.h"
50 
51 #include "CppUTest/TestHarness.h"
52 #include "CppUTest/CommandLineTestRunner.h"
53 
54 static void CHECK_EQUAL_ARRAY(uint8_t * expected, uint8_t * actual, int size){
55     int i;
56     for (i=0; i<size; i++){
57         if (expected[i] != actual[i]) {
58             printf("offset %u wrong\n", i);
59             printf("expected: "); printf_hexdump(expected, size);
60             printf("actual:   "); printf_hexdump(actual, size);
61         }
62         BYTES_EQUAL(expected[i], actual[i]);
63     }
64 }
65 
66 // pb-adv mock for testing
67 
68 static btstack_packet_handler_t pb_adv_packet_handler;
69 
70 static uint8_t * pdu_data;
71 static uint16_t  pdu_size;
72 
73 static void pb_adv_emit_link_open(uint8_t status, uint16_t pb_adv_cid){
74     uint8_t event[7] = { HCI_EVENT_MESH_META, 5, MESH_SUBEVENT_PB_TRANSPORT_LINK_OPEN, status};
75     little_endian_store_16(event, 4, pb_adv_cid);
76     event[6] = MESH_PB_TYPE_ADV;
77     pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event));
78 }
79 
80 static void pb_adv_emit_pdu_sent(uint8_t status){
81     uint8_t event[] = { HCI_EVENT_MESH_META, 2, MESH_SUBEVENT_PB_TRANSPORT_PDU_SENT, status};
82     pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event));
83 }
84 
85 void pb_adv_init(void){}
86 void pb_gatt_init(void){}
87 
88 void pb_adv_close_link(uint16_t pb_adv_cid, uint8_t reason){
89     UNUSED(pb_adv_cid);
90     UNUSED(reason);
91 }
92 
93 void pb_adv_register_provisioner_packet_handler(btstack_packet_handler_t packet_handler){
94     pb_adv_packet_handler = packet_handler;
95 }
96 
97 void pb_gatt_register_packet_handler(btstack_packet_handler_t packet_handler){
98     UNUSED(packet_handler);
99 }
100 
101 void pb_adv_send_pdu(uint16_t pb_transport_cid, const uint8_t * pdu, uint16_t size){
102     UNUSED(pb_transport_cid);
103     pdu_data = (uint8_t*) pdu;
104     pdu_size = size;
105     // dump_data((uint8_t*)pdu,size);
106     // printf_hexdump(pdu, size);
107 }
108 void pb_gatt_send_pdu(uint16_t con_handle, const uint8_t * pdu, uint16_t _pdu_size){
109     UNUSED(con_handle);
110     UNUSED(pdu);
111     UNUSED(_pdu_size);
112 }
113 
114 uint16_t pb_adv_create_link(const uint8_t * device_uuid){
115     UNUSED(device_uuid);
116     // just simluate opened
117     pb_adv_emit_link_open(0, 1);
118     return 1;
119 }
120 
121 //
122 static void perform_crypto_operations(void){
123     int more = 1;
124     while (more){
125         more = mock_process_hci_cmd();
126     }
127 }
128 
129 static void send_prov_pdu(const uint8_t * packet, uint16_t size){
130     pb_adv_packet_handler(PROVISIONING_DATA_PACKET, 0, (uint8_t*) packet, size);
131     perform_crypto_operations();
132 }
133 
134 
135 static int scan_hex_byte(const char * byte_string){
136     int upper_nibble = nibble_for_char(*byte_string++);
137     if (upper_nibble < 0) return -1;
138     int lower_nibble = nibble_for_char(*byte_string);
139     if (lower_nibble < 0) return -1;
140     return (upper_nibble << 4) | lower_nibble;
141 }
142 
143 static int btstack_parse_hex(const char * string, uint16_t len, uint8_t * buffer){
144     int i;
145     for (i = 0; i < len; i++) {
146         int single_byte = scan_hex_byte(string);
147         if (single_byte < 0) return 0;
148         string += 2;
149         buffer[i] = (uint8_t)single_byte;
150         // don't check seperator after last byte
151         if (i == len - 1) {
152             return 1;
153         }
154         // optional seperator
155         char separator = *string;
156         if (separator == ':' && separator == '-' && separator == ' ') {
157             string++;
158         }
159     }
160     return 1;
161 }
162 
163 static uint8_t      prov_static_oob_data[16];
164 static const char * prov_static_oob_string = "00000000000000000102030405060708";
165 
166 static void provisioning_handle_pdu(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
167     UNUSED(channel);
168     UNUSED(size);
169     if (packet_type != HCI_EVENT_PACKET) return;
170     switch(packet[0]){
171         case HCI_EVENT_MESH_META:
172             switch(packet[2]){
173                 case MESH_SUBEVENT_PB_PROV_CAPABILITIES:
174                     printf("Provisioner capabilities\n");
175                     provisioning_provisioner_select_authentication_method(1, 0, 0, 0, 0, 0);
176                     break;
177                 default:
178                     break;
179             }
180         default:
181             break;
182     }
183 }
184 
185 TEST_GROUP(Provisioning){
186     void setup(void){
187         mock_init();
188         btstack_crypto_init();
189         provisioning_provisioner_init();
190         btstack_parse_hex(prov_static_oob_string, 16, prov_static_oob_data);
191         provisioning_provisioner_register_packet_handler(&provisioning_handle_pdu);
192         // provisioning_device_set_static_oob(16, prov_static_oob_data);
193         // provisioning_device_set_output_oob_actions(0x08, 0x08);
194         // provisioning_device_set_input_oob_actions(0x08, 0x08);
195         perform_crypto_operations();
196     }
197 };
198 
199 const static uint8_t device_uuid[] = { 0x00, 0x1B, 0xDC, 0x08, 0x10, 0x21, 0x0B, 0x0E, 0x0A, 0x0C, 0x00, 0x0B, 0x0E, 0x0A, 0x0C, 0x00 };
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, 0x00, 0x00, 0x00 };
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, 0xF3, 0x73, 0xAB, 0xD8, 0xA6, 0x51, 0xD4, 0x18, 0x78, 0x47, 0xBA, 0xD8, 0x07, 0x6E, 0x09, 0x05 };
210 uint8_t prov_random[]  = {   0x06, 0xED, 0x77, 0xBA, 0x5D, 0x2F, 0x16, 0x0B, 0x84, 0xC2, 0xE1, 0xF1, 0xF9, 0x7D, 0x3F, 0x9E, 0xCF };
211 uint8_t prov_data[] = {
212         0x07, 0x89, 0x8B, 0xBF, 0x53, 0xDC, 0xA6, 0xD8, 0x55, 0x1B, 0x9A, 0xA9, 0x57, 0x8C, 0x8E, 0xAC, 0x25, 0x13, 0x80, 0xC3,
213         0x8B, 0xA2, 0xF8, 0xAA, 0x13, 0xAF, 0x60, 0x1A, 0x5B, 0x12, 0xE9, 0xD5, 0x5F,
214 };
215 uint8_t prov_complete[] = { 0x08, };
216 
217 static void expect_packet(const char * packet_name, const uint8_t * packet_data, uint16_t packet_len){
218     printf("Expect '%s'\n", packet_name);
219     CHECK(pdu_data != NULL);
220     CHECK_EQUAL_ARRAY((uint8_t*)packet_data, pdu_data, packet_len);
221 }
222 
223 #define EXPECT_PACKET(packet) expect_packet(#packet, packet, sizeof(packet))
224 
225 TEST(Provisioning, Prov1){
226     // simulate unprovisioned device beacon
227     provisioning_provisioner_start_provisioning(device_uuid);
228     // wait for prov invite
229     EXPECT_PACKET(prov_invite);
230     pb_adv_emit_pdu_sent(0);
231     // send capabilities
232     send_prov_pdu(prov_capabilities, sizeof(prov_capabilities));
233     // wait for start
234     EXPECT_PACKET(prov_start);
235     pb_adv_emit_pdu_sent(0);
236     // wait for public key
237     EXPECT_PACKET(prov_public_key);
238     pb_adv_emit_pdu_sent(0);
239     // send public key
240     send_prov_pdu(prov_public_key, sizeof(prov_public_key));
241     // wait for confirm
242     EXPECT_PACKET(prov_confirm);
243     pb_adv_emit_pdu_sent(0);
244     // send prov confirm
245     send_prov_pdu(prov_confirm, sizeof(prov_confirm));
246     // wait for random
247     CHECK_EQUAL_ARRAY(prov_random, pdu_data, sizeof(prov_random));
248     pb_adv_emit_pdu_sent(0);
249     // send prov random
250     send_prov_pdu(prov_random, sizeof(prov_random));
251     // wait for prov data
252     EXPECT_PACKET(prov_data);
253     pb_adv_emit_pdu_sent(0);
254     // send prov complete
255     send_prov_pdu(prov_complete, sizeof(prov_complete));
256 }
257 
258 int main (int argc, const char * argv[]){
259     // log into file using HCI_DUMP_PACKETLOGGER format
260     const char * log_path = "hci_dump.pklg";
261     hci_dump_posix_fs_open(log_path, HCI_DUMP_PACKETLOGGER);
262     hci_dump_init(hci_dump_posix_fs_get_instance());
263     printf("Packet Log: %s\n", log_path);
264 
265     return CommandLineTestRunner::RunAllTests(argc, argv);
266 }
267