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