Merge pull request #13037 from paul-szczepanek-arm/ble-sm-fix

BLE: Fix privacy and signing handling in Security Manager
pull/13095/head
Martin Kojtal 2020-06-10 12:09:32 +02:00 committed by GitHub
commit 2466411b83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 236 additions and 15 deletions

View File

@ -285,6 +285,22 @@ public:
(void)result; (void)result;
} }
/**
* Indicate that a peer address has been saved by the security manager or if we are
* bonded to the peer the identity has been retrieved from the database on connection.
*
* @param[in] connectionHandle Connection handle.
* @param[in] peer_address Peer address that has been saved by the security database, NULL it not found.
* @param[in] address_is_public Address type, true if public. Invalid if peer_address NULL.
*/
virtual void peerIdentity(ble::connection_handle_t connectionHandle,
const address_t *peer_address,
bool address_is_public) {
(void)connectionHandle;
(void)peer_address;
(void)address_is_public;
}
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Security // Security
// //
@ -561,6 +577,14 @@ public:
*/ */
ble_error_t setPairingRequestAuthorisation(bool required = true); ble_error_t setPairingRequestAuthorisation(bool required = true);
/**
* Retrieve identity address for the peer on the given connection.
*
* @param[in] connectionHandle Handle to identify the connection.
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
ble_error_t getPeerIdentity(ble::connection_handle_t connectionHandle);
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Feature support // Feature support
// //
@ -899,6 +923,10 @@ protected:
ble::connection_handle_t connectionHandle ble::connection_handle_t connectionHandle
); );
ble_error_t getPeerIdentity_(
ble::connection_handle_t connectionHandle
);
ble_error_t setPairingRequestAuthorisation_( ble_error_t setPairingRequestAuthorisation_(
bool required bool required
); );

View File

@ -34,8 +34,6 @@ private:
size_t file_offset; size_t file_offset;
}; };
static const size_t MAX_ENTRIES = 5;
static entry_t* as_entry(entry_handle_t db_handle) { static entry_t* as_entry(entry_handle_t db_handle) {
return reinterpret_cast<entry_t*>(db_handle); return reinterpret_cast<entry_t*>(db_handle);
} }
@ -118,6 +116,21 @@ public:
sign_count_t sign_counter sign_count_t sign_counter
); );
/* local csrk and identity */
virtual void set_local_csrk(
const csrk_t &csrk
);
virtual void set_local_identity(
const irk_t &irk,
const address_t &identity_address,
bool public_address
);
/* I am not overriding set_local_sign_counter to avoid constant filesystem writes,
* instead this is synced by sync (which is called on disconnection) */
/* saving and loading from nvm */ /* saving and loading from nvm */
virtual void restore(); virtual void restore();
@ -146,7 +159,7 @@ private:
static FILE* erase_db_file(FILE* db_file); static FILE* erase_db_file(FILE* db_file);
private: private:
entry_t _entries[MAX_ENTRIES]; entry_t _entries[BLE_SECURITY_DATABASE_MAX_ENTRIES];
FILE *_db_file; FILE *_db_file;
uint8_t _buffer[sizeof(SecurityEntryKeys_t)]; uint8_t _buffer[sizeof(SecurityEntryKeys_t)];
}; };

View File

