diff --git a/ble/sm_minimal.c b/ble/sm_minimal.c new file mode 100644 index 000000000..07dad3013 --- /dev/null +++ b/ble/sm_minimal.c @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2011-2012 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. Any redistribution, use, or modification is done solely for + * personal benefit and not for any commercial purpose or for + * monetary gain. + * + * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS + * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Please inquire about commercial licensing options at contact@bluekitchen-gmbh.com + * + */ + +#include +#include + +#include "debug.h" +#include "hci.h" +#include "l2cap.h" +#include "central_device_db.h" +#include "sm.h" +#include "gap_le.h" + +// +// SM internal types and globals +// + +typedef enum { + SM_STATE_IDLE, + SM_STATE_SEND_LTK_REQUESTED_NEGATIVE_REPLY, + SM_STATE_SEND_PAIRING_FAILED, + SM_STATE_PAIRING_FAILED + +} security_manager_state_t; + +static void sm_run(); + +// used to notify applicationss that user interaction is neccessary, see sm_notify_t below +static btstack_packet_handler_t sm_client_packet_handler = NULL; +static security_manager_state_t sm_state_responding = SM_STATE_IDLE; +static uint16_t sm_response_handle = 0; +static uint8_t sm_pairing_failed_reason = 0; + + + +void sm_set_er(sm_key_t er){} +void sm_set_ir(sm_key_t ir){} +void sm_register_oob_data_callback( int (*get_oob_data_callback)(uint8_t addres_type, bd_addr_t * addr, uint8_t * oob_data)){} + +void sm_set_accepted_stk_generation_methods(uint8_t accepted_stk_generation_methods){} +void sm_set_encrypted_key_size_range(uint8_t min_size, uint8_t max_size){} +void sm_set_authentication_requirements(uint8_t auth_req){} +void sm_set_io_capabilities(io_capability_t io_capability){} +void sm_set_request_security(int enable){} + +void sm_bonding_decline(uint8_t addr_type, bd_addr_t address){} +void sm_just_works_confirm(uint8_t addr_type, bd_addr_t address){} +void sm_passkey_input(uint8_t addr_type, bd_addr_t address, uint32_t passkey){} + +// @returns 0 if not encrypted, 7-16 otherwise +int sm_encryption_key_size(uint8_t addr_type, bd_addr_t address){ + return 0; +} + +// @returns 1 if bonded with OOB/Passkey (AND MITM protection) +int sm_authenticated(uint8_t addr_type, bd_addr_t address){ + return 0; +} + +// @returns authorization_state for the current session +authorization_state_t sm_authorization_state(uint8_t addr_type, bd_addr_t address){ + return AUTHORIZATION_DECLINED; +} + +// request authorization +void sm_request_authorization(uint8_t addr_type, bd_addr_t address){} + +// called by client app on authorization request +void sm_authorization_decline(uint8_t addr_type, bd_addr_t address){} +void sm_authorization_grant(uint8_t addr_type, bd_addr_t address){} + +// Support for signed writes +int sm_cmac_ready(){ + return 0; +} + +void sm_cmac_start(sm_key_t k, uint16_t message_len, uint8_t * message, void (*done_handler)(uint8_t hash[8])){} + +void sm_register_packet_handler(btstack_packet_handler_t handler){ + sm_client_packet_handler = handler; +} + +static void sm_pdu_received_in_wrong_state(){ + sm_pairing_failed_reason = SM_REASON_UNSPECIFIED_REASON; + sm_state_responding = SM_STATE_SEND_PAIRING_FAILED; +} + +static void sm_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size){ + + if (packet_type != SM_DATA_PACKET) return; + + if (handle != sm_response_handle){ + printf("sm_packet_handler: packet from handle %u, but expecting from %u\n", handle, sm_response_handle); + return; + } + + if (packet[0] == SM_CODE_PAIRING_FAILED){ + sm_state_responding = SM_STATE_PAIRING_FAILED; + return; + } + + switch (sm_state_responding){ + + case SM_STATE_IDLE: { + if (packet[0] != SM_CODE_PAIRING_REQUEST){ + sm_pdu_received_in_wrong_state(); + break;; + } + sm_state_responding = SM_STATE_SEND_PAIRING_FAILED; + sm_pairing_failed_reason = SM_REASON_PAIRING_NOT_SUPPORTED; + break; + } + default: + break; + } + + // try to send preparared packet + sm_run(); +} + +static void sm_event_packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ + + switch (packet_type) { + + case HCI_EVENT_PACKET: + switch (packet[0]) { + case HCI_EVENT_LE_META: + switch (packet[2]) { + case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: + // only single connection for peripheral + if (sm_response_handle){ + printf("Already connected, ignoring incoming connection\n"); + return; + } + sm_response_handle = READ_BT_16(packet, 4); + sm_state_responding = SM_STATE_IDLE; + break; + + case HCI_SUBEVENT_LE_LONG_TERM_KEY_REQUEST: + log_info("LTK Request: state %u", sm_state_responding); + sm_state_responding = SM_STATE_SEND_LTK_REQUESTED_NEGATIVE_REPLY; + break; + + default: + break; + } + break; + + case HCI_EVENT_DISCONNECTION_COMPLETE: + sm_state_responding = SM_STATE_IDLE; + sm_response_handle = 0; + break; + } + + // forward packet to higher layer + if (sm_client_packet_handler){ + sm_client_packet_handler(packet_type, 0, packet, size); + } + } + + // try to send preparared packet + sm_run(); +} + +static void sm_run(void){ + + // assert that we can send either one + if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) return; + if (!hci_can_send_packet_now(HCI_ACL_DATA_PACKET)) return; + + switch (sm_state_responding){ + case SM_STATE_SEND_LTK_REQUESTED_NEGATIVE_REPLY: + hci_send_cmd(&hci_le_long_term_key_negative_reply, sm_response_handle); + sm_state_responding = SM_STATE_IDLE; + return; + case SM_STATE_SEND_PAIRING_FAILED: { + uint8_t buffer[2]; + buffer[0] = SM_CODE_PAIRING_FAILED; + buffer[1] = sm_pairing_failed_reason; + l2cap_send_connectionless(sm_response_handle, L2CAP_CID_SECURITY_MANAGER_PROTOCOL, (uint8_t*) buffer, sizeof(buffer)); + sm_state_responding = SM_STATE_IDLE; + break; + } + default: + break; + } +} + +void sm_init(){ + // attach to lower layers + l2cap_register_fixed_channel(sm_packet_handler, L2CAP_CID_SECURITY_MANAGER_PROTOCOL); + l2cap_register_packet_handler(sm_event_packet_handler); +} + +// GAP LE +void gap_random_address_set_mode(gap_random_address_type_t random_address_type){} +void gap_random_address_set_update_period(int period_ms){} + +// Central Device db interface +void central_device_db_init(){} + +// @returns index if successful, -1 otherwise +int central_device_db_add(int addr_type, bd_addr_t addr, sm_key_t irk, sm_key_t csrk){ + return -1; +} + +// @returns number of device in db +int central_device_db_count(void){ + return 0; +} + +// get device information: addr type and address +void central_device_db_info(int index, int * addr_type, bd_addr_t addr, sm_key_t csrk){} + +// get signature key +void central_device_db_csrk(int index, sm_key_t csrk){} + +// query last used/seen signing counter +uint32_t central_device_db_counter_get(int index){ + return 0xffffffff; +} + +// update signing counter +void central_device_db_counter_set(int index, uint32_t counter){} + +// free device +void central_device_db_remove(int index){} + diff --git a/example/libusb/Makefile b/example/libusb/Makefile index 6e4146d5c..15e3c43ae 100644 --- a/example/libusb/Makefile +++ b/example/libusb/Makefile @@ -28,23 +28,33 @@ COMMON = \ ${BTSTACK_ROOT}/src/sdp_parser.c \ ${BTSTACK_ROOT}/src/sdp_query_util.c \ ${BTSTACK_ROOT}/src/sdp_query_rfcomm.c \ + +ATT = \ ${BTSTACK_ROOT}/ble/att.c \ ${BTSTACK_ROOT}/ble/att_server.c \ - ${BTSTACK_ROOT}/ble/sm.c \ - ${BTSTACK_ROOT}/ble/central_device_db_memory.c \ CC2564 = \ ${BTSTACK_ROOT}/chipset-cc256x/bt_control_cc256x.c \ ${BTSTACK_ROOT}/chipset-cc256x/bluetooth_init_cc2564_2.10.c \ +SM_REAL = \ + ${BTSTACK_ROOT}/ble/sm.c \ + ${BTSTACK_ROOT}/ble/central_device_db_memory.c \ + +SM_MINIMAL = \ + ${BTSTACK_ROOT}/ble/sm_minimal.c \ + CORE_OBJ = $(CORE:.c=.o) COMMON_OBJ = $(COMMON:.c=.o) CC2564_OBJ = $(CC2564:.c=.o) +SM_REAL_OBJ = $(SM_REAL:.c=.o) +SM_MINIMAL_OBJ = $(SM_MINIMAL:.c=.o) +ATT_OBJ = $(ATT:.c=.o) # create firmware image from common objects and example source file -all: ../../include/btstack/version.h ble_client ble_client_uart sdp_rfcomm_query sdp_general_query spp_counter ble_peripheral +all: ../../include/btstack/version.h ble_client ble_client_uart sdp_rfcomm_query sdp_general_query spp_counter ble_peripheral ble_peripheral_sm_minimal #spp-usb l2cap-server-usb l2cap-client-usb l2cap-server-uart l2cap-client-uart @@ -67,8 +77,11 @@ spp_counter_ssp: ${CORE_OBJ} ${COMMON_OBJ} spp_counter_ssp.c profile.h: profile.gatt python ${BTSTACK_ROOT}/ble/compile-gatt.py $< $@ -ble_peripheral: ${CORE_OBJ} ${COMMON_OBJ} ble_peripheral.c profile.h - ${CC} ${CORE_OBJ} ${COMMON_OBJ} ble_peripheral.c ${CFLAGS} ${LDFLAGS} -o $@ +ble_peripheral: ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${SM_REAL_OBJ} ble_peripheral.c profile.h + ${CC} ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${SM_REAL_OBJ} ble_peripheral.c ${CFLAGS} ${LDFLAGS} -o $@ + +ble_peripheral_sm_minimal: ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${SM_MINIMAL_OBJ} ble_peripheral.c profile.h + ${CC} ${CORE_OBJ} ${COMMON_OBJ} ${ATT_OBJ} ${SM_MINIMAL_OBJ} ble_peripheral.c ${CFLAGS} ${LDFLAGS} -o $@ ble_client: ${CORE_OBJ} ${COMMON_OBJ} ble_client.c ad_parser.c ${CC} ${CORE_OBJ} ${COMMON_OBJ} ad_parser.c ble_client.c ${CFLAGS} ${LDFLAGS} -o $@