Security Level 4 Connection Failure in Central

Hello Nordic Team,

I am working with the nRF5340 Audio DK as a central device, trying to establish a secure connection using Security Level 4 (128-bit encryption with LE Secure Connections).

My goal is to ensure the central device enforces LESC (LE Secure Connections) with 128-bit encryption, but I am facing two major issues when connecting to different peripherals:

Issue 1: Security Level 4 Fails on Connection with Another nRF5340 board

When using another nRF5340 board as a peripheral, running the inbuilt nRF Audio Server code, the connection is established successfully. However, when I attempt to set Security Level 4, it fails with error .

[00:00:12.813,354] <inf> main: Received Command: connect 73:08:D0:98:FC:BD 

[00:00:12.813,446] <inf> main: Attempting to connect to 73:08:D0:98:FC:BD...

[00:00:12.916,320] <inf> main: Connection initiated index : 0 
[00:00:12.994,049] <inf> main: MTU exchanged: 23/23
[00:00:12.994,171] <inf> main: Connected: 73:08:D0:98:FC:BD (random) (index 0)
Security level: 1

[00:00:13.196,289] <err> main: Security failed: 73:08:D0:98:FC:BD (random) level 1 err (4)

[00:00:13.196,319] <inf> main: Pairing Failed (4). Disconnecting.

[00:00:13.296,417] <inf> main: disconnect index : 0 

[00:00:13.296,508] <inf> main: Disconnected: 73:08:D0:98:FC:BD (random), reason 0x16 (BT_HCI_ERR_LOCALHOST_TERM_CONN)

Disconnected:  (err 22 BT_HCI_ERR_LOCALHOST_TERM_CONN) 

in nrf340_audio code i have change prj.conf file and add following config.

CONFIG_BT=y
CONFIG_BT_SMP=y
CONFIG_BT_BONDABLE=y
CONFIG_BT_SMP_SC_PAIR_ONLY=y
CONFIG_BT_PRIVACY=y

  • Why does Security Level 4 fail with error 234?
  • Are there additional configurations needed for enforcing LE Secure Connections (128-bit encryption with LTK)?
  • Is there a way to debug or confirm why the encryption upgrade fails?

Issue 2: Connection Fails with Headset (Peripheral) - BT_HCI_ERR_UNKNOWN_CONN_ID

When attempting to connect to a headset as a peripheral, the connection fails with error 2 (BT_HCI_ERR_UNKNOWN_CONN_ID):

[00:00:36.785,827] <inf> main: Received Command: connect 7E:32:87:8B:18:4F 
[00:00:36.785,919] <inf> main: Attempting to connect to 7E:32:87:8B:18:4F...
[00:00:36.886,810] <inf> main: Connection initiated index : 0 
[00:00:37.846,679] <wrn> bt_hci_core: Connection creation timeout triggered
[00:00:37.846,832] <err> main: Failed to connect to 7E:32:87:8B:18:4F (random) (err 2: BT_HCI_ERR_UNKNOWN_CONN_ID)
ERROR: Failed to connect  (err 2 BT_HCI_ERR_UNKNOWN_CONN_ID) 

  • Why does the connection timeout and fail with BT_HCI_ERR_UNKNOWN_CONN_ID?
  • Do I need to manually set pairing parameters for headset support?
  • Is this issue related to Security Level 4 enforcement, or is it purely a connection establishment issue?

  and also security level is not work . 

Central-Side Configuration & Code

prj.conf (Security Settings for Central)

CONFIG_BT=y
CONFIG_LOG=y
CONFIG_BT_CENTRAL=y
CONFIG_BT_AUDIO=y
CONFIG_BT_ISO_TX_BUF_COUNT=4
# Support an ISO channel per ASE
CONFIG_BT_ISO_MAX_CHAN=4
CONFIG_BT_KEYS_OVERWRITE_OLDEST=y

CONFIG_BT_HCI=y
CONFIG_BT_EXT_ADV=y
CONFIG_SERIAL=y
CONFIG_UART_CONSOLE=y
CONFIG_UART_ASYNC_API=y

# Security Connection(Level 4 - Authenticated Secure Connections and 128-bit key ) 
CONFIG_BT=y
CONFIG_BT_SMP=y
CONFIG_BT_BONDABLE=y
CONFIG_BT_SMP_SC_PAIR_ONLY=y
CONFIG_BT_PRIVACY=y
CONFIG_BT_SMP_APP_PAIRING_ACCEPT=y


#Converts a HCI error to string
CONFIG_BT_HCI_ERR_TO_STR=y

CONFIG_NRFX_UARTE1=y

CONFIG_BT_MAX_CONN=5

CONFIG_BT_DEVICE_NAME="NRF5340_AUDIO_CLIENT"

CONFIG_MAIN_STACK_SIZE=8192
CONFIG_IDLE_STACK_SIZE=1024
CONFIG_ISR_STACK_SIZE=4096
CONFIG_LOG_BUFFER_SIZE=2048

CONFIG_BT_SCAN_WITH_IDENTITY=y
CONFIG_BT_CONN_CHECK_NULL_BEFORE_CREATE=y

CONFIG_GPIO=y
CONFIG_PWM=y   

Central-Side Connection Code

static struct bt_conn *default_conn;

