diff --git a/features/FEATURE_BLE/ble/GattClient.h b/features/FEATURE_BLE/ble/GattClient.h index 137304bc23..cabfaf9a19 100644 --- a/features/FEATURE_BLE/ble/GattClient.h +++ b/features/FEATURE_BLE/ble/GattClient.h @@ -116,6 +116,15 @@ public: * The server does not acknowledge the status of the operation. */ GATT_OP_WRITE_CMD = 0x02, + + /** + * Signed Write command. + * + * It is used to request the server to write the value of an attribute + * using a signed packet. The server does not acknowledge the status + * of the operation. + */ + GATT_OP_SIGNED_WRITE_CMD = 0x03 }; /** diff --git a/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h b/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h index 583097fa76..9d40acec97 100644 --- a/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h +++ b/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h @@ -313,13 +313,24 @@ private: * Returns the CSRK for the connection. Called by the security db. * * @param[in] connectionHandle Handle to identify the connection. - * @param[in] entryKeys security entry containing keys. + * @param[in] csrk connection signature resolving key. */ void return_csrk_cb( pal::SecurityDb::entry_handle_t connection, const csrk_t *csrk ); + /** + * Set the peer CSRK for the connection. Called by the security db. + * + * @param[in] connectionHandle Handle to identify the connection. + * @param[in] csrk connection signature resolving key. + */ + void set_peer_csrk_cb( + pal::SecurityDb::entry_handle_t connection, + const csrk_t *csrk + ); + /** * Updates the entry for the connection with OOB data presence. * diff --git a/features/FEATURE_BLE/ble/pal/PalSecurityManager.h b/features/FEATURE_BLE/ble/pal/PalSecurityManager.h index 5dca19404b..d99aee2d5c 100644 --- a/features/FEATURE_BLE/ble/pal/PalSecurityManager.h +++ b/features/FEATURE_BLE/ble/pal/PalSecurityManager.h @@ -866,6 +866,18 @@ public: const csrk_t &csrk ) = 0; + /** + * Set the peer CSRK for particular connection. + * + * @param[in] connection connection handle + * @param[in] csrk signing key + * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + */ + virtual ble_error_t set_peer_csrk( + connection_handle_t connection, + const csrk_t &csrk + ) = 0; + //////////////////////////////////////////////////////////////////////////// // Authentication // diff --git a/features/FEATURE_BLE/source/generic/GenericGattClient.cpp b/features/FEATURE_BLE/source/generic/GenericGattClient.cpp index 97c6d57fc0..2309d7a79a 100644 --- a/features/FEATURE_BLE/source/generic/GenericGattClient.cpp +++ b/features/FEATURE_BLE/source/generic/GenericGattClient.cpp @@ -21,6 +21,8 @@ #include #include "ble/generic/GenericGattClient.h" #include "ble/blecommon.h" +#include "ble/BLEInstanceBase.h" +#include "ble/generic/GenericSecurityManager.h" #include using ble::pal::AttServerMessage; @@ -1062,6 +1064,11 @@ ble_error_t GenericGattClient::read( return err; } +#define PREPARE_WRITE_HEADER_LENGTH 5 +#define WRITE_HEADER_LENGTH 3 +#define CMAC_LENGTH 8 +#define MAC_COUNTER_LENGTH 4 + ble_error_t GenericGattClient::write( GattClient::WriteOp_t cmd, Gap::Handle_t connection_handle, @@ -1077,7 +1084,7 @@ ble_error_t GenericGattClient::write( uint16_t mtu = get_mtu(connection_handle); if (cmd == GattClient::GATT_OP_WRITE_CMD) { - if (length > (uint16_t)(mtu - 3)) { + if (length > (uint16_t)(mtu - WRITE_HEADER_LENGTH)) { return BLE_ERROR_PARAM_OUT_OF_RANGE; } return _pal_client->write_without_response( @@ -1085,10 +1092,20 @@ ble_error_t GenericGattClient::write( attribute_handle, make_const_ArrayView(value, length) ); + } else if (cmd == GattClient::GATT_OP_SIGNED_WRITE_CMD) { + + if (length > (uint16_t)(mtu - WRITE_HEADER_LENGTH - CMAC_LENGTH - MAC_COUNTER_LENGTH)) { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + return _pal_client->signed_write_without_response( + connection_handle, + attribute_handle, + make_const_ArrayView(value, length) + ); } else { uint8_t* data = NULL; - if (length > (uint16_t)(mtu - 3)) { + if (length > (uint16_t)(mtu - WRITE_HEADER_LENGTH)) { data = (uint8_t*) malloc(length); if (data == NULL) { return BLE_ERROR_NO_MEM; @@ -1115,7 +1132,7 @@ ble_error_t GenericGattClient::write( err = _pal_client->queue_prepare_write( connection_handle, attribute_handle, - make_const_ArrayView(value, mtu - 5), + make_const_ArrayView(value, mtu - PREPARE_WRITE_HEADER_LENGTH), /* offset */ 0 ); } else { diff --git a/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp b/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp index 2acca2755f..59fe4fd822 100644 --- a/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp +++ b/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp @@ -313,17 +313,27 @@ ble_error_t GenericSecurityManager::enableSigning( } cb->signing_requested = enabled; - cb->signing_override_default = false; + cb->signing_override_default = true; if (cb->encrypted) { return BLE_ERROR_INVALID_STATE; } - if (!cb->csrk_stored && cb->signing_requested) { - init_signing(); - if (cb->is_master) { - return requestPairing(connection); + + if (cb->signing_requested) { + if (cb->csrk_stored) { + /* used the stored ones when available */ + _db.get_entry_peer_csrk( + mbed::callback(this, &GenericSecurityManager::set_peer_csrk_cb), + cb->db_entry + ); } else { - return slave_security_request(connection); + /* crate keys if needed and exchange them */ + init_signing(); + if (cb->is_master) { + return requestPairing(connection); + } else { + return slave_security_request(connection); + } } } @@ -698,6 +708,18 @@ void GenericSecurityManager::set_ltk_cb( } } +void GenericSecurityManager::set_peer_csrk_cb( + pal::SecurityDb::entry_handle_t db_entry, + const csrk_t *csrk +) { + ControlBlock_t *cb = get_control_block(db_entry); + if (!cb) { + return; + } + + _pal.set_peer_csrk(cb->connection, *csrk); +} + void GenericSecurityManager::return_csrk_cb( pal::SecurityDb::entry_handle_t db_entry, const csrk_t *csrk @@ -772,6 +794,17 @@ void GenericSecurityManager::on_connected( if (dist_flags) { *static_cast(cb) = *dist_flags; } + + const bool signing = cb->signing_override_default ? + cb->signing_requested + : _default_key_distribution.get_signing(); + + if (signing && cb->csrk_stored) { + _db.get_entry_peer_csrk( + mbed::callback(this, &GenericSecurityManager::set_peer_csrk_cb), + cb->db_entry + ); + } } void GenericSecurityManager::on_disconnected( diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioPalSecurityManager.h b/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioPalSecurityManager.h index 458f20311c..dbc4346725 100644 --- a/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioPalSecurityManager.h +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioPalSecurityManager.h @@ -239,6 +239,14 @@ public: */ virtual ble_error_t set_csrk(const csrk_t &csrk); + /** + * @see ::ble::pal::SecurityManager::set_peer_csrk + */ + virtual ble_error_t set_peer_csrk( + connection_handle_t connection, + const csrk_t &csrk + ); + //////////////////////////////////////////////////////////////////////////// // Authentication // diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalSecurityManager.cpp b/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalSecurityManager.cpp index 2935fdcc41..c5a1c15811 100644 --- a/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalSecurityManager.cpp +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalSecurityManager.cpp @@ -272,6 +272,14 @@ ble_error_t CordioSecurityManager::set_csrk(const csrk_t& csrk) return BLE_ERROR_NONE; } +ble_error_t CordioSecurityManager::set_peer_csrk( + connection_handle_t connection, + const csrk_t &csrk +) { + /* TODO implement */ + return BLE_ERROR_NOT_IMPLEMENTED; +} + //////////////////////////////////////////////////////////////////////////// // Global parameters //