BLE Just Works on nrf52832 and NRF Connect

Hi, I am working on something that requires me to use Just Works on nrf52832 custom board. Here is the work sccenario. under normal conditions, my module has a bonding PIN and the user is supposed to enter the PIN on his application to get data. My NRF module is a peripheral and i have enabled following in the prj.conf.


CONFIG_BT_NUS_SECURITY_ENABLED

CONFIG_BT_FIXED_PASSKEY

I have registered the necessary callbacks too.

What I now need to implement is a functionality which allows user to bond without a PIN temporarily after a button press. I assume BLE Just Works is what I need for this purpose. But I am open to any other suggestions or new perspectives to get this done.Thanks in advance.

Parents
  • Hi Midhunjac, 

    To be able to change the capability of the device to not have passkey (no display and keyboard) what you need to do is to 

    bt_conn_auth_cb_register() with NULL input to remove the callback. Then you recall the bt_conn_auth_cb_register() without the display or confirm or entry callback. 

    However we need to look at how you define your characteristics as well. Because in the characteristic definitions you also define the minimum level of security to access the characteristics. If you set it to requires MITM, having Just work bonding would not be enough to allow accessing the characteristics. 
    If it's the case you may want to reinitalize the characteristic with new parameter. 
  • I tried your suggestion but it didnt work. When I tried out what you suggested, the bonding failed. These are the logs.

    <inf>: Connected 68:4A:E9:DC:F3:BC (public)
    <wrn>: Security failed: 68:4A:E9:DC:F3:BC (public) level 1 err 4
    <inf> migration1: Pairing failed conn: 68:4A:E9:DC:F3:BC (public), reason 4
    <inf>: Disconnected: 68:4A:E9:DC:F3:BC (public) (reason 19)
    <inf>:Disconnected 68:4A:E9:DC:F3:BC (public) :
    I am sure it must be a mistake on my side. Can you please take a look at this ? Isn't this how you suggested that I do ? Just to make sure that we are not misunderstanding each other, I am using NCSv2.1.0 and for testing purposes, I have switched to the basic peripheral UART example. So the characteristics of that particular service applies now. What I am testing is if I can bond with the peripheral without a passkey. I am not trying to access any particular characteristic. I just want to bond with the peripheral straight away.

    /*some code*/
    err = bt_conn_auth_cb_register(NULL);
    err = bt_conn_auth_cb_register(&conn_auth_callbacks);
    /* some code */
    
    static struct bt_conn_auth_cb conn_auth_callbacks = {
    		.cancel = auth_cancel,
    
    };

    Tried adding the bt_conn_auth_cb_register() with the passkey display and passkey entry and passkey confirm callbacks set to NULL. That didnt work out too.

  • Hi Midhunjac, 

    Please try capturing a sniffer trace of the process. 

    I attached here a quick example that I modified from the peripheral_uart sample, SDK v2.1.2. 

    If you press button 3 it will erase all bond. If you press button 4 it will switch the pairing response from supporting MITM to not supporting MITM ( no display , no keyboard, just work). If you want to have display capability again you would need to modify the code to have another button to enable that or just reset the board. 

    peripheral_uart_changebond.zip

  • Hi, i am working on the sniffer API. But I just wanted to let you know that the source code you provided did not work as expected. I tried in the v2.1.0 SDK as well as the 2.1.2. It behaved the same in both cases. When I press button 4, in you code, the device connects and then suddenly disconnects on its own.

    Is there any explanation for this behavior ?

    Also, can you please confirm if the code that you provided worked in the SDKv2.1.2. Are there any changes in this general area in the SDK V2.1.1 and above ?

  • Hi Midhunjac, 
    I'm not sure if you need to do anything with the sniffer API. To run the sniffer you just need to copy it to wireshark folder and use Wireshark to capture. You don't need to work with the API directly. 
    Please make sure you erase bonding on the phone's side before testing. 

  • Hi, just wanted to provide an update here. I was working on this and I almost got what I wanted. By making the following changes, I could pair the DK with the nrf connect android application without problems

    /*<in prj.conf>*/
    CONFIG_BT_SMP_ALLOW_UNAUTH_OVERWRITE=y
    
    /*<in main.c>*/
    
    static struct bt_conn_auth_cb conn_auth_callbacks = {
    	.passkey_display=NULL,
    	.passkey_confirm=NULL,
    	.cancel = auth_cancel,
    	.pairing_confirm=NULL,
    };

    And for the fixed passkey use case, the following changes were made

    /*in prj.conf*/
    CONFIG_BT_FIXED_PASSKEY=y
    CONFIG_BT_SMP=y
    
    
    /*<in main.c>*/
    
    static struct bt_conn_auth_cb conn_auth_callbacks = {
    	.passkey_display = auth_passkey_display,
    	.passkey_confirm=NULL,
    	.cancel = auth_cancel,
    	.pairing_confirm=NULL,
    };
    unsigned int passkey = 123456;
    bt_passkey_set(passkey);

    The changes seem to do what I want (ALMOST. there are some issue described below) but I am not sure if these are the right methods. especially to get the Just Works working. Please advise me on that.

    As part of debugging, I went through the smp.c (C:\ncs\v2.1.0\zephyr\subsys\bluetooth\host\smp.c) and that is where I found the CONFIG_BT_SMP_ALLOW_UNAUTH_OVERWRITE configuration option inside the function update_keys_check( ).However, there are some issues here regarding the keys->flags in this function.

    1) When I reflash the device and load the program with the first set of attached changes, I get it all working fine with these logs. Please note that the keys->flags is 0 here.

    *** Booting Zephyr OS build v3.1.99-ncs1  ***
    ## starting mainStarting Nordic UART service example
    Bluetooth initializedConnected 66:53:DE:E0:64:51 (random)
    keys->flags is 0 and smp->flags is 536879924
    Pairing completed: 68:4A:E9:DC:F3:BC (public), bonded: 1
    

    2) next i reflash the device and load program with second set of attached changes and it works as I expected. Note that the keys->flags is 16.

    *** Booting Zephyr OS build v3.1.99-ncs1  ***
    ## starting mainStarting Nordic UART service example
    Bluetooth initializedConnected 66:53:DE:E0:64:51 (random)
    keys->flags is 16 and smp->flags is 536879932
    Pairing completed: 68:4A:E9:DC:F3:BC (public), bonded: 1
    

    3) If i reflash and load program with the first set of attached changes, it does NOT work as I expected it to (without passkey. it fails on its own). Note that the keys-> flags is now 17.

    ## starting mainStarting Nordic UART service example
    Bluetooth initializedConnected 68:4A:E9:DC:F3:BC (public)
    keys->flags is 17 and smp->flags is 536879924
    Pairing failed conn: 68:4A:E9:DC:F3:BC (public), reason 4Disconnected: 68:4A:E9:DC:F3:BC (public) (reason 19)

    What I do not understand is that test case 1 and 3 are the same yet has different values for the keys->flags and I believe this is the reason why I cannot get it correctly working in the third case. Since in the function update_keys_check(), these flags are checked against some conditions.

    I reflash using the Visual studio NRF extension. I erae bonding information in the application too.I believe erasing is part of the visual studio NRF extension and so, I expect the keys->flags to be set to 0 and then updated when a new connection comes to play. But I believe, the values are somehow overwritten. I am not sure if I am in the right direction here.

    NCS version : 2.1.0

    i am sorry for such long message. Can you please take a look at this for me ? Any help would be appreciated. Thanks in advance.

  • Hi Midhunjac, 

    To sum up what you described:

    - You have two binary images. One image supports Just work and the other image supports fixed passkey. 

    - When you flash the Fixed passkey to replace the Just work (step 2) it worked fine, you can make new bonding

    - When you flash the Just work back to replace the Fixed passkey it didn't work. 

    Please be aware that CONFIG_BT_SMP_ALLOW_UNAUTH_OVERWRITE=y only allow replacement of unauthorized (Just Work) bonding. So you can't replace bonding automatically if the bonding was done with Passkey. 

    You would need to clear the bond either by erasing the chip or by the application itself. To make sure you have erased the chip, please use nrfjprog (or nRF Connect for desktop) and erase the chip. In VS Code you need to click the one with 2 arrows on the right hand side not the icon next to the "Flash" text.


    Could you explain what you are trying to achieve ? I thought you want to have a button to allow new bond without passkey. This means one single image can handle Just Work and Passkey depends on the state of the button? 
    Do  you still have an issue with my example ? 

