diff --git a/features/FEATURE_BLE/ble/SecurityManager.h b/features/FEATURE_BLE/ble/SecurityManager.h index a01882959a..43a83e7fe7 100644 --- a/features/FEATURE_BLE/ble/SecurityManager.h +++ b/features/FEATURE_BLE/ble/SecurityManager.h @@ -736,7 +736,8 @@ public: // /** - * Enable OOB data usage during paring. + * Enable OOB data usage during paring. If Secure Connections is supported enabling useOOB will + * generate Secure Connections OOB data through oobGenerated(). * * @param[in] connectionHandle Handle to identify the connection. * @param[in] useOOB If set to true, authenticate using OOB data. diff --git a/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h b/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h index 322cef4b5d..583097fa76 100644 --- a/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h +++ b/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h @@ -433,12 +433,21 @@ private: uint8_t attempt_oob:1; uint8_t oob_mitm_protection:1; uint8_t oob_present:1; + uint8_t legacy_pairing_oob_request_pending:1; }; pal::SecurityManager &_pal; pal::SecurityDb &_db; pal::ConnectionEventMonitor &_connection_monitor; + /* OOB data */ + address_t _oob_peer_address; + oob_lesc_value_t _oob_peer_random; + oob_confirm_t _oob_peer_confirm; + oob_lesc_value_t _oob_local_random; + address_t _oob_temporary_key_creator_address; /**< device which generated and sent the TK */ + oob_tk_t _oob_temporary_key; /**< used for legacy pairing */ + pal::AuthenticationMask _default_authentication; pal::KeyDistribution _default_key_distribution; @@ -548,6 +557,12 @@ public: connection_handle_t connection ); + /** @copydoc ble::pal::SecurityManager::on_secure_connections_oob_request + */ + virtual void on_secure_connections_oob_request( + connection_handle_t connection + ); + /** @copydoc ble::pal::SecurityManager::on_legacy_pairing_oob_request */ virtual void on_legacy_pairing_oob_request( @@ -557,7 +572,7 @@ public: /** @copydoc ble::pal::SecurityManager::on_secure_connections_oob_generated */ virtual void on_secure_connections_oob_generated( - const address_t &local_address, + 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 9e7ac94d16..5dca19404b 100644 --- a/features/FEATURE_BLE/ble/pal/PalSecurityManager.h +++ b/features/FEATURE_BLE/ble/pal/PalSecurityManager.h @@ -367,6 +367,17 @@ public: Keypress_t keypress ) = 0; + /** + * Request OOB data from the user application. + * + * @param[in] connection connection handle + * @note shall be followed by: pal::SecurityManager::secure_connections_oob_request_reply + * or a cancellation of the procedure. + */ + virtual void on_secure_connections_oob_request( + connection_handle_t connection + ) = 0; + /** * Request OOB data from the user application. * @@ -381,14 +392,14 @@ public: /** * Send OOB data to the application for transport to the peer. * - * @param[in] address address of the local device + * @param[in] connection connection handle * @param[in] random random number used to generate the confirmation * @param[in] confirm confirmation value to be use for authentication * in secure connections pairing * @return BLE_ERROR_NONE or appropriate error code indicating the failure reason. */ virtual void on_secure_connections_oob_generated( - const address_t &local_address, + connection_handle_t connection, const oob_lesc_value_t &random, const oob_confirm_t &confirm ) = 0; @@ -909,7 +920,24 @@ public: ) = 0; /** - * Reply to an oob data request received from the SecurityManagerEventHandler. + * Reply to a Secure Connections oob data request received from the SecurityManagerEventHandler. + * + * @param[in] connection connection handle + * @param[in] local_random local random number used for the last oob exchange + * @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 + */ + virtual ble_error_t secure_connections_oob_request_reply( + connection_handle_t connection, + const oob_lesc_value_t &local_random, + const oob_lesc_value_t &peer_random, + const oob_confirm_t &peer_confirm + ) = 0; + + /** + * Reply to a legacy pairing oob data request received from the SecurityManagerEventHandler. * * @param[in] connection connection handle * @param[in] oob_data pointer to out of band data @@ -955,32 +983,6 @@ public: connection_handle_t connection ) = 0; - /** - * Supply the stack with the OOB data for secure connections. - * - * @param[in] address address of the peer device this data comes from - * @param[in] random random number used to generate the confirmation - * @param[in] confirm confirmation value to be use for authentication - * in secure connections pairing - * @return BLE_ERROR_NONE or appropriate error code indicating the failure reason. - */ - virtual ble_error_t secure_connections_oob_received( - const address_t &address, - const oob_lesc_value_t &random, - const oob_confirm_t &confirm - ) = 0; - - /** - * Supply the stack with the OOB data for secure connections. - * - * @param[in] address address of the peer device oob data is needed for - * @return True if oob data present, false if not or if the functionality - * is not implemented. - */ - virtual bool is_secure_connections_oob_present( - const address_t &address - ) = 0; - /* Entry points for the underlying stack to report events back to the user. */ public: /** diff --git a/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp b/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp index 6ebe31ae95..2acca2755f 100644 --- a/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp +++ b/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp @@ -519,6 +519,14 @@ 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.buffer(), 16); + + eventHandler->legacyPairingOobGenerated( + &_oob_temporary_key_creator_address, + &_oob_temporary_key + ); + _pal.generate_secure_connections_oob(connection); return BLE_ERROR_NONE; @@ -558,7 +566,20 @@ ble_error_t GenericSecurityManager::legacyPairingOobReceived( return BLE_ERROR_INVALID_PARAM; } - return _pal.legacy_pairing_oob_request_reply(cb->connection, *tk); + _oob_temporary_key = *tk; + _oob_temporary_key_creator_address = *address; + + if (cb->peer_address == _oob_temporary_key_creator_address) { + cb->attempt_oob = true; + } + + if (cb->legacy_pairing_oob_request_pending) { + on_legacy_pairing_oob_request(cb->connection); + /* legacy_pairing_oob_request_pending stops us from + * going into a loop of asking the user for oob + * so this reset needs to happen after the call above */ + cb->legacy_pairing_oob_request_pending = false; + } } return BLE_ERROR_NONE; } @@ -569,7 +590,10 @@ ble_error_t GenericSecurityManager::oobReceived( const oob_confirm_t *confirm ) { if (address && random && confirm) { - return _pal.secure_connections_oob_received(*address, *random, *confirm); + _oob_peer_address = *address; + _oob_peer_random = *random; + _oob_peer_confirm = *confirm; + return BLE_ERROR_NONE; } return BLE_ERROR_INVALID_PARAM; @@ -702,7 +726,7 @@ void GenericSecurityManager::update_oob_presence(connection_handle_t connection) cb->oob_present = cb->attempt_oob; if (_default_authentication.get_secure_connections()) { - cb->oob_present = _pal.is_secure_connections_oob_present(cb->peer_address); + cb->oob_present = (cb->peer_address == _oob_peer_address); } } @@ -710,6 +734,11 @@ void GenericSecurityManager::set_mitm_performed(connection_handle_t connection, ControlBlock_t *cb = get_control_block(connection); if (cb) { cb->mitm_performed = enable; + /* whenever we reset mitm performed we also reset pending requests + * as this happens whenever a new pairing attempt happens */ + if (!enable) { + cb->legacy_pairing_oob_request_pending = false; + } } } @@ -856,16 +885,23 @@ void GenericSecurityManager::on_slave_security_request( return; } - if (authentication.get_secure_connections() - && _default_authentication.get_secure_connections() - && !cb->secure_connections_paired) { - requestPairing(connection); + bool pairing_required = false; + + if (authentication.get_secure_connections() && !cb->secure_connections_paired + && _default_authentication.get_secure_connections()) { + pairing_required = true; } - if (authentication.get_mitm() - && !cb->ltk_mitm_protected) { + if (authentication.get_mitm() && !cb->ltk_mitm_protected) { + pairing_required = true; cb->mitm_requested = true; + } + + if (pairing_required) { requestPairing(connection); + } else if (!cb->encryption_requested) { + /* this will refresh keys if encryption is already present */ + enable_encryption(connection); } } @@ -950,17 +986,52 @@ void GenericSecurityManager::on_confirmation_request(connection_handle_t connect eventHandler->confirmationRequest(connection); } -void GenericSecurityManager::on_legacy_pairing_oob_request(connection_handle_t connection) { +void GenericSecurityManager::on_secure_connections_oob_request(connection_handle_t connection) { set_mitm_performed(connection); - eventHandler->legacyPairingOobRequest(connection); + + ControlBlock_t *cb = get_control_block(connection); + if (!cb) { + return; + } + + if (cb->peer_address == _oob_peer_address) { + _pal.secure_connections_oob_request_reply(connection, _oob_local_random, _oob_peer_random, _oob_peer_confirm); + } else { + _pal.cancel_pairing(connection, pairing_failure_t::OOB_NOT_AVAILABLE); + } +} + +void GenericSecurityManager::on_legacy_pairing_oob_request(connection_handle_t connection) { + ControlBlock_t *cb = get_control_block(connection); + if (!cb) { + return; + } + + if (cb->peer_address == _oob_temporary_key_creator_address + || cb->local_address == _oob_temporary_key_creator_address) { + + set_mitm_performed(connection); + _pal.legacy_pairing_oob_request_reply(connection, _oob_temporary_key); + + } else if (!cb->legacy_pairing_oob_request_pending) { + + cb->legacy_pairing_oob_request_pending = true; + eventHandler->legacyPairingOobRequest(connection); + + } } void GenericSecurityManager::on_secure_connections_oob_generated( - const address_t &local_address, + connection_handle_t connection, const oob_lesc_value_t &random, const oob_confirm_t &confirm ) { - eventHandler->oobGenerated(&local_address, &random, &confirm); + ControlBlock_t *cb = get_control_block(connection); + if (!cb) { + return; + } + eventHandler->oobGenerated(&cb->local_address, &random, &confirm); + _oob_local_random = random; } //////////////////////////////////////////////////////////////////////////// @@ -1118,7 +1189,8 @@ GenericSecurityManager::ControlBlock_t::ControlBlock_t() : mitm_performed(false), attempt_oob(false), oob_mitm_protection(false), - oob_present(false) { } + oob_present(false), + legacy_pairing_oob_request_pending(false) { } 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 9e66ed47b7..458f20311c 100644 --- a/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioPalSecurityManager.h +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioPalSecurityManager.h @@ -85,16 +85,42 @@ public: virtual ble_error_t clear_resolving_list(); //////////////////////////////////////////////////////////////////////////// - // Feature support + // Pairing // /** - * @see ::ble::pal::SecurityManager::set_secure_connections_support + * @see ::ble::pal::SecurityManager::send_pairing_request */ - virtual ble_error_t set_secure_connections_support( - bool enabled, bool secure_connections_only = false + virtual ble_error_t send_pairing_request( + connection_handle_t connection, + bool oob_data_flag, + AuthenticationMask authentication_requirements, + KeyDistribution initiator_dist, + KeyDistribution responder_dist ); + /** + * @see ::ble::pal::SecurityManager::send_pairing_response + */ + virtual ble_error_t send_pairing_response( + connection_handle_t connection, + bool oob_data_flag, + AuthenticationMask authentication_requirements, + KeyDistribution initiator_dist, + KeyDistribution responder_dist + ); + + /** + * @see ::ble::pal::SecurityManager::cancel_pairing + */ + virtual ble_error_t cancel_pairing( + connection_handle_t connection, pairing_failure_t reason + ); + + //////////////////////////////////////////////////////////////////////////// + // Feature support + // + /** * @see ::ble::pal::SecurityManager::get_secure_connections_support */ @@ -102,6 +128,11 @@ public: bool &enabled ); + /** + * @see ::ble::pal::SecurityManager::set_io_capability + */ + virtual ble_error_t set_io_capability(io_capability_t io_capability); + //////////////////////////////////////////////////////////////////////////// // Security settings // @@ -120,6 +151,17 @@ public: connection_handle_t, uint16_t &timeout_in_10ms ); + /** + * @see ::ble::pal::SecurityManager::set_encryption_key_requirements + */ + virtual ble_error_t set_encryption_key_requirements( + uint8_t min_encryption_key_size, + uint8_t max_encryption_key_size + ); + + /** + * @see ::ble::pal::SecurityManager::slave_security_request + */ virtual ble_error_t slave_security_request( connection_handle_t connection, AuthenticationMask authentication @@ -197,61 +239,10 @@ public: */ virtual ble_error_t set_csrk(const csrk_t &csrk); - //////////////////////////////////////////////////////////////////////////// - // Global parameters - // - - /** - * @see ::ble::pal::SecurityManager::set_display_passkey - */ - virtual ble_error_t set_display_passkey(passkey_num_t passkey); - - /** - * @see ::ble::pal::SecurityManager::set_io_capability - */ - virtual ble_error_t set_io_capability(io_capability_t io_capability); - - /** - * @see ::ble::pal::SecurityManager::set_encryption_key_requirements - */ - virtual ble_error_t set_encryption_key_requirements( - uint8_t min_encryption_key_size, - uint8_t max_encryption_key_size - ); - //////////////////////////////////////////////////////////////////////////// // Authentication // - /** - * @see ::ble::pal::SecurityManager::send_pairing_request - */ - virtual ble_error_t send_pairing_request( - connection_handle_t connection, - bool oob_data_flag, - AuthenticationMask authentication_requirements, - KeyDistribution initiator_dist, - KeyDistribution responder_dist - ); - - /** - * @see ::ble::pal::SecurityManager::send_pairing_response - */ - virtual ble_error_t send_pairing_response( - connection_handle_t connection, - bool oob_data_flag, - AuthenticationMask authentication_requirements, - KeyDistribution initiator_dist, - KeyDistribution responder_dist - ); - - /** - * @see ::ble::pal::SecurityManager::cancel_pairing - */ - virtual ble_error_t cancel_pairing( - connection_handle_t connection, pairing_failure_t reason - ); - /** * @see ::ble::pal::SecurityManager::get_random_data */ @@ -261,6 +252,11 @@ public: // MITM // + /** + * @see ::ble::pal::SecurityManager::set_display_passkey + */ + virtual ble_error_t set_display_passkey(passkey_num_t passkey); + /** * @see ::ble::pal::SecurityManager::passkey_request_reply */ @@ -269,6 +265,16 @@ public: passkey_num_t passkey ); + /** + * @see ::ble::pal::SecurityManager::secure_connections_oob_request_reply + */ + virtual ble_error_t secure_connections_oob_request_reply( + connection_handle_t connection, + const oob_lesc_value_t &local_random, + const oob_lesc_value_t &peer_random, + const oob_confirm_t &peer_confirm + ); + /** * @see ::ble::pal::SecurityManager::legacy_pairing_oob_request_reply */ @@ -298,22 +304,6 @@ public: connection_handle_t connection ); - /** - * @see ::ble::pal::SecurityManager::secure_connections_oob_received - */ - virtual ble_error_t secure_connections_oob_received( - const address_t &address, - const oob_lesc_value_t &random, - const oob_confirm_t &confirm - ); - - /** - * @see ::ble::pal::SecurityManager::is_secure_connections_oob_present - */ - virtual bool is_secure_connections_oob_present( - const address_t &address - ); - // singleton of the ARM Cordio Security Manager static CordioSecurityManager &get_security_manager(); @@ -325,13 +315,6 @@ private: passkey_num_t _default_passkey; bool _lesc_keys_generated; uint8_t _public_key_x[SEC_ECC_KEY_LEN]; - bool _peer_oob_present; - address_t _peer_oob_address; - oob_lesc_value_t _peer_oob_random; - oob_confirm_t _peer_oob_confirm; - bool _own_oob_present; - uint8_t _confirm[SMP_CONFIRM_LEN]; - uint8_t _random[SMP_RAND_LEN]; }; } // cordio diff --git a/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalSecurityManager.cpp b/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalSecurityManager.cpp index c78fae76c6..2935fdcc41 100644 --- a/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalSecurityManager.cpp +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO/source/CordioPalSecurityManager.cpp @@ -30,15 +30,8 @@ CordioSecurityManager::CordioSecurityManager() : ::ble::pal::SecurityManager(), _use_default_passkey(false), _default_passkey(0), - _lesc_keys_generated(false), - _public_key_x(), - _peer_oob_present(false), - _peer_oob_address(), - _peer_oob_random(), - _peer_oob_confirm(), - _own_oob_present(false), - _confirm(), - _random() + _lesc_keys_generated(false), + _public_key_x() { } @@ -54,15 +47,16 @@ CordioSecurityManager::~CordioSecurityManager() ble_error_t CordioSecurityManager::initialize() { - // reset local state + // reset local state _use_default_passkey = false; _default_passkey = 0; - _lesc_keys_generated = false; - _peer_oob_present = false; - _own_oob_present = false; + _lesc_keys_generated = false; - // generate a new set of keys - DmSecGenerateEccKeyReq(); +#if 0 + // FIXME: need help from the stack or local calculation + // generate a new set of keys + DmSecGenerateEccKeyReq(); +#endif return BLE_ERROR_NONE; } @@ -74,7 +68,7 @@ ble_error_t CordioSecurityManager::terminate() ble_error_t CordioSecurityManager::reset() { - initialize(); + initialize(); return BLE_ERROR_NONE; } @@ -115,6 +109,8 @@ ble_error_t CordioSecurityManager::clear_resolving_list() // Feature support // +// FIXME: Enable when new function available in the pal. +#if 0 ble_error_t CordioSecurityManager::set_secure_connections_support( bool enabled, bool secure_connections_only ) { @@ -126,6 +122,7 @@ ble_error_t CordioSecurityManager::set_secure_connections_support( } return BLE_ERROR_NONE; } +#endif ble_error_t CordioSecurityManager::get_secure_connections_support( bool &enabled @@ -413,8 +410,8 @@ ble_error_t CordioSecurityManager::send_keypress_notification( 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. + // Note: this is not tie to a connection; only one oob value is present in + // the pal. uint8_t oobLocalRandom[SMP_RAND_LEN]; SecRand(oobLocalRandom, SMP_RAND_LEN); @@ -423,28 +420,26 @@ ble_error_t CordioSecurityManager::generate_secure_connections_oob( return BLE_ERROR_NOT_IMPLEMENTED; } -ble_error_t CordioSecurityManager::secure_connections_oob_received( - const address_t &address, - const oob_lesc_value_t &random, - const oob_confirm_t &confirm +ble_error_t CordioSecurityManager::secure_connections_oob_request_reply( + connection_handle_t connection, + const oob_lesc_value_t &local_random, + const oob_lesc_value_t &peer_random, + const oob_confirm_t &peer_confirm ) { - _peer_oob_present = true; - _peer_oob_address = address; - _peer_oob_random = random; - _peer_oob_confirm = confirm; + dmSecLescOobCfg_t oob_config = { 0 }; + + memcpy(oob_config.localRandom, local_random.data(), local_random.size()); + // FIXME: + // memcpy(oob_config.localConfirm, ?, ?); + memcpy(oob_config.peerRandom, peer_random.data(), peer_random.size()); + memcpy(oob_config.peerConfirm, peer_confirm.data(), peer_confirm.size()); + + DmSecSetOob(connection, &oob_config); + DmSecAuthRsp(connection, 0, NULL); return BLE_ERROR_NONE; } -bool CordioSecurityManager::is_secure_connections_oob_present( - const address_t &address -) { - if (!_peer_oob_present) { - return false; - } - return address == _peer_oob_address; -} - CordioSecurityManager& CordioSecurityManager::get_security_manager() { static CordioSecurityManager _security_manager; @@ -515,11 +510,11 @@ bool CordioSecurityManager::sm_handler(const wsfMsgHdr_t* msg) { connection_handle_t connection = evt->hdr.param; if (evt->oob) { - // FIXME: Nothing in the API indicates if smp or sc OOB are - // requested. - // To set secure connection OOB: - // - DmSecSetOob(connection, oob_data) - // - DmSecAuthRsp(connection, 0, NULL) + // FIXME: Nothing in the API indicates if smp or sc OOB are + // requested. + // To set secure connection OOB: + // - DmSecSetOob(connection, oob_data) + // - DmSecAuthRsp(connection, 0, NULL) handler->on_legacy_pairing_oob_request(connection); } else if (evt->display) { if (get_security_manager()._use_default_passkey) { @@ -644,39 +639,35 @@ bool CordioSecurityManager::sm_handler(const wsfMsgHdr_t* msg) { } case DM_SEC_CALC_OOB_IND: { - dmSecOobCalcIndEvt_t* evt = (dmSecOobCalcIndEvt_t*) msg; - self._own_oob_present = true; - memcpy(self._confirm, evt->confirm, sizeof(_confirm)); - memcpy(self._random, evt->random, sizeof(_random)); - handler->on_secure_connections_oob_generated( - address_t(), /* which address should be used ??? */ - evt->random, - evt->confirm - ); + dmSecOobCalcIndEvt_t* evt = (dmSecOobCalcIndEvt_t*) msg; + handler->on_secure_connections_oob_generated( + evt->hdr.param, + evt->random, + evt->confirm + ); return true; } case DM_SEC_ECC_KEY_IND: { - secEccMsg_t* evt = (secEccMsg_t*) msg; - DmSecSetEccKey(&evt->data.key); - memcpy(self._public_key_x, evt->data.key.pubKey_x, sizeof(_public_key_x)); - self._lesc_keys_generated = true; + secEccMsg_t* evt = (secEccMsg_t*) msg; + DmSecSetEccKey(&evt->data.key); + memcpy(self._public_key_x, evt->data.key.pubKey_x, sizeof(_public_key_x)); + self._lesc_keys_generated = true; return true; } case DM_SEC_COMPARE_IND: { - dmSecCnfIndEvt_t* evt = (dmSecCnfIndEvt_t*) msg; - handler->on_passkey_display( - /* connection */ evt->hdr.param, - DmSecGetCompareValue(evt->confirm) - ); - handler->on_confirmation_request(/* connection */ evt->hdr.param); - return true; + dmSecCnfIndEvt_t* evt = (dmSecCnfIndEvt_t*) msg; + handler->on_passkey_display( + /* connection */ evt->hdr.param, + DmSecGetCompareValue(evt->confirm) + ); + handler->on_confirmation_request(/* connection */ evt->hdr.param); + return true; } case DM_SEC_KEYPRESS_IND: { dmSecKeypressIndEvt_t* evt = (dmSecKeypressIndEvt_t*) msg; - handler->on_keypress_notification( /* connection */ evt->hdr.param, (Keypress_t) evt->notificationType