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