Nordic BLE: Update GATT server security management

This patch refines permission applied to characteristic and descriptors; instead of a single level of permission , each characteristic receives a permission for the read operation, one for the write operation and another one for the update operation.

As a consequence, updates are not sent if the link does not cover the update permission requirement.

Descriptors also benefits individually from read and write permission.
pull/6932/head
Vincent Coubard 2018-05-02 19:15:24 +01:00
parent 4f1e574eff
commit 0a59e00b23
3 changed files with 79 additions and 68 deletions

View File

@ -30,6 +30,34 @@ typedef struct {
static unsigned uuidTableEntries = 0; /* current usage of the table */
converted_uuid_table_entry_t convertedUUIDTable[UUID_TABLE_MAX_ENTRIES];
namespace {
static void set_perm(ble_gap_conn_sec_mode_t& dest, GattAttribute::Security_t src) {
switch (src.value()) {
case GattAttribute::Security_t::NONE:
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&dest);
break;
case GattAttribute::Security_t::UNAUTHENTICATED:
BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&dest);
break;
case GattAttribute::Security_t::AUTHENTICATED:
BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(&dest);
break;
case GattAttribute::Security_t::SC_AUTHENTICATED:
BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(&dest);
break;
default:
break;
}
}
}
void custom_reset_128bits_uuid_table() {
uuidTableEntries = 0;
}
@ -203,7 +231,9 @@ error_t custom_decode_uuid_base(uint8_t const *const p_uuid_base,
error_t custom_add_in_characteristic(uint16_t service_handle,
ble_uuid_t *p_uuid,
uint8_t properties,
SecurityManager::SecurityMode_t requiredSecurity,
GattAttribute::Security_t read_security,
GattAttribute::Security_t write_security,
GattAttribute::Security_t update_security,
uint8_t *p_data,
uint16_t length,
uint16_t max_length,
@ -226,8 +256,8 @@ error_t custom_add_in_characteristic(uint16_t service_handle,
/* Notification requires cccd */
memclr_( &cccd_md, sizeof(ble_gatts_attr_md_t));
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
set_perm(cccd_md.read_perm, GattAttribute::Security_t::NONE);
set_perm(cccd_md.write_perm, update_security);
}
ble_gatts_char_md_t char_md = {0};
@ -256,49 +286,8 @@ error_t custom_add_in_characteristic(uint16_t service_handle,
/* Always set variable size */
attr_md.vlen = has_variable_len;
if (char_props.read || char_props.notify || char_props.indicate) {
switch (requiredSecurity) {
case SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK :
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
break;
case SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM :
BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.read_perm);
break;
case SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM :
BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(&attr_md.read_perm);
break;
case SecurityManager::SECURITY_MODE_SIGNED_NO_MITM :
BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(&attr_md.read_perm);
break;
case SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM :
BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(&attr_md.read_perm);
break;
default:
break;
};
}
if (char_props.write || char_props.write_wo_resp) {
switch (requiredSecurity) {
case SecurityManager::SECURITY_MODE_ENCRYPTION_OPEN_LINK :
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
break;
case SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM :
BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&attr_md.write_perm);
break;
case SecurityManager::SECURITY_MODE_ENCRYPTION_WITH_MITM :
BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(&attr_md.write_perm);
break;
case SecurityManager::SECURITY_MODE_SIGNED_NO_MITM :
BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(&attr_md.write_perm);
break;
case SecurityManager::SECURITY_MODE_SIGNED_WITH_MITM :
BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(&attr_md.write_perm);
break;
default:
break;
};
}
set_perm(attr_md.read_perm, read_security);
set_perm(attr_md.write_perm, write_security);
ble_gatts_attr_t attr_char_value = {0};
@ -342,7 +331,9 @@ error_t custom_add_in_descriptor(uint16_t char_handle,
uint16_t length,
uint16_t max_length,
bool has_variable_len,
uint16_t *p_desc_handle)
uint16_t *p_desc_handle,
GattAttribute::Security_t read_security,
GattAttribute::Security_t write_security)
{
/* Descriptor metadata */
ble_gatts_attr_md_t desc_md = {0};
@ -352,8 +343,8 @@ error_t custom_add_in_descriptor(uint16_t char_handle,
desc_md.vlen = has_variable_len;
/* Make it readable and writable */
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&desc_md.write_perm);
set_perm(desc_md.read_perm, read_security);
set_perm(desc_md.write_perm, write_security);
ble_gatts_attr_t attr_desc = {0};

View File

@ -45,7 +45,9 @@ ble_uuid_t custom_convert_to_nordic_uuid(const UUID &uuid);
error_t custom_add_in_characteristic(uint16_t service_handle,
ble_uuid_t *p_uuid,
uint8_t properties,
SecurityManager::SecurityMode_t requiredSecurity,
GattAttribute::Security_t read_security,
GattAttribute::Security_t write_security,
GattAttribute::Security_t update_security,
uint8_t *p_data,
uint16_t length,
uint16_t max_length,
@ -64,7 +66,9 @@ error_t custom_add_in_descriptor(uint16_t char_handle,
uint16_t length,
uint16_t max_length,
bool has_variable_len,
uint16_t *p_desc_handle);
uint16_t *p_desc_handle,
GattAttribute::Security_t read_security,
GattAttribute::Security_t write_security);
#ifdef __cplusplus
}