@ -124,6 +124,10 @@ public:
bool required = true bool required = true
); );
ble_error_t getPeerIdentity_(
connection_handle_t connection
);
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Feature support // Feature support
// //
@ -321,6 +325,13 @@ private:
*/ */
ble_error_t init_signing(); ble_error_t init_signing();
/**
* Generate the IRK if needed.
*
* @return BLE_ERROR_NONE or appropriate error code indicating the failure reason.
*/
ble_error_t init_identity();
/** /**
* Fills the buffer with the specified number of bytes of random data * Fills the buffer with the specified number of bytes of random data
* produced by the link controller * produced by the link controller

View File

@ -34,8 +34,6 @@ private:
SecurityEntrySigning_t peer_signing; SecurityEntrySigning_t peer_signing;
}; };
static const size_t MAX_ENTRIES = 5;
static entry_t* as_entry(entry_handle_t db_handle) static entry_t* as_entry(entry_handle_t db_handle)
{ {
return reinterpret_cast<entry_t*>(db_handle); return reinterpret_cast<entry_t*>(db_handle);
@ -150,11 +148,11 @@ public:
private: private:
virtual uint8_t get_entry_count() { virtual uint8_t get_entry_count() {
return MAX_ENTRIES; return BLE_SECURITY_DATABASE_MAX_ENTRIES;
} }
virtual SecurityDistributionFlags_t* get_entry_handle_by_index(uint8_t index) { virtual SecurityDistributionFlags_t* get_entry_handle_by_index(uint8_t index) {
if (index < MAX_ENTRIES) { if (index < BLE_SECURITY_DATABASE_MAX_ENTRIES) {
return &_entries[index].flags; return &_entries[index].flags;
} else { } else {
return NULL; return NULL;
@ -187,7 +185,7 @@ private:
}; };
private: private:
entry_t _entries[MAX_ENTRIES]; entry_t _entries[BLE_SECURITY_DATABASE_MAX_ENTRIES];
}; };
} /* namespace pal */ } /* namespace pal */

View File

@ -425,6 +425,31 @@ public:
_local_sign_counter = sign_counter; _local_sign_counter = sign_counter;
} }
/* local identity */
/**
* Update the local identity.
*
* @param[in] csrk new CSRK value
*/
virtual void set_local_identity(
const irk_t &irk,
const address_t &identity_address,
bool public_address
) {
_local_identity.irk = irk;
_local_identity.identity_address = identity_address;
_local_identity.identity_address_is_public = public_address;
}
/**
* Return local irk.
*
* @return irk
*/
virtual irk_t get_local_irk() {
return _local_identity.irk;
}
/* list management */ /* list management */
/** /**
@ -592,6 +617,21 @@ public:
continue; continue;
} }
// Add the connection address
whitelist->addresses[whitelist->size].address = flags->peer_address.data();
if (flags->peer_address_is_public) {
whitelist->addresses[whitelist->size].type = peer_address_type_t::PUBLIC;
} else {
whitelist->addresses[whitelist->size].type = peer_address_type_t::RANDOM;
}
whitelist->size++;
if (whitelist->size == whitelist->capacity) {
break;
}
// Add the identity address
SecurityEntryIdentity_t* identity = read_in_entry_peer_identity(db_handle); SecurityEntryIdentity_t* identity = read_in_entry_peer_identity(db_handle);
if (!identity) { if (!identity) {
continue; continue;

View File

@ -964,7 +964,23 @@ public:
ble_error_t set_private_address_timeout( ble_error_t set_private_address_timeout(
uint16_t timeout_in_seconds uint16_t timeout_in_seconds
) { ) {
return impl()->set_private_address_timeout(timeout_in_seconds); return impl()->set_private_address_timeout_(timeout_in_seconds);
}
/**
* Retrieve the identity address used by the controller
*
* @param address Will contain the address retrieved.
* @param public_address will be true if the address is public and false
* otherwise.
* @return BLE_ERROR_NONE On success, else an error code indicating the reason
* of the failure
*/
ble_error_t get_identity_address(
address_t& address,
bool& public_address
) {
return impl()->get_identity_address_(address, public_address);
} }
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////

View File

@ -71,6 +71,11 @@
"help": "Include periodic advertising support, depends on the extended advertising feature.", "help": "Include periodic advertising support, depends on the extended advertising feature.",
"value": true, "value": true,
"macro_name": "BLE_FEATURE_PERIODIC_ADVERTISING" "macro_name": "BLE_FEATURE_PERIODIC_ADVERTISING"
},
"ble-security-database-max-entries": {
"help": "How many entries can be stored in the db, depends on security manager.",
"value": 5,
"macro_name": "BLE_SECURITY_DATABASE_MAX_ENTRIES"
} }
} }
} }

View File

