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