From 7a766ebf4fe397f360afa0cacdab95c06b8cb0f1 Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Fri, 13 Jan 2017 18:56:26 +0100 Subject: [PATCH] LE: require ENABLE_LE_SIGNED_WRITE for ATT/GATT Signed Writes --- doc/manual/docs/how_to.md | 1 + src/ble/att_db.c | 2 ++ src/ble/att_server.c | 6 ++++-- src/ble/gatt_client.c | 11 ++++++++++ src/ble/sm.c | 44 +++++++++++++++++++++++++++------------ 5 files changed, 49 insertions(+), 15 deletions(-) diff --git a/doc/manual/docs/how_to.md b/doc/manual/docs/how_to.md index 93cbb551e..4cf46f211 100644 --- a/doc/manual/docs/how_to.md +++ b/doc/manual/docs/how_to.md @@ -76,6 +76,7 @@ ENABLE_LOG_INTO_HCI_DUMP | Log debug messages as part of packet log ENABLE_SCO_OVER_HCI | Enable SCO over HCI for chipsets (only CC256x/WL18xx and USB CSR controllers) ENABLE_LE_SECURE_CONNECTIONS | Enable LE Secure Connections using [mbed TLS library](https://tls.mbed.org) ENABLE_LE_DATA_CHANNELS | Enable LE Data Channels in credit-based flow control mode +ENABLE_LE_SIGNED_WRITE | Enable LE Signed Writes in ATT/GATT ### Memory configuration directives {#sec:memoryConfigurationHowTo} diff --git a/src/ble/att_db.c b/src/ble/att_db.c index fb8df605a..87ee0f290 100644 --- a/src/ble/att_db.c +++ b/src/ble/att_db.c @@ -1120,9 +1120,11 @@ uint16_t att_handle_request(att_connection_t * att_connection, case ATT_WRITE_COMMAND: handle_write_command(att_connection, request_buffer, request_len, response_buffer, response_buffer_size); break; +#ifdef ENABLE_LE_SIGNED_WRITE case ATT_SIGNED_WRITE_COMMAND: log_info("handle_signed_write_command preprocessed by att_server.c"); break; +#endif default: log_info("Unhandled ATT Command: %02X, DATA: ", request_buffer[0]); log_info_hexdump(&request_buffer[9], request_len-9); diff --git a/src/ble/att_server.c b/src/ble/att_server.c index aba1e01d8..0723b9d00 100644 --- a/src/ble/att_server.c +++ b/src/ble/att_server.c @@ -235,6 +235,7 @@ static void att_event_packet_handler (uint8_t packet_type, uint16_t channel, uin } } +#ifdef ENABLE_LE_SIGNED_WRITE static void att_signed_write_handle_cmac_result(uint8_t hash[8]){ att_server_t * att_server = att_server_for_state(ATT_SERVER_W4_SIGNED_WRITE_VALIDATION); @@ -255,7 +256,7 @@ static void att_signed_write_handle_cmac_result(uint8_t hash[8]){ att_server->state = ATT_SERVER_REQUEST_RECEIVED_AND_VALIDATED; att_dispatch_server_request_can_send_now_event(att_server->connection.con_handle); } - +#endif // pre: att_server->state == ATT_SERVER_REQUEST_RECEIVED_AND_VALIDATED // pre: can send now @@ -303,6 +304,7 @@ static int att_server_process_validated_request(att_server_t * att_server){ static void att_run_for_context(att_server_t * att_server){ switch (att_server->state){ case ATT_SERVER_REQUEST_RECEIVED: +#ifdef ENABLE_LE_SIGNED_WRITE if (att_server->request_buffer[0] == ATT_SIGNED_WRITE_COMMAND){ log_info("ATT Signed Write!"); if (!sm_cmac_ready()) { @@ -344,7 +346,7 @@ static void att_run_for_context(att_server_t * att_server){ sm_cmac_signed_write_start(csrk, att_server->request_buffer[0], attribute_handle, att_server->request_size - 15, &att_server->request_buffer[3], counter_packet, att_signed_write_handle_cmac_result); return; } - +#endif // move on att_server->state = ATT_SERVER_REQUEST_RECEIVED_AND_VALIDATED; att_dispatch_server_request_can_send_now_event(att_server->connection.con_handle); diff --git a/src/ble/gatt_client.c b/src/ble/gatt_client.c index 7b7f108bd..b94570a37 100644 --- a/src/ble/gatt_client.c +++ b/src/ble/gatt_client.c @@ -68,7 +68,10 @@ static uint8_t pts_suppress_mtu_exchange; static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle, uint8_t *packet, uint16_t size); static void gatt_client_hci_event_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); static void gatt_client_report_error_if_pending(gatt_client_t *peripheral, uint8_t error_code); + +#ifdef ENABLE_LE_SIGNED_WRITE static void att_signed_write_handle_cmac_result(uint8_t hash[8]); +#endif static uint16_t peripheral_mtu(gatt_client_t *peripheral){ if (peripheral->mtu > l2cap_max_le_mtu()){ @@ -275,6 +278,7 @@ static void att_read_multiple_request(uint16_t peripheral_handle, uint16_t num_v l2cap_send_prepared_connectionless(peripheral_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, offset); } +#ifdef ENABLE_LE_SIGNED_WRITE // precondition: can_send_packet_now == TRUE static void att_signed_write_request(uint16_t request_type, uint16_t peripheral_handle, uint16_t attribute_handle, uint16_t value_length, uint8_t * value, uint32_t sign_counter, uint8_t sgn[8]){ l2cap_reserve_packet_buffer(); @@ -286,6 +290,7 @@ static void att_signed_write_request(uint16_t request_type, uint16_t peripheral_ reverse_64(sgn, &request[3 + value_length + 4]); l2cap_send_prepared_connectionless(peripheral_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, 3 + value_length + 12); } +#endif // precondition: can_send_packet_now == TRUE static void att_write_request(uint16_t request_type, uint16_t peripheral_handle, uint16_t attribute_handle, uint16_t value_length, uint8_t * value){ @@ -424,9 +429,11 @@ static void send_gatt_read_characteristic_descriptor_request(gatt_client_t * per att_read_request(ATT_READ_REQUEST, peripheral->con_handle, peripheral->attribute_handle); } +#ifdef ENABLE_LE_SIGNED_WRITE static void send_gatt_signed_write_request(gatt_client_t * peripheral, uint32_t sign_counter){ att_signed_write_request(ATT_SIGNED_WRITE_COMMAND, peripheral->con_handle, peripheral->attribute_handle, peripheral->attribute_length, peripheral->attribute_value, sign_counter, peripheral->cmac); } +#endif static uint16_t get_last_result_handle_from_service_list(uint8_t * packet, uint16_t size){ uint8_t attr_length = packet[1]; @@ -960,6 +967,7 @@ static void gatt_client_run(void){ send_gatt_execute_write_request(peripheral); return; +#ifdef ENABLE_LE_SIGNED_WRITE case P_W4_CMAC_READY: if (sm_cmac_ready()){ sm_key_t csrk; @@ -982,6 +990,7 @@ static void gatt_client_run(void){ gatt_client_handle_transaction_complete(peripheral); return; } +#endif default: break; @@ -1346,6 +1355,7 @@ static void gatt_client_att_packet_handler(uint8_t packet_type, uint16_t handle, gatt_client_run(); } +#ifdef ENABLE_LE_SIGNED_WRITE static void att_signed_write_handle_cmac_result(uint8_t hash[8]){ btstack_linked_list_iterator_t it; btstack_linked_list_iterator_init(&it, &gatt_client_connections); @@ -1377,6 +1387,7 @@ uint8_t gatt_client_signed_write_without_response(btstack_packet_handler_t callb gatt_client_run(); return 0; } +#endif uint8_t gatt_client_discover_primary_services(btstack_packet_handler_t callback, hci_con_handle_t con_handle){ gatt_client_t * peripheral = provide_context_for_conn_handle_and_start_timer(con_handle); diff --git a/src/ble/sm.c b/src/ble/sm.c index 52c443692..40e618d02 100644 --- a/src/ble/sm.c +++ b/src/ble/sm.c @@ -68,6 +68,10 @@ #include "sm_mbedtls_allocator.h" #endif +#if defined(ENABLE_LE_SIGNED_WRITE) || defined(ENABLE_LE_SECURE_CONNECTIONS) +#define ENABLE_CMAC_ENGINE +#endif + // // SM internal types and globals // @@ -180,6 +184,7 @@ static random_address_update_t rau_state; static bd_addr_t sm_random_address; // CMAC Calculation: General +#ifdef ENABLE_CMAC_ENGINE static cmac_state_t sm_cmac_state; static uint16_t sm_cmac_message_len; static sm_key_t sm_cmac_k; @@ -189,11 +194,14 @@ static uint8_t sm_cmac_block_current; static uint8_t sm_cmac_block_count; static uint8_t (*sm_cmac_get_byte)(uint16_t offset); static void (*sm_cmac_done_handler)(uint8_t * hash); +#endif // CMAC for ATT Signed Writes +#ifdef ENABLE_LE_SIGNED_WRITE static uint8_t sm_cmac_header[3]; static const uint8_t * sm_cmac_message; static uint8_t sm_cmac_sign_counter[4]; +#endif // CMAC for Secure Connection functions #ifdef ENABLE_LE_SECURE_CONNECTIONS @@ -363,7 +371,6 @@ static void sm_done_for_handle(hci_con_handle_t con_handle); static sm_connection_t * sm_get_connection_for_handle(hci_con_handle_t con_handle); static inline int sm_calc_actual_encryption_key_size(int other); static int sm_validate_stk_generation_method(void); -static void sm_shift_left_by_one_bit_inplace(int len, uint8_t * data); static void log_info_hex16(const char * name, uint16_t value){ log_info("%-6s 0x%04x", name, value); @@ -841,17 +848,6 @@ int sm_address_resolution_lookup(uint8_t address_type, bd_addr_t address){ return 0; } -// CMAC Implementation using AES128 engine -static void sm_shift_left_by_one_bit_inplace(int len, uint8_t * data){ - int i; - int carry = 0; - for (i=len-1; i >= 0 ; i--){ - int new_carry = data[i] >> 7; - data[i] = data[i] << 1 | carry; - carry = new_carry; - } -} - // while x_state++ for an enum is possible in C, it isn't in C++. we use this helpers to avoid compile errors for now static inline void sm_next_responding_state(sm_connection_t * sm_conn){ sm_conn->sm_engine_state = (security_manager_state_t) (((int)sm_conn->sm_engine_state) + 1); @@ -864,6 +860,7 @@ static inline void rau_next_state(void){ } // CMAC calculation using AES Engine +#ifdef ENABLE_CMAC_ENGINE static inline void sm_cmac_next_state(void){ sm_cmac_state = (cmac_state_t) (((int)sm_cmac_state) + 1); @@ -903,8 +900,10 @@ void sm_cmac_general_start(const sm_key_t key, uint16_t message_len, uint8_t (*g // let's go sm_run(); } +#endif // cmac for ATT Message signing +#ifdef ENABLE_LE_SIGNED_WRITE static uint8_t sm_cmac_signed_write_message_get_byte(uint16_t offset){ if (offset >= sm_cmac_message_len) { log_error("sm_cmac_signed_write_message_get_byte. out of bounds, access %u, len %u", offset, sm_cmac_message_len); @@ -933,8 +932,9 @@ void sm_cmac_signed_write_start(const sm_key_t k, uint8_t opcode, hci_con_handle sm_cmac_message = message; sm_cmac_general_start(k, total_message_len, &sm_cmac_signed_write_message_get_byte, done_handler); } +#endif - +#ifdef ENABLE_CMAC_ENGINE static void sm_cmac_handle_aes_engine_ready(void){ switch (sm_cmac_state){ case CMAC_CALC_SUBKEYS: { @@ -973,6 +973,17 @@ static void sm_cmac_handle_aes_engine_ready(void){ } } +// CMAC Implementation using AES128 engine +static void sm_shift_left_by_one_bit_inplace(int len, uint8_t * data){ + int i; + int carry = 0; + for (i=len-1; i >= 0 ; i--){ + int new_carry = data[i] >> 7; + data[i] = data[i] << 1 | carry; + carry = new_carry; + } +} + static void sm_cmac_handle_encryption_result(sm_key_t data){ switch (sm_cmac_state){ case CMAC_W4_SUBKEYS: { @@ -1034,6 +1045,7 @@ static void sm_cmac_handle_encryption_result(sm_key_t data){ break; } } +#endif static void sm_trigger_user_response(sm_connection_t * sm_conn){ // notify client for: JUST WORKS confirm, Numeric comparison confirm, PASSKEY display or input @@ -1857,6 +1869,7 @@ static void sm_run(void){ break; } +#ifdef ENABLE_CMAC_ENGINE // CMAC switch (sm_cmac_state){ case CMAC_CALC_SUBKEYS: @@ -1869,6 +1882,7 @@ static void sm_run(void){ default: break; } +#endif // CSRK Lookup // -- if csrk lookup ready, find connection that require csrk lookup @@ -2583,6 +2597,7 @@ static void sm_handle_encryption_result(uint8_t * data){ break; } +#ifdef ENABLE_CMAC_ENGINE switch (sm_cmac_state){ case CMAC_W4_SUBKEYS: case CMAC_W4_MI: @@ -2596,6 +2611,7 @@ static void sm_handle_encryption_result(uint8_t * data){ default: break; } +#endif // retrieve sm_connection provided to sm_aes128_start_encryption sm_connection_t * connection = (sm_connection_t*) sm_aes128_context; @@ -3635,7 +3651,9 @@ void sm_init(void){ sm_max_encryption_key_size = 16; sm_min_encryption_key_size = 7; +#ifdef ENABLE_CMAC_ENGINE sm_cmac_state = CMAC_IDLE; +#endif dkg_state = DKG_W4_WORKING; rau_state = RAU_W4_WORKING; sm_aes128_state = SM_AES128_IDLE;