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 "mesh/mesh_node.h" 45 #include "ble/gatt-service/mesh_provisioning_service_server.h" 46 #include "provisioning.h" 47 #include "provisioning_device.h" 48 #include "btstack.h" 49 50 #include "CppUTest/TestHarness.h" 51 #include "CppUTest/CommandLineTestRunner.h" 52 53 static void CHECK_EQUAL_ARRAY(uint8_t * expected, uint8_t * actual, int size){ 54 int i; 55 for (i=0; i<size; i++){ 56 if (expected[i] != actual[i]) { 57 printf("offset %u wrong\n", i); 58 printf("expected: "); printf_hexdump(expected, size); 59 printf("actual: "); printf_hexdump(actual, size); 60 } 61 BYTES_EQUAL(expected[i], actual[i]); 62 } 63 } 64 65 void dump_data(uint8_t * buffer, uint16_t size){ 66 static int data_counter = 1; 67 char var_name[80]; 68 sprintf(var_name, "test_data_%02u", data_counter); 69 printf("uint8_t %s[] = { ", var_name); 70 for (int i = 0; i < size ; i++){ 71 if ((i % 16) == 0) printf("\n "); 72 printf ("0x%02x, ", buffer[i]); 73 } 74 printf("};\n"); 75 data_counter++; 76 } 77 78 int parse_hex(uint8_t * buffer, const char * hex_string){ 79 int len = 0; 80 while (*hex_string){ 81 if (*hex_string == ' '){ 82 hex_string++; 83 continue; 84 } 85 int high_nibble = nibble_for_char(*hex_string++); 86 int low_nibble = nibble_for_char(*hex_string++); 87 *buffer++ = (high_nibble << 4) | low_nibble; 88 len++; 89 } 90 return len; 91 } 92 93 // returns if anything was done 94 extern "C" int mock_process_hci_cmd(void); 95 96 const static uint8_t device_uuid[] = { 0x00, 0x1B, 0xDC, 0x08, 0x10, 0x21, 0x0B, 0x0E, 0x0A, 0x0C, 0x00, 0x0B, 0x0E, 0x0A, 0x0C, 0x00 }; 97 98 // pb-adv mock for testing 99 100 static btstack_packet_handler_t pb_adv_packet_handler; 101 102 static uint8_t * pdu_data; 103 static uint16_t pdu_size; 104 105 /** 106 * Initialize Provisioning Bearer using Advertisement Bearer 107 * @param DeviceUUID 108 */ 109 void pb_adv_init(void){} 110 void pb_gatt_init(void){} 111 112 /** 113 * Close Link 114 * @param con_handle 115 * @param reason 0 = success, 1 = timeout, 2 = fail 116 */ 117 void pb_gatt_close_link(hci_con_handle_t con_handle, uint8_t reason){} 118 void pb_adv_close_link(hci_con_handle_t con_handle, uint8_t reason){} 119 120 121 /** 122 * Register listener for Provisioning PDUs and MESH_PBV_ADV_SEND_COMPLETE 123 */ 124 void pb_adv_register_packet_handler(btstack_packet_handler_t packet_handler){ 125 pb_adv_packet_handler = packet_handler; 126 } 127 128 void pb_gatt_register_packet_handler(btstack_packet_handler_t packet_handler){ 129 UNUSED(packet_handler); 130 } 131 /** 132 * Send Provisioning PDU 133 */ 134 void pb_adv_send_pdu(uint16_t pb_transport_cid, const uint8_t * pdu, uint16_t size){ 135 UNUSED(pb_transport_cid); 136 pdu_data = (uint8_t*) pdu; 137 pdu_size = size; 138 // dump_data((uint8_t*)pdu,size); 139 // printf_hexdump(pdu, size); 140 } 141 void pb_gatt_send_pdu(uint16_t con_handle, const uint8_t * pdu, uint16_t pdu_size){} 142 143 static mesh_network_key_t network_key; 144 mesh_network_key_t * btstack_memory_mesh_network_key_get(void){ 145 return &network_key; 146 } 147 148 static void perform_crypto_operations(void){ 149 int more = 1; 150 while (more){ 151 more = mock_process_hci_cmd(); 152 } 153 } 154 155 static void send_prov_pdu(const uint8_t * packet, uint16_t size){ 156 pb_adv_packet_handler(PROVISIONING_DATA_PACKET, 0, (uint8_t*) packet, size); 157 perform_crypto_operations(); 158 } 159 160 static void pb_adv_emit_pdu_sent(uint8_t status){ 161 uint8_t event[] = { HCI_EVENT_MESH_META, 2, MESH_SUBEVENT_PB_TRANSPORT_PDU_SENT, status}; 162 pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event)); 163 } 164 165 static int scan_hex_byte(const char * byte_string){ 166 int upper_nibble = nibble_for_char(*byte_string++); 167 if (upper_nibble < 0) return -1; 168 int lower_nibble = nibble_for_char(*byte_string); 169 if (lower_nibble < 0) return -1; 170 return (upper_nibble << 4) | lower_nibble; 171 } 172 173 static int btstack_parse_hex(const char * string, uint16_t len, uint8_t * buffer){ 174 int i; 175 for (i = 0; i < len; i++) { 176 int single_byte = scan_hex_byte(string); 177 if (single_byte < 0) return 0; 178 string += 2; 179 buffer[i] = (uint8_t)single_byte; 180 // don't check seperator after last byte 181 if (i == len - 1) { 182 return 1; 183 } 184 // optional seperator 185 char separator = *string; 186 if (separator == ':' && separator == '-' && separator == ' ') { 187 string++; 188 } 189 } 190 return 1; 191 } 192 193 // void pb_gatt_close_link(hci_con_handle_t con_handle, uint8_t reason){ 194 // } 195 196 static uint8_t prov_static_oob_data[16]; 197 static const char * prov_static_oob_string = "00000000000000000102030405060708"; 198 199 TEST_GROUP(Provisioning){ 200 void setup(void){ 201 btstack_crypto_init(); 202 provisioning_device_init(); 203 mesh_node_set_device_uuid(device_uuid); 204 btstack_parse_hex(prov_static_oob_string, 16, prov_static_oob_data); 205 provisioning_device_set_static_oob(16, prov_static_oob_data); 206 provisioning_device_set_output_oob_actions(0x08, 0x08); 207 provisioning_device_set_input_oob_actions(0x08, 0x08); 208 perform_crypto_operations(); 209 } 210 }; 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, 0x02, 0x00, 0x01 }; 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, 0x80, 0x4d, 0xdc, 0x3b, 0xba, 0x60, 0xd5, 0x93, 0x5b, 0x56, 0xef, 0xb5, 0xcb, 0x59, 0x31, 0xfa, }; 221 uint8_t prov_random[] = { 0x06, 0x9b, 0x4d, 0x39, 0xf6, 0xf7, 0xe8, 0xa1, 0x05, 0xd3, 0xfe, 0xed, 0xa5, 0xd5, 0xf3, 0xd9, 0xe4, }; 222 uint8_t prov_data[] = { 223 0x07, 224 0x85, 0x66, 0xac, 0x46, 0x37, 0x34, 0x86, 0xe1, 0x3e, 0x4c, 0x13, 0x52, 0xd0, 0x6d, 0x34, 0x7d, 225 0xce, 0xf1, 0xd1, 0x7d, 0xbd, 0xbe, 0xcc, 0x99, 0xc3, 226 0x93, 0x87, 0xfc, 0xb0, 0x72, 0x0f, 0xd8, 0x8d }; 227 uint8_t prov_complete[] = { 0x08, }; 228 229 TEST(Provisioning, Prov1){ 230 // send prov inviate 231 send_prov_pdu(prov_invite, sizeof(prov_invite)); 232 // check for prov cap 233 CHECK_EQUAL_ARRAY(prov_capabilities, pdu_data, sizeof(prov_capabilities)); 234 pb_adv_emit_pdu_sent(0); 235 // send prov start 236 send_prov_pdu(prov_start, sizeof(prov_start)); 237 // send public key 238 send_prov_pdu(prov_public_key, sizeof(prov_public_key)); 239 // check for public key 240 CHECK_EQUAL_ARRAY(prov_public_key, pdu_data, sizeof(prov_public_key)); 241 pb_adv_emit_pdu_sent(0); 242 // send prov confirm 243 send_prov_pdu(prov_confirm, sizeof(prov_confirm)); 244 // check for prov confirm 245 CHECK_EQUAL_ARRAY(prov_confirm, pdu_data, sizeof(prov_confirm)); 246 pb_adv_emit_pdu_sent(0); 247 // send prov random 248 send_prov_pdu(prov_random, sizeof(prov_random)); 249 // check for prov random 250 CHECK_EQUAL_ARRAY(prov_random, pdu_data, sizeof(prov_random)); 251 pb_adv_emit_pdu_sent(0); 252 // send prov data 253 send_prov_pdu(prov_data, sizeof(prov_data)); 254 // check prov complete 255 CHECK_EQUAL_ARRAY(prov_complete, pdu_data, sizeof(prov_complete)); 256 pb_adv_emit_pdu_sent(0); 257 } 258 259 int main (int argc, const char * argv[]){ 260 hci_dump_open("hci_dump.pklg", HCI_DUMP_PACKETLOGGER); 261 return CommandLineTestRunner::RunAllTests(argc, argv); 262 } 263