How to set device security level mode1, level4

hi
I am configuring a BLE peripheral using NCS v2.2.99-dev3 and the nRF5340 DK.
I want to set the security level of the device to mode1, level 4 for cyber security.
I searched several tickets to get the information, but the security level change is failing.
My settings are below.

prj.conf

CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_SMP=y
CONFIG_BT_SMP_SC_ONLY=y
CONFIG_BT_TINYCRYPT_ECC=y

CONFIG_BT_BUF_ACL_RX_SIZE=251
CONFIG_BT_BUF_ACL_TX_SIZE=251
CONFIG_BT_L2CAP_TX_MTU=247
CONFIG_BT_CTLR_DATA_LENGTH_MAX=251

# Enable bonding
CONFIG_BT_SETTINGS=y
CONFIG_FLASH=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_FLASH_MAP=y
CONFIG_NVS=y
CONFIG_SETTINGS=y

ble.c

static struct bt_conn_cb conn_callbacks = 
{
	.connected    = connected,
	.disconnected = disconnected,
	.le_param_req = le_param_req,
	.le_param_updated = le_param_updated,
    .identity_resolved = identity_resolved,	
	.security_changed = security_changed,	
};

static struct bt_conn_auth_cb conn_auth_callbacks =
{
	.passkey_display = auth_passkey_display,
	.passkey_confirm = auth_passkey_confirm,
	.cancel = auth_cancel,
};

static struct bt_conn_auth_info_cb conn_auth_info_callbacks =
{
	.pairing_complete = pairing_complete,
	.pairing_failed = pairing_failed
};

static void connected(struct bt_conn *conn, uint8_t err)
{
	char addr[BT_ADDR_LE_STR_LEN];

	if(err)
	{
        EO_LOG_ERROR("Failed to connect to %s (%u)", addr, err);
		return;
	}

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
	EO_LOG_INFO("Connected %s", addr);

	current_conn = bt_conn_ref(conn);
}

static void disconnected(struct bt_conn *conn, uint8_t reason)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

    EO_LOG_INFO("Disconnected from %s (reason 0x%02x)", addr, reason);

	if(auth_conn != NULL)
	{
		bt_conn_unref(auth_conn);
		auth_conn = NULL;
	}

	if(current_conn != NULL)
	{
		bt_conn_unref(current_conn);
		current_conn = NULL;
	}
}

static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
{
	EO_LOG_INFO("Connection parameters update request received.");
	EO_LOG_INFO("Minimum interval: %d, Maximum interval: %d", param->interval_min, param->interval_max);
	EO_LOG_INFO("Latency: %d, Timeout: %d", param->latency, param->timeout);

	//If acceptable params, return true, otherwise return false.
	return true;
}

static void le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency, uint16_t timeout)
{
	EO_LOG_INFO("Connection parameters updated.");
	EO_LOG_INFO("interval: %d, latency: %d, timeout: %d", interval, latency, timeout);
}

static void identity_resolved(struct bt_conn *conn, const bt_addr_le_t *rpa, const bt_addr_le_t *identity)
{
    char addr_identity[BT_ADDR_LE_STR_LEN];
    char addr_rpa[BT_ADDR_LE_STR_LEN];

    bt_addr_le_to_str(identity, addr_identity, sizeof(addr_identity));
    bt_addr_le_to_str(rpa, addr_rpa, sizeof(addr_rpa));

    EO_LOG_INFO("Identity resolved %s -> %s", addr_rpa, addr_identity);
}

static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

    if(!err)
	{
		EO_LOG_INFO("Security changed: %s level %u", addr, level);
	}
	else
	{
		EO_LOG_WARNING("Security failed: %s level %u err %d", addr, level, err);
	}
}

static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	EO_LOG_INFO("Passkey for %s: %06u", addr, passkey);
}

