Skip to content

BLE Bluedroid: If you fail to enter the correct PIN the 1st time, on 2nd try it will not give you any prompt and just connect you #11807

@Rob58329

Description

@Rob58329

Board

NodeMCU ESP32

Device Description

Plain module

Hardware Configuration

Plain module

Version

latest stable Release (if not listed below)

Type

Task

IDE Name

Arduino IDE v1.8.19 with https://github.com/espressif/arduino-esp32 at 5Sep25 (v3.3.0)

Operating System

Windows10

Flash frequency

80MHz

PSRAM enabled

no

Upload speed

115200

Description

There appears to be a new bug in the current "github.com/espressif/arduino-esp32 @5Sept25" Bluedroid-software (ESP32 orig) - (prossibly in BLESecurity.cpp): that after reboot it will only give you the prompt to enter a PIN the 1st time you try to connect, and if you fail to enter the correct PIN the 1st time, it will disconnect you, but subsequently will allow you to connect but NOT go through any securuty-authentication, and will NOT disconnect you.

Note that if you instead use "github.com/espressif/arduino-esp32 @19Jan25" (or infact just copy the "hardware\esp32\esp32\libraries\BLE\src" directory from 19Jan25 to the above 5Sept25 version), then the above bug does NOT happen (ie. it shows the correct behavior being that every time you connect after an incorrect-PIN you get the prompt to re-enter a correct-PIN, and it disconnects you if you dont get it right).

The below sketch demonstrates this - just try to connect using your mobile phone (eg. using the nRF-Connect App), but enter an incorrect PIN.

Sketch

// There appears to be a new bug in the current "github.com/espressif/arduino-esp32 @5Sept25" Bluedroid-software
// (ESP32 orig) - (prossibly in BLESecurity.cpp): that after reboot it will only give you the prompt to enter a
// PIN the 1st time you try to connect, and if you fail to enter the correct PIN the 1st time, it will disconnect
// you, but subsequently will allow you to connect but NOT go through any securuty-authentication, and will NOT
// disconnect you.

// Note that if you instead use "github.com/espressif/arduino-esp32 @19Jan25" (or infact just copy the
// "hardware\esp32\esp32\libraries\BLE\src" directory from 19Jan25 to the above 5Sept25 version), then
// the above bug does NOT happen (ie. it shows the correct behavior being that every time you connect after
// an incorrect-PIN you get the prompt to re-enter a correct-PIN, and it disconnects you if you dont get it right). 

// The below sketch demonstrates this - just try to connect using your mobile phone (eg. using the nRF-Connect App),
// but enter an incorrect PIN.
  
#if !defined(CONFIG_BLUEDROID_ENABLED)
  #error "This will only compile on Bluedroid based devices such as the ESP32 (ie. not the ESP32S3 etc)"
#endif

#define NEW_BLUEDROID_CODE ((ESP_ARDUINO_VERSION_MAJOR>=3) and (ESP_ARDUINO_VERSION_MINOR>=3)) 
// #define NEW_BLUEDROID_CODE false // use this if you copy the "BLE/src" directory from 19Jan25 to the above 5Sept25 version
// NB. Ensure you re-start the Arduino-IDE after swapping the "BLE/src" directory to ensure it re-compiles everything.


#include <BLEDevice.h>
#include <BLEServer.h>
BLEServer *pServer=nullptr;

uint32_t BLE_PASSKEY=123456; // for BLE must be exactly 6 digits long! // once bonded passkey is n/a (can be changed without effecting bonded devices) 
volatile boolean BLE_connected=false;
volatile boolean BLE_security=false;

class MySecurityCallbacks : public BLESecurityCallbacks {
  bool onConfirmPIN(uint32_t pin)                         {Serial.printf("onConfirmPIN=%u\n",pin); return (pin==BLE_PASSKEY);}
  uint32_t onPassKeyRequest()                             {Serial.println("onPassKeyRequest"); return BLE_PASSKEY;}
  void onPassKeyNotify(uint32_t pass_key)                 {Serial.printf("onPassKeyNotify=%u\n", pass_key);}
  bool onSecurityRequest()                                {Serial.println("onSecurityRequest"); return true;}
  void onAuthenticationComplete(esp_ble_auth_cmpl_t cmpl) {Serial.printf("Auth %s\n",cmpl.success ? "OK" : "FAIL"); BLE_security=(cmpl.success);}
};

class MyServerCallbacks : public BLEServerCallbacks {
  void onConnect(BLEServer *pServer)    {BLE_connected=true; Serial.printf("Device connected (ID=%u)\n",pServer->getConnId());}
  void onDisconnect(BLEServer *pServer) {BLE_connected=false; BLE_security=false; pServer->startAdvertising();Serial.println("Device Disconnected");}
};

