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