View File

@ -25,6 +25,7 @@
#include "btle/custom/custom_helper.h"
#include "nRF5xn.h"
#include "nrf_ble_gap.h"
namespace {
@ -164,21 +165,25 @@ ble_error_t nRF5xGattServer::addService(GattService &service)
}
ASSERT_TRUE ( ERROR_NONE ==
custom_add_in_characteristic(BLE_GATT_HANDLE_INVALID,
&nordicUUID,
p_char->getProperties(),
p_char->getRequiredSecurity(),
p_char->getValueAttribute().getValuePtr(),
p_char->getValueAttribute().getLength(),
p_char->getValueAttribute().getMaxLength(),
p_char->getValueAttribute().hasVariableLength(),
userDescriptionDescriptorValuePtr,
userDescriptionDescriptorValueLen,
presentationFormatDescriptorValuePtr,
presentationFormatDescriptorValueLen,
p_char->isReadAuthorizationEnabled(),
p_char->isWriteAuthorizationEnabled(),
&nrfCharacteristicHandles[characteristicCount]),
custom_add_in_characteristic(
BLE_GATT_HANDLE_INVALID,
&nordicUUID,
p_char->getProperties(),
p_char->getReadSecurityRequirement(),
p_char->getWriteSecurityRequirement(),
p_char->getUpdateSecurityRequirement(),
p_char->getValueAttribute().getValuePtr(),
p_char->getValueAttribute().getLength(),
p_char->getValueAttribute().getMaxLength(),
p_char->getValueAttribute().hasVariableLength(),
userDescriptionDescriptorValuePtr,
userDescriptionDescriptorValueLen,
presentationFormatDescriptorValuePtr,
presentationFormatDescriptorValueLen,
p_char->isReadAuthorizationEnabled(),
p_char->isWriteAuthorizationEnabled(),
&nrfCharacteristicHandles[characteristicCount]
),
BLE_ERROR_PARAM_OUT_OF_RANGE );
/* Update the characteristic handle */
@ -218,7 +223,9 @@ ble_error_t nRF5xGattServer::addService(GattService &service)
p_desc->getLength(),
p_desc->getMaxLength(),
p_desc->hasVariableLength(),
&nrfDescriptorHandles[descriptorCount]),
&nrfDescriptorHandles[descriptorCount],
p_desc->getReadSecurityRequirement(),
p_desc->getWriteSecurityRequirement()),
BLE_ERROR_PARAM_OUT_OF_RANGE);
p_descriptors[descriptorCount] = p_desc;
@ -345,7 +352,16 @@ ble_error_t nRF5xGattServer::write(Gap::Handle_t connectionHandle, GattAttribute
}
}
if (updatesEnabled) {
bool updates_permitted = false;
ble_gap_conn_sec_t connection_security;
uint32_t err = sd_ble_gap_conn_sec_get(connectionHandle, &connection_security);
if (!err &&
(connection_security.sec_mode.sm == 1) &&
(connection_security.sec_mode.lv >= p_characteristics[characteristicIndex]->getUpdateSecurityRequirement().value())) {
updates_permitted = true;
}
if (updatesEnabled && updates_permitted) {
error_t error = (error_t) sd_ble_gatts_hvx(connectionHandle, &hvx_params);
if (error != ERROR_NONE) {
switch (error) {