NimBLE-Arduino icon indicating copy to clipboard operation
NimBLE-Arduino copied to clipboard

onPassKeyNotify not called

Open baumschubser opened this issue 4 years ago • 6 comments
trafficstars

Hi, is use NimBLE to connect to a Microsoft Surface Ergonomic Keyboard. When I set my devices capabilities to "keyboard only", the callback onPassKeyRequest is called, I return "123456", enter that PIN on the keyboard and indeed paring is done:

NimBLE code:

  NimBLEDevice::init("");
  NimBLEDevice::setSecurityAuth(true, true, true);
  NimBLEDevice::setSecurityIOCap(BLE_HS_IO_KEYBOARD_ONLY);
  NimBLEDevice::setSecurityRespKey(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID);

When I change the capabilities to BLE_HS_IO_KEYBOARD_DISPLAY, I would expect ~~onPassKeyNotify~~ onConfirmPIN to be called with a PIN generated by the keyboard. This is indeed what happens when I try to do the same thing with the Arduino BLE lib like this:

Arduino BLE code:

    BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT);
    BLEDevice::setSecurityCallbacks(new MySecurity());
    BLESecurity *pSecurity = new BLESecurity();
    pSecurity->setAuthenticationMode(ESP_LE_AUTH_BOND);
    pSecurity->setCapability(ESP_IO_CAP_KBDISP);
    pSecurity->setRespEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);

But no callback function is called, no PIN procedure is initiated. Is this a bug or am I missing something?

baumschubser avatar Apr 18 '21 19:04 baumschubser

I can think of 2 possible reasons you are seeing this.

  • First, since you have bonding enabled you are already bonded to the keyboard which means it will not ask for the passkey again as the devices have stored each others identity. You would need to delete the bonding info to force the procedure to happen again.
  • Next is the possibility of numeric comparison being used instead since you have specified display capability, this shouldn't happen though unless the other device also specifies that capability. You can test this by changing the last parameter in NimBLEDevice::setSecurityAuth(true, true, true); to false.

h2zero avatar Apr 18 '21 20:04 h2zero

Thank you for the response! I did esptool.py erase_flash to remove previous bonding info and tried again: Still no callback. setSecurityAuth(true, true, false) did not change anything, neither. For me it's OK since I can pair with other capability settings. Since I have no experience with BLE it may be that that I am doing something wrong. Just wanted to report a possible bug, since I managed to receive a PIN with Arduino BLE.

baumschubser avatar Apr 18 '21 20:04 baumschubser

That's quite strange indeed. Thanks for reporting your test results, I will try to reproduce here and see whats going on.

h2zero avatar Apr 18 '21 20:04 h2zero

I have posted my code in Topic and found a way to get it work for an android. A keyboard is whole other story. This is what I found for hid device.

podaen avatar Apr 25 '21 13:04 podaen

@h2zero

In NimBLEServer.h I see the following methods commented out in NimBLEServerCallbacks:

    //virtual void onPassKeyNotify(uint32_t pass_key);
    //virtual bool onSecurityRequest();

These methods still exist in the deprecated NimBLESecurityCallbacks. So are these not implemented for the server callbacks then?

Is there some documentation how to achieve this?

evtimDev avatar Jan 15 '23 04:01 evtimDev

These methods are removed from the latest version of the interface, a work-around to get the same functionality is to implement NimBLEServerCallbacks::onConnect and when a new connection occurs do something like this:

    const uint16_t connectionId     = desc->conn_handle;
    _pairPin = esp_random() % 1000000;
    BLEDevice::setSecurityPasskey(_pairPin);

    int result = NimBLEDevice::startSecurity(connectionId);
    if (result != 0) {
        Serial.println("Security failed, disconnecting.");
        _pServer->disconnect(connectionId);
    }

Basically you want to initiate the authentication on new connections - also good place to generate a random pin and display it to the user. Once the authentication completes inside your implementation of - virtual void onAuthenticationComplete(ble_gap_conn_desc desc)* you can stop displaying the random pin. Note that if the peer device had previously bonded the new pin will be ignored and not new boding will occur.

evtimDev avatar Jan 15 '23 05:01 evtimDev