@ -54,7 +54,7 @@ const uint16_t DB_VERSION = 1;
) )
#define DB_SIZE_STORES \ #define DB_SIZE_STORES \
(FileSecurityDb::MAX_ENTRIES * DB_SIZE_STORE) (BLE_SECURITY_DATABASE_MAX_ENTRIES * DB_SIZE_STORE)
#define DB_OFFSET_VERSION (0) #define DB_OFFSET_VERSION (0)
#define DB_OFFSET_RESTORE (DB_OFFSET_VERSION + sizeof(DB_VERSION)) #define DB_OFFSET_RESTORE (DB_OFFSET_VERSION + sizeof(DB_VERSION))
@ -265,6 +265,22 @@ void FileSecurityDb::set_entry_peer_sign_counter(
} }
} }
void FileSecurityDb::set_local_csrk(
const csrk_t &csrk
) {
this->SecurityDb::set_local_csrk(csrk);
db_write(&_local_csrk, DB_OFFSET_LOCAL_CSRK);
}
void FileSecurityDb::set_local_identity(
const irk_t &irk,
const address_t &identity_address,
bool public_address
) {
this->SecurityDb::set_local_identity(irk, identity_address, public_address);
db_write(&_local_identity, DB_OFFSET_LOCAL_IDENTITY);
}
/* saving and loading from nvm */ /* saving and loading from nvm */
void FileSecurityDb::restore() { void FileSecurityDb::restore() {
@ -299,6 +315,7 @@ void FileSecurityDb::sync(entry_handle_t db_handle) {
db_write(&entry->peer_sign_counter, entry->file_offset + DB_STORE_OFFSET_PEER_SIGNING_COUNT); db_write(&entry->peer_sign_counter, entry->file_offset + DB_STORE_OFFSET_PEER_SIGNING_COUNT);
db_write(&entry->flags, entry->file_offset + DB_STORE_OFFSET_FLAGS); db_write(&entry->flags, entry->file_offset + DB_STORE_OFFSET_FLAGS);
db_write(&_local_sign_counter, DB_OFFSET_LOCAL_SIGN_COUNT);
} }
void FileSecurityDb::set_restore(bool reload) { void FileSecurityDb::set_restore(bool reload) {
@ -308,11 +325,11 @@ void FileSecurityDb::set_restore(bool reload) {
/* helper functions */ /* helper functions */
uint8_t FileSecurityDb::get_entry_count() { uint8_t FileSecurityDb::get_entry_count() {
return MAX_ENTRIES; return BLE_SECURITY_DATABASE_MAX_ENTRIES;
} }
SecurityDistributionFlags_t* FileSecurityDb::get_entry_handle_by_index(uint8_t index) { SecurityDistributionFlags_t* FileSecurityDb::get_entry_handle_by_index(uint8_t index) {
if (index < MAX_ENTRIES) { if (index < BLE_SECURITY_DATABASE_MAX_ENTRIES) {
return &_entries[index].flags; return &_entries[index].flags;
} else { } else {
return NULL; return NULL;

View File

@ -102,13 +102,19 @@ ble_error_t GenericSecurityManager<TPalSecurityManager, SigningMonitor>::init_(
result = init_resolving_list(); result = init_resolving_list();
#endif #endif
#if BLE_FEATURE_PRIVACY
// set the local identity address and irk
if (result != BLE_ERROR_NONE) {
result = init_identity();
}
#endif // BLE_FEATURE_PRIVACY
if (result != BLE_ERROR_NONE) { if (result != BLE_ERROR_NONE) {
delete _db; delete _db;
_db = NULL; _db = NULL;
return result;
} }
return BLE_ERROR_NONE; return result;
} }
template<template<class> class TPalSecurityManager, template<class> class SigningMonitor> template<template<class> class TPalSecurityManager, template<class> class SigningMonitor>
@ -161,7 +167,21 @@ template<template<class> class TPalSecurityManager, template<class> class Signin
ble_error_t GenericSecurityManager<TPalSecurityManager, SigningMonitor>::purgeAllBondingState_(void) { ble_error_t GenericSecurityManager<TPalSecurityManager, SigningMonitor>::purgeAllBondingState_(void) {
if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE; if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
_db->clear_entries(); _db->clear_entries();
return BLE_ERROR_NONE;
ble_error_t ret = BLE_ERROR_NONE;
#if BLE_FEATURE_SIGNING
// generate new csrk and irk
ret = init_signing();
if (ret) {
return ret;
}
#endif // BLE_FEATURE_SIGNING
#if BLE_FEATURE_PRIVACY
ret = init_identity();
#endif // BLE_FEATURE_PRIVACY
return ret;
} }
template<template<class> class TPalSecurityManager, template<class> class SigningMonitor> template<template<class> class TPalSecurityManager, template<class> class SigningMonitor>
@ -309,6 +329,33 @@ ble_error_t GenericSecurityManager<TPalSecurityManager, SigningMonitor>::setPair
return BLE_ERROR_NONE; return BLE_ERROR_NONE;
} }
template<template<class> class TPalSecurityManager, template<class> class SigningMonitor>
ble_error_t GenericSecurityManager<TPalSecurityManager, SigningMonitor>::getPeerIdentity_(connection_handle_t connection) {
if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
if (eventHandler) {
ControlBlock_t *cb = get_control_block(connection);
if (!cb) {
return BLE_ERROR_INVALID_PARAM;
}
_db->get_entry_identity(
[connection,this](SecurityDb::entry_handle_t handle, const SecurityEntryIdentity_t* identity) {
if (eventHandler) {
eventHandler->peerIdentity(
connection,
identity ? &identity->identity_address : nullptr,
identity ? identity->identity_address_is_public : false
);
}
},
cb->db_entry
);
return BLE_ERROR_NONE;
} else {
return BLE_ERROR_INVALID_STATE;
}
}
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Feature support // Feature support
// //
@ -901,6 +948,33 @@ ble_error_t GenericSecurityManager<TPalSecurityManager, SigningMonitor>::init_si
return _pal.set_csrk(*pcsrk, local_sign_counter); return _pal.set_csrk(*pcsrk, local_sign_counter);
} }
template<template<class> class TPalSecurityManager, template<class> class SigningMonitor>
ble_error_t GenericSecurityManager<TPalSecurityManager, SigningMonitor>::init_identity() {
if (!_db) return BLE_ERROR_INITIALIZATION_INCOMPLETE;
const irk_t *pirk = nullptr;
irk_t irk = _db->get_local_irk();
if (irk != irk_t()) {
pirk = &irk;
} else {
ble_error_t ret = get_random_data(irk.data(), irk.size());
if (ret != BLE_ERROR_NONE) {
return ret;
}
pirk = &irk;
address_t identity_address;
bool public_address;
ret = _pal.get_identity_address(identity_address, public_address);
if (ret != BLE_ERROR_NONE) {
return ret;
}
_db->set_local_identity(irk, identity_address, public_address);
}
return _pal.set_irk(*pirk);
}
template<template<class> class TPalSecurityManager, template<class> class SigningMonitor> template<template<class> class TPalSecurityManager, template<class> class SigningMonitor>
ble_error_t GenericSecurityManager<TPalSecurityManager, SigningMonitor>::get_random_data(uint8_t *buffer, size_t size) { ble_error_t GenericSecurityManager<TPalSecurityManager, SigningMonitor>::get_random_data(uint8_t *buffer, size_t size) {
byte_array_t<8> random_data; byte_array_t<8> random_data;

View File

@ -212,6 +212,11 @@ public:
*/ */
ble_error_t set_private_address_timeout_(uint16_t timeout_in_seconds); ble_error_t set_private_address_timeout_(uint16_t timeout_in_seconds);
/**
* @see ::ble::pal::SecurityManager::get_identity_address
*/
ble_error_t get_identity_address_(address_t& address, bool& public_address);
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Keys // Keys
// //

View File

@ -279,6 +279,20 @@ ble_error_t CordioSecurityManager<EventHandler>::set_private_address_timeout_(
return BLE_ERROR_NONE; return BLE_ERROR_NONE;
} }
/**
* @see ::ble::pal::SecurityManager::get_identity_address
*/
template <class EventHandler>
ble_error_t CordioSecurityManager<EventHandler>::get_identity_address_(
address_t& address,
bool& public_address
) {
// On cordio, the public address is hardcoded as the identity address.
address = address_t(HciGetBdAddr());
public_address = true;
return BLE_ERROR_NONE;
}
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Keys // Keys
// //