BLE Peer Manager может использоваться приложениями для обеспечения безопасности BLE - шифрование (encryption), установка парного взаимодействия (pairing) и привязка (bonding).
Peer Manager использует память FLASH для энергонезависимого хранения информации привязки (bonding information) и данных GATT для каждого устройства BLE (пира, peer), с которым осуществлялось взаимодействие. Peer Manager обрабатывает различные процедуры безопасности, как этого требует спецификация Bluetooth, что упрощает создание совместимых приложений.
Примечание: для организации хранилища в памяти FLASH используется SDK-модуль Flash Data Storage (FDS) [3].
Peer Manager заменяет предыдущую реализацию Device Manager. Основной функционал остался прежним, однако следующие основные улучшения предоставляют выгоду при переключении на Peer Manager:
• Поддержка нескольких ролей BLE: Device Manager поддерживает обе роли, Central и Peripheral, однако роль должна быть определена во время компиляции. Peer Manager ведет себя более непринужденно с ролями и поддерживает одновременно как роль Central, так и роль Peripheral. • Автономность: Peer Manager работает более автономно, чем Device Manager. Например, Peer Manager автоматически отвечает на запросы безопасности, и имеет встроенную процедуру восстановления из состояния ошибки. Если SoftDevice или FDS оповещают о некритичном отказе (temporary failure), то Peer Manager будет делать повторные попытки, и сообщит только о ситуации постоянной, неустранимой ошибки (permanent failures). • Простота в использовании: из-за высокой степени автономности Peer Manager API легок в использовании и менее подвержен влиянию мелких ошибок пользователя. • Модульность: Peer Manager разработан по модульному принципу. Это облегчает поддержку, тестирование и добавление новых функций. • Кеширование атрибутов GATT: в дополнение к сохранению значений CCCD для осуществивших привязку устройств (как требуется для всех серверов GATT согласно спецификации Bluetooth), Peer Manager может также кешировать информацию атрибута GATT для серверов GATT, к которым осуществляется доступ по радиоканалу BLE (remote server GATT). Кеширование remote-базы данных снижает требуемый трафик по обмене пакетами, что экономит энергию батареи. • Дистрибьюция индикаторов изменения службы: когда что-либо меняется в базе данных GATT, Peer Manager может распространить соответствующую информацию об изменении службы (service changed indication) на все устройства, осуществившие взаимную привязку (bonded peers). Приложение должно оповещать Peer Manager каждый раз, когда меняется база служб. • Разрешение случайных адресов для устройств BLE: Peer Manager включает в себя функционал возможности подключения к устройствам со случайным приватным адресом (resolve random resolvable private addresses), используя для этого соответствующие ключи идентификации (Identity Resolving Keys, IRK).
Миграция на Peer Manager описывается в статье [2].
[Архитектура Peer Manager]
Peer Manager для своей работы использует несколько различных модулей SDK, см. рис. 1.
Рис. 1. Модули Peer Manager.
Peer Manager состоит из следующих программных модулей:
Security Manager & Dispatcher. Когда приложение или подключившееся устройство (peer) запрашивают шифрованное соединение (secured link), Security Manager & Dispatcher отвечают за обслуживания необходимой для этого процедуры. Они взаимодействуют с SoftDevice в создании защищенного соединения, сохраняют и извлекают ключи (которыми обменялись устройства), а также обслуживают процедуру установки парного взаимодействия (pairing).
Этот модуль состоит из двух частей: Security Manager и Security Dispatcher. Security Manager сохраняет параметры безопасности, отслеживает текущее состояние и координирует процедуру установки парного взаимодействия. Security Dispatcher организует взаимодействие с двоичным кодом SoftDevice и памятью FLASH, чтобы осуществить реальный pairing.
ID Manager. Этот модуль отслеживает подключенные пиры и идентифицирует на основе различных видов идентификаторов: статический адрес устройства, master ID, Identity Resolving Key (IRK), индекс белого списка ключа идентификации (IRK whitelist index) и peer ID. ID Manager определяет, относятся ли разные ID к тому же самому пиру и определяет, какой из соединенных пиров реализовал привязку. Когда подключилось привязанное устройство (bonded device), приложение может запросить для дескриптор соединения (connection handle), связанный с peer ID (или другой способ реализации подключения).
Дополнительно ID Manager создает и обслуживает белые списки подключений (whitelists).
GATT Cache Manager. Менеджер кеша GATT (состоящий из субмодулей GATT Server Cache Manager и GATT Client Cache Manager) решает 3 основные задачи:
• Сохраняет значения CCCD: как требует спецификация Bluetooth, GATT Server Cache Manager записывает в постоянное хранилище значения CCCD для всех привязанных пиров по всем осуществленным соединениям. • Распространяет оповещения об изменениях в службе (service changed indications): когда приложение оповещает Peer Manager о том, что его база данных поменялась, GATT Server Cache Manager посылает оповещение об изменении службы (service changed indication) на все подключенные пиры (и на все привязанные пиры, когда они снова подключатся). • Сохраняют базы данных атрибутов удаленных устройств BLE (remote ATT databases) во FLASH микроконтроллера: если поступил запрос от приложения, то GATT Client Cache Manager сохраняет remote database для всех пиров. Это кеширование атрибутов опционально, но оно снижает требуемый радиообмен пакетами, снижая тем самым энергопотребление.
Peer Database. База данных пиров хранит данные всех peer ID. Она предоставляет функции для создания уникальных peer ID, записи и чтения данных для определенных peer ID, освобождения peer ID, и выполнения энумерации всех существующих peer ID.
Peer Data Storage. Модуль хранилища данных пира осуществляет взаимодействие между модулем Peer Database и модулем Flash Data Storage [3]. Он отвечает за сохранение данных пира в память FLASH. Для этой цели используется модуль Flash Data Storage, и требуется эксклюзивное использование определенных записей ключей (record keys) и идентификаторов файлов (file ID). Для дополнительной информации по ограничениям см. далее секцию "Ограничения для ключей и ID". Кроме того, модуль Peer Data Storage назначает peer ID.
[Функции Peer Manager]
Peer Manager API предоставляет функции для обслуживания безопасности линка (например, для инициации процедуры pairing и шифрования), управления пирами (например, для манипулирования данными, связанными с bonded peers), и управления белыми списками (whitelists).
Защита линка. После того, как SoftDevice установит соединение BLE, код Peer Manager отвечает за процедуру установки парного взаимодействия (pairing), и если это запрашивается, то создает привязку (bond).
Перед тем, как может быть инициирована процедура pairing, приложение должно сконфигурировать используемые параметры безопасности. Например, эти параметры содержат степень защиты лика (security level), должна ли осуществляться привязка, и если должна, то какие данные должны быть общими при осуществлении привязки. Подробнее про параметры безопасности см. структуру ble_gap_sec_params_t. Также Вы можете извлечь информацию по уровню безопасности, который был установлен на определенном линке.
Чтобы зашифровать трафик линка, приложение должно вызвать функцию pm_conn_secure. В зависимости от взаимоотношений с пиром и сконфигурированных параметров безопасности, эта функция установит зашифрованный линк. Если привязка уже была осуществлена, то будет использоваться сохраненный ключ шифрования. Иначе будет инициирована процедура установки парного взаимодействия (pairing).
Управление пирами. После установки привязки с новым пиром Peer Manager назначает пиру уникальный идентификатор peer ID, и сохранит данные привязки и данные GATT в память FLASH. Приложение может впоследствии прочитать или обновить эти данные, если необходимо, однако в большинстве случаев это должно делаться исключительно кодом Peer Manager.
В дополнение к данным привязки и данным GATT приложение может сохранить специфическую для приложения информацию для каждого пира. Содержимое этих данных, их формат и размер определяется приложением.
Peer Manager также предоставляет функции для запроса количества достоверных peer ID, и для итерации по списку всех используемых peer ID. Использование этого механизма может быть удобным например для того, чтобы записывать данные приложения для всех пиров.
Если изменяется база данных GATT приложения, то все пиры должны информироваться об этих изменениях. Peer Manager предоставляет функцию, которую приложение вызывает для распространения оповещений об изменениях службы.
Управление белыми списками. Peer Manager может использоваться для создания белого списка (whitelist), который ограничивает для пиров возможность подключения. Для конструирования белого списка необходимо предоставить список из peer ID. Белый список будет тогда содержать адреса и ключи IRK для указанных пиров.
Обратите внимание, что если Peer Manager был добавлен в приложение, и необходимо использовать подключения по белому списку, то этот белый список должен быть создан кодом Peer Manager.
Ограничения для ключей и ID. Записи ключей (record key) должны быть в диапазоне 0x0001 - 0xBFFF. Значение 0x0000 зарезервировано для использования системой. Значения 0xC000 .. 0xFFFF зарезервированы модулем Peer Manager, и могут использоваться только приложениях, которые не применяют Peer Manager.
Идентификаторы файлов (file ID) должны быть в диапазоне 0x0000 - 0xBFFF. Значение 0xFFFF используется системой. Значения 0xC000 .. 0xFFFE для использования модулем Peer Manager, и могут использоваться только в тех приложениях, которые не применяют Peer Manager.
[Использование Peer Manager]
Следующие примеры кода показывают типовое использование Peer Manager в приложении.
Инициализация. Процесс инициализации Peer Manager обычно состоит из 3 шагов:
1. Однократный вызов pm_init для инициализации модуля.
2. Опционально делается вызов pm_sec_params_set для установки параметров безопасности. Если не делать вызов этой функции, то процедуры pairing (установка парного взаимодействия по защите линка) и bonding (привязка) не поддерживаются. См. далее секцию "Параметры безопасности".
3. Выполняется подписка на обработку событий Peer Manager путем вызова pm_register.
Следующий кусок кода из примера SDK BLE Relay Example [4] показывает, как инициализировать Peer Manager:
static void peer_manager_init(bool erase_bonds)
{
ble_gap_sec_params_t sec_param;
ret_code_t err_code;
err_code = pm_init();
APP_ERROR_CHECK(err_code);
if (erase_bonds)
{
pm_peers_delete();
}
memset(&sec_param, 0, sizeof(ble_gap_sec_params_t));
// Установка параметров безопасности, используемых для всех
// процедур защиты линка:
sec_param.bond = SEC_PARAM_BOND;
sec_param.mitm = SEC_PARAM_MITM;
sec_param.lesc = SEC_PARAM_LESC;
sec_param.keypress = SEC_PARAM_KEYPRESS;
sec_param.io_caps = SEC_PARAM_IO_CAPABILITIES;
sec_param.oob = SEC_PARAM_OOB;
sec_param.min_key_size = SEC_PARAM_MIN_KEY_SIZE;
sec_param.max_key_size = SEC_PARAM_MAX_KEY_SIZE;
sec_param.kdist_own.enc = 1;
sec_param.kdist_own.id = 1;
sec_param.kdist_peer.enc = 1;
sec_param.kdist_peer.id = 1;
err_code = pm_sec_params_set(&sec_param);
APP_ERROR_CHECK(err_code);
err_code = pm_register(pm_evt_handler);
APP_ERROR_CHECK(err_code);
}
Параметры безопасности. Вызов функции pm_sec_params_set конфигурирует поведение Peer Manager для защиты линка, таким образом это конфигурирует процессы bonding (привязка пира), pairing (установка парного взаимодействия) и encryption (шифрование). Конфигурация задается параметрами безопасности (security parameters, указанными в структуре ble_gap_sec_params_t). Эти параметры безопасности также используются в SoftDevice security API, и содержат параметры, отправляемые по радио в процессе процедуры привязки. Для дополнительной информации см. Bluetooth Core Specification (секции 3.H.3.5.1 и 3.H.3.5.2).
Функция pm_sec_params_set отклоняет недопустимые параметры безопасности. Для информации об накладываемых ограничениях на параметры см. вышеупомянутые секции Bluetooth Core Specification, или функцию проверки в исходном коде Peer Manager.
В следующем списке показаны требуемые в большинстве случаев параметры безопасности:
1. Когда не используется pairing/bonding: NULL (или не надо делать вызов pm_sec_params_set).
2. Pairing используется, bonding не используется:
sec_param.bond = false;
sec_param.mitm = false;
sec_param.lesc = 0;
sec_param.keypress = 0;
sec_param.io_caps = BLE_GAP_IO_CAPS_NONE;
sec_param.oob = false;
sec_param.min_key_size = 7;
sec_param.max_key_size = 16;
sec_param.kdist_own.enc = 0;
sec_param.kdist_own.id = 0;
sec_param.kdist_peer.enc = 0;
sec_param.kdist_peer.id = 0;
3. Только Works bonding:
sec_param.bond = true;
sec_param.mitm = false;
sec_param.lesc = 0;
sec_param.keypress = 0;
sec_param.io_caps = BLE_GAP_IO_CAPS_NONE;
sec_param.oob = false;
sec_param.min_key_size = 7;
sec_param.max_key_size = 16;
sec_param.kdist_own.enc = 1;
sec_param.kdist_own.id = 1;
sec_param.kdist_peer.enc = 1;
sec_param.kdist_peer.id = 1;
4. Привязка пароля (passkey bonding) с возможностями клавиатуры. Остальные параметры такие же, как и для Works bonding:
sec_param.bond = true;
sec_param.mitm = true;
sec_param.lesc = 0;
sec_param.keypress = 0;
sec_param.io_caps = BLE_GAP_IO_CAPS_KEYBOARD_ONLY;
sec_param.oob = false;
5. OOB bonding. Остальные параметры такие же, как и для Works bonding:
sec_param.bond = true;
sec_param.mitm = true;
sec_param.lesc = 0;
sec_param.keypress = 0;
sec_param.io_caps = BLE_GAP_IO_CAPS_NONE;
sec_param.oob = true;
6. С запретом использования IPK:
sec_param.bond = true;
/* Установка произвольных параметров удалена. */
sec_param.kdist_own.enc = 1;
sec_param.kdist_own.id = 0;
sec_param.kdist_peer.enc = 1;
sec_param.kdist_peer.id = 0;
Обработка событий. Как обрабатывать события Peer Manager - зависит от приложения. Peer Manager предоставляет различные виды событий; некоторые должны быть обработаны обязательно, другие могут быть проигнорированы.
Следующий пример кода показывает начальную точку для создания в приложении обработчика событий Peer Manager:
static void peer_manager_event_handler(pm_evt_t const * p_evt)
{
ret_code_t err_code;
switch(p_evt->evt_id)
{
case PM_EVT_BONDED_PEER_CONNECTED:
// Обновление ранга пира.
err_code = pm_peer_rank_highest(p_evt->peer_id);
break;
case PM_EVT_CONN_SEC_START:
break;
case PM_EVT_CONN_SEC_SUCCEEDED:
// Обновление ранга пира.
err_code = pm_peer_rank_highest(p_evt->peer_id);
break;
case PM_EVT_CONN_SEC_FAILED:
// В некоторых случаях, когда установка защиты не получилась, она может быть перезапущена
// напрямую. Иногда это может быть перезапущено, но только после изменения некоторых
// параметров безопасности. Иногда это не может быть перезапущено до тех пор, пока линк
// не будет установлен заново (disconnect и reconnect). Иногда можно защитить линк, но
// пир это не поддерживает. Поэтому как обрабатывать эту ошибку - в значительной мере
// зависит от приложения.
break;
case PM_EVT_CONN_SEC_CONFIG_REQ:
{
// Подключенный пир (устройство Central) пытается выполнить pair, но Peer Manager
// уже имеет привязку (bond) для этого пира. Установка allow_repairing в false
// отклонит запрос на pairing. Если это событие игнорируется (pm_conn_sec_config_reply
// не вызывается в обработчике события), то Peer Manager подразумевает, что
// allow_repairing == false.
pm_conn_sec_config_t conn_sec_config = {.allow_repairing = false};
pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config);
}
break;
case PM_EVT_STORAGE_FULL:
// Запуск сборки мусора (garbage collection) на FLASH.
err_code = fds_gc();
if (err_code == FDS_ERR_BUSY || err_code == FDS_ERR_NO_SPACE_IN_QUEUES)
{
// Повторная попытка.
}
else
{
APP_ERROR_CHECK(err_code);
}
break;
case PM_EVT_ERROR_UNEXPECTED:
// Assert.
APP_ERROR_CHECK(p_evt->params.error_unexpected.error);
break;
case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
break;
case PM_EVT_PEER_DATA_UPDATE_FAILED:
// Assert.
APP_ERROR_CHECK_BOOL(false);
break;
case PM_EVT_PEER_DELETE_SUCCEEDED:
break;
case PM_EVT_PEER_DELETE_FAILED:
// Assert.
APP_ERROR_CHECK(p_evt->params.peer_delete_failed.error);
break;
case PM_EVT_PEERS_DELETE_SUCCEEDED:
// В этой точке можно безопасно запустить процессы
// оповещения (advertising) или сканирования (scanning).
break;
case PM_EVT_PEERS_DELETE_FAILED:
// Assert.
APP_ERROR_CHECK(p_evt->params.peers_delete_failed_evt.error);
break;
case PM_EVT_LOCAL_DB_CACHE_APPLIED:
break;
case PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED:
// Возможно изменилась локальная база данных, отправка
// оповещения об изменении службы.
pm_local_database_has_changed();
break;
case PM_EVT_SERVICE_CHANGED_IND_SENT:
break;
case PM_EVT_SERVICE_CHANGED_IND_CONFIRMED:
break;
}
}
Сохранение данных. Peer Manager сохраняет данные и делает их извлечение автономно, не требуя никакого участия со стороны пользователя. Однако, если Вы хотите вручную сохранить, добавить или удалить данные, то Peer Manager предоставляет API-функции для манипуляции на всеми данными, которые связаны с его bonded пирами.
Данные могут быть сохранены порциями (chunk). Например, все данные привязки (ключи и идентификаторы) сохранены вместе, как одна порция данных. Порция не может быть сохранена или обновлена частями, однако каждая порция может быть сохранена или обновлена независимо от других порций. Единственные ограничения - всегда должны быть достоверны данные привязки для пира, и существует только один экземпляр для каждой порции для каждого bonded пира. Две порции, база данных дальнего пира (remote GATT database) и данные приложения, не используется внутри Peer Manager. Однако доступ к ним предусмотрен исключительно через Peer Manager API.
Следующий пример кода показывает, как сохранить remote GATT database (в array_of_services). Обратите внимание, что array_of_services должен быть доступен в течение (асинхронной) операции сохранения. Операция сохранения завершена, когда поступило событие PM_EVT_PEER_DATA_UPDATE_SUCCEEDED или PM_EVT_PEER_DATA_UPDATE_FAILED.
ret_code_t err_code;
pm_store_token_t store_token;
err_code = pm_peer_data_remote_db_store(peer_id,
array_of_services,
number_of_services,
&store_token);
if (err_code != NRF_ERROR_BUSY)
{
APP_ERROR_CHECK(err_code);
}
Функции pm_peer_data_remote_db_store, как и pm_peer_data_bonding_store и pm_peer_data_app_data_store, делают вызов pm_peer_data_store. Функцию pm_peer_data_store можно также вызвать напрямую, как в следующем примере:
ret_code_t err_code;
pm_store_token_t store_token;
err_code = pm_peer_data_store(peer_id,
PM_PEER_DATA_ID_GATT_REMOTE,
array_of_services,
number_of_services,
&store_token);
if (err_code != NRF_ERROR_BUSY)
{
APP_ERROR_CHECK(err_code);
}
Использование белого списка. Peer Manager может использоваться для установки и получения белого списка (whitelist), который может быть предоставлен для Advertising Module и использован во время оповещения (advertising). Когда необходим whitelist, вызовите функцию pm_whitelist_set для помещения в белый список пиров на основе их идентификаторов (peer ID).
Следующий пример показывает, как использовать pm_whitelist_set для помещения в белый список нескольких пиров, и как использовать pm_whitelist_get, чтобы получить такой список и предоставить его для Advertising Module, чтобы он применялся при advertising:
...
// Получение списка peer ID от Peer Manager, и составление на его
// основе белого списка.
pm_peer_id_t peer_ids[8] = {PM_PEER_ID_INVALID};
uint32_t n_peer_ids = 0;
pm_peer_id_t peer_id = pm_next_peer_id_get(PM_PEER_ID_INVALID);
while((peer_id != PM_PEER_ID_INVALID) && (n_peer_ids < 8))
{
peer_ids[n_peer_ids++] = peer_id;
peer_id = pm_next_peer_id_get(peer_id);
}
// Помещение пиров в белый список.
err_code = pm_whitelist_set(peer_ids, n_peer_ids);
APP_ERROR_CHECK(err_code);
...
static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
{
switch (ble_adv_evt)
{
...
case BLE_ADV_EVT_WHITELIST_REQUEST:
// Когда модуль Advertising собирается выполнять оповещение, это событие
// будет получено приложением. В этом событии приложение получает белый
// список от Peer Manager, основанный на пирах, которые были ранее
// помещены в белый список вызовом pm_whitelist_set().
ret_code_t err_code;
// Хранилище для белого списка.
ble_gap_irk_t irks[8] = {0};
ble_gap_addr_t addrs[8] = {0};
uint32_t irk_cnt = 8;
uint32_t addr_cnt = 8;
err_code = pm_whitelist_get(addrs, &addr_cnt, irks, &irk_cnt);
APP_ERROR_CHECK(err_code);
// Применение белого списка.
err_code = ble_advertising_whitelist_reply(addrs, addr_cnt, irks, irk_cnt);
APP_ERROR_CHECK(err_code);
...
}
}
[Ссылки]
1. nRF5 SDK v12 Peer Manager site:nordicsemi.com. 2. Migrating to Peer Manager site:nordicsemi.com. 3. nRF5 SDK Flash Data Storage. 4. SDK BLE Relay Example site:nordicsemi.com. |