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_device.h" 47 #include "btstack.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 const static uint8_t device_uuid[] = { 0x00, 0x1B, 0xDC, 0x08, 0x10, 0x21, 0x0B, 0x0E, 0x0A, 0x0C, 0x00, 0x0B, 0x0E, 0x0A, 0x0C, 0x00 }; 96 97 // pb-adv mock for testing 98 99 static btstack_packet_handler_t pb_adv_packet_handler; 100 101 static uint8_t * pdu_data; 102 static uint16_t pdu_size; 103 104 /** 105 * Initialize Provisioning Bearer using Advertisement Bearer 106 * @param DeviceUUID 107 */ 108 void pb_adv_init(const uint8_t * device_uuid){} 109 void pb_gatt_init(const uint8_t * device_uuid){} 110 111 /** 112 * Close Link 113 * @param con_handle 114 * @param reason 0 = success, 1 = timeout, 2 = fail 115 */ 116 void pb_gatt_close_link(hci_con_handle_t con_handle, uint8_t reason){} 117 void pb_adv_close_link(hci_con_handle_t con_handle, uint8_t reason){} 118 119 120 /** 121 * Register listener for Provisioning PDUs and MESH_PBV_ADV_SEND_COMPLETE 122 */ 123 void pb_adv_register_packet_handler(btstack_packet_handler_t packet_handler){ 124 pb_adv_packet_handler = packet_handler; 125 } 126 127 void pb_gatt_register_packet_handler(btstack_packet_handler_t packet_handler){ 128 UNUSED(packet_handler); 129 } 130 /** 131 * Send Provisioning PDU 132 */ 133 void pb_adv_send_pdu(uint16_t pb_transport_cid, const uint8_t * pdu, uint16_t size){ 134 UNUSED(pb_transport_cid); 135 pdu_data = (uint8_t*) pdu; 136 pdu_size = size; 137 // dump_data((uint8_t*)pdu,size); 138 // printf_hexdump(pdu, size); 139 } 140 void pb_gatt_send_pdu(uint16_t con_handle, const uint8_t * pdu, uint16_t pdu_size){} 141 142 static mesh_network_key_t network_key; 143 mesh_network_key_t * btstack_memory_mesh_network_key_get(void){ 144 return &network_key; 145 } 146 147 static void perform_crypto_operations(void){ 148 int more = 1; 149 while (more){ 150 more = mock_process_hci_cmd(); 151 } 152 } 153 154 static void send_prov_pdu(const uint8_t * packet, uint16_t size){ 155 pb_adv_packet_handler(PROVISIONING_DATA_PACKET, 0, (uint8_t*) packet, size); 156 perform_crypto_operations(); 157 } 158 159 static void pb_adv_emit_pdu_sent(uint8_t status){ 160 uint8_t event[] = { HCI_EVENT_MESH_META, 2, MESH_SUBEVENT_PB_TRANSPORT_PDU_SENT, status}; 161 pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event)); 162 } 163 164 static int scan_hex_byte(const char * byte_string){ 165 int upper_nibble = nibble_for_char(*byte_string++); 166 if (upper_nibble < 0) return -1; 167 int lower_nibble = nibble_for_char(*byte_string); 168 if (lower_nibble < 0) return -1; 169 return (upper_nibble << 4) | lower_nibble; 170 } 171 172 static int btstack_parse_hex(const char * string, uint16_t len, uint8_t * buffer){ 173 int i; 174 for (i = 0; i < len; i++) { 175 int single_byte = scan_hex_byte(string); 176 if (single_byte < 0) return 0; 177 string += 2; 178 buffer[i] = (uint8_t)single_byte; 179 // don't check seperator after last byte 180 if (i == len - 1) { 181 return 1; 182 } 183 // optional seperator 184 char separator = *string; 185 if (separator == ':' && separator == '-' && separator == ' ') { 186 string++; 187 } 188 } 189 return 1; 190 } 191 192 // void pb_gatt_close_link(hci_con_handle_t con_handle, uint8_t reason){ 193 // } 194 195 static uint8_t prov_static_oob_data[16]; 196 static const char * prov_static_oob_string = "00000000000000000102030405060708"; 197 198 TEST_GROUP(Provisioning){ 199 void setup(void){ 200 btstack_crypto_init(); 201 provisioning_device_init(device_uuid); 202 btstack_parse_hex(prov_static_oob_string, 16, prov_static_oob_data); 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 uint8_t prov_invite[] = { 0x00, 0x00 }; 211 uint8_t prov_capabilities[] = { 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x08, 0x00, 0x08, 0x08, 0x00, 0x08, }; 212 uint8_t prov_start[] = { 0x02, 0x00, 0x00, 0x02, 0x00, 0x01 }; 213 uint8_t prov_public_key[] = { 0x03, 214 0xf0, 0xc8, 0x63, 0xf8, 0xe5, 0x55, 0x11, 0x4b, 0xf4, 0x88, 0x2c, 0xc7, 0x87, 0xb9, 0x5c, 0x27, 215 0x2a, 0x7f, 0xe4, 0xdc, 0xdd, 0xf1, 0x92, 0x2f, 0x4f, 0x18, 0xa4, 0x94, 0xe1, 0xc3, 0x57, 0xa1, 216 0xa6, 0xc3, 0x2d, 0x07, 0xbe, 0xb5, 0x76, 0xab, 0x60, 0x10, 0x68, 0x06, 0x8f, 0x0a, 0x9e, 0x01, 217 0x60, 0xc3, 0xa1, 0x41, 0x19, 0xf5, 0xd4, 0x26, 0xa7, 0x95, 0x5d, 0xa3, 0xe6, 0xed, 0x3e, 0x81, }; 218 uint8_t prov_confirm[] = { 0x05, 0x80, 0x4d, 0xdc, 0x3b, 0xba, 0x60, 0xd5, 0x93, 0x5b, 0x56, 0xef, 0xb5, 0xcb, 0x59, 0x31, 0xfa, }; 219 uint8_t prov_random[] = { 0x06, 0x9b, 0x4d, 0x39, 0xf6, 0xf7, 0xe8, 0xa1, 0x05, 0xd3, 0xfe, 0xed, 0xa5, 0xd5, 0xf3, 0xd9, 0xe4, }; 220 uint8_t prov_data[] = { 221 0x07, 222 0x85, 0x66, 0xac, 0x46, 0x37, 0x34, 0x86, 0xe1, 0x3e, 0x4c, 0x13, 0x52, 0xd0, 0x6d, 0x34, 0x7d, 223 0xce, 0xf1, 0xd1, 0x7d, 0xbd, 0xbe, 0xcc, 0x99, 0xc3, 224 0x93, 0x87, 0xfc, 0xb0, 0x72, 0x0f, 0xd8, 0x8d }; 225 uint8_t prov_complete[] = { 0x08, }; 226 227 TEST(Provisioning, Prov1){ 228 // send prov inviate 229 send_prov_pdu(prov_invite, sizeof(prov_invite)); 230 // check for prov cap 231 CHECK_EQUAL_ARRAY(prov_capabilities, pdu_data, sizeof(prov_capabilities)); 232 pb_adv_emit_pdu_sent(0); 233 // send prov start 234 send_prov_pdu(prov_start, sizeof(prov_start)); 235 // send public key 236 send_prov_pdu(prov_public_key, sizeof(prov_public_key)); 237 // check for public key 238 CHECK_EQUAL_ARRAY(prov_public_key, pdu_data, sizeof(prov_public_key)); 239 pb_adv_emit_pdu_sent(0); 240 // send prov confirm 241 send_prov_pdu(prov_confirm, sizeof(prov_confirm)); 242 // check for prov confirm 243 CHECK_EQUAL_ARRAY(prov_confirm, pdu_data, sizeof(prov_confirm)); 244 pb_adv_emit_pdu_sent(0); 245 // send prov random 246 send_prov_pdu(prov_random, sizeof(prov_random)); 247 // check for prov random 248 CHECK_EQUAL_ARRAY(prov_random, pdu_data, sizeof(prov_random)); 249 pb_adv_emit_pdu_sent(0); 250 // send prov data 251 send_prov_pdu(prov_data, sizeof(prov_data)); 252 // check prov complete 253 CHECK_EQUAL_ARRAY(prov_complete, pdu_data, sizeof(prov_complete)); 254 pb_adv_emit_pdu_sent(0); 255 } 256 257 int main (int argc, const char * argv[]){ 258 hci_dump_open("hci_dump.pklg", HCI_DUMP_PACKETLOGGER); 259 return CommandLineTestRunner::RunAllTests(argc, argv); 260 } 261