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.
* @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

View File

@ -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.
*

View File

@ -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<SecurityEntryIdentity_t> 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<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() {
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;