diff --git a/features/FEATURE_BLE/ble/SecurityManager.h b/features/FEATURE_BLE/ble/SecurityManager.h index c99ebd702a..358e2478a4 100644 --- a/features/FEATURE_BLE/ble/SecurityManager.h +++ b/features/FEATURE_BLE/ble/SecurityManager.h @@ -441,7 +441,7 @@ public: * support out-of-band exchanges of security data. * @param[in] passkey To specify a static passkey. * @param[in] signing Generate and distribute signing key during pairing - * @param[in] dbPath Path to the folder used to store keys in the filesystem, + * @param[in] dbPath Path to the file used to store keys in the filesystem, * if NULL keys will be only stored in memory * * @@ -452,17 +452,33 @@ public: SecurityIOCapabilities_t iocaps = IO_CAPS_NONE, const Passkey_t passkey = NULL, bool signing = true, - const char *dbPath = NULL) { + const char *dbFilepath = NULL) { /* Avoid compiler warnings about unused variables. */ (void)enableBonding; (void)requireMITM; (void)iocaps; (void)passkey; - (void)dbPath; + (void)dbFilepath; return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */ } + /** + * Change the file used for the security database. If path is invalid or a NULL is passed + * keys will only be stored in memory. + * + * @note This operation is only allowed with no active connections. + * + * @param[in] dbPath Path to the file used to store keys in the filesystem, + * if NULL keys will be only stored in memory + * + * @return BLE_ERROR_NONE on success. + */ + virtual ble_error_t setDatabaseFilepath(const char *dbFilepath = NULL) { + (void)dbFilepath; + return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */ + } + /** * Notify all registered onShutdown callbacks that the SecurityManager is * about to be shutdown and clear all SecurityManager state of the diff --git a/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h b/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h index f5f060a5e6..b2a2e8ff97 100644 --- a/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h +++ b/features/FEATURE_BLE/ble/generic/GenericSecurityManager.h @@ -53,6 +53,8 @@ public: const char* db_path = NULL ); + virtual ble_error_t setDatabaseFilepath(const char *db_path = NULL); + virtual ble_error_t reset(); virtual ble_error_t preserveBondingStateOnReset( @@ -263,6 +265,22 @@ public: // private: + + /** + * Initialise the database, if database already exists it will close it and open the new one. + * + * @param db_path path to file to store secure db + * @return BLE_ERROR_NONE or appropriate error code indicating the failure reason. + */ + ble_error_t init_database(const char *db_path = NULL); + + /** + * Generate identity list based on the database of IRK and apply it to the resolving list. + * + * @return BLE_ERROR_NONE or appropriate error code indicating the failure reason. + */ + ble_error_t init_resolving_list(); + /** * Generate the CSRK if needed. * diff --git a/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp b/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp index bb03c2f548..29adce2ba4 100644 --- a/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp +++ b/features/FEATURE_BLE/source/generic/GenericSecurityManager.cpp @@ -42,30 +42,18 @@ ble_error_t GenericSecurityManager::init( bool signing, const char* db_path ) { + ble_error_t result = _pal.initialize(); - ble_error_t err = _pal.initialize(); - if (err) { - return err; + if (result != BLE_ERROR_NONE) { + return result; } - if (_db) { - delete _db; + result = init_database(db_path); + + if (result != BLE_ERROR_NONE) { + return result; } - FILE* db_file = FileSecurityDb::open_db_file(db_path); - - if (db_file) { - _db = new (std::nothrow) FileSecurityDb(db_file); - } else { - _db = new (std::nothrow) MemorySecurityDb(); - } - - if (!_db) { - return BLE_ERROR_NO_MEM; - } - - _db->restore(); - _pal.set_io_capability((io_capability_t::type) iocaps); if (passkey) { @@ -96,25 +84,38 @@ ble_error_t GenericSecurityManager::init( _signing_monitor.set_signing_event_handler(this); _pal.set_event_handler(this); - uint8_t resolving_list_capacity = _pal.read_resolving_list_capacity(); - SecurityEntryIdentity_t* identity_list_p = - new (std::nothrow) SecurityEntryIdentity_t[resolving_list_capacity]; + result = init_resolving_list(); - if (identity_list_p) { - ArrayView identity_list( - identity_list_p, - resolving_list_capacity - ); - - _db->get_identity_list( - mbed::callback(this, &GenericSecurityManager::on_identity_list_retrieved), - identity_list - ); + if (result != BLE_ERROR_NONE) { + delete _db; + return result; } return BLE_ERROR_NONE; } +ble_error_t GenericSecurityManager::setDatabaseFilepath( + const char *db_path +) { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; + + /* operation only allowed with no connections active */ + for (size_t i = 0; i < MAX_CONTROL_BLOCKS; i++) { + if (_control_blocks[i].connected) { + return BLE_ERROR_OPERATION_NOT_PERMITTED; + } + } + + ble_error_t result = init_database(db_path); + if (result != BLE_ERROR_NONE) { + return result; + } + + init_resolving_list(); + + return BLE_ERROR_NONE; +} + ble_error_t GenericSecurityManager::reset(void) { _pal.reset(); SecurityManager::reset(); @@ -123,7 +124,7 @@ ble_error_t GenericSecurityManager::reset(void) { } ble_error_t GenericSecurityManager::preserveBondingStateOnReset(bool enabled) { - MBED_ASSERT(_db); + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; _db->set_restore(enabled); return BLE_ERROR_NONE; } @@ -133,13 +134,13 @@ ble_error_t GenericSecurityManager::preserveBondingStateOnReset(bool enabled) { // ble_error_t GenericSecurityManager::purgeAllBondingState(void) { - MBED_ASSERT(_db); + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; _db->clear_entries(); return BLE_ERROR_NONE; } ble_error_t GenericSecurityManager::generateWhitelistFromBondTable(Gap::Whitelist_t *whitelist) const { - MBED_ASSERT(_db); + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; if (eventHandler) { _db->generate_whitelist_from_bond_table( mbed::callback(eventHandler, &::SecurityManager::EventHandler::whitelistFromBondTable), @@ -154,6 +155,7 @@ ble_error_t GenericSecurityManager::generateWhitelistFromBondTable(Gap::Whitelis // ble_error_t GenericSecurityManager::requestPairing(connection_handle_t connection) { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; ControlBlock_t *cb = get_control_block(connection); if (!cb) { return BLE_ERROR_INVALID_PARAM; @@ -206,6 +208,7 @@ ble_error_t GenericSecurityManager::requestPairing(connection_handle_t connectio } ble_error_t GenericSecurityManager::acceptPairingRequest(connection_handle_t connection) { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; ControlBlock_t *cb = get_control_block(connection); if (!cb) { return BLE_ERROR_INVALID_PARAM; @@ -263,10 +266,12 @@ ble_error_t GenericSecurityManager::acceptPairingRequest(connection_handle_t con } ble_error_t GenericSecurityManager::cancelPairingRequest(connection_handle_t connection) { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; return _pal.cancel_pairing(connection, pairing_failure_t::UNSPECIFIED_REASON); } ble_error_t GenericSecurityManager::setPairingRequestAuthorisation(bool required) { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; _pairing_authorisation_required = required; return BLE_ERROR_NONE; } @@ -289,10 +294,12 @@ ble_error_t GenericSecurityManager::getSecureConnectionsSupport(bool *enabled) { // ble_error_t GenericSecurityManager::setIoCapability(SecurityIOCapabilities_t iocaps) { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; return _pal.set_io_capability((io_capability_t::type) iocaps); } ble_error_t GenericSecurityManager::setDisplayPasskey(const Passkey_t passkey) { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; return _pal.set_display_passkey(PasskeyAscii::to_num(passkey)); } @@ -300,6 +307,7 @@ ble_error_t GenericSecurityManager::setAuthenticationTimeout( connection_handle_t connection, uint32_t timeout_in_ms ) { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; return _pal.set_authentication_timeout(connection, timeout_in_ms / 10); } @@ -307,6 +315,7 @@ ble_error_t GenericSecurityManager::getAuthenticationTimeout( connection_handle_t connection, uint32_t *timeout_in_ms ) { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; uint16_t timeout_in_10ms; ble_error_t status = _pal.get_authentication_timeout(connection, timeout_in_10ms); *timeout_in_ms = 10 * timeout_in_10ms; @@ -317,6 +326,7 @@ ble_error_t GenericSecurityManager::setLinkSecurity( connection_handle_t connection, SecurityMode_t securityMode ) { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; ControlBlock_t *cb = get_control_block(connection); if (!cb) { return BLE_ERROR_INVALID_PARAM; @@ -348,6 +358,7 @@ ble_error_t GenericSecurityManager::setLinkSecurity( } ble_error_t GenericSecurityManager::setKeypressNotification(bool enabled) { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; _default_authentication.set_keypress_notification(enabled); return BLE_ERROR_NONE; } @@ -356,7 +367,7 @@ ble_error_t GenericSecurityManager::enableSigning( connection_handle_t connection, bool enabled ) { - MBED_ASSERT(_db); + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; ControlBlock_t *cb = get_control_block(connection); if (!cb) { return BLE_ERROR_INVALID_PARAM; @@ -406,7 +417,7 @@ ble_error_t GenericSecurityManager::getLinkEncryption( connection_handle_t connection, link_encryption_t *encryption ) { - MBED_ASSERT(_db); + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; ControlBlock_t *cb = get_control_block(connection); if (!cb) { return BLE_ERROR_INVALID_PARAM; @@ -440,7 +451,7 @@ ble_error_t GenericSecurityManager::setLinkEncryption( connection_handle_t connection, link_encryption_t encryption ) { - MBED_ASSERT(_db); + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; ControlBlock_t *cb = get_control_block(connection); if (!cb) { return BLE_ERROR_INVALID_PARAM; @@ -511,7 +522,7 @@ ble_error_t GenericSecurityManager::getEncryptionKeySize( connection_handle_t connection, uint8_t *size ) { - MBED_ASSERT(_db); + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; ControlBlock_t *cb = get_control_block(connection); if (!cb) { return BLE_ERROR_INVALID_PARAM; @@ -530,6 +541,7 @@ ble_error_t GenericSecurityManager::setEncryptionKeyRequirements( uint8_t minimumByteSize, uint8_t maximumByteSize ) { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; return _pal.set_encryption_key_requirements(minimumByteSize, maximumByteSize); } @@ -538,7 +550,7 @@ ble_error_t GenericSecurityManager::setEncryptionKeyRequirements( // ble_error_t GenericSecurityManager::getSigningKey(connection_handle_t connection, bool authenticated) { - MBED_ASSERT(_db); + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; ControlBlock_t *cb = get_control_block(connection); if (!cb) { return BLE_ERROR_INVALID_PARAM; @@ -576,6 +588,7 @@ ble_error_t GenericSecurityManager::getSigningKey(connection_handle_t connection // ble_error_t GenericSecurityManager::setPrivateAddressTimeout(uint16_t timeout_in_seconds) { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; return _pal.set_private_address_timeout(timeout_in_seconds); } @@ -584,7 +597,7 @@ ble_error_t GenericSecurityManager::setPrivateAddressTimeout(uint16_t timeout_in // ble_error_t GenericSecurityManager::requestAuthentication(connection_handle_t connection) { - MBED_ASSERT(_db); + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; ControlBlock_t *cb = get_control_block(connection); if (!cb) { return BLE_ERROR_INVALID_PARAM; @@ -619,6 +632,7 @@ ble_error_t GenericSecurityManager::requestAuthentication(connection_handle_t co ble_error_t GenericSecurityManager::generateOOB( const address_t *address ) { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; /* legacy pairing */ ble_error_t status = get_random_data(_oob_temporary_key.data(), 16); @@ -658,6 +672,7 @@ ble_error_t GenericSecurityManager::setOOBDataUsage( bool useOOB, bool OOBProvidesMITM ) { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; ControlBlock_t *cb = get_control_block(connection); if (!cb) { return BLE_ERROR_INVALID_PARAM; @@ -677,6 +692,7 @@ ble_error_t GenericSecurityManager::confirmationEntered( connection_handle_t connection, bool confirmation ) { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; return _pal.confirmation_entered(connection, confirmation); } @@ -684,6 +700,7 @@ ble_error_t GenericSecurityManager::passkeyEntered( connection_handle_t connection, Passkey_t passkey ) { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; return _pal.passkey_request_reply( connection, PasskeyAscii::to_num(passkey) @@ -694,6 +711,7 @@ ble_error_t GenericSecurityManager::sendKeypressNotification( connection_handle_t connection, Keypress_t keypress ) { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; return _pal.send_keypress_notification(connection, keypress); } @@ -701,7 +719,7 @@ ble_error_t GenericSecurityManager::legacyPairingOobReceived( const address_t *address, const oob_tk_t *tk ) { - MBED_ASSERT(_db); + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; if (address && tk) { ControlBlock_t *cb = get_control_block(*address); if (!cb) { @@ -736,6 +754,7 @@ ble_error_t GenericSecurityManager::oobReceived( const oob_lesc_value_t *random, const oob_confirm_t *confirm ) { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; if (address && random && confirm) { _oob_peer_address = *address; _oob_peer_random = *random; @@ -750,8 +769,55 @@ ble_error_t GenericSecurityManager::oobReceived( // Helper functions // +ble_error_t GenericSecurityManager::init_database( + const char *db_path +) { + delete _db; + + FILE* db_file = FileSecurityDb::open_db_file(db_path); + + if (db_file) { + _db = new (std::nothrow) FileSecurityDb(db_file); + } else { + _db = new (std::nothrow) MemorySecurityDb(); + } + + if (!_db) { + return BLE_ERROR_NO_MEM; + } + + _db->restore(); + + return BLE_ERROR_NONE; +} + +ble_error_t GenericSecurityManager::init_resolving_list() { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; + + /* match the resolving list to the currently stored set of IRKs */ + uint8_t resolving_list_capacity = _pal.read_resolving_list_capacity(); + SecurityEntryIdentity_t* identity_list_p = + new (std::nothrow) SecurityEntryIdentity_t[resolving_list_capacity]; + + if (identity_list_p) { + ArrayView identity_list( + identity_list_p, + resolving_list_capacity + ); + + _db->get_identity_list( + mbed::callback(this, &GenericSecurityManager::on_identity_list_retrieved), + identity_list + ); + } else { + return BLE_ERROR_NO_MEM; + } + + return BLE_ERROR_NONE; +} + ble_error_t GenericSecurityManager::init_signing() { - MBED_ASSERT(_db); + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; const csrk_t *pcsrk = _db->get_local_csrk(); sign_count_t local_sign_counter = _db->get_local_sign_counter(); @@ -791,6 +857,7 @@ ble_error_t GenericSecurityManager::get_random_data(uint8_t *buffer, size_t size } ble_error_t GenericSecurityManager::slave_security_request(connection_handle_t connection) { + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; ControlBlock_t *cb = get_control_block(connection); if (!cb) { return BLE_ERROR_INVALID_PARAM; @@ -801,7 +868,7 @@ ble_error_t GenericSecurityManager::slave_security_request(connection_handle_t c } ble_error_t GenericSecurityManager::enable_encryption(connection_handle_t connection) { - MBED_ASSERT(_db); + if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; ControlBlock_t *cb = get_control_block(connection); if (!cb) { return BLE_ERROR_INVALID_PARAM;