1 /* 2 * Copyright (C) 2014 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 #define __BTSTACK_FILE__ "provisioner.c" 39 40 #include <stdint.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include "ble/mesh/adv_bearer.h" 45 #include "ble/mesh/pb_adv.h" 46 #include "ble/mesh/beacon.h" 47 #include "provisioning.h" 48 #include "provisioning_provisioner.h" 49 #include "btstack.h" 50 #include "btstack_tlv.h" 51 52 static btstack_packet_callback_registration_t hci_event_callback_registration; 53 54 static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 55 56 static mesh_provisioning_data provisioning_data; 57 58 // pin entry 59 static int ui_chars_for_pin; 60 static uint8_t ui_pin[17]; 61 static int ui_pin_offset; 62 63 static const btstack_tlv_t * btstack_tlv_singleton_impl; 64 static void * btstack_tlv_singleton_context; 65 66 static uint16_t pb_adv_cid; 67 68 // PTS defaults 69 static uint8_t prov_static_oob_data[16]; 70 static const char * prov_static_oob_string = "00000000000000000102030405060708"; 71 72 static uint8_t prov_public_key_data[64]; 73 static const char * prov_public_key_string = "F465E43FF23D3F1B9DC7DFC04DA8758184DBC966204796ECCF0D6CF5E16500CC0201D048BCBBD899EEEFC424164E33C201C2B010CA6B4D43A8A155CAD8ECB279"; 74 75 static int scan_hex_byte(const char * byte_string){ 76 int upper_nibble = nibble_for_char(*byte_string++); 77 if (upper_nibble < 0) return -1; 78 int lower_nibble = nibble_for_char(*byte_string); 79 if (lower_nibble < 0) return -1; 80 return (upper_nibble << 4) | lower_nibble; 81 } 82 83 static int btstack_parse_hex(const char * string, uint16_t len, uint8_t * buffer){ 84 int i; 85 for (i = 0; i < len; i++) { 86 int single_byte = scan_hex_byte(string); 87 if (single_byte < 0) return 0; 88 string += 2; 89 buffer[i] = (uint8_t)single_byte; 90 // don't check seperator after last byte 91 if (i == len - 1) { 92 return 1; 93 } 94 // optional seperator 95 char separator = *string; 96 if (separator == ':' && separator == '-' && separator == ' ') { 97 string++; 98 } 99 } 100 return 1; 101 } 102 103 static void btstack_print_hex(const uint8_t * data, uint16_t len, char separator){ 104 int i; 105 for (i=0;i<len;i++){ 106 printf("%02x", data[i]); 107 if (separator){ 108 printf("%c", separator); 109 } 110 } 111 printf("\n"); 112 } 113 114 static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 115 UNUSED(channel); 116 UNUSED(size); 117 bd_addr_t addr; 118 int i; 119 int prov_len; 120 121 switch (packet_type) { 122 case HCI_EVENT_PACKET: 123 switch (hci_event_packet_get_type(packet)) { 124 case BTSTACK_EVENT_STATE: 125 if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) break; 126 // dump bd_addr in pts format 127 gap_local_bd_addr(addr); 128 printf("Local addr: %s - ", bd_addr_to_str(addr)); 129 for (i=0;i<6;i++) { 130 printf("%02x", addr[i]); 131 } 132 printf("\n"); 133 // get tlv 134 btstack_tlv_get_instance(&btstack_tlv_singleton_impl, &btstack_tlv_singleton_context); 135 // load provisioning data 136 prov_len = btstack_tlv_singleton_impl->get_tag(btstack_tlv_singleton_context, 'PROV', (uint8_t *) &provisioning_data, sizeof(mesh_provisioning_data)); 137 printf("Provisioning data available: %u\n", prov_len ? 1 : 0); 138 // setup scanning 139 gap_set_scan_parameters(0, 0x300, 0x300); 140 gap_start_scan(); 141 break; 142 default: 143 break; 144 } 145 break; 146 } 147 } 148 149 static void mesh_message_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 150 if (packet_type != HCI_EVENT_PACKET) return; 151 152 uint8_t public_oob = 0; 153 uint8_t auth_method = 0; 154 uint8_t auth_action = 0; 155 uint8_t auth_size = 0; 156 157 uint8_t auth_static_oob = 0; 158 uint16_t auth_output_oob_action; 159 uint16_t auth_input_oob_action; 160 161 switch(packet[0]){ 162 case HCI_EVENT_MESH_META: 163 switch(packet[2]){ 164 case MESH_PB_ADV_LINK_OPEN: 165 printf("Provisioner link opened"); 166 break; 167 case MESH_PB_PROV_CAPABILITIES: 168 printf("// Provisioner capabilities\n"); 169 public_oob = mesh_pb_prov_capabilities_event_get_public_key(packet); 170 if (public_oob){ 171 printf("PTS supports Public OOB, select Public OOB\n"); 172 } else { 173 printf("PTS does not supports Public OOB, select No Public OOB\n"); 174 } 175 auth_static_oob = mesh_pb_prov_capabilities_event_get_static_oob_type(packet); 176 auth_input_oob_action = mesh_pb_prov_capabilities_event_get_input_oob_action(packet); 177 auth_output_oob_action = mesh_pb_prov_capabilities_event_get_output_oob_action(packet); 178 if (auth_output_oob_action){ 179 auth_method = 0x02; // Output OOB 180 // find output action 181 int i; 182 for (i=0;i<5;i++){ 183 if (auth_output_oob_action & (1<<i)){ 184 auth_action = i; 185 auth_size = mesh_pb_prov_capabilities_event_get_output_oob_size(packet); 186 printf("// - Pick Output OOB Action with index %u, size %u\n", i, auth_size); 187 break; 188 } 189 } 190 } else if(auth_input_oob_action){ 191 auth_method = 0x03; // Input OOB 192 // find output action 193 int i; 194 for (i=0;i<5;i++){ 195 if (auth_input_oob_action & (1<<i)){ 196 auth_action = i; 197 auth_size = mesh_pb_prov_capabilities_event_get_input_oob_size(packet); 198 printf("// - Pick Input OOB Action with index %u, size %u\n", i, auth_size); 199 break; 200 } 201 } 202 } else if (auth_static_oob & 1){ 203 // set static oob - used for PTS 204 btstack_parse_hex(prov_static_oob_string, 16, prov_static_oob_data); 205 provisioning_provisioner_set_static_oob(pb_adv_cid, 16, prov_static_oob_data); 206 // pick Static OOB method 207 printf("// - Pick Static OOB\n"); 208 auth_method = 0x01; 209 } 210 provisioning_provisioner_select_authentication_method(1, 0, public_oob, auth_method, auth_action, auth_size); 211 break; 212 case MESH_PB_PROV_START_RECEIVE_PUBLIC_KEY_OOB: 213 printf("Simulate Read Public Key OOB\n"); 214 btstack_parse_hex(prov_public_key_string, 64, prov_public_key_data); 215 provisioning_provisioner_public_key_oob_received(pb_adv_cid, prov_public_key_data); 216 break; 217 case MESH_PB_PROV_OUTPUT_OOB_REQUEST: 218 printf("Enter passphrase: "); 219 fflush(stdout); 220 ui_chars_for_pin = 1; 221 ui_pin_offset = 0; 222 break; 223 case MESH_PB_PROV_START_EMIT_INPUT_OOB: 224 break; 225 case MESH_PB_PROV_COMPLETE: 226 printf("Provisioning complete\n"); 227 break; 228 default: 229 break; 230 } 231 break; 232 case GAP_EVENT_ADVERTISING_REPORT: 233 printf("received mesh message\n"); 234 break; 235 default: 236 break; 237 } 238 } 239 240 static uint8_t device_uuid[16]; 241 242 static void mesh_unprovisioned_beacon_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 243 if (packet_type != HCI_EVENT_PACKET) return; 244 uint16_t oob; 245 const uint8_t * data; 246 switch(packet[0]){ 247 case GAP_EVENT_ADVERTISING_REPORT: 248 data = gap_event_advertising_report_get_data(packet); 249 memcpy(device_uuid, &packet[15], 16); 250 oob = big_endian_read_16(data, 31); 251 printf("received unprovisioned device beacon, oob data %x, device uuid: ", oob); 252 printf_hexdump(device_uuid, 16); 253 pb_adv_cid = pb_adv_create_link(device_uuid); 254 break; 255 default: 256 break; 257 } 258 } 259 260 uint8_t pts_device_uuid[16]; 261 const char * pts_device_uuid_string = "001BDC0810210B0E0A0C000B0E0A0C00"; 262 263 static uint8_t adv_prov_invite_pdu[] = { 0x00, 0x00 }; 264 static uint8_t adv_prov_start_pdu[] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00}; 265 static uint8_t adv_prov_public_key_pdu[65]; 266 267 static btstack_crypto_aes128_cmac_t mesh_cmac_request; 268 static uint8_t mesh_secure_network_beacon[22]; 269 static uint8_t mesh_secure_network_beacon_auth_value[16]; 270 271 static void mesh_secure_network_beacon_auth_value_calculated(void * arg){ 272 UNUSED(arg); 273 memcpy(&mesh_secure_network_beacon[14], mesh_secure_network_beacon_auth_value, 8); 274 printf("Secure Network Beacon\n"); 275 printf("- "); 276 printf_hexdump(mesh_secure_network_beacon, sizeof(mesh_secure_network_beacon)); 277 adv_bearer_send_mesh_beacon(mesh_secure_network_beacon, sizeof(mesh_secure_network_beacon)); 278 } 279 280 static void stdin_process(char cmd){ 281 if (ui_chars_for_pin){ 282 printf("%c", cmd); 283 fflush(stdout); 284 if (cmd == '\n'){ 285 ui_pin[ui_pin_offset] = 0; 286 printf("\nSending Pin '%s'\n", ui_pin); 287 // provisioning_provisioner_input_oob_complete_alphanumeric(1, ui_pin, ui_pin_offset); 288 provisioning_provisioner_input_oob_complete_numeric(1, btstack_atoi((char*)ui_pin)); 289 ui_chars_for_pin = 0; 290 } else { 291 ui_pin[ui_pin_offset++] = cmd; 292 } 293 return; 294 } 295 switch (cmd){ 296 default: 297 printf("Command: '%c'\n", cmd); 298 break; 299 } 300 } 301 302 int btstack_main(void); 303 int btstack_main(void) 304 { 305 // register for HCI events 306 hci_event_callback_registration.callback = &packet_handler; 307 hci_add_event_handler(&hci_event_callback_registration); 308 309 // console 310 btstack_stdin_setup(stdin_process); 311 312 // crypto 313 btstack_crypto_init(); 314 315 // mesh 316 adv_bearer_init(); 317 adv_bearer_register_for_mesh_message(&mesh_message_handler); 318 319 beacon_init(NULL, 0); 320 beacon_register_for_unprovisioned_device_beacons(&mesh_unprovisioned_beacon_handler); 321 322 // Provisioning in device role 323 provisioning_provisioner_init(); 324 provisioning_provisioner_register_packet_handler(&mesh_message_handler); 325 326 // 327 btstack_parse_hex(pts_device_uuid_string, 16, pts_device_uuid); 328 btstack_print_hex(pts_device_uuid, 16, 0); 329 330 // turn on! 331 hci_power_control(HCI_POWER_ON); 332 333 return 0; 334 } 335 /* EXAMPLE_END */ 336