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! 

  • Hi,

    Are my configurations correct for enforcing Security Level 4?

    Security level 4 is Autenticated LESC, so there is a form of numeric comparison or passkey entry. As you are making an audio product this is a bit unusual, as there is typically no other I/O than a speaker and/or microhone. That said, I see from your code snippets that you have code for passkey handling, so the basics are in place. Note that in Bluetooth the security requiermetns are set for each characteristic separately

    Other than that, it looks like the question has been processed by AI, and it is difficult to extract the key information here and ther eare some information that I suspect may be some AI hallucination. Can you share your original (non AI processed) question?

  • Hi Einar,

    Thanks for your response! I understand that Security Level 4 requires Authenticated LE Secure Connections (LESC) and a 128-bit encryption key.

    you're absolutely correct! that  Numeric Comparison requires a display or input, while 128-bit AES-CCM encryption does not.

    I have  questions regarding implementing Security Level 4 (Authenticated Secure Connections with 128-bit encryption) on my devices:


    Question 1: Connection and Security Failure with Headset

               Setup:        

                           Central: nRF5340 Audio DK

                           Peripheral: A headset that advertises and waits for connection

                           I want to establish a secure connection using Security Level 4  (Authenticated Secure Connections with 128-bit encryption).

             Issue:

                          The central initiates a connection, but it fails with an unknown connection ID error (err 2: BT_HCI_ERR_UNKNOWN_CONN_ID) after a timeout.

    [00:00:29.509,552] <inf> main: Received Command: connect 8C:64:A2:2D:76:BB 
    [00:00:29.509,643] <inf> main: Attempting to connect to 8C:64:A2:2D:76:BB...
    [00:00:29.612,548] <inf> main: Connection initiated index : 0 
    [00:00:30.570,404] <wrn> bt_hci_core: Connection creation timeout triggered
    [00:00:30.570,556] <err> main: Failed to connect to 8C:64:A2:2D:76:BB (random) (err 2: BT_HCI_ERR_UNKNOWN_CONN_ID)
    ERROR: Failed to connect  (err 2 BT_HCI_ERR_UNKNOWN_CONN_ID) 
    

    Question 2: Security Level 4 Failure Between Two nRF5340 Audio DK Boards

                Setup:

                          Central: nRF5340 Audio DK

                           Peripheral: Another nRF5340 Audio DK (running the example of peripheral secure only code)

                           Security Level 4 is set on the central side.

               Issue

                         The connection establishes successfully, but Security Level 4 fails with error 9 (Authentication Failure) and then disconnects.

    [00:00:09.458,526] <inf> main: Received Command: connect E7:56:71:C4:55:2D 
    
    [00:00:09.458,618] <inf> main: Attempting to connect to E7:56:71:C4:55:2D...
    
    [00:00:09.559,814] <inf> main: Connection initiated index : 0 
                                                                   
    [00:00:09.636,871] <inf> main: MTU exchanged: 23/23
    
    [00:00:09.636,993] <inf> main: Connected: E7:56:71:C4:55:2D (random) (index 0)
    
    [00:00:09.888,427] <err> main: Security failed: E7:56:71:C4:55:2D (random) level 1 err (9)
    
    [00:00:09.888,458] <inf> main: Pairing Failed (9). Disconnecting.
    
    [00:00:09.888,702] <inf> main: disconnect index : 0 
    
    [00:00:09.888,793] <inf> main: Disconnected: E7:56:71:C4:55:2D (random), reason 0x05 (BT_HCI_ERR_AUTH_FAIL)
    
    Disconnected:  (err 5 BT_HCI_ERR_AUTH_FAIL) 
    

    Security Configurations in prj.conf

    CONFIG_BT_SMP=y
    CONFIG_BT_BONDABLE=y
    CONFIG_BT_BONDING_REQUIRED=y
    CONFIG_BT_SMP_SC_PAIR_ONLY=y
    CONFIG_BT_PRIVACY=y
    CONFIG_BT_SMP_APP_PAIRING_ACCEPT=y
    CONFIG_BT_GATT_CLIENT=y
    CONFIG_BT_TINYCRYPT_ECC=y
    CONFIG_BT_HOST_CCM=y
    CONFIG_BT_GATT_CACHING=y
    CONFIG_BT_SETTINGS_CCC_STORE_ON_WRITE=y
    CONFIG_BT_L2CAP_TX_MTU=128
    
    CONFIG_SETTINGS=y
    CONFIG_NVS=y
    CONFIG_BT_SETTINGS=y
    CONFIG_FLASH=y
    CONFIG_FLASH_PAGE_LAYOUT=y
    CONFIG_FLASH_MAP=y
    

    I want to ensure that in both cases  my central device successfully enforces Security Level 4 and pairing should success, meaning:

    • Security Level 4 should be enforced on all connections.
    • 128-bit encryption should be applied between the central and peripheral.
    • Pairing should succeed without downgrading to lower security levels.

    Would appreciate guidance on what I might be missing or need to adjust!

    Thanks in advance!

  • Hi,

    Yash48 said:

    you're absolutely correct! that  Numeric Comparison requires a display or input, while 128-bit AES-CCM encryption does not.

    I have  questions regarding implementing Security Level 4 (Authenticated Secure Connections with 128-bit encryption) on my devices:

    To be clear, all Bluetooh LE encryption is using 128 bit AES CCM. The difference is in various way the LTK is established. To use level 4, there has to be some form of I/O for numeric comparision or passkey entry, or other out of band method. What I/O do you have on your device and what do you want to use for this? If you do not have I/O that can be used for this, you cannot achieve level 4 security.

  • Hi Einar,

    Thanks for your response!

    I'm using an nRF5340 Audio DK as the central device, which has buttons and can display a passkey via UART. The peripheral is a standard headset/headphones without a display or input method.

    I need to establish a secure connection for LE Audio testing. How do I implement LE Secure Connections (LESC) pairing on the nRF5340 Audio DK (central side)? Additionally, which LESC pairing method would be the most suitable for this setup?

    I’d appreciate any guidance on what I might be missing or need to adjust.

    Thanks in advance for your help!

  • With a headset that does not have a way to handle passkeys, you normally use just works. However, you can still use LESC, but level 4 is not possible as it requiers more I/O (conceptually it could be possible for  a headset to read the LESC passkey out loud, but that would have to be supproted in the headset itself).

    So I suggsest you revert your changes as lecel 4 is not possible. (If you want to only suppor LESC and not legacy pairign, that is possible, and you can do that by adding CONFIG_BT_SMP_DISABLE_LEGACY_JW_PASSKEY=y.)

Related