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/gatt-service/mesh_provisioning_service_server.h" 45 #include "mesh/provisioning.h" 46 #include "mesh/provisioning_provisioner.h" 47 #include "hci_dump.h" 48 #include "hci_dump_posix_fs.h" 49 #include "mock.h" 50 51 #include "CppUTest/TestHarness.h" 52 #include "CppUTest/CommandLineTestRunner.h" 53 54 static void CHECK_EQUAL_ARRAY(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("offset %u wrong\n", 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 // pb-adv mock for testing 67 68 static btstack_packet_handler_t pb_adv_packet_handler; 69 70 static uint8_t * pdu_data; 71 static uint16_t pdu_size; 72 73 static void pb_adv_emit_link_open(uint8_t status, uint16_t pb_adv_cid){ 74 uint8_t event[7] = { HCI_EVENT_MESH_META, 5, MESH_SUBEVENT_PB_TRANSPORT_LINK_OPEN, status}; 75 little_endian_store_16(event, 4, pb_adv_cid); 76 event[6] = MESH_PB_TYPE_ADV; 77 pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event)); 78 } 79 80 static void pb_adv_emit_pdu_sent(uint8_t status){ 81 uint8_t event[] = { HCI_EVENT_MESH_META, 2, MESH_SUBEVENT_PB_TRANSPORT_PDU_SENT, status}; 82 pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event)); 83 } 84 85 void pb_adv_init(void){} 86 void pb_gatt_init(void){} 87 88 void pb_adv_close_link(uint16_t pb_adv_cid, uint8_t reason){ 89 UNUSED(pb_adv_cid); 90 UNUSED(reason); 91 } 92 93 void pb_adv_register_provisioner_packet_handler(btstack_packet_handler_t packet_handler){ 94 pb_adv_packet_handler = packet_handler; 95 } 96 97 void pb_gatt_register_packet_handler(btstack_packet_handler_t packet_handler){ 98 UNUSED(packet_handler); 99 } 100 101 void pb_adv_send_pdu(uint16_t pb_transport_cid, const uint8_t * pdu, uint16_t size){ 102 UNUSED(pb_transport_cid); 103 pdu_data = (uint8_t*) pdu; 104 pdu_size = size; 105 // dump_data((uint8_t*)pdu,size); 106 // printf_hexdump(pdu, size); 107 } 108 void pb_gatt_send_pdu(uint16_t con_handle, const uint8_t * pdu, uint16_t _pdu_size){ 109 UNUSED(con_handle); 110 UNUSED(pdu); 111 UNUSED(_pdu_size); 112 } 113 114 uint16_t pb_adv_create_link(const uint8_t * device_uuid){ 115 UNUSED(device_uuid); 116 // just simluate opened 117 pb_adv_emit_link_open(0, 1); 118 return 1; 119 } 120 121 // 122 static void perform_crypto_operations(void){ 123 int more = 1; 124 while (more){ 125 more = mock_process_hci_cmd(); 126 } 127 } 128 129 static void send_prov_pdu(const uint8_t * packet, uint16_t size){ 130 pb_adv_packet_handler(PROVISIONING_DATA_PACKET, 0, (uint8_t*) packet, size); 131 perform_crypto_operations(); 132 } 133 134 135 static int scan_hex_byte(const char * byte_string){ 136 int upper_nibble = nibble_for_char(*byte_string++); 137 if (upper_nibble < 0) return -1; 138 int lower_nibble = nibble_for_char(*byte_string); 139 if (lower_nibble < 0) return -1; 140 return (upper_nibble << 4) | lower_nibble; 141 } 142 143 static int btstack_parse_hex(const char * string, uint16_t len, uint8_t * buffer){ 144 int i; 145 for (i = 0; i < len; i++) { 146 int single_byte = scan_hex_byte(string); 147 if (single_byte < 0) return 0; 148 string += 2; 149 buffer[i] = (uint8_t)single_byte; 150 // don't check seperator after last byte 151 if (i == len - 1) { 152 return 1; 153 } 154 // optional seperator 155 char separator = *string; 156 if (separator == ':' && separator == '-' && separator == ' ') { 157 string++; 158 } 159 } 160 return 1; 161 } 162 163 static uint8_t prov_static_oob_data[16]; 164 static const char * prov_static_oob_string = "00000000000000000102030405060708"; 165 166 static void provisioning_handle_pdu(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 167 UNUSED(channel); 168 UNUSED(size); 169 if (packet_type != HCI_EVENT_PACKET) return; 170 switch(packet[0]){ 171 case HCI_EVENT_MESH_META: 172 switch(packet[2]){ 173 case MESH_SUBEVENT_PB_PROV_CAPABILITIES: 174 printf("Provisioner capabilities\n"); 175 provisioning_provisioner_select_authentication_method(1, 0, 0, 0, 0, 0); 176 break; 177 default: 178 break; 179 } 180 default: 181 break; 182 } 183 } 184 185 TEST_GROUP(Provisioning){ 186 void setup(void){ 187 mock_init(); 188 btstack_crypto_init(); 189 provisioning_provisioner_init(); 190 btstack_parse_hex(prov_static_oob_string, 16, prov_static_oob_data); 191 provisioning_provisioner_register_packet_handler(&provisioning_handle_pdu); 192 // provisioning_device_set_static_oob(16, prov_static_oob_data); 193 // provisioning_device_set_output_oob_actions(0x08, 0x08); 194 // provisioning_device_set_input_oob_actions(0x08, 0x08); 195 perform_crypto_operations(); 196 } 197 }; 198 199 const static uint8_t device_uuid[] = { 0x00, 0x1B, 0xDC, 0x08, 0x10, 0x21, 0x0B, 0x0E, 0x0A, 0x0C, 0x00, 0x0B, 0x0E, 0x0A, 0x0C, 0x00 }; 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, 0x00, 0x00, 0x00 }; 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, 0xF3, 0x73, 0xAB, 0xD8, 0xA6, 0x51, 0xD4, 0x18, 0x78, 0x47, 0xBA, 0xD8, 0x07, 0x6E, 0x09, 0x05 }; 210 uint8_t prov_random[] = { 0x06, 0xED, 0x77, 0xBA, 0x5D, 0x2F, 0x16, 0x0B, 0x84, 0xC2, 0xE1, 0xF1, 0xF9, 0x7D, 0x3F, 0x9E, 0xCF }; 211 uint8_t prov_data[] = { 212 0x07, 0x89, 0x8B, 0xBF, 0x53, 0xDC, 0xA6, 0xD8, 0x55, 0x1B, 0x9A, 0xA9, 0x57, 0x8C, 0x8E, 0xAC, 0x25, 0x13, 0x80, 0xC3, 213 0x8B, 0xA2, 0xF8, 0xAA, 0x13, 0xAF, 0x60, 0x1A, 0x5B, 0x12, 0xE9, 0xD5, 0x5F, 214 }; 215 uint8_t prov_complete[] = { 0x08, }; 216 217 static void expect_packet(const char * packet_name, const uint8_t * packet_data, uint16_t packet_len){ 218 printf("Expect '%s'\n", packet_name); 219 CHECK(pdu_data != NULL); 220 CHECK_EQUAL_ARRAY((uint8_t*)packet_data, pdu_data, packet_len); 221 } 222 223 #define EXPECT_PACKET(packet) expect_packet(#packet, packet, sizeof(packet)) 224 225 TEST(Provisioning, Prov1){ 226 // simulate unprovisioned device beacon 227 provisioning_provisioner_start_provisioning(device_uuid); 228 // wait for prov invite 229 EXPECT_PACKET(prov_invite); 230 pb_adv_emit_pdu_sent(0); 231 // send capabilities 232 send_prov_pdu(prov_capabilities, sizeof(prov_capabilities)); 233 // wait for start 234 EXPECT_PACKET(prov_start); 235 pb_adv_emit_pdu_sent(0); 236 // wait for public key 237 EXPECT_PACKET(prov_public_key); 238 pb_adv_emit_pdu_sent(0); 239 // send public key 240 send_prov_pdu(prov_public_key, sizeof(prov_public_key)); 241 // wait for confirm 242 EXPECT_PACKET(prov_confirm); 243 pb_adv_emit_pdu_sent(0); 244 // send prov confirm 245 send_prov_pdu(prov_confirm, sizeof(prov_confirm)); 246 // wait for random 247 CHECK_EQUAL_ARRAY(prov_random, pdu_data, sizeof(prov_random)); 248 pb_adv_emit_pdu_sent(0); 249 // send prov random 250 send_prov_pdu(prov_random, sizeof(prov_random)); 251 // wait for prov data 252 EXPECT_PACKET(prov_data); 253 pb_adv_emit_pdu_sent(0); 254 // send prov complete 255 send_prov_pdu(prov_complete, sizeof(prov_complete)); 256 } 257 258 int main (int argc, const char * argv[]){ 259 // log into file using HCI_DUMP_PACKETLOGGER format 260 const char * log_path = "hci_dump.pklg"; 261 hci_dump_posix_fs_open(log_path, HCI_DUMP_PACKETLOGGER); 262 hci_dump_init(hci_dump_posix_fs_get_instance()); 263 printf("Packet Log: %s\n", log_path); 264 265 return CommandLineTestRunner::RunAllTests(argc, argv); 266 } 267