Skip to content

Commit bfde0dc

Browse files
gmarullsjanc
authored andcommitted
nimble/host: inherit characteristic security requirements in CCCD
The CCCD was registered with plain read/write permissions regardless of the security declared on its characteristic, so any unencrypted client could subscribe and receive an otherwise protected value via notifications/indications, bypassing its protection. The Core Specification leaves CCCD write permissions to the implementation and anticipates gating them (Vol 3, Part G, 3.3.3.3; Vol 3, Part F, 3.2.5). Zephyr already enforces this: the CCC carries its own security permissions, and the value's read security is checked in the notify/indicate send path. NimBLE auto-generates the CCCD with no per-descriptor permission API, so inherit the characteristic's security requirements to achieve the same protection. Require for the CCCD write the union of the characteristic's read and write encryption/authentication flags, derived via ble_gatts_att_flags_from_chr_flags to keep a single mapping point, and propagate min_key_size as well. Authorization flags are deliberately not inherited: ble_att_svr_check_perms does not enforce authorization (left to the access callback, which for the CCCD is stack-internal), and the flag alone would activate the min_key_size check, rejecting every CCCD write on an unencrypted link. CCCD reads remain unprotected, per Vol 3, Part G, 3.3.3.3. Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>
1 parent 2c9685e commit bfde0dc

1 file changed

Lines changed: 21 additions & 3 deletions

File tree

nimble/host/src/ble_gatts.c

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -830,11 +830,29 @@ ble_gatts_clt_cfg_access(uint16_t conn_handle, uint16_t attr_handle,
830830
}
831831

832832
static int
833-
ble_gatts_register_clt_cfg_dsc(uint16_t *att_handle)
833+
ble_gatts_register_clt_cfg_dsc(const struct ble_gatt_chr_def *chr, uint16_t *att_handle)
834834
{
835+
uint8_t chr_att_flags;
836+
uint8_t att_flags;
835837
int rc;
836838

837-
rc = ble_att_svr_register(uuid_ccc, BLE_ATT_F_READ | BLE_ATT_F_WRITE, 0,
839+
/* Writing the CCCD enables notifications/indications of the
840+
* characteristic value, so require the same encryption/authentication
841+
* level as the characteristic itself. Authorization is not inherited:
842+
* the stack cannot enforce it on the internal CCCD access callback,
843+
* and its flag alone would wrongly activate the key-size check.
844+
*/
845+
chr_att_flags = ble_gatts_att_flags_from_chr_flags(chr->flags);
846+
847+
att_flags = BLE_ATT_F_READ | BLE_ATT_F_WRITE;
848+
if (chr_att_flags & (BLE_ATT_F_READ_ENC | BLE_ATT_F_WRITE_ENC)) {
849+
att_flags |= BLE_ATT_F_WRITE_ENC;
850+
}
851+
if (chr_att_flags & (BLE_ATT_F_READ_AUTHEN | BLE_ATT_F_WRITE_AUTHEN)) {
852+
att_flags |= BLE_ATT_F_WRITE_AUTHEN;
853+
}
854+
855+
rc = ble_att_svr_register(uuid_ccc, att_flags, chr->min_key_size,
838856
att_handle, ble_gatts_clt_cfg_access, NULL);
839857
if (rc != 0) {
840858
return rc;
@@ -958,7 +976,7 @@ ble_gatts_register_chr(const struct ble_gatt_svc_def *svc,
958976
}
959977

960978
if (ble_gatts_chr_clt_cfg_allowed(chr) != 0) {
961-
rc = ble_gatts_register_clt_cfg_dsc(&dsc_handle);
979+
rc = ble_gatts_register_clt_cfg_dsc(chr, &dsc_handle);
962980
if (rc != 0) {
963981
return rc;
964982
}

0 commit comments

Comments
 (0)