xref: /btstack/test/mesh/provisioning_device_test.cpp (revision 1fbe4564be530ba975f4cd70443a76f0afda5276)
1*1fbe4564SMatthias Ringwald /*
2*1fbe4564SMatthias Ringwald  * Copyright (C) 2017 BlueKitchen GmbH
3*1fbe4564SMatthias Ringwald  *
4*1fbe4564SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5*1fbe4564SMatthias Ringwald  * modification, are permitted provided that the following conditions
6*1fbe4564SMatthias Ringwald  * are met:
7*1fbe4564SMatthias Ringwald  *
8*1fbe4564SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9*1fbe4564SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10*1fbe4564SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*1fbe4564SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*1fbe4564SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13*1fbe4564SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*1fbe4564SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15*1fbe4564SMatthias Ringwald  *    from this software without specific prior written permission.
16*1fbe4564SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*1fbe4564SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18*1fbe4564SMatthias Ringwald  *    monetary gain.
19*1fbe4564SMatthias Ringwald  *
20*1fbe4564SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*1fbe4564SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*1fbe4564SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*1fbe4564SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24*1fbe4564SMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*1fbe4564SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*1fbe4564SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*1fbe4564SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*1fbe4564SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*1fbe4564SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*1fbe4564SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*1fbe4564SMatthias Ringwald  * SUCH DAMAGE.
32*1fbe4564SMatthias Ringwald  *
33*1fbe4564SMatthias Ringwald  * Please inquire about commercial licensing options at
34*1fbe4564SMatthias Ringwald  * [email protected]
35*1fbe4564SMatthias Ringwald  *
36*1fbe4564SMatthias Ringwald  */
37*1fbe4564SMatthias Ringwald 
38*1fbe4564SMatthias Ringwald #include <stdint.h>
39*1fbe4564SMatthias Ringwald #include <stdio.h>
40*1fbe4564SMatthias Ringwald #include <stdlib.h>
41*1fbe4564SMatthias Ringwald #include <string.h>
42*1fbe4564SMatthias Ringwald #include "ble/mesh/pb_adv.h"
43*1fbe4564SMatthias Ringwald #include "provisioning_device.h"
44*1fbe4564SMatthias Ringwald #include "btstack.h"
45*1fbe4564SMatthias Ringwald 
46*1fbe4564SMatthias Ringwald #include "CppUTest/TestHarness.h"
47*1fbe4564SMatthias Ringwald #include "CppUTest/CommandLineTestRunner.h"
48*1fbe4564SMatthias Ringwald 
49*1fbe4564SMatthias Ringwald static void CHECK_EQUAL_ARRAY(uint8_t * expected, uint8_t * actual, int size){
50*1fbe4564SMatthias Ringwald     int i;
51*1fbe4564SMatthias Ringwald     for (i=0; i<size; i++){
52*1fbe4564SMatthias Ringwald         if (expected[i] != actual[i]) {
53*1fbe4564SMatthias Ringwald             printf("offset %u wrong\n", i);
54*1fbe4564SMatthias Ringwald             printf("expected: "); printf_hexdump(expected, size);
55*1fbe4564SMatthias Ringwald             printf("actual:   "); printf_hexdump(actual, size);
56*1fbe4564SMatthias Ringwald         }
57*1fbe4564SMatthias Ringwald         BYTES_EQUAL(expected[i], actual[i]);
58*1fbe4564SMatthias Ringwald     }
59*1fbe4564SMatthias Ringwald }
60*1fbe4564SMatthias Ringwald 
61*1fbe4564SMatthias Ringwald static void dump_data(uint8_t * buffer, uint16_t size){
62*1fbe4564SMatthias Ringwald     static int data_counter = 1;
63*1fbe4564SMatthias Ringwald     char var_name[80];
64*1fbe4564SMatthias Ringwald     sprintf(var_name, "test_data_%02u", data_counter);
65*1fbe4564SMatthias Ringwald     printf("uint8_t %s[] = { ", var_name);
66*1fbe4564SMatthias Ringwald     for (int i = 0; i < size ; i++){
67*1fbe4564SMatthias Ringwald         if ((i % 16) == 0) printf("\n    ");
68*1fbe4564SMatthias Ringwald         printf ("0x%02x, ", buffer[i]);
69*1fbe4564SMatthias Ringwald     }
70*1fbe4564SMatthias Ringwald     printf("};\n");
71*1fbe4564SMatthias Ringwald     data_counter++;
72*1fbe4564SMatthias Ringwald }
73*1fbe4564SMatthias Ringwald 
74*1fbe4564SMatthias Ringwald static int parse_hex(uint8_t * buffer, const char * hex_string){
75*1fbe4564SMatthias Ringwald     int len = 0;
76*1fbe4564SMatthias Ringwald     while (*hex_string){
77*1fbe4564SMatthias Ringwald         if (*hex_string == ' '){
78*1fbe4564SMatthias Ringwald             hex_string++;
79*1fbe4564SMatthias Ringwald             continue;
80*1fbe4564SMatthias Ringwald         }
81*1fbe4564SMatthias Ringwald         int high_nibble = nibble_for_char(*hex_string++);
82*1fbe4564SMatthias Ringwald         int low_nibble = nibble_for_char(*hex_string++);
83*1fbe4564SMatthias Ringwald         *buffer++ = (high_nibble << 4) | low_nibble;
84*1fbe4564SMatthias Ringwald         len++;
85*1fbe4564SMatthias Ringwald     }
86*1fbe4564SMatthias Ringwald     return len;
87*1fbe4564SMatthias Ringwald }
88*1fbe4564SMatthias Ringwald 
89*1fbe4564SMatthias Ringwald // returns if anything was done
90*1fbe4564SMatthias Ringwald extern "C" int mock_process_hci_cmd(void);
91*1fbe4564SMatthias Ringwald 
92*1fbe4564SMatthias Ringwald const static uint8_t device_uuid[] = { 0x00, 0x1B, 0xDC, 0x08, 0x10, 0x21, 0x0B, 0x0E, 0x0A, 0x0C, 0x00, 0x0B, 0x0E, 0x0A, 0x0C, 0x00 };
93*1fbe4564SMatthias Ringwald 
94*1fbe4564SMatthias Ringwald // pb-adv mock for testing
95*1fbe4564SMatthias Ringwald 
96*1fbe4564SMatthias Ringwald static btstack_packet_handler_t pb_adv_packet_handler;
97*1fbe4564SMatthias Ringwald 
98*1fbe4564SMatthias Ringwald static uint8_t * pdu_data;
99*1fbe4564SMatthias Ringwald static uint16_t  pdu_size;
100*1fbe4564SMatthias Ringwald 
101*1fbe4564SMatthias Ringwald /**
102*1fbe4564SMatthias Ringwald  * Initialize Provisioning Bearer using Advertisement Bearer
103*1fbe4564SMatthias Ringwald  * @param DeviceUUID
104*1fbe4564SMatthias Ringwald  */
105*1fbe4564SMatthias Ringwald void pb_adv_init(const uint8_t * device_uuid){
106*1fbe4564SMatthias Ringwald     printf("pb_adv_init\n");
107*1fbe4564SMatthias Ringwald }
108*1fbe4564SMatthias Ringwald 
109*1fbe4564SMatthias Ringwald void pb_adv_close_link(uint16_t pb_adv_cid, uint8_t reason){
110*1fbe4564SMatthias Ringwald }
111*1fbe4564SMatthias Ringwald 
112*1fbe4564SMatthias Ringwald /**
113*1fbe4564SMatthias Ringwald  * Register listener for Provisioning PDUs and MESH_PBV_ADV_SEND_COMPLETE
114*1fbe4564SMatthias Ringwald  */
115*1fbe4564SMatthias Ringwald void pb_adv_register_packet_handler(btstack_packet_handler_t packet_handler){
116*1fbe4564SMatthias Ringwald     pb_adv_packet_handler = packet_handler;
117*1fbe4564SMatthias Ringwald }
118*1fbe4564SMatthias Ringwald 
119*1fbe4564SMatthias Ringwald /**
120*1fbe4564SMatthias Ringwald  * Send Provisioning PDU
121*1fbe4564SMatthias Ringwald  */
122*1fbe4564SMatthias Ringwald void pb_adv_send_pdu(const uint8_t * pdu, uint16_t size){
123*1fbe4564SMatthias Ringwald     pdu_data = (uint8_t*) pdu;
124*1fbe4564SMatthias Ringwald     pdu_size = size;
125*1fbe4564SMatthias Ringwald     // dump_data((uint8_t*)pdu,size);
126*1fbe4564SMatthias Ringwald     // printf_hexdump(pdu, size);
127*1fbe4564SMatthias Ringwald }
128*1fbe4564SMatthias Ringwald 
129*1fbe4564SMatthias Ringwald static void perform_crypto_operations(void){
130*1fbe4564SMatthias Ringwald     int more = 1;
131*1fbe4564SMatthias Ringwald     while (more){
132*1fbe4564SMatthias Ringwald         more = mock_process_hci_cmd();
133*1fbe4564SMatthias Ringwald     }
134*1fbe4564SMatthias Ringwald }
135*1fbe4564SMatthias Ringwald 
136*1fbe4564SMatthias Ringwald static void send_prov_pdu(const uint8_t * packet, uint16_t size){
137*1fbe4564SMatthias Ringwald     pb_adv_packet_handler(PROVISIONING_DATA_PACKET, 0, (uint8_t*) packet, size);
138*1fbe4564SMatthias Ringwald     perform_crypto_operations();
139*1fbe4564SMatthias Ringwald }
140*1fbe4564SMatthias Ringwald 
141*1fbe4564SMatthias Ringwald static void pb_adv_emit_pdu_sent(uint8_t status){
142*1fbe4564SMatthias Ringwald     uint8_t event[] = { HCI_EVENT_MESH_META, 2, MESH_PB_ADV_PDU_SENT, status};
143*1fbe4564SMatthias Ringwald     pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event));
144*1fbe4564SMatthias Ringwald }
145*1fbe4564SMatthias Ringwald 
146*1fbe4564SMatthias Ringwald static int scan_hex_byte(const char * byte_string){
147*1fbe4564SMatthias Ringwald     int upper_nibble = nibble_for_char(*byte_string++);
148*1fbe4564SMatthias Ringwald     if (upper_nibble < 0) return -1;
149*1fbe4564SMatthias Ringwald     int lower_nibble = nibble_for_char(*byte_string);
150*1fbe4564SMatthias Ringwald     if (lower_nibble < 0) return -1;
151*1fbe4564SMatthias Ringwald     return (upper_nibble << 4) | lower_nibble;
152*1fbe4564SMatthias Ringwald }
153*1fbe4564SMatthias Ringwald 
154*1fbe4564SMatthias Ringwald static int btstack_parse_hex(const char * string, uint16_t len, uint8_t * buffer){
155*1fbe4564SMatthias Ringwald     int i;
156*1fbe4564SMatthias Ringwald     for (i = 0; i < len; i++) {
157*1fbe4564SMatthias Ringwald         int single_byte = scan_hex_byte(string);
158*1fbe4564SMatthias Ringwald         if (single_byte < 0) return 0;
159*1fbe4564SMatthias Ringwald         string += 2;
160*1fbe4564SMatthias Ringwald         buffer[i] = (uint8_t)single_byte;
161*1fbe4564SMatthias Ringwald         // don't check seperator after last byte
162*1fbe4564SMatthias Ringwald         if (i == len - 1) {
163*1fbe4564SMatthias Ringwald             return 1;
164*1fbe4564SMatthias Ringwald         }
165*1fbe4564SMatthias Ringwald         // optional seperator
166*1fbe4564SMatthias Ringwald         char separator = *string;
167*1fbe4564SMatthias Ringwald         if (separator == ':' && separator == '-' && separator == ' ') {
168*1fbe4564SMatthias Ringwald             string++;
169*1fbe4564SMatthias Ringwald         }
170*1fbe4564SMatthias Ringwald     }
171*1fbe4564SMatthias Ringwald     return 1;
172*1fbe4564SMatthias Ringwald }
173*1fbe4564SMatthias Ringwald 
174*1fbe4564SMatthias Ringwald static uint8_t      prov_static_oob_data[16];
175*1fbe4564SMatthias Ringwald static const char * prov_static_oob_string = "00000000000000000102030405060708";
176*1fbe4564SMatthias Ringwald 
177*1fbe4564SMatthias Ringwald TEST_GROUP(Provisioning){
178*1fbe4564SMatthias Ringwald     void setup(void){
179*1fbe4564SMatthias Ringwald         btstack_crypto_init();
180*1fbe4564SMatthias Ringwald         provisioning_device_init(device_uuid);
181*1fbe4564SMatthias Ringwald         btstack_parse_hex(prov_static_oob_string, 16, prov_static_oob_data);
182*1fbe4564SMatthias Ringwald         provisioning_device_set_static_oob(16, prov_static_oob_data);
183*1fbe4564SMatthias Ringwald         provisioning_device_set_output_oob_actions(0x08, 0x08);
184*1fbe4564SMatthias Ringwald         provisioning_device_set_input_oob_actions(0x08, 0x08);
185*1fbe4564SMatthias Ringwald         perform_crypto_operations();
186*1fbe4564SMatthias Ringwald     }
187*1fbe4564SMatthias Ringwald };
188*1fbe4564SMatthias Ringwald 
189*1fbe4564SMatthias Ringwald uint8_t prov_invite[] = { 0x00, 0x00 };
190*1fbe4564SMatthias Ringwald uint8_t prov_capabilities[] = { 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x08, 0x00, 0x08, 0x08, 0x00, 0x08, };
191*1fbe4564SMatthias Ringwald uint8_t prov_start[] = { 0x02, 0x00, 0x00, 0x02, 0x00, 0x01 };
192*1fbe4564SMatthias Ringwald uint8_t prov_public_key[] = { 0x03,
193*1fbe4564SMatthias Ringwald     0xf0, 0xc8, 0x63, 0xf8, 0xe5, 0x55, 0x11, 0x4b, 0xf4, 0x88, 0x2c, 0xc7, 0x87, 0xb9, 0x5c, 0x27,
194*1fbe4564SMatthias Ringwald     0x2a, 0x7f, 0xe4, 0xdc, 0xdd, 0xf1, 0x92, 0x2f, 0x4f, 0x18, 0xa4, 0x94, 0xe1, 0xc3, 0x57, 0xa1,
195*1fbe4564SMatthias Ringwald     0xa6, 0xc3, 0x2d, 0x07, 0xbe, 0xb5, 0x76, 0xab, 0x60, 0x10, 0x68, 0x06, 0x8f, 0x0a, 0x9e, 0x01,
196*1fbe4564SMatthias Ringwald     0x60, 0xc3, 0xa1, 0x41, 0x19, 0xf5, 0xd4, 0x26, 0xa7, 0x95, 0x5d, 0xa3, 0xe6, 0xed, 0x3e, 0x81, };
197*1fbe4564SMatthias Ringwald uint8_t prov_confirm[] = { 0x05, 0x80, 0x4d, 0xdc, 0x3b, 0xba, 0x60, 0xd5, 0x93, 0x5b, 0x56, 0xef, 0xb5, 0xcb, 0x59, 0x31, 0xfa, };
198*1fbe4564SMatthias Ringwald uint8_t prov_random[]  = { 0x06, 0x9b, 0x4d, 0x39, 0xf6, 0xf7, 0xe8, 0xa1, 0x05, 0xd3, 0xfe, 0xed, 0xa5, 0xd5, 0xf3, 0xd9, 0xe4, };
199*1fbe4564SMatthias Ringwald uint8_t prov_data[] = {
200*1fbe4564SMatthias Ringwald     0x07,
201*1fbe4564SMatthias Ringwald     0x85, 0x66, 0xac, 0x46, 0x37, 0x34, 0x86, 0xe1, 0x3e, 0x4c, 0x13, 0x52, 0xd0, 0x6d, 0x34, 0x7d,
202*1fbe4564SMatthias Ringwald     0xce, 0xf1, 0xd1, 0x7d, 0xbd, 0xbe, 0xcc, 0x99, 0xc3,
203*1fbe4564SMatthias Ringwald     0x93, 0x87, 0xfc, 0xb0, 0x72, 0x0f, 0xd8, 0x8d };
204*1fbe4564SMatthias Ringwald uint8_t prov_complete[] = { 0x08, };
205*1fbe4564SMatthias Ringwald 
206*1fbe4564SMatthias Ringwald TEST(Provisioning, Prov1){
207*1fbe4564SMatthias Ringwald     // send prov inviate
208*1fbe4564SMatthias Ringwald     send_prov_pdu(prov_invite, sizeof(prov_invite));
209*1fbe4564SMatthias Ringwald     // check for prov cap
210*1fbe4564SMatthias Ringwald     CHECK_EQUAL_ARRAY(prov_capabilities, pdu_data, sizeof(prov_capabilities));
211*1fbe4564SMatthias Ringwald     pb_adv_emit_pdu_sent(0);
212*1fbe4564SMatthias Ringwald     // send prov start
213*1fbe4564SMatthias Ringwald     send_prov_pdu(prov_start, sizeof(prov_start));
214*1fbe4564SMatthias Ringwald     // send public key
215*1fbe4564SMatthias Ringwald     send_prov_pdu(prov_public_key, sizeof(prov_public_key));
216*1fbe4564SMatthias Ringwald     // check for public key
217*1fbe4564SMatthias Ringwald     CHECK_EQUAL_ARRAY(prov_public_key, pdu_data, sizeof(prov_public_key));
218*1fbe4564SMatthias Ringwald     pb_adv_emit_pdu_sent(0);
219*1fbe4564SMatthias Ringwald     // send prov confirm
220*1fbe4564SMatthias Ringwald     send_prov_pdu(prov_confirm, sizeof(prov_confirm));
221*1fbe4564SMatthias Ringwald     // check for prov confirm
222*1fbe4564SMatthias Ringwald     CHECK_EQUAL_ARRAY(prov_confirm, pdu_data, sizeof(prov_confirm));
223*1fbe4564SMatthias Ringwald     pb_adv_emit_pdu_sent(0);
224*1fbe4564SMatthias Ringwald     // send prov random
225*1fbe4564SMatthias Ringwald     send_prov_pdu(prov_random, sizeof(prov_random));
226*1fbe4564SMatthias Ringwald     // check for prov random
227*1fbe4564SMatthias Ringwald     CHECK_EQUAL_ARRAY(prov_random, pdu_data, sizeof(prov_random));
228*1fbe4564SMatthias Ringwald     pb_adv_emit_pdu_sent(0);
229*1fbe4564SMatthias Ringwald     // send prov data
230*1fbe4564SMatthias Ringwald     send_prov_pdu(prov_data, sizeof(prov_data));
231*1fbe4564SMatthias Ringwald     // check prov complete
232*1fbe4564SMatthias Ringwald     CHECK_EQUAL_ARRAY(prov_complete, pdu_data, sizeof(prov_complete));
233*1fbe4564SMatthias Ringwald     pb_adv_emit_pdu_sent(0);
234*1fbe4564SMatthias Ringwald }
235*1fbe4564SMatthias Ringwald 
236*1fbe4564SMatthias Ringwald int main (int argc, const char * argv[]){
237*1fbe4564SMatthias Ringwald     hci_dump_open("hci_dump.pklg", HCI_DUMP_PACKETLOGGER);
238*1fbe4564SMatthias Ringwald     return CommandLineTestRunner::RunAllTests(argc, argv);
239*1fbe4564SMatthias Ringwald }
240