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