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 "btstack_memory.h" 41 #include "mesh/gatt-service/mesh_provisioning_service_server.h" 42 #include "hci_dump.h" 43 #include "hci_dump_posix_fs.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 #include "mock.h" 54 55 static void CHECK_EQUAL_ARRAY(const char * name, uint8_t * expected, uint8_t * actual, int size){ 56 int i; 57 for (i=0; i<size; i++){ 58 if (expected[i] != actual[i]) { 59 printf("%s: offset %u wrong\n", name, i); 60 printf("expected: "); printf_hexdump(expected, size); 61 printf("actual: "); printf_hexdump(actual, size); 62 } 63 BYTES_EQUAL(expected[i], actual[i]); 64 } 65 } 66 67 const static uint8_t device_uuid[] = { 0x00, 0x1B, 0xDC, 0x08, 0x10, 0x21, 0x0B, 0x0E, 0x0A, 0x0C, 0x00, 0x0B, 0x0E, 0x0A, 0x0C, 0x00 }; 68 69 // pb-adv mock for testing 70 71 static btstack_packet_handler_t pb_adv_packet_handler; 72 73 static uint8_t * pdu_data; 74 static uint16_t pdu_size; 75 76 /** 77 * Initialize Provisioning Bearer using Advertisement Bearer 78 * @param DeviceUUID 79 */ 80 void pb_adv_init(void){} 81 void pb_gatt_init(void){} 82 83 /** 84 * Close Link 85 * @param con_handle 86 * @param reason 0 = success, 1 = timeout, 2 = fail 87 */ 88 void pb_gatt_close_link(hci_con_handle_t con_handle, uint8_t reason){ 89 UNUSED(con_handle); 90 UNUSED(reason); 91 } 92 void pb_adv_close_link(hci_con_handle_t con_handle, uint8_t reason){ 93 UNUSED(con_handle); 94 UNUSED(reason); 95 } 96 97 98 /** 99 * Register listener for Provisioning PDUs and MESH_PBV_ADV_SEND_COMPLETE 100 */ 101 void pb_adv_register_device_packet_handler(btstack_packet_handler_t packet_handler){ 102 pb_adv_packet_handler = packet_handler; 103 } 104 105 void pb_gatt_register_packet_handler(btstack_packet_handler_t packet_handler){ 106 UNUSED(packet_handler); 107 } 108 /** 109 * Send Provisioning PDU 110 */ 111 void pb_adv_send_pdu(uint16_t pb_transport_cid, const uint8_t * pdu, uint16_t size){ 112 UNUSED(pb_transport_cid); 113 pdu_data = (uint8_t*) pdu; 114 pdu_size = size; 115 // dump_data((uint8_t*)pdu,size); 116 // printf_hexdump(pdu, size); 117 } 118 void pb_gatt_send_pdu(uint16_t con_handle, const uint8_t * pdu, uint16_t _pdu_size){ 119 UNUSED(con_handle); 120 UNUSED(pdu); 121 UNUSED(_pdu_size); 122 } 123 124 uint16_t mesh_network_key_get_free_index(void){ 125 return 0; 126 } 127 128 static mesh_network_key_t network_key; 129 extern "C" mesh_network_key_t * btstack_memory_mesh_network_key_get(void){ 130 return &network_key; 131 } 132 133 static void perform_crypto_operations(void){ 134 int more = 1; 135 while (more){ 136 more = mock_process_hci_cmd(); 137 } 138 } 139 140 static void send_prov_pdu(const uint8_t * packet, uint16_t size){ 141 pb_adv_packet_handler(PROVISIONING_DATA_PACKET, 0, (uint8_t*) packet, size); 142 perform_crypto_operations(); 143 } 144 145 static void pb_adv_emit_pdu_sent(uint8_t status){ 146 uint8_t event[] = { HCI_EVENT_MESH_META, 2, MESH_SUBEVENT_PB_TRANSPORT_PDU_SENT, status}; 147 pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event)); 148 } 149 150 static int scan_hex_byte(const char * byte_string){ 151 int upper_nibble = nibble_for_char(*byte_string++); 152 if (upper_nibble < 0) return -1; 153 int lower_nibble = nibble_for_char(*byte_string); 154 if (lower_nibble < 0) return -1; 155 return (upper_nibble << 4) | lower_nibble; 156 } 157 158 static int btstack_parse_hex(const char * string, uint16_t len, uint8_t * buffer){ 159 int i; 160 for (i = 0; i < len; i++) { 161 int single_byte = scan_hex_byte(string); 162 if (single_byte < 0) return 0; 163 string += 2; 164 buffer[i] = (uint8_t)single_byte; 165 // don't check seperator after last byte 166 if (i == len - 1) { 167 return 1; 168 } 169 // optional seperator 170 char separator = *string; 171 if (separator == ':' && separator == '-' && separator == ' ') { 172 string++; 173 } 174 } 175 return 1; 176 } 177 178 // void pb_gatt_close_link(hci_con_handle_t con_handle, uint8_t reason){ 179 // } 180 181 static uint8_t prov_static_oob_data[16]; 182 static const char * prov_static_oob_string = "00000000000000000102030405060708"; 183 184 TEST_GROUP(Provisioning){ 185 void setup(void){ 186 mock_init(); 187 for (unsigned int i = 0 ; i < 4 ; i ++){ 188 printf("rand: %08x\n", rand()); 189 } 190 btstack_crypto_init(); 191 provisioning_device_init(); 192 mesh_node_set_device_uuid(device_uuid); 193 btstack_parse_hex(prov_static_oob_string, 16, prov_static_oob_data); 194 provisioning_device_set_static_oob(16, prov_static_oob_data); 195 provisioning_device_set_output_oob_actions(0x08, 0x08); 196 provisioning_device_set_input_oob_actions(0x08, 0x08); 197 perform_crypto_operations(); 198 } 199 }; 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, 0x02, 0x00, 0x01 }; 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, 210 0x5F, 0xDE, 0x98, 0x35, 0x7F, 0x0B, 0xA2, 0xB2, 0x94, 0x72, 0x03, 0xD6, 0x82, 0x57, 0xF0, 0x6E }; 211 uint8_t prov_random[] = { 0x06, 0xC2, 0xE1, 0xF1, 0xF9, 0x7D, 0x3F, 0x9E, 0xCF, 0xE6, 0x73, 0xB8, 0x5C, 0x2E, 0x97, 0x4A, 0x25, }; 212 uint8_t prov_data[] = { 213 0x07, 214 0x85, 0x66, 0xac, 0x46, 0x37, 0x34, 0x86, 0xe1, 0x3e, 0x4c, 0x13, 0x52, 0xd0, 0x6d, 0x34, 0x7d, 215 0xce, 0xf1, 0xd1, 0x7d, 0xbd, 0xbe, 0xcc, 0x99, 0xc3, 216 0x93, 0x87, 0xfc, 0xb0, 0x72, 0x0f, 0xd8, 0x8d }; 217 uint8_t prov_complete[] = { 0x08, }; 218 219 TEST(Provisioning, Prov1){ 220 // send prov inviate 221 send_prov_pdu(prov_invite, sizeof(prov_invite)); 222 // check for prov cap 223 CHECK_EQUAL_ARRAY("prov_capabilities", prov_capabilities, pdu_data, sizeof(prov_capabilities)); 224 pb_adv_emit_pdu_sent(0); 225 // send prov start 226 send_prov_pdu(prov_start, sizeof(prov_start)); 227 // send public key 228 send_prov_pdu(prov_public_key, sizeof(prov_public_key)); 229 // check for public key 230 CHECK_EQUAL_ARRAY("prov_public_key", prov_public_key, pdu_data, sizeof(prov_public_key)); 231 pb_adv_emit_pdu_sent(0); 232 // send prov confirm 233 send_prov_pdu(prov_confirm, sizeof(prov_confirm)); 234 // check for prov confirm 235 CHECK_EQUAL_ARRAY("prov_confirm", prov_confirm, pdu_data, sizeof(prov_confirm)); 236 pb_adv_emit_pdu_sent(0); 237 // send prov random 238 send_prov_pdu(prov_random, sizeof(prov_random)); 239 // check for prov random 240 CHECK_EQUAL_ARRAY("prov_random", prov_random, pdu_data, sizeof(prov_random)); 241 pb_adv_emit_pdu_sent(0); 242 // send prov data 243 send_prov_pdu(prov_data, sizeof(prov_data)); 244 // check prov complete 245 CHECK_EQUAL_ARRAY("prov_complete", prov_complete, pdu_data, sizeof(prov_complete)); 246 pb_adv_emit_pdu_sent(0); 247 } 248 249 int main (int argc, const char * argv[]){ 250 // log into file using HCI_DUMP_PACKETLOGGER format 251 const char * log_path = "hci_dump.pklg"; 252 hci_dump_posix_fs_open(log_path, HCI_DUMP_PACKETLOGGER); 253 hci_dump_init(hci_dump_posix_fs_get_instance()); 254 printf("Packet Log: %s\n", log_path); 255 256 return CommandLineTestRunner::RunAllTests(argc, argv); 257 } 258