/* Callback function when connection is established */
static void connected_cb(struct bt_conn *conn, uint8_t err) {
    char addr[BT_ADDR_LE_STR_LEN];
    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

    if (err) {
        LOG_ERR("Failed to connect to %s (err %d: %s)\n", addr, err, bt_hci_err_to_str(err));
        return;
    }

    default_conn = bt_conn_ref(conn);
    LOG_INF("Connected: %s\n", addr);

    /* Get current security level */
    uint8_t sec_level = bt_conn_get_security(conn);
    printk("Security level: %d\n", sec_level);

    /* Attempt to set security level to 4 */
    err = bt_conn_set_security(conn, BT_SECURITY_L4);
    if (err) {
        LOG_ERR("Security Level 4 failed, error code: %d", err);
    }
}

/* Callback function when connection is disconnected */
static void disconnected_cb(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));

    if (default_conn) {
        bt_conn_unref(default_conn);
        default_conn = NULL;
    }

    LOG_INF("Disconnected: %s, reason 0x%02x (%s)\n", addr, reason, bt_hci_err_to_str(reason));
}

/* Callback function when identity is resolved */
static void identity_resolved_cb(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));

    LOG_INF("Identity resolved %s -> %s\n", addr_rpa, addr_identity);
}

/* Callback function when security level changes */
static void security_changed_cb(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) {
        LOG_ERR("Security failed: %s level %u err %s(%d)\n", addr, level, bt_security_err_to_str(err), err);
    } else {
        LOG_INF("Security changed: %s level %u\n", addr, level);
    }
}

/* Connection callbacks */
static struct bt_conn_cb conn_callbacks = {
    .connected = connected_cb,
    .disconnected = disconnected_cb,
    .identity_resolved = identity_resolved_cb,
    .security_changed = security_changed_cb,
};

/* Handle pairing success */
static void auth_pairing_complete_cb(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));

    LOG_INF("Pairing complete with %s (Bonded: %s)\n", addr, bonded ? "Yes" : "No");

    uint8_t sec_level = bt_conn_get_security(conn);
    if (sec_level == 4) {
        printk("Secure Connections (Level 4) established\n");
    } else {
        printk("Security level: %d\n", sec_level);
    }
}

/* Handle pairing failure */
static void auth_pairing_failed_cb(struct bt_conn *conn, enum bt_security_err reason) {
    LOG_INF("Pairing Failed (%d). Disconnecting.\n", reason);
    bt_conn_disconnect(conn, BT_HCI_ERR_AUTH_FAIL);
}

/* Callback function for bond deletion */
static void auth_bond_deleted_cb(uint8_t id, const bt_addr_le_t *peer) {
    LOG_INF("Bond Information Deleted\n");
}

/* Bluetooth authentication info callback structure */
static struct bt_conn_auth_info_cb auth_info_callbacks = {
    .pairing_complete = auth_pairing_complete_cb,
    .pairing_failed = auth_pairing_failed_cb,
    .bond_deleted = auth_bond_deleted_cb,
};

/* Callback when ATT MTU is updated */
static void att_mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx) {
    LOG_INF("MTU exchanged: %u/%u\n", tx, rx);
}

/* GATT callbacks */
static struct bt_gatt_cb gatt_callbacks = {
    .att_mtu_updated = att_mtu_updated,
};

/* Function to handle pairing accept */
static enum bt_security_err auth_pairing_accept_cb(struct bt_conn *conn, const struct bt_conn_pairing_feat *const feat) {
    char addr[BT_ADDR_LE_STR_LEN];
    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    printk("Pairing accept for %s\n", addr);

    /* Accept pairing */
    return BT_SECURITY_ERR_SUCCESS;
}

/* Function to handle pairing confirmation */
static void auth_pairing_confirm_cb(struct bt_conn *conn) {
    LOG_INF("Pairing Confirm\n");
    bt_conn_auth_pairing_confirm(conn);
}

/* Function to handle passkey confirmation */
static void auth_passkey_confirm_cb(struct bt_conn *conn, uint32_t passkey) {
    char addr[BT_ADDR_LE_STR_LEN];
    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    printk("Passkey confirmation for %s with passkey %u\n", addr, passkey);

    /* Confirm passkey */
    bt_conn_auth_passkey_confirm(conn);
}

/* Function to display passkey */
static void auth_passkey_display_cb(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));
    LOG_INF("Passkey for %s: %06u\n", addr, passkey);
}

/* Function to handle pairing cancellation */
static void auth_cancel_cb(struct bt_conn *conn) {
    char addr[BT_ADDR_LE_STR_LEN];
    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    LOG_INF("Pairing cancelled: %s\n", addr);
}

/* Define the authentication callbacks structure */
static struct bt_conn_auth_cb auth_cb_callbacks = {
    .pairing_accept = auth_pairing_accept_cb,
    .pairing_confirm = auth_pairing_confirm_cb,
    .passkey_confirm = auth_passkey_confirm_cb,
    .passkey_display = auth_passkey_display_cb,
    .cancel = auth_cancel_cb,
};

My ultimate aim is to ensure that my central device always connects using Security Level 4, which requires:
  LE Secure Connections (LESC)
  128-bit encryption using Long-Term Key (LTK)
  MITM protection enabled

My Key Questions:

  1. Are my configurations correct for enforcing Security Level 4?
  2. What additional steps or configurations are needed to make it work with both peripherals?
  3. How can I debug or ensure that both devices negotiate LE Secure Connections properly?

I would greatly appreciate any insights, recommendations, or debugging steps to resolve these issues.

Thank you for your time and support! 

Related