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