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 void perform_crypto_operations(void){ 143 int more = 1; 144 while (more){ 145 more = mock_process_hci_cmd(); 146 } 147 } 148 149 static void send_prov_pdu(const uint8_t * packet, uint16_t size){ 150 pb_adv_packet_handler(PROVISIONING_DATA_PACKET, 0, (uint8_t*) packet, size); 151 perform_crypto_operations(); 152 } 153 154 static void pb_adv_emit_pdu_sent(uint8_t status){ 155 uint8_t event[] = { HCI_EVENT_MESH_META, 2, MESH_SUBEVENT_PB_TRANSPORT_PDU_SENT, status}; 156 pb_adv_packet_handler(HCI_EVENT_PACKET, 0, event, sizeof(event)); 157 } 158 159 static int scan_hex_byte(const char * byte_string){ 160 int upper_nibble = nibble_for_char(*byte_string++); 161 if (upper_nibble < 0) return -1; 162 int lower_nibble = nibble_for_char(*byte_string); 163 if (lower_nibble < 0) return -1; 164 return (upper_nibble << 4) | lower_nibble; 165 } 166 167 static int btstack_parse_hex(const char * string, uint16_t len, uint8_t * buffer){ 168 int i; 169 for (i = 0; i < len; i++) { 170 int single_byte = scan_hex_byte(string); 171 if (single_byte < 0) return 0; 172 string += 2; 173 buffer[i] = (uint8_t)single_byte; 174 // don't check seperator after last byte 175 if (i == len - 1) { 176 return 1; 177 } 178 // optional seperator 179 char separator = *string; 180 if (separator == ':' && separator == '-' && separator == ' ') { 181 string++; 182 } 183 } 184 return 1; 185 } 186 187 // void pb_gatt_close_link(hci_con_handle_t con_handle, uint8_t reason){ 188 // } 189 190 static uint8_t prov_static_oob_data[16]; 191 static const char * prov_static_oob_string = "00000000000000000102030405060708"; 192 193 TEST_GROUP(Provisioning){ 194 void setup(void){ 195 btstack_crypto_init(); 196 provisioning_device_init(device_uuid); 197 btstack_parse_hex(prov_static_oob_string, 16, prov_static_oob_data); 198 provisioning_device_set_static_oob(16, prov_static_oob_data); 199 provisioning_device_set_output_oob_actions(0x08, 0x08); 200 provisioning_device_set_input_oob_actions(0x08, 0x08); 201 perform_crypto_operations(); 202 } 203 }; 204 205 uint8_t prov_invite[] = { 0x00, 0x00 }; 206 uint8_t prov_capabilities[] = { 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x08, 0x00, 0x08, 0x08, 0x00, 0x08, }; 207 uint8_t prov_start[] = { 0x02, 0x00, 0x00, 0x02, 0x00, 0x01 }; 208 uint8_t prov_public_key[] = { 0x03, 209 0xf0, 0xc8, 0x63, 0xf8, 0xe5, 0x55, 0x11, 0x4b, 0xf4, 0x88, 0x2c, 0xc7, 0x87, 0xb9, 0x5c, 0x27, 210 0x2a, 0x7f, 0xe4, 0xdc, 0xdd, 0xf1, 0x92, 0x2f, 0x4f, 0x18, 0xa4, 0x94, 0xe1, 0xc3, 0x57, 0xa1, 211 0xa6, 0xc3, 0x2d, 0x07, 0xbe, 0xb5, 0x76, 0xab, 0x60, 0x10, 0x68, 0x06, 0x8f, 0x0a, 0x9e, 0x01, 212 0x60, 0xc3, 0xa1, 0x41, 0x19, 0xf5, 0xd4, 0x26, 0xa7, 0x95, 0x5d, 0xa3, 0xe6, 0xed, 0x3e, 0x81, }; 213 uint8_t prov_confirm[] = { 0x05, 0x80, 0x4d, 0xdc, 0x3b, 0xba, 0x60, 0xd5, 0x93, 0x5b, 0x56, 0xef, 0xb5, 0xcb, 0x59, 0x31, 0xfa, }; 214 uint8_t prov_random[] = { 0x06, 0x9b, 0x4d, 0x39, 0xf6, 0xf7, 0xe8, 0xa1, 0x05, 0xd3, 0xfe, 0xed, 0xa5, 0xd5, 0xf3, 0xd9, 0xe4, }; 215 uint8_t prov_data[] = { 216 0x07, 217 0x85, 0x66, 0xac, 0x46, 0x37, 0x34, 0x86, 0xe1, 0x3e, 0x4c, 0x13, 0x52, 0xd0, 0x6d, 0x34, 0x7d, 218 0xce, 0xf1, 0xd1, 0x7d, 0xbd, 0xbe, 0xcc, 0x99, 0xc3, 219 0x93, 0x87, 0xfc, 0xb0, 0x72, 0x0f, 0xd8, 0x8d }; 220 uint8_t prov_complete[] = { 0x08, }; 221 222 TEST(Provisioning, Prov1){ 223 // send prov inviate 224 send_prov_pdu(prov_invite, sizeof(prov_invite)); 225 // check for prov cap 226 CHECK_EQUAL_ARRAY(prov_capabilities, pdu_data, sizeof(prov_capabilities)); 227 pb_adv_emit_pdu_sent(0); 228 // send prov start 229 send_prov_pdu(prov_start, sizeof(prov_start)); 230 // send public key 231 send_prov_pdu(prov_public_key, sizeof(prov_public_key)); 232 // check for public key 233 CHECK_EQUAL_ARRAY(prov_public_key, pdu_data, sizeof(prov_public_key)); 234 pb_adv_emit_pdu_sent(0); 235 // send prov confirm 236 send_prov_pdu(prov_confirm, sizeof(prov_confirm)); 237 // check for prov confirm 238 CHECK_EQUAL_ARRAY(prov_confirm, pdu_data, sizeof(prov_confirm)); 239 pb_adv_emit_pdu_sent(0); 240 // send prov random 241 send_prov_pdu(prov_random, sizeof(prov_random)); 242 // check for prov random 243 CHECK_EQUAL_ARRAY(prov_random, pdu_data, sizeof(prov_random)); 244 pb_adv_emit_pdu_sent(0); 245 // send prov data 246 send_prov_pdu(prov_data, sizeof(prov_data)); 247 // check prov complete 248 CHECK_EQUAL_ARRAY(prov_complete, pdu_data, sizeof(prov_complete)); 249 pb_adv_emit_pdu_sent(0); 250 } 251 252 int main (int argc, const char * argv[]){ 253 hci_dump_open("hci_dump.pklg", HCI_DUMP_PACKETLOGGER); 254 return CommandLineTestRunner::RunAllTests(argc, argv); 255 } 256