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/mesh/pb_adv.h" 43 #include "provisioning_provisioner.h" 44 #include "btstack.h" 45 46 #include "CppUTest/TestHarness.h" 47 #include "CppUTest/CommandLineTestRunner.h" 48 49 static void CHECK_EQUAL_ARRAY(uint8_t * expected, uint8_t * actual, int size){ 50 int i; 51 for (i=0; i<size; i++){ 52 if (expected[i] != actual[i]) { 53 printf("offset %u wrong\n", i); 54 printf("expected: "); printf_hexdump(expected, size); 55 printf("actual: "); printf_hexdump(actual, size); 56 } 57 BYTES_EQUAL(expected[i], actual[i]); 58 } 59 } 60 61 static void dump_data(uint8_t * buffer, uint16_t size){ 62 static int data_counter = 1; 63 char var_name[80]; 64 sprintf(var_name, "test_data_%02u", data_counter); 65 printf("uint8_t %s[] = { ", var_name); 66 for (int i = 0; i < size ; i++){ 67 if ((i % 16) == 0) printf("\n "); 68 printf ("0x%02x, ", buffer[i]); 69 } 70 printf("};\n"); 71 data_counter++; 72 } 73 74 static int parse_hex(uint8_t * buffer, const char * hex_string){ 75 int len = 0; 76 while (*hex_string){ 77 if (*hex_string == ' '){ 78 hex_string++; 79 continue; 80 } 81 int high_nibble = nibble_for_char(*hex_string++); 82 int low_nibble = nibble_for_char(*hex_string++); 83 *buffer++ = (high_nibble << 4) | low_nibble; 84 len++; 85 } 86 return len; 87 } 88 89 // returns if anything was done 90 extern "C" int mock_process_hci_cmd(void); 91 92 // pb-adv mock for testing 93 94 static btstack_packet_handler_t pb_adv_packet_handler; 95 96 static uint8_t * pdu_data; 97 static uint16_t pdu_size; 98 99 static void pb_adv_emit_link_open(uint8_t status, uint16_t pb_adv_cid){ 100 uint8_t event[7] = { HCI_EVENT_MESH_META, 5, MESH_PB_TRANSPORT_LINK_OPEN, status}; 101 little_endian_store_16(event, 4, pb_adv_cid); 102 event[6] = PB_TYPE_ADV; 103 pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event)); 104 } 105 106 static void pb_adv_emit_pdu_sent(uint8_t status){ 107 uint8_t event[] = { HCI_EVENT_MESH_META, 2, MESH_PB_TRANSPORT_PDU_SENT, status}; 108 pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event)); 109 } 110 111 void pb_adv_init(const uint8_t * device_uuid){} 112 void pb_gatt_init(const uint8_t * device_uuid){} 113 114 void pb_adv_close_link(uint16_t pb_adv_cid, uint8_t reason){} 115 116 void pb_adv_register_packet_handler(btstack_packet_handler_t packet_handler){ 117 pb_adv_packet_handler = packet_handler; 118 } 119 120 void pb_gatt_register_packet_handler(btstack_packet_handler_t packet_handler){ 121 UNUSED(packet_handler); 122 } 123 124 void pb_adv_send_pdu(uint16_t pb_transport_cid, const uint8_t * pdu, uint16_t size){ 125 UNUSED(pb_transport_cid); 126 pdu_data = (uint8_t*) pdu; 127 pdu_size = size; 128 // dump_data((uint8_t*)pdu,size); 129 // printf_hexdump(pdu, size); 130 } 131 void pb_gatt_send_pdu(uint16_t con_handle, const uint8_t * pdu, uint16_t pdu_size){} 132 133 uint16_t pb_adv_create_link(const uint8_t * device_uuid){ 134 // just simluate opened 135 pb_adv_emit_link_open(0, 1); 136 return 1; 137 } 138 139 // 140 static void perform_crypto_operations(void){ 141 int more = 1; 142 while (more){ 143 more = mock_process_hci_cmd(); 144 } 145 } 146 147 static void send_prov_pdu(const uint8_t * packet, uint16_t size){ 148 pb_adv_packet_handler(PROVISIONING_DATA_PACKET, 0, (uint8_t*) packet, size); 149 perform_crypto_operations(); 150 } 151 152 153 static int scan_hex_byte(const char * byte_string){ 154 int upper_nibble = nibble_for_char(*byte_string++); 155 if (upper_nibble < 0) return -1; 156 int lower_nibble = nibble_for_char(*byte_string); 157 if (lower_nibble < 0) return -1; 158 return (upper_nibble << 4) | lower_nibble; 159 } 160 161 static int btstack_parse_hex(const char * string, uint16_t len, uint8_t * buffer){ 162 int i; 163 for (i = 0; i < len; i++) { 164 int single_byte = scan_hex_byte(string); 165 if (single_byte < 0) return 0; 166 string += 2; 167 buffer[i] = (uint8_t)single_byte; 168 // don't check seperator after last byte 169 if (i == len - 1) { 170 return 1; 171 } 172 // optional seperator 173 char separator = *string; 174 if (separator == ':' && separator == '-' && separator == ' ') { 175 string++; 176 } 177 } 178 return 1; 179 } 180 181 static uint8_t prov_static_oob_data[16]; 182 static const char * prov_static_oob_string = "00000000000000000102030405060708"; 183 184 static void provisioning_handle_pdu(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 185 if (packet_type != HCI_EVENT_PACKET) return; 186 switch(packet[0]){ 187 case HCI_EVENT_MESH_META: 188 switch(packet[2]){ 189 case MESH_PB_PROV_CAPABILITIES: 190 printf("Provisioner capabilities\n"); 191 provisioning_provisioner_select_authentication_method(1, 0, 0, 0, 0, 0); 192 break; 193 default: 194 break; 195 } 196 default: 197 break; 198 } 199 } 200 201 TEST_GROUP(Provisioning){ 202 void setup(void){ 203 btstack_crypto_init(); 204 provisioning_provisioner_init(); 205 btstack_parse_hex(prov_static_oob_string, 16, prov_static_oob_data); 206 provisioning_provisioner_register_packet_handler(&provisioning_handle_pdu); 207 // provisioning_device_set_static_oob(16, prov_static_oob_data); 208 // provisioning_device_set_output_oob_actions(0x08, 0x08); 209 // provisioning_device_set_input_oob_actions(0x08, 0x08); 210 perform_crypto_operations(); 211 } 212 }; 213 214 const static uint8_t device_uuid[] = { 0x00, 0x1B, 0xDC, 0x08, 0x10, 0x21, 0x0B, 0x0E, 0x0A, 0x0C, 0x00, 0x0B, 0x0E, 0x0A, 0x0C, 0x00 }; 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, 0x00, 0x00, 0x00 }; 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, 0x3d, 0x0d, 0x55, 0xc4, 0x83, 0xb9, 0x49, 0x6f, 0xab, 0x05, 0xdd, 0xb2, 0x3b, 0x5b, 0xc2, 0x9d}; 225 uint8_t prov_random[] = { 0x06, 0xe9, 0xc5, 0xf1, 0xb0, 0xc4, 0x15, 0x8a, 0xe5, 0x9b, 0x4d, 0x39, 0xf6, 0xf7, 0xe8, 0xa1, 0x05}; 226 uint8_t prov_data[] = { 227 0x07, 0x47, 0x1a, 0x19, 0xcc, 0x17, 0x5c, 0xd0, 0xe8, 0x10, 0x3c, 0x85, 228 0x0a, 0x36, 0x10, 0x07, 0x35, 0x17, 0x41, 0x6a, 0xc3, 0x1e, 0x07, 0xe7, 229 0x90, 0x77, 0x3b, 0xab, 0xbb, 0x40, 0x37, 0x75, 0xb7 230 }; 231 uint8_t prov_complete[] = { 0x08, }; 232 233 static void expect_packet(const char * packet_name, const uint8_t * packet_data, uint16_t packet_len){ 234 printf("Expect '%s'\n", packet_name); 235 CHECK(pdu_data != NULL); 236 CHECK_EQUAL_ARRAY((uint8_t*)packet_data, pdu_data, packet_len); 237 } 238 239 #define EXPECT_PACKET(packet) expect_packet(#packet, packet, sizeof(packet)) 240 241 TEST(Provisioning, Prov1){ 242 // simulate unprovisioned device beacon 243 provisioning_provisioner_start_provisioning(device_uuid); 244 // wait for prov invite 245 EXPECT_PACKET(prov_invite); 246 pb_adv_emit_pdu_sent(0); 247 // send capabilities 248 send_prov_pdu(prov_capabilities, sizeof(prov_capabilities)); 249 // wait for start 250 EXPECT_PACKET(prov_start); 251 pb_adv_emit_pdu_sent(0); 252 // wait for public key 253 EXPECT_PACKET(prov_public_key); 254 pb_adv_emit_pdu_sent(0); 255 // send public key 256 send_prov_pdu(prov_public_key, sizeof(prov_public_key)); 257 // wait for confirm 258 EXPECT_PACKET(prov_confirm); 259 pb_adv_emit_pdu_sent(0); 260 // send prov confirm 261 send_prov_pdu(prov_confirm, sizeof(prov_confirm)); 262 // wait for random 263 CHECK_EQUAL_ARRAY(prov_random, pdu_data, sizeof(prov_random)); 264 pb_adv_emit_pdu_sent(0); 265 // send prov random 266 send_prov_pdu(prov_random, sizeof(prov_random)); 267 // wait for prov data 268 EXPECT_PACKET(prov_data); 269 pb_adv_emit_pdu_sent(0); 270 // send prov complete 271 send_prov_pdu(prov_complete, sizeof(prov_complete)); 272 } 273 274 int main (int argc, const char * argv[]){ 275 hci_dump_open("hci_dump.pklg", HCI_DUMP_PACKETLOGGER); 276 return CommandLineTestRunner::RunAllTests(argc, argv); 277 } 278