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 printf("pb_adv_init\n"); 113 } 114 115 void pb_adv_close_link(uint16_t pb_adv_cid, uint8_t reason){ 116 } 117 118 void pb_adv_register_packet_handler(btstack_packet_handler_t packet_handler){ 119 pb_adv_packet_handler = packet_handler; 120 } 121 122 void pb_adv_send_pdu(uint16_t pb_transport_cid, const uint8_t * pdu, uint16_t size){ 123 UNUSED(pb_transport_cid); 124 pdu_data = (uint8_t*) pdu; 125 pdu_size = size; 126 // dump_data((uint8_t*)pdu,size); 127 // printf_hexdump(pdu, size); 128 } 129 130 uint16_t pb_adv_create_link(const uint8_t * device_uuid){ 131 // just simluate opened 132 pb_adv_emit_link_open(0, 1); 133 return 1; 134 } 135 136 // 137 static void perform_crypto_operations(void){ 138 int more = 1; 139 while (more){ 140 more = mock_process_hci_cmd(); 141 } 142 } 143 144 static void send_prov_pdu(const uint8_t * packet, uint16_t size){ 145 pb_adv_packet_handler(PROVISIONING_DATA_PACKET, 0, (uint8_t*) packet, size); 146 perform_crypto_operations(); 147 } 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 static uint8_t prov_static_oob_data[16]; 179 static const char * prov_static_oob_string = "00000000000000000102030405060708"; 180 181 static void provisioning_handle_pdu(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 182 if (packet_type != HCI_EVENT_PACKET) return; 183 switch(packet[0]){ 184 case HCI_EVENT_MESH_META: 185 switch(packet[2]){ 186 case MESH_PB_PROV_CAPABILITIES: 187 printf("Provisioner capabilities\n"); 188 provisioning_provisioner_select_authentication_method(1, 0, 0, 0, 0, 0); 189 break; 190 default: 191 break; 192 } 193 default: 194 break; 195 } 196 } 197 198 TEST_GROUP(Provisioning){ 199 void setup(void){ 200 btstack_crypto_init(); 201 provisioning_provisioner_init(); 202 btstack_parse_hex(prov_static_oob_string, 16, prov_static_oob_data); 203 provisioning_provisioner_register_packet_handler(&provisioning_handle_pdu); 204 // provisioning_device_set_static_oob(16, prov_static_oob_data); 205 // provisioning_device_set_output_oob_actions(0x08, 0x08); 206 // provisioning_device_set_input_oob_actions(0x08, 0x08); 207 perform_crypto_operations(); 208 } 209 }; 210 211 const static uint8_t device_uuid[] = { 0x00, 0x1B, 0xDC, 0x08, 0x10, 0x21, 0x0B, 0x0E, 0x0A, 0x0C, 0x00, 0x0B, 0x0E, 0x0A, 0x0C, 0x00 }; 212 213 uint8_t prov_invite[] = { 0x00, 0x00 }; 214 uint8_t prov_capabilities[] = { 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x08, 0x00, 0x08, 0x08, 0x00, 0x08, }; 215 uint8_t prov_start[] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 }; 216 uint8_t prov_public_key[] = { 0x03, 217 0xf0, 0xc8, 0x63, 0xf8, 0xe5, 0x55, 0x11, 0x4b, 0xf4, 0x88, 0x2c, 0xc7, 0x87, 0xb9, 0x5c, 0x27, 218 0x2a, 0x7f, 0xe4, 0xdc, 0xdd, 0xf1, 0x92, 0x2f, 0x4f, 0x18, 0xa4, 0x94, 0xe1, 0xc3, 0x57, 0xa1, 219 0xa6, 0xc3, 0x2d, 0x07, 0xbe, 0xb5, 0x76, 0xab, 0x60, 0x10, 0x68, 0x06, 0x8f, 0x0a, 0x9e, 0x01, 220 0x60, 0xc3, 0xa1, 0x41, 0x19, 0xf5, 0xd4, 0x26, 0xa7, 0x95, 0x5d, 0xa3, 0xe6, 0xed, 0x3e, 0x81, }; 221 uint8_t prov_confirm[] = { 0x05, 0x3d, 0x0d, 0x55, 0xc4, 0x83, 0xb9, 0x49, 0x6f, 0xab, 0x05, 0xdd, 0xb2, 0x3b, 0x5b, 0xc2, 0x9d}; 222 uint8_t prov_random[] = { 0x06, 0xe9, 0xc5, 0xf1, 0xb0, 0xc4, 0x15, 0x8a, 0xe5, 0x9b, 0x4d, 0x39, 0xf6, 0xf7, 0xe8, 0xa1, 0x05}; 223 uint8_t prov_data[] = { 224 0x07, 0x47, 0x1a, 0x19, 0xcc, 0x17, 0x5c, 0xd0, 0xe8, 0x10, 0x3c, 0x85, 225 0x0a, 0x36, 0x10, 0x07, 0x35, 0x17, 0x41, 0x6a, 0xc3, 0x1e, 0x07, 0xe7, 226 0x90, 0x77, 0x3b, 0xab, 0xbb, 0x40, 0x37, 0x75, 0xb7 227 }; 228 uint8_t prov_complete[] = { 0x08, }; 229 230 static void expect_packet(const char * packet_name, const uint8_t * packet_data, uint16_t packet_len){ 231 printf("Expect '%s'\n", packet_name); 232 CHECK(pdu_data != NULL); 233 CHECK_EQUAL_ARRAY((uint8_t*)packet_data, pdu_data, packet_len); 234 } 235 236 #define EXPECT_PACKET(packet) expect_packet(#packet, packet, sizeof(packet)) 237 238 TEST(Provisioning, Prov1){ 239 // simulate unprovisioned device beacon 240 provisioning_provisioner_start_provisioning(device_uuid); 241 // wait for prov invite 242 EXPECT_PACKET(prov_invite); 243 pb_adv_emit_pdu_sent(0); 244 // send capabilities 245 send_prov_pdu(prov_capabilities, sizeof(prov_capabilities)); 246 // wait for start 247 EXPECT_PACKET(prov_start); 248 pb_adv_emit_pdu_sent(0); 249 // wait for public key 250 EXPECT_PACKET(prov_public_key); 251 pb_adv_emit_pdu_sent(0); 252 // send public key 253 send_prov_pdu(prov_public_key, sizeof(prov_public_key)); 254 // wait for confirm 255 EXPECT_PACKET(prov_confirm); 256 pb_adv_emit_pdu_sent(0); 257 // send prov confirm 258 send_prov_pdu(prov_confirm, sizeof(prov_confirm)); 259 // wait for random 260 CHECK_EQUAL_ARRAY(prov_random, pdu_data, sizeof(prov_random)); 261 pb_adv_emit_pdu_sent(0); 262 // send prov random 263 send_prov_pdu(prov_random, sizeof(prov_random)); 264 // wait for prov data 265 EXPECT_PACKET(prov_data); 266 pb_adv_emit_pdu_sent(0); 267 // send prov complete 268 send_prov_pdu(prov_complete, sizeof(prov_complete)); 269 } 270 271 int main (int argc, const char * argv[]){ 272 hci_dump_open("hci_dump.pklg", HCI_DUMP_PACKETLOGGER); 273 return CommandLineTestRunner::RunAllTests(argc, argv); 274 } 275