Merge pull request #48 from paul-szczepanek-arm/sm-init-error

allow changing database at runtime and add checking for initialisation
pull/6932/head
Vincent Coubard 2018-05-21 11:36:43 +01:00 committed by GitHub
commit 4e3a9ffabb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 148 additions and 47 deletions

View File

@ -441,7 +441,7 @@ public:
* support out-of-band exchanges of security data. * support out-of-band exchanges of security data.
* @param[in] passkey To specify a static passkey. * @param[in] passkey To specify a static passkey.
* @param[in] signing Generate and distribute signing key during pairing * @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 * if NULL keys will be only stored in memory
* *
* *
@ -452,17 +452,33 @@ public:
SecurityIOCapabilities_t iocaps = IO_CAPS_NONE, SecurityIOCapabilities_t iocaps = IO_CAPS_NONE,
const Passkey_t passkey = NULL, const Passkey_t passkey = NULL,
bool signing = true, bool signing = true,
const char *dbPath = NULL) { const char *dbFilepath = NULL) {
/* Avoid compiler warnings about unused variables. */ /* Avoid compiler warnings about unused variables. */
(void)enableBonding; (void)enableBonding;
(void)requireMITM; (void)requireMITM;
(void)iocaps; (void)iocaps;
(void)passkey; (void)passkey;
(void)dbPath; (void)dbFilepath;
return BLE_ERROR_NOT_IMPLEMENTED; /* Requesting action from porters: override this API if security is supported. */ 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 * Notify all registered onShutdown callbacks that the SecurityManager is
* about to be shutdown and clear all SecurityManager state of the * about to be shutdown and clear all SecurityManager state of the

View File

@ -53,6 +53,8 @@ public:
const char* db_path = NULL const char* db_path = NULL
); );
virtual ble_error_t setDatabaseFilepath(const char *db_path = NULL);
virtual ble_error_t reset(); virtual ble_error_t reset();
virtual ble_error_t preserveBondingStateOnReset( virtual ble_error_t preserveBondingStateOnReset(
@ -263,6 +265,22 @@ public:
// //
private: 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. * Generate the CSRK if needed.
* *

View File

@ -42,30 +42,18 @@ ble_error_t GenericSecurityManager::init(
bool signing, bool signing,
const char* db_path const char* db_path
) { ) {
ble_error_t result = _pal.initialize();
ble_error_t err = _pal.initialize(); if (result != BLE_ERROR_NONE) {
if (err) { return result;
return err;
} }
if (_db) { result = init_database(db_path);
delete _db;
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); _pal.set_io_capability((io_capability_t::type) iocaps);
if (passkey) { if (passkey) {
@ -96,25 +84,38 @@ ble_error_t GenericSecurityManager::init(
_signing_monitor.set_signing_event_handler(this); _signing_monitor.set_signing_event_handler(this);
_pal.set_event_handler(this); _pal.set_event_handler(this);
uint8_t resolving_list_capacity = _pal.read_resolving_list_capacity(); result = init_resolving_list();
SecurityEntryIdentity_t* identity_list_p =
new (std::nothrow) SecurityEntryIdentity_t[resolving_list_capacity];
if (identity_list_p) { if (result != BLE_ERROR_NONE) {
ArrayView<SecurityEntryIdentity_t> identity_list( delete _db;
identity_list_p, return result;
resolving_list_capacity
);
_db->get_identity_list(
mbed::callback(this, &GenericSecurityManager::on_identity_list_retrieved),
identity_list
);
} }
return BLE_ERROR_NONE; 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) { ble_error_t GenericSecurityManager::reset(void) {
_pal.reset(); _pal.reset();
SecurityManager::reset(); SecurityManager::reset();
@ -123,7 +124,7 @@ ble_error_t GenericSecurityManager::reset(void) {
} }
ble_error_t GenericSecurityManager::preserveBondingStateOnReset(bool enabled) { ble_error_t GenericSecurityManager::preserveBondingStateOnReset(bool enabled) {
MBED_ASSERT(_db); if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
_db->set_restore(enabled); _db->set_restore(enabled);
return BLE_ERROR_NONE; return BLE_ERROR_NONE;
} }
@ -133,13 +134,13 @@ ble_error_t GenericSecurityManager::preserveBondingStateOnReset(bool enabled) {
// //
ble_error_t GenericSecurityManager::purgeAllBondingState(void) { ble_error_t GenericSecurityManager::purgeAllBondingState(void) {
MBED_ASSERT(_db); if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
_db->clear_entries(); _db->clear_entries();
return BLE_ERROR_NONE; return BLE_ERROR_NONE;
} }
ble_error_t GenericSecurityManager::generateWhitelistFromBondTable(Gap::Whitelist_t *whitelist) const { ble_error_t GenericSecurityManager::generateWhitelistFromBondTable(Gap::Whitelist_t *whitelist) const {
MBED_ASSERT(_db); if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
if (eventHandler) { if (eventHandler) {
_db->generate_whitelist_from_bond_table( _db->generate_whitelist_from_bond_table(
mbed::callback(eventHandler, &::SecurityManager::EventHandler::whitelistFromBondTable), 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) { ble_error_t GenericSecurityManager::requestPairing(connection_handle_t connection) {
if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; 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) { ble_error_t GenericSecurityManager::acceptPairingRequest(connection_handle_t connection) {
if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; 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) { 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); return _pal.cancel_pairing(connection, pairing_failure_t::UNSPECIFIED_REASON);
} }
ble_error_t GenericSecurityManager::setPairingRequestAuthorisation(bool required) { ble_error_t GenericSecurityManager::setPairingRequestAuthorisation(bool required) {
if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
_pairing_authorisation_required = required; _pairing_authorisation_required = required;
return BLE_ERROR_NONE; return BLE_ERROR_NONE;
} }
@ -289,10 +294,12 @@ ble_error_t GenericSecurityManager::getSecureConnectionsSupport(bool *enabled) {
// //
ble_error_t GenericSecurityManager::setIoCapability(SecurityIOCapabilities_t iocaps) { 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); return _pal.set_io_capability((io_capability_t::type) iocaps);
} }
ble_error_t GenericSecurityManager::setDisplayPasskey(const Passkey_t passkey) { 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)); return _pal.set_display_passkey(PasskeyAscii::to_num(passkey));
} }
@ -300,6 +307,7 @@ ble_error_t GenericSecurityManager::setAuthenticationTimeout(
connection_handle_t connection, connection_handle_t connection,
uint32_t timeout_in_ms uint32_t timeout_in_ms
) { ) {
if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
return _pal.set_authentication_timeout(connection, timeout_in_ms / 10); return _pal.set_authentication_timeout(connection, timeout_in_ms / 10);
} }
@ -307,6 +315,7 @@ ble_error_t GenericSecurityManager::getAuthenticationTimeout(
connection_handle_t connection, connection_handle_t connection,
uint32_t *timeout_in_ms uint32_t *timeout_in_ms
) { ) {
if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
uint16_t timeout_in_10ms; uint16_t timeout_in_10ms;
ble_error_t status = _pal.get_authentication_timeout(connection, timeout_in_10ms); ble_error_t status = _pal.get_authentication_timeout(connection, timeout_in_10ms);
*timeout_in_ms = 10 * timeout_in_10ms; *timeout_in_ms = 10 * timeout_in_10ms;
@ -317,6 +326,7 @@ ble_error_t GenericSecurityManager::setLinkSecurity(
connection_handle_t connection, connection_handle_t connection,
SecurityMode_t securityMode SecurityMode_t securityMode
) { ) {
if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; return BLE_ERROR_INVALID_PARAM;
@ -348,6 +358,7 @@ ble_error_t GenericSecurityManager::setLinkSecurity(
} }
ble_error_t GenericSecurityManager::setKeypressNotification(bool enabled) { ble_error_t GenericSecurityManager::setKeypressNotification(bool enabled) {
if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
_default_authentication.set_keypress_notification(enabled); _default_authentication.set_keypress_notification(enabled);
return BLE_ERROR_NONE; return BLE_ERROR_NONE;
} }
@ -356,7 +367,7 @@ ble_error_t GenericSecurityManager::enableSigning(
connection_handle_t connection, connection_handle_t connection,
bool enabled bool enabled
) { ) {
MBED_ASSERT(_db); if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; return BLE_ERROR_INVALID_PARAM;
@ -406,7 +417,7 @@ ble_error_t GenericSecurityManager::getLinkEncryption(
connection_handle_t connection, connection_handle_t connection,
link_encryption_t *encryption link_encryption_t *encryption
) { ) {
MBED_ASSERT(_db); if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; return BLE_ERROR_INVALID_PARAM;
@ -440,7 +451,7 @@ ble_error_t GenericSecurityManager::setLinkEncryption(
connection_handle_t connection, connection_handle_t connection,
link_encryption_t encryption link_encryption_t encryption
) { ) {
MBED_ASSERT(_db); if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; return BLE_ERROR_INVALID_PARAM;
@ -511,7 +522,7 @@ ble_error_t GenericSecurityManager::getEncryptionKeySize(
connection_handle_t connection, connection_handle_t connection,
uint8_t *size uint8_t *size
) { ) {
MBED_ASSERT(_db); if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; return BLE_ERROR_INVALID_PARAM;
@ -530,6 +541,7 @@ ble_error_t GenericSecurityManager::setEncryptionKeyRequirements(
uint8_t minimumByteSize, uint8_t minimumByteSize,
uint8_t maximumByteSize uint8_t maximumByteSize
) { ) {
if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
return _pal.set_encryption_key_requirements(minimumByteSize, maximumByteSize); 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) { 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); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; 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) { 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); 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) { 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); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; return BLE_ERROR_INVALID_PARAM;
@ -619,6 +632,7 @@ ble_error_t GenericSecurityManager::requestAuthentication(connection_handle_t co
ble_error_t GenericSecurityManager::generateOOB( ble_error_t GenericSecurityManager::generateOOB(
const address_t *address const address_t *address
) { ) {
if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
/* legacy pairing */ /* legacy pairing */
ble_error_t status = get_random_data(_oob_temporary_key.data(), 16); ble_error_t status = get_random_data(_oob_temporary_key.data(), 16);
@ -658,6 +672,7 @@ ble_error_t GenericSecurityManager::setOOBDataUsage(
bool useOOB, bool useOOB,
bool OOBProvidesMITM bool OOBProvidesMITM
) { ) {
if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
ControlBlock_t *cb = get_control_block(connection); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; return BLE_ERROR_INVALID_PARAM;
@ -677,6 +692,7 @@ ble_error_t GenericSecurityManager::confirmationEntered(
connection_handle_t connection, connection_handle_t connection,
bool confirmation bool confirmation
) { ) {
if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
return _pal.confirmation_entered(connection, confirmation); return _pal.confirmation_entered(connection, confirmation);
} }
@ -684,6 +700,7 @@ ble_error_t GenericSecurityManager::passkeyEntered(
connection_handle_t connection, connection_handle_t connection,
Passkey_t passkey Passkey_t passkey
) { ) {
if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
return _pal.passkey_request_reply( return _pal.passkey_request_reply(
connection, connection,
PasskeyAscii::to_num(passkey) PasskeyAscii::to_num(passkey)
@ -694,6 +711,7 @@ ble_error_t GenericSecurityManager::sendKeypressNotification(
connection_handle_t connection, connection_handle_t connection,
Keypress_t keypress Keypress_t keypress
) { ) {
if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
return _pal.send_keypress_notification(connection, keypress); return _pal.send_keypress_notification(connection, keypress);
} }
@ -701,7 +719,7 @@ ble_error_t GenericSecurityManager::legacyPairingOobReceived(
const address_t *address, const address_t *address,
const oob_tk_t *tk const oob_tk_t *tk
) { ) {
MBED_ASSERT(_db); if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
if (address && tk) { if (address && tk) {
ControlBlock_t *cb = get_control_block(*address); ControlBlock_t *cb = get_control_block(*address);
if (!cb) { if (!cb) {
@ -736,6 +754,7 @@ ble_error_t GenericSecurityManager::oobReceived(
const oob_lesc_value_t *random, const oob_lesc_value_t *random,
const oob_confirm_t *confirm const oob_confirm_t *confirm
) { ) {
if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
if (address && random && confirm) { if (address && random && confirm) {
_oob_peer_address = *address; _oob_peer_address = *address;
_oob_peer_random = *random; _oob_peer_random = *random;
@ -750,8 +769,55 @@ ble_error_t GenericSecurityManager::oobReceived(
// Helper functions // 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<SecurityEntryIdentity_t> 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() { ble_error_t GenericSecurityManager::init_signing() {
MBED_ASSERT(_db); if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
const csrk_t *pcsrk = _db->get_local_csrk(); const csrk_t *pcsrk = _db->get_local_csrk();
sign_count_t local_sign_counter = _db->get_local_sign_counter(); 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) { 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); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; 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) { 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); ControlBlock_t *cb = get_control_block(connection);
if (!cb) { if (!cb) {
return BLE_ERROR_INVALID_PARAM; return BLE_ERROR_INVALID_PARAM;