Reply
  • Hi Midhunjac, 

    To sum up what you described:

    - You have two binary images. One image supports Just work and the other image supports fixed passkey. 

    - When you flash the Fixed passkey to replace the Just work (step 2) it worked fine, you can make new bonding

    - When you flash the Just work back to replace the Fixed passkey it didn't work. 

    Please be aware that CONFIG_BT_SMP_ALLOW_UNAUTH_OVERWRITE=y only allow replacement of unauthorized (Just Work) bonding. So you can't replace bonding automatically if the bonding was done with Passkey. 

    You would need to clear the bond either by erasing the chip or by the application itself. To make sure you have erased the chip, please use nrfjprog (or nRF Connect for desktop) and erase the chip. In VS Code you need to click the one with 2 arrows on the right hand side not the icon next to the "Flash" text.


    Could you explain what you are trying to achieve ? I thought you want to have a button to allow new bond without passkey. This means one single image can handle Just Work and Passkey depends on the state of the button? 
    Do  you still have an issue with my example ? 

Children
  • Hi, you are right about my final goal. I want a button press event to allow both Just Work and passkey states. But it does not work. The example that you provided also did not yield any success. The button press events are registered but it does not allow the Just Work method. The two separate images were just part of debugging, to get a better clarity.

    But the summary you derived is not quite right. I will make myself clear.

    • First I flash the Just Works image. It works fine. (No passkey,just bonded fine) (log 1)
    • Next i flashed the Fixed passkey image. It works fine too.(Prompted to enter passkey. If passkey is right, bonded) (log 2)
    • Finally, flash the Just Works image again. This time it does not work as it worked in the first iteration.(log 3)

    As for the extension in VS code, I had been using the icon next to "flash". Maybe that explains my observation in the above three iterations. I will give the icon you mentioned a try and see if the situation changes.

    Please be aware that CONFIG_BT_SMP_ALLOW_UNAUTH_OVERWRITE=y only allow replacement of unauthorized (Just Work) bonding. So you can't replace bonding automatically if the bonding was done with Passkey. 

    Can you please elaborate on this ? Or can you point me to a document which explains what this is and its application? This seems to do what I want but somehow it feels like this is not the right way to implement Just Works.

    Also, what is the correct way to get Just Works working ?My characteristics do not require any encryption at all yet Just Works does not seem to work. Thank you for the help.

  • Hi again, 

    You can read about the CONFIG_BT_SMP_ALLOW_UNAUTH_OVERWRITE here. For any KConfig configuration you can search there.

    Basically when you enable this option, it allow a device that you already bonded can make another bond. Just like what you did in Step 2 and 3. 
    However this option only allow overwriting when the previous bond is UNAUTHORIZED (Just work) At step 3 , the previous bond as Passkey so it not allowed to overwrite the bond without erasing it first. 

    Please try to test my example again and list how you tested it and what you observed. 
    My suggestion is: 

    - First use nRF Connect to connect and bond, you should see a passkey appear and you need to press button 1 on the board to confirm the pass key (numeric comparison)

    - Disconnect

    - Press button 3 to erase bond

    - Press button 4 to change mode

    - Use nRF Connect to connect, then bond. You will see a pop up asking to pair, but no passkey, you don't have to press anything on the DK , only on the phone. This is Just work pairing. 

    If you still have issue please try to capture the sniffer trace. You don't need to install the Sniffer API, just need to follow what in the documentation. 

  • Hi,

    Thank you for the help. It works now as you described above.. Maybe i was using the wrong button for flashing the device in the VS code. There needs to be a few changes though. As I said, my module has a static passkey and the user should enter that passkey to bond. Not the other way round as it is in your example.

    normal conditions, my module has a bonding PIN and the user is supposed to enter the PIN on his application to get data. My NRF module is a peripheral and i have enabled following in the prj.conf.

    The way I understand, for the module to work like that, we need to set CONFIG_BT_FIXED_PASSKEY and CONFIG_BT_SMP to 'y'. right ?

    But if we do that, is there some way I can switch mode to Just Works during run time as I think that these configuration options blocks the working of Just Works ? I am aware that they are build configurations and may not be modifiable during runtime but is there any chance of achieving this ? Thanks again for helping me through this.

  • Hi Midhunjac, 

    No I don't see a problem with the configuration. A device can support both passkey and Just work. You can configure with passkey in the prj.conf and then if in the code you don't supply the callback for display then only Just work allowed.

  • Hi  

    Are you sure about that ? Because I made the above two changes to the prj.conf and deleted the display callback. Now I can set my passkey on the module with bt_passkey_set(). It works fine. I have to enter the said passkey in nrf connect application to bond. But now I cannot switch to Just Works with the changes you attached. The nrf connect will still prompt me to enter the preset passkey even after pressing the Button 4. Is there anything I am missing? Can you confirm this behavior at your end please? These are my callbacks and prj.conf configurations.

    /*<main.c>*/
    
    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_cb conn_auth_callbacks2 = {
    	.cancel = auth_cancel,
    };
    
    static struct bt_conn_auth_info_cb conn_auth_info_callbacks = {
    	.pairing_complete = pairing_complete,
    	.pairing_failed = pairing_failed
    };
    
    /*<prj.conf>*/
    
    CONFIG_BT_SMP=y
    CONFIG_BT_FIXED_PASSKEY=y

Related