From 14ff34c561f7f72443b2a68a2faa9c0a8ed480ad Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 23 Aug 2026 12:59:03 -0400 Subject: [PATCH] Require encryption to write the CCCD of an encrypted characteristic (espressif) NimBLE derives the auto-generated CCCD's permissions only from the BLE_GATT_CHR_F_NOTIFY_INDICATE_* flags, which were never set, so the CCCD of an encryption-requiring characteristic was writable on an unencrypted link. An unpaired central could subscribe, nothing ever demanded pairing, and its file transfer commands -- Write Commands, which ATT requires the server to silently ignore when unauthorized -- were dropped with no error, hanging the client forever. Now the CCCD write permission follows the characteristic read permission, as in the nordic port. The central's subscribe attempt gets an ATT insufficient-authentication error, which is what makes it initiate pairing. Co-Authored-By: Claude Fable 5 --- ports/espressif/common-hal/_bleio/Characteristic.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ports/espressif/common-hal/_bleio/Characteristic.c b/ports/espressif/common-hal/_bleio/Characteristic.c index ff9ab35c1b9..12180b7bfc9 100644 --- a/ports/espressif/common-hal/_bleio/Characteristic.c +++ b/ports/espressif/common-hal/_bleio/Characteristic.c @@ -62,11 +62,18 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, read_perm == SECURITY_MODE_SIGNED_WITH_MITM || write_perm == SECURITY_MODE_SIGNED_WITH_MITM) { mp_raise_NotImplementedError(MP_ERROR_TEXT("MITM security not supported")); } + // The BLE_GATT_CHR_F_NOTIFY_INDICATE_* flags are set below to require encryption or + // authentication when writing the auto-generated CCCD, if reading the + // characteristic requires it. This matches the nordic port behavior. + // Without the flags, NimBLE registers the CCCD as writable on an unencrypted link, + // so an unpaired central can subscribe and nothing ever requires it to pair. + // + // TODO: This behavior was fixed in NimBLE 1.10.0. ESP-IDF 6.0.1 uses a fork of NimBLE. if (read_perm == SECURITY_MODE_ENC_NO_MITM) { - self->flags |= BLE_GATT_CHR_F_READ_ENC; + self->flags |= BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_NOTIFY_INDICATE_ENC; } if (read_perm == SECURITY_MODE_SIGNED_NO_MITM) { - self->flags |= BLE_GATT_CHR_F_READ_AUTHEN; + self->flags |= BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_NOTIFY_INDICATE_AUTHEN; } if (write_perm == SECURITY_MODE_ENC_NO_MITM) { self->flags |= BLE_GATT_CHR_F_WRITE_ENC;