static void auth_passkey_confirm(struct bt_conn *conn, unsigned int passkey)
{
	char addr[BT_ADDR_LE_STR_LEN];

	auth_conn = bt_conn_ref(conn);

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	EO_LOG_INFO("Passkey for %s: %06u", addr, passkey);

	if(auth_conn)
	{
		bt_conn_auth_passkey_confirm(auth_conn);
		EO_LOG_INFO("Numeric Match, conn %p", (void *)auth_conn);		
	}

	bt_conn_unref(auth_conn);
	auth_conn = NULL;
}
static void auth_cancel(struct bt_conn *conn)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	EO_LOG_INFO("Pairing cancelled: %s", addr);
}

static void pairing_complete(struct bt_conn *conn, bool bonded)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	EO_LOG_INFO("Pairing completed: %s, bonded: %d", addr, bonded);
}

static void pairing_failed(struct bt_conn *conn, enum bt_security_err reason)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	EO_LOG_INFO("Pairing failed conn: %s, reason %d", addr, reason);
}

The debug output is below.

[00:00:08.185,668] <inf> wrapper_ble: Connected 7F:88:D6:55:C0:32 (random)
[00:00:08.795,837] <inf> wrapper_ble: Connection parameters updated.
[00:00:08.795,867] <inf> wrapper_ble: interval: 6, latency: 0, timeout: 2000
[00:00:09.197,052] <inf> wrapper_ble: Connection parameters updated.
[00:00:09.197,082] <inf> wrapper_ble: interval: 39, latency: 0, timeout: 2000
[00:00:16.000,366] <inf> wrapper_ble: Passkey for 7F:88:D6:55:C0:32 (random): 669482
[00:00:16.000,396] <inf> wrapper_ble: Numeric Match, conn 0x200096b8
[00:00:16.000,885] <inf> wrapper_ble: Connection parameters updated.
[00:00:16.000,885] <inf> wrapper_ble: interval: 6, latency: 0, timeout: 2000
[00:00:46.000,518] <err> bt_smp: SMP Timeout
[00:00:46.000,854] <wrn> wrapper_ble: Security failed: 7F:88:D6:55:C0:32 (random) level 1 err 9
[00:00:49.649,322] <inf> wrapper_ble: Pairing failed conn: 7F:88:D6:55:C0:32 (random), reason 9
[00:00:49.649,932] <inf> wrapper_ble: Disconnected from 7F:88:D6:55:C0:32 (random) (reason 0x13)

Looking at the log, the callbacks are being called in the following order:
auth_passkey_confirm -> security_changed -> pairing_failed -> disconnected

How can I set the security level of the device to mode1, level 4?
Anyone please advise.

Parents
  • Hi, 

    First of all, for numeric comparison to work, you need a display and buttons to confirm or reject the passkey on both devices. If the peripheral only has a display, the standardized approach would be to display the passkey on the peripheral and enter the passkey on the central, assuming you have a keyboard capable of inputting digits on the central. You can of course just fake this and always accept on the peripheral, as it seems to me is what you intend to do, but that is not directly supported or described in the Bluetooth specification. From a firmware perspective, it does not matter much if the input comes from the real-world or internally though, so it is fine with regard to the implementation. Try to use bt_conn_auth_pairing_confirm(auth_conn); instead of bt_conn_auth_passkey_confirm(auth_conn);.

    Regards,
    Amanda H.

Reply
  • Hi, 

    First of all, for numeric comparison to work, you need a display and buttons to confirm or reject the passkey on both devices. If the peripheral only has a display, the standardized approach would be to display the passkey on the peripheral and enter the passkey on the central, assuming you have a keyboard capable of inputting digits on the central. You can of course just fake this and always accept on the peripheral, as it seems to me is what you intend to do, but that is not directly supported or described in the Bluetooth specification. From a firmware perspective, it does not matter much if the input comes from the real-world or internally though, so it is fine with regard to the implementation. Try to use bt_conn_auth_pairing_confirm(auth_conn); instead of bt_conn_auth_passkey_confirm(auth_conn);.

    Regards,
    Amanda H.

Children
No Data
Related