diff --git a/features/FEATURE_BLE/ble/BLETypes.h b/features/FEATURE_BLE/ble/BLETypes.h index a4b0c1da05..4fb9b8f001 100644 --- a/features/FEATURE_BLE/ble/BLETypes.h +++ b/features/FEATURE_BLE/ble/BLETypes.h @@ -262,6 +262,27 @@ private: uint8_t ascii[PASSKEY_LEN]; }; +/** + * Returns true if every byte is equal to zero + */ +template +bool is_all_zeros(byte_array_class &byte_array) { + for (size_t i = 0; i < byte_array.size(); i++) { + if (byte_array[i] != 0) { + return false; + } + } + return true; +} + +/** + * Zero out all bytes + */ +template +void set_all_zeros(byte_array_class &byte_array) { + memset(&byte_array[0], 0x00, byte_array.size()); +} + template struct byte_array_t { /** 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/SecurityManager.h b/features/FEATURE_BLE/ble/SecurityManager.h index 43a83e7fe7..11294a7461 100644 --- a/features/FEATURE_BLE/ble/SecurityManager.h +++ b/features/FEATURE_BLE/ble/SecurityManager.h @@ -735,15 +735,48 @@ public: // MITM // + /** + * Generate OOB data with the given address. If Secure Connections is supported this will + * also generate Secure Connections OOB data on top of legacy pairing OOB data. This can be used + * to generate such data before the connection takes place. + * + * In this model the OOB exchange takes place before the devices connect. Devices should establish + * communication over another channel and exchange the OOB data. The address provided will be used + * by the peer to associate the received data with the address of the device it will then connect + * to over BLE. + * + * @param[in] address The local address you will use in the connection using this OOB data. This + * address will be returned along with the rest of the OOB data when generation + * is complete. Using an invalid address is illegal. + * @return BLE_ERROR_NONE or appropriate error code indicating the failure reason. + */ + virtual ble_error_t generateOOB(const ble::address_t *address) { + /* Avoid compiler warnings about unused variables */ + (void) address; + return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */ + } + /** * Enable OOB data usage during paring. If Secure Connections is supported enabling useOOB will - * generate Secure Connections OOB data through oobGenerated(). + * generate Secure Connections OOB data through oobGenerated() on top of legacy pairing OOB data. + * + * You do not have to call this function to return received OOB data. Use legacyPairingOobReceived + * or oobReceived to hand it in. This will allow the stack to use it if possible. You only need to + * call this function to attempt legacy OOB data exchange after pairing start and to inform + * the stack OOB data does not provide MITM protection (by default it is set to provide this). + * + * In this model the OOB exchange takes places after the devices have connected but possibly + * prior to pairing. For secure connections pairing must not be started until after the OOB + * data has been sent and/or received. The address in the OOB data generated will match + * the original address used to establish the connection and will be used by the peer to + * identify which connection the OOB data belongs to. * * @param[in] connectionHandle Handle to identify the connection. * @param[in] useOOB If set to true, authenticate using OOB data. * @param[in] OOBProvidesMITM If set to true keys exchanged during pairing using OOB data - * will provide MITM protection. This indicates that the form - * of exchange used by the OOB data itself provides MITM protection. + * will provide Man-in-the-Middle protection. This indicates that + * the form of exchange used by the OOB data itself provides MITM + * protection. * @return BLE_ERROR_NONE or appropriate error code indicating the failure reason. */ virtual ble_error_t setOOBDataUsage(ble::connection_handle_t connectionHandle, bool useOOB, bool OOBProvidesMITM = true) { diff --git a/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h b/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h index 583097fa76..7fe92b3b30 100644 --- a/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h +++ b/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h @@ -192,6 +192,10 @@ public: // MITM // + virtual ble_error_t generateOOB( + const address_t *address + ); + virtual ble_error_t setOOBDataUsage( connection_handle_t connection, bool useOOB, @@ -240,6 +244,11 @@ public: _legacy_pairing_allowed(true), _master_sends_keys(false) { _pal.set_event_handler(this); + + /* We create a fake value for oob to allow creation of the next oob which needs + * the last process to finish first before restarting (this is to simplify checking). + * This fake value will not be used as the oob address is currently invalid */ + _oob_local_random[0] = 1; } //////////////////////////////////////////////////////////////////////////// @@ -313,13 +322,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. * @@ -434,6 +454,8 @@ private: uint8_t oob_mitm_protection:1; uint8_t oob_present:1; uint8_t legacy_pairing_oob_request_pending:1; + + uint8_t csrk_failures:2; }; pal::SecurityManager &_pal; @@ -441,6 +463,7 @@ private: pal::ConnectionEventMonitor &_connection_monitor; /* OOB data */ + address_t _oob_local_address; address_t _oob_peer_address; oob_lesc_value_t _oob_peer_random; oob_confirm_t _oob_peer_confirm; @@ -503,6 +526,12 @@ public: connection_handle_t connection ); + /** @copydoc ble::pal::SecurityManager::on_signature_verification_failure + */ + virtual void on_signature_verification_failure( + connection_handle_t connection + ); + /** @copydoc ble::pal::SecurityManager::on_slave_security_request */ virtual void on_slave_security_request( @@ -572,7 +601,6 @@ public: /** @copydoc ble::pal::SecurityManager::on_secure_connections_oob_generated */ virtual void on_secure_connections_oob_generated( - connection_handle_t connection, const oob_lesc_value_t &random, const oob_confirm_t &confirm ); diff --git a/features/FEATURE_BLE/ble/pal/PalSecurityManager.h b/features/FEATURE_BLE/ble/pal/PalSecurityManager.h index 5dca19404b..9b98f8e3b7 100644 --- a/features/FEATURE_BLE/ble/pal/PalSecurityManager.h +++ b/features/FEATURE_BLE/ble/pal/PalSecurityManager.h @@ -280,6 +280,16 @@ public: connection_handle_t connection ) = 0; + /** + * Indicate that signed data was rejected due to verification failure. This could + * be due to an invalid CSRK key. + * + * @param[in] connection connection handle + */ + virtual void on_signature_verification_failure( + connection_handle_t connection + ) = 0; + /** * Ask the stack to evaluate the security request received from the slave. * This might result in the stack enabling encryption, or pairing/re-pairing. @@ -399,7 +409,6 @@ public: * @return BLE_ERROR_NONE or appropriate error code indicating the failure reason. */ virtual void on_secure_connections_oob_generated( - connection_handle_t connection, const oob_lesc_value_t &random, const oob_confirm_t &confirm ) = 0; @@ -545,21 +554,21 @@ public: /** * Initialise stack. Called before first use. * - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t initialize() = 0; /** * Finalise all actions. Called before shutdown. * - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t terminate() = 0; /** * Reset to same state as after initialize. * - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t reset() = 0; @@ -574,7 +583,7 @@ public: * @warning: The number of entries is considered fixed. * * @see BLUETOOTH SPECIFICATION Version 5.0 | Vol 2, Part E: 7.8.41 - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual uint8_t read_resolving_list_capacity() = 0; @@ -585,7 +594,7 @@ public: * @param[in] peer_identity_address address of the device whose entry is to be added * @param[in] peer_irk peer identity resolving key * @see BLUETOOTH SPECIFICATION Version 5.0 | Vol 2, Part E: 7.8.38 - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t add_device_to_resolving_list( advertising_peer_address_type_t peer_identity_address_type, @@ -599,7 +608,7 @@ public: * @param[in] peer_identity_address_type public/private indicator * @param[in] peer_identity_address address of the device whose entry is to be removed * @see BLUETOOTH SPECIFICATION Version 5.0 | Vol 2, Part E: 7.8.39 - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t remove_device_from_resolving_list( advertising_peer_address_type_t peer_identity_address_type, @@ -610,7 +619,7 @@ public: * Remove all devices from the resolving list. * * @see BLUETOOTH SPECIFICATION Version 5.0 | Vol 2, Part E: 7.8.40 - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t clear_resolving_list() = 0; @@ -627,7 +636,7 @@ public: * @param[in] initiator_dist key distribution * @param[in] responder_dist key distribution * @see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part H - 3.5.1 - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t send_pairing_request( connection_handle_t connection, @@ -646,7 +655,7 @@ public: * @param[in] authentication_requirements authentication requirements * @param[in] initiator_dist key distribution * @param[in] responder_dist key distribution - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t send_pairing_response( connection_handle_t connection, @@ -662,7 +671,7 @@ public: * @param[in] connection connection handle * @param[in] reason pairing failure error * @see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part H - 3.5.5 - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t cancel_pairing( connection_handle_t connection, @@ -677,7 +686,7 @@ public: * Check if the Secure Connections feature is supported by the stack and controller. * * @param[out] enabled true if SC are supported - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t get_secure_connections_support( bool &enabled @@ -687,7 +696,7 @@ public: * Set the IO capability that will be used during pairing feature exchange. * * @param[in] io_capability type of IO capabilities available on the local device - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t set_io_capability( io_capability_t io_capability @@ -703,7 +712,7 @@ public: * * @param[in] connection connection handle * @param[in] timeout_in_10ms time measured in units of 10 milliseconds - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t set_authentication_timeout( connection_handle_t connection, @@ -716,7 +725,7 @@ public: * * @param[in] connection connection handle * @param[out] timeout_in_10ms time measured in units of 10 milliseconds - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t get_authentication_timeout( connection_handle_t connection, @@ -734,7 +743,7 @@ public: * required for pairing. This value shall be in the range * [min_encryption_key_size : 16]. * - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t set_encryption_key_requirements( uint8_t min_encryption_key_size, @@ -749,7 +758,7 @@ public: * * @param[in] connection connection handle * @param[in] authentication authentication requirements - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t slave_security_request( connection_handle_t connection, @@ -770,7 +779,7 @@ public: * @param[in] ediv encryption diversifier from the peer * @param[in] rand random value from the peer * @param[in] mitm does the LTK have man in the middle protection - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t enable_encryption( connection_handle_t connection, @@ -787,7 +796,7 @@ public: * @param[in] connection connection handle * @param[in] ltk long term key from the peer * @param[in] mitm does the LTK have man in the middle protection - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t enable_encryption( connection_handle_t connection, @@ -801,7 +810,7 @@ public: * * @param[in] key encryption key * @param[in,out] data data to be encrypted, if successful contains the result - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t encrypt_data( const byte_array_t<16> &key, @@ -827,7 +836,7 @@ public: * @param[in] ltk long term key * @param[in] mitm does the LTK have man in the middle protection * @param[in] secure_connections is this a secure_connections pairing - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t set_ltk( connection_handle_t connection, @@ -840,7 +849,7 @@ public: * Inform the stack we don't have the LTK. * * @param[in] connection connection handle - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t set_ltk_not_found( connection_handle_t connection @@ -850,7 +859,7 @@ public: * Set the local IRK. * * @param[in] irk identity resolution key - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t set_irk( const irk_t &irk @@ -860,12 +869,25 @@ public: * Set the local CSRK. * * @param[in] csrk signing key - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t set_csrk( 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, + bool authenticated + ) = 0; + //////////////////////////////////////////////////////////////////////////// // Authentication // @@ -875,7 +897,7 @@ public: * * @param[out] random_data returns 8 octets of random data * @see BLUETOOTH SPECIFICATION Version 5.0 | Vol 2, Part H 2 - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t get_random_data( byte_array_t<8> &random_data @@ -903,7 +925,7 @@ public: * passkey is set to 0 then the security manager generates a random * passkey every time it calls SecurityManagerEvent::on_passkey_display. * - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t set_display_passkey( passkey_num_t passkey @@ -912,7 +934,7 @@ public: /** * Reply to a passkey request received from the SecurityManagerEventHandler. * - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t passkey_request_reply( connection_handle_t connection, @@ -927,7 +949,7 @@ public: * @param[in] peer_random random number used to generate the confirmation on peer * @param[in] peer_confirm confirmation value to be use for authentication * in secure connections pairing - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t secure_connections_oob_request_reply( connection_handle_t connection, @@ -941,7 +963,7 @@ public: * * @param[in] connection connection handle * @param[in] oob_data pointer to out of band data - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t legacy_pairing_oob_request_reply( connection_handle_t connection, @@ -954,7 +976,7 @@ public: * * @param[in] connection connection handle * @param[in] confirmation true if the user indicated the numbers match - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t confirmation_entered( connection_handle_t connection, @@ -967,7 +989,7 @@ public: * * @param[in] connection connection handle * @param[in] keypress type of keypress event - * @retval BLE_ERROR_NONE On success, else an error code indicating reason for failure + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ virtual ble_error_t send_keypress_notification( connection_handle_t connection, @@ -976,12 +998,9 @@ public: /** * Generate local OOB data to be sent to the application which sends it to the peer. - * - * @param[in] connectionHandle Handle to identify the connection. + * @return BLE_ERROR_NONE On success, else an error code indicating reason for failure */ - virtual ble_error_t generate_secure_connections_oob( - connection_handle_t connection - ) = 0; + virtual ble_error_t generate_secure_connections_oob() = 0; /* Entry points for the underlying stack to report events back to the user. */ public: diff --git a/features/FEATURE_BLE/source/generic/GenericGattClient.cpp b/features/FEATURE_BLE/source/generic/GenericGattClient.cpp index 97c6d57fc0..4962b9dd2b 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; @@ -38,6 +40,11 @@ using ble::pal::AttHandleValueIndication; using ble::pal::AttHandleValueNotification; using ble::pal::AttFindInformationResponse; +#define PREPARE_WRITE_HEADER_LENGTH 5 +#define WRITE_HEADER_LENGTH 3 +#define CMAC_LENGTH 8 +#define MAC_COUNTER_LENGTH 4 + namespace ble { namespace generic { @@ -1074,67 +1081,77 @@ ble_error_t GenericGattClient::write( return BLE_ERROR_INVALID_STATE; } - uint16_t mtu = get_mtu(connection_handle); + uint16_t mtu = get_mtu(connection_handle); - if (cmd == GattClient::GATT_OP_WRITE_CMD) { - if (length > (uint16_t)(mtu - 3)) { - return BLE_ERROR_PARAM_OUT_OF_RANGE; - } - return _pal_client->write_without_response( - connection_handle, - attribute_handle, - make_const_ArrayView(value, length) - ); - } else { - uint8_t* data = NULL; + if (cmd == GattClient::GATT_OP_WRITE_CMD) { + if (length > (uint16_t) (mtu - WRITE_HEADER_LENGTH)) { + return BLE_ERROR_PARAM_OUT_OF_RANGE; + } + return _pal_client->write_without_response( + connection_handle, + attribute_handle, + make_const_ArrayView(value, length) + ); + } else if (cmd == GattClient::GATT_OP_SIGNED_WRITE_CMD) { + /*TODO check encryption status */ + 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)) { - data = (uint8_t*) malloc(length); - if (data == NULL) { - return BLE_ERROR_NO_MEM; - } - memcpy(data, value, length); - } + if (length > (uint16_t) (mtu - WRITE_HEADER_LENGTH)) { + data = (uint8_t*) malloc(length); + if (data == NULL) { + return BLE_ERROR_NO_MEM; + } + memcpy(data, value, length); + } - WriteControlBlock* write_pcb = new(std::nothrow) WriteControlBlock( - connection_handle, - attribute_handle, - data, - length - ); + WriteControlBlock* write_pcb = new (std::nothrow) WriteControlBlock( + connection_handle, + attribute_handle, + data, + length + ); - if (write_pcb == NULL) { - free(data); - return BLE_ERROR_NO_MEM; - } + if (write_pcb == NULL) { + free(data); + return BLE_ERROR_NO_MEM; + } - insert_control_block(write_pcb); + insert_control_block(write_pcb); - ble_error_t err = BLE_ERROR_UNSPECIFIED; - if (data) { - err = _pal_client->queue_prepare_write( - connection_handle, - attribute_handle, - make_const_ArrayView(value, mtu - 5), - /* offset */ 0 - ); - } else { - err = _pal_client->write_attribute( - connection_handle, - attribute_handle, - make_const_ArrayView(value, length) - ); - } + ble_error_t err = BLE_ERROR_UNSPECIFIED; + if (data) { + err = _pal_client->queue_prepare_write( + connection_handle, + attribute_handle, + make_const_ArrayView(value, mtu - PREPARE_WRITE_HEADER_LENGTH), + /* offset */0 + ); + } else { + err = _pal_client->write_attribute( + connection_handle, + attribute_handle, + make_const_ArrayView(value, length) + ); + } - if (err) { - remove_control_block(write_pcb); - delete write_pcb; - } + if (err) { + remove_control_block(write_pcb); + delete write_pcb; + } - return err; - } + return err; + } - return BLE_ERROR_NOT_IMPLEMENTED; + return BLE_ERROR_NOT_IMPLEMENTED; } void GenericGattClient::onServiceDiscoveryTermination( diff --git a/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp b/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp index 50a77c870b..2ccef19963 100644 --- a/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp +++ b/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp @@ -140,14 +140,10 @@ ble_error_t GenericSecurityManager::requestPairing(connection_handle_t connectio * use when roles are changed */ if (_master_sends_keys) { initiator_distribution = _default_key_distribution; - } - - /* override default if requested */ - if (cb->signing_override_default) { - initiator_distribution.set_signing(cb->signing_requested); - } else { - /* because _master_sends_keys might be false so we need to set this */ - initiator_distribution.set_signing(_default_key_distribution.get_signing()); + /* override default if requested */ + if (cb->signing_override_default) { + initiator_distribution.set_signing(cb->signing_requested); + } } KeyDistribution responder_distribution(_default_key_distribution); @@ -312,19 +308,27 @@ ble_error_t GenericSecurityManager::enableSigning( return BLE_ERROR_INVALID_PARAM; } - 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 (enabled && !cb->signing_requested && !_default_key_distribution.get_signing()) { + cb->signing_requested = true; + 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); + /* create keys if needed and exchange them */ + init_signing(); + if (cb->is_master) { + return requestPairing(connection); + } else { + return slave_security_request(connection); + } } + } else { + cb->signing_requested = enabled; } return BLE_ERROR_NONE; @@ -506,6 +510,43 @@ ble_error_t GenericSecurityManager::requestAuthentication(connection_handle_t co // MITM // +ble_error_t GenericSecurityManager::generateOOB( + const address_t *address +) { + /* legacy pairing */ + ble_error_t status = get_random_data(_oob_temporary_key.buffer(), 16); + + if (status == BLE_ERROR_NONE) { + _oob_temporary_key_creator_address = *address; + + eventHandler->legacyPairingOobGenerated( + &_oob_temporary_key_creator_address, + &_oob_temporary_key + ); + } else { + return status; + } + + /* Secure connections. Avoid generating if we're already waiting for it. + * If a local random is set to 0 it means we're already calculating. */ + if (!is_all_zeros(_oob_local_random)) { + status = _pal.generate_secure_connections_oob(); + + if (status == BLE_ERROR_NONE) { + _oob_local_address = *address; + /* this will be updated when calculation completes, + * a value of all zeros is an invalid random value */ + set_all_zeros(_oob_local_random); + } else if (status != BLE_ERROR_NOT_IMPLEMENTED) { + return status; + } + } else { + return BLE_STACK_BUSY; + } + + return BLE_ERROR_NONE; +} + ble_error_t GenericSecurityManager::setOOBDataUsage( connection_handle_t connection, bool useOOB, @@ -519,17 +560,11 @@ ble_error_t GenericSecurityManager::setOOBDataUsage( cb->attempt_oob = useOOB; cb->oob_mitm_protection = OOBProvidesMITM; - _oob_temporary_key_creator_address = cb->local_address; - get_random_data(_oob_temporary_key.data(), 16); - - eventHandler->legacyPairingOobGenerated( - &_oob_temporary_key_creator_address, - &_oob_temporary_key - ); - - _pal.generate_secure_connections_oob(connection); - - return BLE_ERROR_NONE; + if (useOOB) { + return generateOOB(&cb->local_address); + } else { + return BLE_ERROR_NONE; + } } ble_error_t GenericSecurityManager::confirmationEntered( @@ -698,6 +733,22 @@ 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, + cb->csrk_mitm_protected + ); +} + void GenericSecurityManager::return_csrk_cb( pal::SecurityDb::entry_handle_t db_entry, const csrk_t *csrk @@ -720,13 +771,18 @@ void GenericSecurityManager::update_oob_presence(connection_handle_t connection) return; } - /* only update the oob state if we support secure connections, - * otherwise follow the user set preference for providing legacy - * pairing oob data */ - cb->oob_present = cb->attempt_oob; - + /* if we support secure connection we only care about secure connections oob data */ if (_default_authentication.get_secure_connections()) { cb->oob_present = (cb->peer_address == _oob_peer_address); + } else { + /* otherwise for legacy pairing we first set the oob based on set preference */ + cb->oob_present = cb->attempt_oob; + + /* and also turn it on if we have oob data for legacy pairing */ + if (cb->peer_address == _oob_temporary_key_creator_address + || cb->local_address == _oob_temporary_key_creator_address) { + cb->oob_present = true; + } } } @@ -772,6 +828,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( @@ -876,6 +943,31 @@ void GenericSecurityManager::on_valid_mic_timeout(connection_handle_t connection (void)connection; } +void GenericSecurityManager::on_signature_verification_failure( + connection_handle_t connection +) { + ControlBlock_t *cb = get_control_block(connection); + if (!cb) { + return; + } + + const bool signing = cb->signing_override_default ? + cb->signing_requested : + _default_key_distribution.get_signing(); + + if (signing) { + cb->csrk_failures++; + if (cb->csrk_failures == 3) { + cb->csrk_failures = 0; + if (cb->is_master) { + requestPairing(connection); + } else { + slave_security_request(connection); + } + } + } +} + void GenericSecurityManager::on_slave_security_request( connection_handle_t connection, AuthenticationMask authentication @@ -996,6 +1088,8 @@ void GenericSecurityManager::on_secure_connections_oob_request(connection_handle if (cb->peer_address == _oob_peer_address) { _pal.secure_connections_oob_request_reply(connection, _oob_local_random, _oob_peer_random, _oob_peer_confirm); + /* do not re-use peer OOB */ + set_all_zeros(_oob_peer_address); } else { _pal.cancel_pairing(connection, pairing_failure_t::OOB_NOT_AVAILABLE); } @@ -1013,6 +1107,11 @@ void GenericSecurityManager::on_legacy_pairing_oob_request(connection_handle_t c set_mitm_performed(connection); _pal.legacy_pairing_oob_request_reply(connection, _oob_temporary_key); + /* do not re-use peer OOB */ + if (cb->peer_address == _oob_temporary_key_creator_address) { + set_all_zeros(_oob_temporary_key_creator_address); + } + } else if (!cb->legacy_pairing_oob_request_pending) { cb->legacy_pairing_oob_request_pending = true; @@ -1022,15 +1121,10 @@ void GenericSecurityManager::on_legacy_pairing_oob_request(connection_handle_t c } void GenericSecurityManager::on_secure_connections_oob_generated( - connection_handle_t connection, const oob_lesc_value_t &random, const oob_confirm_t &confirm ) { - ControlBlock_t *cb = get_control_block(connection); - if (!cb) { - return; - } - eventHandler->oobGenerated(&cb->local_address, &random, &confirm); + eventHandler->oobGenerated(&_oob_local_address, &random, &confirm); _oob_local_random = random; } @@ -1190,7 +1284,8 @@ GenericSecurityManager::ControlBlock_t::ControlBlock_t() : attempt_oob(false), oob_mitm_protection(false), oob_present(false), - legacy_pairing_oob_request_pending(false) { } + legacy_pairing_oob_request_pending(false), + csrk_failures(0) { } void GenericSecurityManager::on_ltk_request(connection_handle_t connection) { diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioPalSecurityManager.h b/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioPalSecurityManager.h index 458f20311c..fe5da7d159 100644 --- a/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioPalSecurityManager.h +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioPalSecurityManager.h @@ -239,6 +239,15 @@ 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, + bool authenticated + ); + //////////////////////////////////////////////////////////////////////////// // Authentication // @@ -300,9 +309,7 @@ public: /** * @see ::ble::pal::SecurityManager::generate_secure_connections_oob */ - virtual ble_error_t generate_secure_connections_oob( - connection_handle_t connection - ); + virtual ble_error_t generate_secure_connections_oob(); // singleton of the ARM Cordio Security Manager static CordioSecurityManager &get_security_manager(); diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalSecurityManager.cpp b/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalSecurityManager.cpp index ea07b71c48..8680bc9733 100644 --- a/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalSecurityManager.cpp +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalSecurityManager.cpp @@ -272,6 +272,15 @@ 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, + bool authenticated +) { + /* TODO implement */ + return BLE_ERROR_NOT_IMPLEMENTED; +} + //////////////////////////////////////////////////////////////////////////// // Global parameters // @@ -407,17 +416,12 @@ ble_error_t CordioSecurityManager::send_keypress_notification( return BLE_ERROR_NONE; } -ble_error_t CordioSecurityManager::generate_secure_connections_oob( - connection_handle_t connection -) { - // Note: this is not tie to a connection; only one oob value is present in - // the pal. +ble_error_t CordioSecurityManager::generate_secure_connections_oob() { uint8_t oobLocalRandom[SMP_RAND_LEN]; SecRand(oobLocalRandom, SMP_RAND_LEN); DmSecCalcOobReq(oobLocalRandom, _public_key_x); - - return BLE_ERROR_NOT_IMPLEMENTED; + return BLE_ERROR_NONE; } ble_error_t CordioSecurityManager::secure_connections_oob_request_reply( @@ -641,7 +645,6 @@ bool CordioSecurityManager::sm_handler(const wsfMsgHdr_t* msg) { case DM_SEC_CALC_OOB_IND: { dmSecOobCalcIndEvt_t* evt = (dmSecOobCalcIndEvt_t*) msg; handler->on_secure_connections_oob_generated( - evt->hdr.param, evt->random, evt->confirm );