diff --git a/features/FEATURE_BLE/ble/generic/GenericSecurityDb.h b/features/FEATURE_BLE/ble/generic/GenericSecurityDb.h index 54c61a44a9..80f7817feb 100644 --- a/features/FEATURE_BLE/ble/generic/GenericSecurityDb.h +++ b/features/FEATURE_BLE/ble/generic/GenericSecurityDb.h @@ -41,16 +41,16 @@ struct SecurityEntry_t { SecurityEntry_t() : handle(0), encryption_key_size(0), - peer_address_public(false), - local_address_public(false), + peer_address_is_public(false), + local_address_is_public(false), csrk_stored(false), - mitm_csrk(false), + csrk_mitm_protected(false), ltk_stored(false), - mitm_ltk(false), - secure_connections(false), + ltk_mitm_protected(false), + secure_connections_paired(false), connected(false), authenticated(false), - master(false), + is_master(false), encryption_requested(false), encryption_failed(false), encrypted(false), @@ -65,14 +65,20 @@ struct SecurityEntry_t { * Reset state of the connection when disconnected. */ void reset() { - mitm_requested = false; - mitm_performed = false; + local_address = address_t(); + connected = true; authenticated = false; + is_master = false; + encryption_requested = false; encryption_failed = false; encrypted = false; signing_requested = false; + + mitm_requested = false; + mitm_performed = false; + attempt_oob = false; oob_mitm_protection = false; oob_present = false; @@ -80,21 +86,24 @@ struct SecurityEntry_t { connection_handle_t handle; address_t peer_address; + uint8_t encryption_key_size; - uint8_t peer_address_public:1; - uint8_t local_address_public:1; + uint8_t peer_address_is_public:1; + uint8_t local_address_is_public:1; uint8_t csrk_stored:1; - uint8_t mitm_csrk:1; + uint8_t csrk_mitm_protected:1; uint8_t ltk_stored:1; - uint8_t mitm_ltk:1; - uint8_t secure_connections:1; + uint8_t ltk_mitm_protected:1; + uint8_t secure_connections_paired:1; /* do not store in NVM */ + address_t local_address; /**< address used for connection, possibly different from identity */ + uint8_t connected:1; uint8_t authenticated:1; /**< have we turned encryption on during this connection */ - uint8_t master:1; + uint8_t is_master:1; uint8_t encryption_requested:1; uint8_t encryption_failed:1; @@ -444,8 +453,9 @@ public: */ virtual SecurityEntry_t* connect_entry( connection_handle_t connection, - connection_peer_address_type_t::type peer_address_type, - const address_t& peer_address + BLEProtocol::AddressType_t peer_address_type, + const address_t& peer_address, + const address_t& local_address ) = 0; /** @@ -830,17 +840,18 @@ public: virtual SecurityEntry_t* connect_entry( connection_handle_t connection, - connection_peer_address_type_t::type peer_address_type, - const address_t& peer_address + BLEProtocol::AddressType_t peer_address_type, + const address_t& peer_address, + const address_t& local_address ) { const bool peer_address_public = - (peer_address_type == connection_peer_address_type_t::PUBLIC_ADDRESS); + (peer_address_type == BLEProtocol::AddressType::PUBLIC); for (size_t i = 0; i < MAX_ENTRIES; i++) { if (_db[i].entry.connected) { continue; } else if (peer_address == _identities[i].identity_address - && _db[i].entry.peer_address_public == peer_address_public) { + && _db[i].entry.peer_address_is_public == peer_address_public) { return &_db[i].entry; } } @@ -850,8 +861,9 @@ public: if (!_db[i].entry.connected) { _db[i] = db_store_t(); _identities[i] = SecurityEntryIdentity_t(); - _identities[i].identity_address = peer_address; - _db[i].entry.peer_address_public = peer_address_public; + _db[i].entry.peer_address = peer_address; + _db[i].entry.local_address = local_address; + _db[i].entry.peer_address_is_public = peer_address_public; return &_db[i].entry; } } @@ -878,7 +890,7 @@ public: virtual void generate_whitelist_from_bond_table(WhitelistDbCb_t cb, Gap::Whitelist_t *whitelist) { for (size_t i = 0; i < MAX_ENTRIES && i < whitelist->capacity; i++) { - if (_db[i].entry.peer_address_public) { + if (_db[i].entry.peer_address_is_public) { whitelist->addresses[i].type = BLEProtocol::AddressType::PUBLIC; } else { whitelist->addresses[i].type = BLEProtocol::AddressType::RANDOM_STATIC; diff --git a/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h b/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h index f04fbce35a..4c910823c8 100644 --- a/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h +++ b/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h @@ -21,6 +21,7 @@ #include "ble/BLETypes.h" #include "ble/generic/GenericSecurityDb.h" #include "Callback.h" +#include "ble/Gap.h" namespace ble { namespace generic { @@ -47,39 +48,6 @@ class GenericSecurityManagerEventHandler; class GenericSecurityManager : public SecurityManager, public ble::pal::SecurityManagerEventHandler { public: - //////////////////////////////////////////////////////////////////////////// - // GAP integration - // - - /** - * Inform the security manager that a device has been disconnected and its - * entry can be put in NVM storage. Called by GAP. - * - * @param[in] connectionHandle Handle to identify the connection. - * @return BLE_ERROR_NONE or appropriate error code indicating the failure reason. - */ - virtual void disconnected( - connection_handle_t connection - ); - - /** - * Inform the Security manager of a new connection. This will create - * or retrieve an existing security manager entry for the connected device. - * Called by GAP. - * - * @param[in] connectionHandle Handle to identify the connection. - * @param[in] is_master True if device is the master. - * @param[in] peer_address_type type of address - * @param[in] peer_address Address of the connected device. - * @return BLE_ERROR_NONE or appropriate error code indicating the failure reason. - */ - virtual void connected( - connection_handle_t connection, - bool is_master, - connection_peer_address_type_t::type peer_address_type, - const address_t &peer_address - ); - /* implements SecurityManager */ //////////////////////////////////////////////////////////////////////////// @@ -270,9 +238,10 @@ public: /* ends implements SecurityManager */ protected: - GenericSecurityManager(ble::pal::SecurityManager& palImpl, GenericSecurityDb& dbImpl) + GenericSecurityManager(ble::pal::SecurityManager& palImpl, GenericSecurityDb& dbImpl, Gap& gapImpl) : _pal(palImpl), _db(dbImpl), + _gap(gapImpl), _default_authentication(0), _default_key_distribution(KeyDistribution::KEY_DISTRIBUTION_ALL), _pairing_authorisation_required(false), @@ -394,9 +363,48 @@ private: ); #endif + /** + * Inform the security manager that a device has been disconnected and its + * entry can be put in NVM storage. Called by GAP. + * + * @param[in] connectionHandle Handle to identify the connection. + * @return BLE_ERROR_NONE or appropriate error code indicating the failure reason. + */ + void on_disconnected( + connection_handle_t connection + ); + + /** + * Inform the Security manager of a new connection. This will create + * or retrieve an existing security manager entry for the connected device. + * Called by GAP. + * + * @param[in] connectionHandle Handle to identify the connection. + * @param[in] is_master True if device is the master. + * @param[in] peer_address_type type of address + * @param[in] peer_address Address of the connected device. + * @return BLE_ERROR_NONE or appropriate error code indicating the failure reason. + */ + void on_connected( + connection_handle_t connection, + bool is_master, + BLEProtocol::AddressType_t peer_address_type, + const address_t &peer_address, + const address_t &local_address + ); + + void connection_callback( + const Gap::ConnectionCallbackParams_t* params + ); + + void disconnection_callback( + const Gap::DisconnectionCallbackParams_t* params + ); + private: ble::pal::SecurityManager& _pal; GenericSecurityDb& _db; + Gap& _gap; AuthenticationMask _default_authentication; KeyDistribution _default_key_distribution; diff --git a/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp b/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp index 26bac3c9ed..225fe9d6fe 100644 --- a/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp +++ b/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp @@ -26,39 +26,6 @@ namespace generic { /* Implements SecurityManager */ -//////////////////////////////////////////////////////////////////////////// -// GAP integration -// - -void GenericSecurityManager::disconnected(connection_handle_t connection) { - SecurityEntry_t *entry = _db.get_entry(connection); - if (!entry) { - return; - } - entry->connected = false; - _db.sync(); -} - -void GenericSecurityManager::connected( - connection_handle_t connection, - bool is_master, - connection_peer_address_type_t::type peer_address_type, - const address_t &peer_address -) { - SecurityEntry_t *entry = _db.connect_entry( - connection, - peer_address_type, - peer_address - ); - - if (!entry) { - return; - } - - entry->reset(); - entry->master = is_master; -} - //////////////////////////////////////////////////////////////////////////// // SM lifecycle management // @@ -88,6 +55,9 @@ ble_error_t GenericSecurityManager::init( init_signing(); } + _gap.onConnection(this, &GenericSecurityManager::connection_callback); + _gap.onDisconnection(this, &GenericSecurityManager::disconnection_callback); + _pal.generate_public_key(); return BLE_ERROR_NONE; @@ -135,10 +105,6 @@ ble_error_t GenericSecurityManager::requestPairing(connection_handle_t connectio return BLE_ERROR_INVALID_PARAM; } - /* TODO: remove */ - _db.get_entry(connection)->master = true; - /* end temp code */ - if (!_legacy_pairing_allowed && !_default_authentication.get_secure_connections()) { return BLE_ERROR_OPERATION_NOT_PERMITTED; } @@ -291,7 +257,7 @@ ble_error_t GenericSecurityManager::enableSigning( } if (!entry->csrk_stored && entry->signing_requested) { init_signing(); - if (entry->master) { + if (entry->is_master) { return requestPairing(connection); } else { return slave_security_request(connection); @@ -321,7 +287,7 @@ ble_error_t GenericSecurityManager::getLinkEncryption( } if (entry->encrypted) { - if (entry->mitm_ltk) { + if (entry->ltk_mitm_protected) { *encryption = link_encryption_t::ENCRYPTED_WITH_MITM; } else { *encryption = link_encryption_t::ENCRYPTED; @@ -373,7 +339,7 @@ ble_error_t GenericSecurityManager::setLinkEncryption( } else if (encryption == link_encryption_t::ENCRYPTED_WITH_MITM) { - if (entry->mitm_ltk && !entry->encrypted) { + if (entry->ltk_mitm_protected && !entry->encrypted) { entry->encryption_requested = true; return enable_encryption(connection); } else { @@ -418,7 +384,7 @@ ble_error_t GenericSecurityManager::getSigningKey(connection_handle_t connection return BLE_ERROR_INVALID_PARAM; } - if (entry->csrk_stored && (entry->mitm_csrk || !authenticated)) { + if (entry->csrk_stored && (entry->csrk_mitm_protected || !authenticated)) { /* we have a key that is either authenticated or we don't care if it is * so retrieve it from the db now */ _db.get_entry_peer_csrk( @@ -432,7 +398,7 @@ ble_error_t GenericSecurityManager::getSigningKey(connection_handle_t connection * keys exchange will create the signingKey event */ if (authenticated) { return requestAuthentication(connection); - } else if (entry->master) { + } else if (entry->is_master) { return requestPairing(connection); } else { return slave_security_request(connection); @@ -458,7 +424,7 @@ ble_error_t GenericSecurityManager::requestAuthentication(connection_handle_t co return BLE_ERROR_INVALID_PARAM; } - if (entry->mitm_ltk) { + if (entry->ltk_mitm_protected) { if (entry->authenticated) { return BLE_ERROR_NONE; } else { @@ -467,7 +433,7 @@ ble_error_t GenericSecurityManager::requestAuthentication(connection_handle_t co } } else { entry->mitm_requested = true; - if (entry->master) { + if (entry->is_master) { return requestPairing(connection); } else { return slave_security_request(connection); @@ -612,7 +578,7 @@ ble_error_t GenericSecurityManager::enable_encryption(connection_handle_t connec if (!entry) { return BLE_ERROR_INVALID_PARAM; } - if (entry->master) { + if (entry->is_master) { if (entry->ltk_stored) { _db.get_entry_peer_keys( mbed::callback(this, &GenericSecurityManager::enable_encryption_cb), @@ -661,7 +627,7 @@ void GenericSecurityManager::return_csrk_cb( eventHandler->signingKey( connection, csrk, - entry->mitm_csrk + entry->csrk_mitm_protected ); } @@ -669,11 +635,13 @@ void GenericSecurityManager::return_csrk_cb( void GenericSecurityManager::generate_secure_connections_oob( connection_handle_t connection ) { - address_t local_address; oob_confirm_t confirm; oob_rand_t random; - /*TODO: get local address*/ + SecurityEntry_t *entry = _db.get_entry(connection); + if (!entry) { + return; + } ble_error_t ret = get_random_data(random.buffer(), random.size()); if (ret != BLE_ERROR_NONE) { @@ -688,7 +656,7 @@ void GenericSecurityManager::generate_secure_connections_oob( ); _app_event_handler->oobGenerated( - &local_address, + &entry->local_address, &random, &confirm ); @@ -748,6 +716,54 @@ bool GenericSecurityManager::crypto_toolbox_f4( } #endif +void GenericSecurityManager::on_disconnected(connection_handle_t connection) { + SecurityEntry_t *entry = _db.get_entry(connection); + if (!entry) { + return; + } + entry->connected = false; + _db.sync(); +} + +void GenericSecurityManager::on_connected( + connection_handle_t connection, + bool is_master, + BLEProtocol::AddressType_t peer_address_type, + const address_t &peer_address, + const address_t &local_address +) { + SecurityEntry_t *entry = _db.connect_entry( + connection, + peer_address_type, + peer_address, + local_address + ); + + if (!entry) { + return; + } + + entry->reset(); + entry->is_master = is_master; +} + +void GenericSecurityManager::connection_callback( + const Gap::ConnectionCallbackParams_t* params +) { + on_connected( + params->handle, + (params->role == Gap::CENTRAL), + params->peerAddrType, + address_t(params->peerAddr), + address_t(params->ownAddr) + ); +} +void GenericSecurityManager::disconnection_callback( + const Gap::DisconnectionCallbackParams_t* params +) { + on_disconnected(params->handle); +} + /* Implements ble::pal::SecurityManagerEventHandler */ //////////////////////////////////////////////////////////////////////////// @@ -761,10 +777,6 @@ void GenericSecurityManager::on_pairing_request( KeyDistribution initiator_dist, KeyDistribution responder_dist ) { - /* TODO: remove */ - _db.get_entry(connection)->master = false; - /* end temp code */ - /* cancel pairing if secure connection paring is not possible */ if (!_legacy_pairing_allowed && !authentication.get_secure_connections()) { canceltPairingRequest(connection); @@ -816,8 +828,8 @@ void GenericSecurityManager::on_pairing_completed(connection_handle_t connection } /* sc doesn't need to exchange ltk */ - if (entry->secure_connections) { - entry->mitm_ltk = entry->mitm_performed; + if (entry->secure_connections_paired) { + entry->ltk_mitm_protected = entry->mitm_performed; } } @@ -846,12 +858,12 @@ void GenericSecurityManager::on_slave_security_request( if (authentication.get_secure_connections() && _default_authentication.get_secure_connections() - && !entry->secure_connections) { + && !entry->secure_connections_paired) { requestPairing(connection); } if (authentication.get_mitm() - && !entry->mitm_ltk) { + && !entry->ltk_mitm_protected) { entry->mitm_requested = true; requestPairing(connection); } @@ -1006,8 +1018,8 @@ void GenericSecurityManager::on_secure_connections_ltk_generated( return; } - entry->mitm_ltk = entry->mitm_performed; - entry->secure_connections = true; + entry->ltk_mitm_protected = entry->mitm_performed; + entry->secure_connections_paired = true; _db.set_entry_peer_ltk(connection, ltk); } @@ -1027,8 +1039,8 @@ void GenericSecurityManager::on_keys_distributed( return; } - entry->mitm_ltk = entry->mitm_performed; - entry->mitm_csrk = entry->mitm_performed; + entry->ltk_mitm_protected = entry->mitm_performed; + entry->csrk_mitm_protected = entry->mitm_performed; _db.set_entry_peer( connection, @@ -1044,7 +1056,7 @@ void GenericSecurityManager::on_keys_distributed( eventHandler->signingKey( connection, csrk, - entry->mitm_csrk + entry->csrk_mitm_protected ); } @@ -1056,7 +1068,7 @@ void GenericSecurityManager::on_keys_distributed_ltk( if (!entry) { return; } - entry->mitm_ltk = entry->mitm_performed; + entry->ltk_mitm_protected = entry->mitm_performed; _db.set_entry_peer_ltk(connection, ltk); } @@ -1111,14 +1123,14 @@ void GenericSecurityManager::on_keys_distributed_csrk( return; } - entry->mitm_csrk = entry->mitm_performed; + entry->csrk_mitm_protected = entry->mitm_performed; _db.set_entry_peer_csrk(connection, csrk); eventHandler->signingKey( connection, csrk, - entry->mitm_csrk + entry->csrk_mitm_protected ); }