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/mesh_node.h" 45 #include "ble/gatt-service/mesh_provisioning_service_server.h" 46 #include "provisioning.h" 47 #include "provisioning_device.h" 48 #include "hci_dump.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 144 static mesh_network_key_t network_key; 145 extern "C" mesh_network_key_t * btstack_memory_mesh_network_key_get(void){ 146 return &network_key; 147 } 148 149 static void perform_crypto_operations(void){ 150 int more = 1; 151 while (more){ 152 more = mock_process_hci_cmd(); 153 } 154 } 155 156 static void send_prov_pdu(const uint8_t * packet, uint16_t size){ 157 pb_adv_packet_handler(PROVISIONING_DATA_PACKET, 0, (uint8_t*) packet, size); 158 perform_crypto_operations(); 159 } 160 161 static void pb_adv_emit_pdu_sent(uint8_t status){ 162 uint8_t event[] = { HCI_EVENT_MESH_META, 2, MESH_SUBEVENT_PB_TRANSPORT_PDU_SENT, status}; 163 pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event)); 164 } 165 166 static int scan_hex_byte(const char * byte_string){ 167 int upper_nibble = nibble_for_char(*byte_string++); 168 if (upper_nibble < 0) return -1; 169 int lower_nibble = nibble_for_char(*byte_string); 170 if (lower_nibble < 0) return -1; 171 return (upper_nibble << 4) | lower_nibble; 172 } 173 174 static int btstack_parse_hex(const char * string, uint16_t len, uint8_t * buffer){ 175 int i; 176 for (i = 0; i < len; i++) { 177 int single_byte = scan_hex_byte(string); 178 if (single_byte < 0) return 0; 179 string += 2; 180 buffer[i] = (uint8_t)single_byte; 181 // don't check seperator after last byte 182 if (i == len - 1) { 183 return 1; 184 } 185 // optional seperator 186 char separator = *string; 187 if (separator == ':' && separator == '-' && separator == ' ') { 188 string++; 189 } 190 } 191 return 1; 192 } 193 194 // void pb_gatt_close_link(hci_con_handle_t con_handle, uint8_t reason){ 195 // } 196 197 static uint8_t prov_static_oob_data[16]; 198 static const char * prov_static_oob_string = "00000000000000000102030405060708"; 199 200 TEST_GROUP(Provisioning){ 201 void setup(void){ 202 btstack_crypto_init(); 203 provisioning_device_init(); 204 mesh_node_set_device_uuid(device_uuid); 205 btstack_parse_hex(prov_static_oob_string, 16, prov_static_oob_data); 206 provisioning_device_set_static_oob(16, prov_static_oob_data); 207 provisioning_device_set_output_oob_actions(0x08, 0x08); 208 provisioning_device_set_input_oob_actions(0x08, 0x08); 209 perform_crypto_operations(); 210 } 211 }; 212 213 uint8_t prov_invite[] = { 0x00, 0x00 }; 214 uint8_t prov_capabilities[] = { 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x08, 0x00, 0x08, 0x08, 0x00, 0x08, }; 215 uint8_t prov_start[] = { 0x02, 0x00, 0x00, 0x02, 0x00, 0x01 }; 216 uint8_t prov_public_key[] = { 0x03, 217 0xf0, 0xc8, 0x63, 0xf8, 0xe5, 0x55, 0x11, 0x4b, 0xf4, 0x88, 0x2c, 0xc7, 0x87, 0xb9, 0x5c, 0x27, 218 0x2a, 0x7f, 0xe4, 0xdc, 0xdd, 0xf1, 0x92, 0x2f, 0x4f, 0x18, 0xa4, 0x94, 0xe1, 0xc3, 0x57, 0xa1, 219 0xa6, 0xc3, 0x2d, 0x07, 0xbe, 0xb5, 0x76, 0xab, 0x60, 0x10, 0x68, 0x06, 0x8f, 0x0a, 0x9e, 0x01, 220 0x60, 0xc3, 0xa1, 0x41, 0x19, 0xf5, 0xd4, 0x26, 0xa7, 0x95, 0x5d, 0xa3, 0xe6, 0xed, 0x3e, 0x81, }; 221 uint8_t prov_confirm[] = { 0x05, 0x80, 0x4d, 0xdc, 0x3b, 0xba, 0x60, 0xd5, 0x93, 0x5b, 0x56, 0xef, 0xb5, 0xcb, 0x59, 0x31, 0xfa, }; 222 uint8_t prov_random[] = { 0x06, 0x9b, 0x4d, 0x39, 0xf6, 0xf7, 0xe8, 0xa1, 0x05, 0xd3, 0xfe, 0xed, 0xa5, 0xd5, 0xf3, 0xd9, 0xe4, }; 223 uint8_t prov_data[] = { 224 0x07, 225 0x85, 0x66, 0xac, 0x46, 0x37, 0x34, 0x86, 0xe1, 0x3e, 0x4c, 0x13, 0x52, 0xd0, 0x6d, 0x34, 0x7d, 226 0xce, 0xf1, 0xd1, 0x7d, 0xbd, 0xbe, 0xcc, 0x99, 0xc3, 227 0x93, 0x87, 0xfc, 0xb0, 0x72, 0x0f, 0xd8, 0x8d }; 228 uint8_t prov_complete[] = { 0x08, }; 229 230 TEST(Provisioning, Prov1){ 231 // send prov inviate 232 send_prov_pdu(prov_invite, sizeof(prov_invite)); 233 // check for prov cap 234 CHECK_EQUAL_ARRAY(prov_capabilities, pdu_data, sizeof(prov_capabilities)); 235 pb_adv_emit_pdu_sent(0); 236 // send prov start 237 send_prov_pdu(prov_start, sizeof(prov_start)); 238 // send public key 239 send_prov_pdu(prov_public_key, sizeof(prov_public_key)); 240 // check for public key 241 CHECK_EQUAL_ARRAY(prov_public_key, pdu_data, sizeof(prov_public_key)); 242 pb_adv_emit_pdu_sent(0); 243 // send prov confirm 244 send_prov_pdu(prov_confirm, sizeof(prov_confirm)); 245 // check for prov confirm 246 CHECK_EQUAL_ARRAY(prov_confirm, pdu_data, sizeof(prov_confirm)); 247 pb_adv_emit_pdu_sent(0); 248 // send prov random 249 send_prov_pdu(prov_random, sizeof(prov_random)); 250 // check for prov random 251 CHECK_EQUAL_ARRAY(prov_random, pdu_data, sizeof(prov_random)); 252 pb_adv_emit_pdu_sent(0); 253 // send prov data 254 send_prov_pdu(prov_data, sizeof(prov_data)); 255 // check prov complete 256 CHECK_EQUAL_ARRAY(prov_complete, pdu_data, sizeof(prov_complete)); 257 pb_adv_emit_pdu_sent(0); 258 } 259 260 int main (int argc, const char * argv[]){ 261 hci_dump_open("hci_dump.pklg", HCI_DUMP_PACKETLOGGER); 262 return CommandLineTestRunner::RunAllTests(argc, argv); 263 } 264