From 21f8986388c3183401f720bd57371a5cb72a9fc0 Mon Sep 17 00:00:00 2001 From: Sumeet Singh Date: Mon, 24 Jun 2024 19:20:32 +0530 Subject: [PATCH] feat(nimble): Added LE GATT Security Levels Characteristic --- nimble/host/include/host/ble_gatt.h | 8 ++++ .../gap/include/services/gap/ble_svc_gap.h | 1 + nimble/host/services/gap/src/ble_svc_gap.c | 34 +++++++++++++++ nimble/host/src/ble_att_priv.h | 3 ++ nimble/host/src/ble_att_svr.c | 41 +++++++++++++++++++ nimble/host/src/ble_gatts.c | 11 +++++ 6 files changed, 98 insertions(+) diff --git a/nimble/host/include/host/ble_gatt.h b/nimble/host/include/host/ble_gatt.h index 068639395..f361516e9 100644 --- a/nimble/host/include/host/ble_gatt.h +++ b/nimble/host/include/host/ble_gatt.h @@ -1376,6 +1376,14 @@ typedef void (*ble_gatt_svc_foreach_fn)(const struct ble_gatt_svc_def *svc, */ void ble_gatts_show_local(void); +#if MYNEWT_VAL(BLE_SVC_GAP_GATT_SECURITY_LEVEL) +/** + * Calculates and returns the maximum + * Security Mode 1 Level requirement. + */ +uint8_t ble_gatts_security_mode_1_level(void); +#endif + /** * Resets the GATT server to its initial state. On success, this function * removes all supported services, characteristics, and descriptors. This diff --git a/nimble/host/services/gap/include/services/gap/ble_svc_gap.h b/nimble/host/services/gap/include/services/gap/ble_svc_gap.h index f748d6494..a6986ca14 100644 --- a/nimble/host/services/gap/include/services/gap/ble_svc_gap.h +++ b/nimble/host/services/gap/include/services/gap/ble_svc_gap.h @@ -34,6 +34,7 @@ extern "C" { #define BLE_SVC_GAP_CHR_UUID16_APPEARANCE 0x2a01 #define BLE_SVC_GAP_CHR_UUID16_PERIPH_PREF_CONN_PARAMS 0x2a04 #define BLE_SVC_GAP_CHR_UUID16_CENTRAL_ADDRESS_RESOLUTION 0x2aa6 +#define BLE_SVC_GAP_CHR_UUID16_LE_GATT_SECURITY_LEVELS 0x2BF5 #if MYNEWT_VAL(ENC_ADV_DATA) #define BLE_SVC_GAP_CHR_UUID16_KEY_MATERIAL 0x2B88 diff --git a/nimble/host/services/gap/src/ble_svc_gap.c b/nimble/host/services/gap/src/ble_svc_gap.c index 2f7832282..5950e53d3 100644 --- a/nimble/host/services/gap/src/ble_svc_gap.c +++ b/nimble/host/services/gap/src/ble_svc_gap.c @@ -99,6 +99,13 @@ static const struct ble_gatt_svc_def ble_svc_gap_defs[] = { .access_cb = ble_svc_gap_access, .flags = BLE_GATT_CHR_F_READ, }, { +#endif +#if MYNEWT_VAL(BLE_SVC_GAP_GATT_SECURITY_LEVEL) + /*** Characteristic: LE GATT Security Levels. */ + .uuid = BLE_UUID16_DECLARE(BLE_SVC_GAP_CHR_UUID16_LE_GATT_SECURITY_LEVELS), + .access_cb = ble_svc_gap_access, + .flags = BLE_GATT_CHR_F_READ, + }, { #endif 0, /* No more characteristics in this service. */ } }, @@ -190,6 +197,26 @@ ble_svc_gap_appearance_write_access(struct ble_gatt_access_ctxt *ctxt) #endif } +#if MYNEWT_VAL(BLE_SVC_GAP_GATT_SECURITY_LEVEL) +static int +ble_svc_gap_security_level_read_access(uint16_t conn_handle, struct os_mbuf * om) +{ + uint8_t security_level[2]; + int rc; + + /* Currently this characteristic is only supported for + * Security Mode 1 + */ + security_level[0] = 0x01; //Mode 1 + security_level[1] = ble_gatts_security_mode_1_level(); //Mode 1 Level + + rc = os_mbuf_append(om, security_level, sizeof(security_level)); + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} +#endif + + static int ble_svc_gap_access(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) @@ -256,6 +283,13 @@ ble_svc_gap_access(uint16_t conn_handle, uint16_t attr_handle, return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; #endif +#if MYNEWT_VAL(BLE_SVC_GAP_GATT_SECURITY_LEVEL) + case BLE_SVC_GAP_CHR_UUID16_LE_GATT_SECURITY_LEVELS: + assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR); + rc = ble_svc_gap_security_level_read_access(conn_handle, ctxt->om); + return rc; +#endif + default: assert(0); return BLE_ATT_ERR_UNLIKELY; diff --git a/nimble/host/src/ble_att_priv.h b/nimble/host/src/ble_att_priv.h index ae8f4b920..7494cb6e9 100644 --- a/nimble/host/src/ble_att_priv.h +++ b/nimble/host/src/ble_att_priv.h @@ -240,6 +240,9 @@ void ble_att_svr_restore_range(uint16_t start_handle, uint16_t end_handle); int ble_att_svr_tx_error_rsp(uint16_t conn_handle, uint16_t cid, struct os_mbuf *txom, uint8_t req_op, uint16_t handle, uint8_t error_code); +#if MYNEWT_VAL(BLE_SVC_GAP_GATT_SECURITY_LEVEL) +uint8_t ble_att_svr_security_mode_1_level(void); +#endif /*** $clt */ /** An information-data entry in a find information response. */ diff --git a/nimble/host/src/ble_att_svr.c b/nimble/host/src/ble_att_svr.c index 977efe565..4190db9ca 100644 --- a/nimble/host/src/ble_att_svr.c +++ b/nimble/host/src/ble_att_svr.c @@ -3415,4 +3415,45 @@ int ble_att_fill_database_info(uint8_t *out_data) return 0; } #endif + +#if MYNEWT_VAL(BLE_SVC_GAP_GATT_SECURITY_LEVEL) +/** + * Return the highest Security Mode 1 Level requirement. + * + * @return Maximum level requirement + */ +uint8_t +ble_att_svr_security_mode_1_level() +{ + struct ble_att_svr_entry *entry; + uint8_t highest_security_level = 0x01; //No Security + uint8_t sec_level; + uint8_t flags; + + for (entry = STAILQ_FIRST(&ble_att_svr_list); + entry != NULL; + entry = STAILQ_NEXT(entry, ha_next)) { + + flags = entry->ha_flags; + if ((flags & BLE_ATT_F_READ_AUTHEN) || (flags & BLE_ATT_F_WRITE_AUTHEN)) { + sec_level = 0x03; //Authenticated pairing with encryption + /* This is the highest currently supported value. + * Break here. + */ + highest_security_level = 0x03; + break; + } else if ((flags & BLE_ATT_F_READ_ENC) || (flags & BLE_ATT_F_WRITE_ENC)) { + sec_level = 0x02; //Unauthenticated pairing with encryption + } else { + sec_level = 0x01; //No security (No authentication and no encryption) + } + + if (sec_level > highest_security_level) { + highest_security_level = sec_level; + } + } + + return highest_security_level; +} +#endif #endif diff --git a/nimble/host/src/ble_gatts.c b/nimble/host/src/ble_gatts.c index 8e308efdc..84857b5b9 100644 --- a/nimble/host/src/ble_gatts.c +++ b/nimble/host/src/ble_gatts.c @@ -3185,6 +3185,17 @@ ble_gatts_lcl_svc_foreach(ble_gatt_svc_foreach_fn cb, void *arg) #endif } +#if MYNEWT_VAL(BLE_SVC_GAP_GATT_SECURITY_LEVEL) +uint8_t +ble_gatts_security_mode_1_level() { + uint8_t security_level; + + security_level = ble_att_svr_security_mode_1_level(); + + return security_level; +} +#endif + int ble_gatts_reset(void) {