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