From b512db213a88a152e06aba248017252b4d6745cc Mon Sep 17 00:00:00 2001 From: "matthias.ringwald@gmail.com" Date: Mon, 6 Jan 2014 17:43:46 +0000 Subject: [PATCH] more security checkes --- ble/att.c | 122 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 96 insertions(+), 26 deletions(-) diff --git a/ble/att.c b/ble/att.c index 28f2a4dc1..74398fad7 100644 --- a/ble/att.c +++ b/ble/att.c @@ -82,6 +82,12 @@ static int is_Bluetooth_Base_UUID(uint8_t const *uuid){ } +static uint16_t uuid16_from_uuid(uint16_t uuid_len, uint8_t * uuid){ + if (uuid_len == 2) return READ_BT_16(uuid, 0); + if (!is_Bluetooth_Base_UUID(uuid)) return 0; + return READ_BT_16(uuid, 12); +} + // ATT Database static uint8_t const * att_db = NULL; static att_read_callback_t att_read_callback = NULL; @@ -231,7 +237,11 @@ static uint16_t setup_error(uint8_t * response_buffer, uint16_t request, uint16_ return 5; } -static inline uint16_t setup_error_write_not_permited(uint8_t * response_buffer, uint16_t request, uint16_t start_handle){ +static inline uint16_t setup_error_read_not_permitted(uint8_t * response_buffer, uint16_t request, uint16_t start_handle){ + return setup_error(response_buffer, request, start_handle, ATT_ERROR_READ_NOT_PERMITTED); +} + +static inline uint16_t setup_error_write_not_permitted(uint8_t * response_buffer, uint16_t request, uint16_t start_handle){ return setup_error(response_buffer, request, start_handle, ATT_ERROR_WRITE_NOT_PERMITTED); } @@ -247,6 +257,23 @@ static inline uint16_t setup_error_invalid_offset(uint8_t * response_buffer, uin return setup_error(response_buffer, request, handle, ATT_ERROR_INVALID_OFFSET); } +static uint8_t att_validate_security(att_connection_t * att_connection, att_iterator_t * it){ + int required_encryption_size = it->flags >> 24; + if (required_encryption_size > 0 && att_connection->encryption_key_size == 0){ + return ATT_ERROR_INSUFFICIENT_ENCRYPTION; + } + if (required_encryption_size > att_connection->encryption_key_size){ + return ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE; + } + if ((it->flags & ATT_PROPERTY_AUTHENTICATION_REQUIRED) && att_connection->authenticated == 0) { + return ATT_ERROR_INSUFFICIENT_AUTHENTICATION; + } + if ((it->flags & ATT_PROPERTY_AUTHORIZATION_REQUIRED) && att_connection->authorized == 0) { + return ATT_ERROR_INSUFFICIENT_AUTHORIZATION; + } + return 0; +} + // // MARK: ATT_EXCHANGE_MTU_REQUEST // @@ -409,23 +436,6 @@ static uint16_t handle_find_by_type_value_request(att_connection_t * att_connect READ_BT_16(request_buffer, 3), READ_BT_16(request_buffer, 5), attribute_len, &request_buffer[7]); } -uint8_t att_validate_security(att_connection_t * att_connection, att_iterator_t * it){ - int required_encryption_size = it->flags >> 24; - if (required_encryption_size > 0 && att_connection->encryption_key_size == 0){ - return ATT_ERROR_INSUFFICIENT_ENCRYPTION; - } - if (required_encryption_size > att_connection->encryption_key_size){ - return ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE; - } - if ((it->flags & ATT_PROPERTY_AUTHENTICATION_REQUIRED) && att_connection->authenticated == 0) { - return ATT_ERROR_INSUFFICIENT_AUTHENTICATION; - } - if ((it->flags & ATT_PROPERTY_AUTHORIZATION_REQUIRED) && att_connection->authorized == 0) { - return ATT_ERROR_INSUFFICIENT_AUTHORIZATION; - } - return 0; -} - // // MARK: ATT_READ_BY_TYPE_REQUEST // @@ -532,6 +542,17 @@ static uint16_t handle_read_request2(att_connection_t * att_connection, uint8_t return setup_error_atribute_not_found(response_buffer, ATT_READ_REQUEST, handle); } + // check if handle can be read + if ((it.flags & ATT_PROPERTY_READ) == 0) { + return setup_error_read_not_permitted(response_buffer, ATT_READ_REQUEST, handle); + } + + // check security requirements + uint8_t error_code = att_validate_security(att_connection, &it); + if (error_code) { + return setup_error(response_buffer, ATT_READ_REQUEST, handle, error_code); + } + att_update_value_len(&it); uint16_t offset = 1; @@ -565,6 +586,17 @@ static uint16_t handle_read_blob_request2(att_connection_t * att_connection, uin return setup_error_atribute_not_found(response_buffer, ATT_READ_BLOB_REQUEST, handle); } + // check if handle can be read + if ((it.flags & ATT_PROPERTY_READ) == 0) { + return setup_error_read_not_permitted(response_buffer, ATT_READ_REQUEST, handle); + } + + // check security requirements + uint8_t error_code = att_validate_security(att_connection, &it); + if (error_code) { + return setup_error(response_buffer, ATT_READ_REQUEST, handle, error_code); + } + att_update_value_len(&it); if (value_offset >= it.value_len){ @@ -596,11 +628,17 @@ uint16_t handle_read_blob_request(att_connection_t * att_connection, uint8_t * r static uint16_t handle_read_multiple_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t num_handles, uint16_t * handles){ printf("ATT_READ_MULTIPLE_REQUEST: num handles %u\n", num_handles); + // TODO: figure out which error to respond with + // if (num_handles < 2){ + // return setup_error(response_buffer, ATT_READ_MULTIPLE_REQUEST, handle, ???); + // } + uint16_t offset = 1; int i; + uint8_t error_code = 0; + uint16_t handle = handles[i]; for (i=0;i end_handle || start_handle == 0){ + return setup_error_invalid_handle(response_buffer, ATT_READ_BY_TYPE_REQUEST, start_handle); + } + + // assert UUID is primary or secondary service uuid + uint16_t uuid16 = uuid16_from_uuid(attribute_type_len, attribute_type); + if (uuid16 != GATT_PRIMARY_SERVICE_UUID && uuid16 != GATT_SECONDARY_SERVICE_UUID){ + return setup_error(response_buffer, ATT_READ_BY_GROUP_TYPE_REQUEST, start_handle, ATT_ERROR_UNSUPPORTED_GROUP_TYPE); + } + uint16_t offset = 1; uint16_t pair_len = 0; uint16_t in_group = 0; @@ -666,7 +737,6 @@ static uint16_t handle_read_by_group_type_request2(att_connection_t * att_connec // close current tag, if within a group and a new service definition starts or we reach end of att db if (in_group && (it.handle == 0 || att_iterator_match_uuid16(&it, GATT_PRIMARY_SERVICE_UUID) || att_iterator_match_uuid16(&it, GATT_SECONDARY_SERVICE_UUID))){ - // TODO: check if handle is included in start/end range // printf("End of group, handle 0x%04x, val_len: %u\n", prev_handle, pair_len - 4); bt_store_16(response_buffer, offset, group_start_handle); @@ -742,10 +812,10 @@ static uint16_t handle_write_request(att_connection_t * att_connection, uint8_t return setup_error_atribute_not_found(response_buffer, ATT_WRITE_REQUEST, handle); } if (!att_write_callback) { - return setup_error_write_not_permited(response_buffer, ATT_WRITE_REQUEST, handle); + return setup_error_write_not_permitted(response_buffer, ATT_WRITE_REQUEST, handle); } if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) { - return setup_error_write_not_permited(response_buffer, ATT_WRITE_REQUEST, handle); + return setup_error_write_not_permitted(response_buffer, ATT_WRITE_REQUEST, handle); } (*att_write_callback)(handle, ATT_TRANSACTION_MODE_NONE, 0, request_buffer + 3, request_len - 3, NULL); response_buffer[0] = ATT_WRITE_RESPONSE; @@ -758,7 +828,7 @@ static uint16_t handle_prepare_write_request(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size){ uint16_t handle = READ_BT_16(request_buffer, 1); if (!att_write_callback) { - return setup_error_write_not_permited(response_buffer, ATT_PREPARE_WRITE_REQUEST, handle); + return setup_error_write_not_permitted(response_buffer, ATT_PREPARE_WRITE_REQUEST, handle); } att_iterator_t it; int ok = att_find_handle(&it, handle); @@ -766,7 +836,7 @@ static uint16_t handle_prepare_write_request(att_connection_t * att_connection, return setup_error_atribute_not_found(response_buffer, ATT_WRITE_REQUEST, handle); } if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) { - return setup_error_write_not_permited(response_buffer, ATT_WRITE_REQUEST, handle); + return setup_error_write_not_permitted(response_buffer, ATT_WRITE_REQUEST, handle); } (*att_write_callback)(handle, ATT_TRANSACTION_MODE_ACTIVE, 0, request_buffer + 3, request_len - 3, NULL); @@ -780,7 +850,7 @@ static uint16_t handle_prepare_write_request(att_connection_t * att_connection, static uint16_t handle_execute_write_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, uint8_t * response_buffer, uint16_t response_buffer_size){ if (!att_write_callback) { - return setup_error_write_not_permited(response_buffer, ATT_EXECUTE_WRITE_REQUEST, 0); + return setup_error_write_not_permitted(response_buffer, ATT_EXECUTE_WRITE_REQUEST, 0); } if (request_buffer[1]) { (*att_write_callback)(0, ATT_TRANSACTION_MODE_EXECUTE, 0, request_buffer + 3, request_len - 3, NULL);