void setup() {
  Serial.begin(115200); delay(2999);
  Serial.printf("ESP_ARDUINO=v%s\n",ESP_ARDUINO_VERSION_STR); // ESP_ARDUINO=v3.3.0
  #if (NEW_BLUEDROID_CODE) 
    Serial.println("Running on the new NEW_BLUEDROID_CODE (BLE/src)");
    Serial.print("Using BLE stack: "); Serial.println(BLEDevice::getBLEStackString()); // Using BLE stack: Bluedroid 
  #else
    Serial.println("Running on the older BLUEDROID_CODE (BLE/src)");
  #endif
  Serial.println("BLEDevice::init...");
  BLEDevice::init("Secure BLE Client"); 
  BLEDevice::setSecurityCallbacks(new MySecurityCallbacks());
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());
  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->start();
  BLESecurity *pSecurity = new BLESecurity();
  pSecurity->setCapability(ESP_IO_CAP_OUT); // Not sure if this is necessary?
  #if (NEW_BLUEDROID_CODE)
    pSecurity->setPassKey(true,BLE_PASSKEY);    
    pSecurity->setAuthenticationMode(true,false,false);
    BLESecurity::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT); // Not sure if this is necessary?
  #else
    esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &BLE_PASSKEY, sizeof(uint32_t));
    BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT); // Necessary
  #endif
  uint8_t auth_option = ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_ENABLE; // essential to stop Clients with No-PIN connecting/authorising
  esp_ble_gap_set_security_param(ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH, &auth_option, sizeof(uint8_t));
  pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_MITM_BOND); // override the "pSecurity->setAuthenticationMode(true,0,0);" // Not sure if this is necessary?
  pSecurity->setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);  // Not sure if this is necessary?
  pSecurity->setRespEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK); // Not sure if this is necessary?
  Serial.println("BLE Started. You can now connect from your phone (eg. using nRF-Connect)");
  Serial.println("Serial Commands: d=Display Bonds, e=Erase All-Bonds"); 
}

void loop() { 
  boolean secure=BLE_security;
  static boolean secure_old=false; if (secure_old!=secure) {secure_old=secure; Serial.printf("**Secure Connection=%s\n", secure ? "On" : "Off");} 
  while (Serial.available()) {
    char c=Serial.read();
    if (c>=32) Serial.write(c);
    else Serial.println();
    if (c=='d') show_bonded_devices();
    if (c=='e') remove_all_bonded_devices();
  }
  delay(100);
}

char bda_str[18];
char *bda2str(const uint8_t *bda) {
  sprintf(bda_str, "%02x:%02x:%02x:%02x:%02x:%02x", bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
  return bda_str;
}

void show_bonded_devices() { 
  int dev_num = esp_ble_get_bond_device_num();
  esp_ble_bond_dev_t *dev_list = (esp_ble_bond_dev_t *)malloc(sizeof(esp_ble_bond_dev_t) * dev_num);
  esp_ble_get_bond_device_list(&dev_num, dev_list);
  Serial.printf("\nBonded devices number: %d\n", dev_num);
  for (int i = 0; i < dev_num; i++) {Serial.printf("Found bonded device #%d = %s\n", i+1, bda2str(dev_list[i].bd_addr));}
  free(dev_list);
}

void remove_all_bonded_devices() {
  Serial.println("\nRemoving all bonded devices");
  int dev_num = esp_ble_get_bond_device_num();
  esp_ble_bond_dev_t *dev_list = (esp_ble_bond_dev_t *)malloc(sizeof(esp_ble_bond_dev_t) * dev_num);
  esp_ble_get_bond_device_list(&dev_num, dev_list);
  for (int i = 0; i < dev_num; i++) esp_ble_remove_bond_device(dev_list[i].bd_addr);
  free(dev_list);
}

Debug Message

ESP_ARDUINO=v3.3.0
Running on the new NEW_BLUEDROID_CODE (BLE/src)
Using BLE stack: Bluedroid
BLEDevice::init...
BLESecurity: Initializing
setPassKey: staticPasskey=1, passkey=123456
BLE Started. You can now connect from your phone (eg. using nRF-Connect)
Serial Commands: d=Display Bonds, e=Erase All-Bonds
// 1st connect with incorrect PIN
Device connected (ID=0)
onPassKeyNotify=123456
Auth FAIL
Device Disconnected
// 2nd connect
Device connected (ID=0)
// ... server never disconnects client...

Other Steps to Reproduce

No response

I have checked existing issues, online documentation and the Troubleshooting Guide

  • I confirm I have checked existing issues, online documentation and Troubleshooting guide.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions