linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH BlueZ v4 0/2] Optionally require security for notify/indicate
@ 2021-10-01 14:17 Dagan Martinez
  2021-10-01 14:17 ` [PATCH BlueZ v4 1/2] gatt: Allow GATT server to dicate CCC permissions Dagan Martinez
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Dagan Martinez @ 2021-10-01 14:17 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Dagan Martinez

In some cases, it is desirable to require encryption and/or
authentication for server-initiated updates, as they may contain
sensitive data.

Currently, there is no way to do this with BlueZ.

Here is a query about this feature from 2019:
https://stackoverflow.com/questions/55884233

This patch implements this feature by introducing new `x-notify` and
`x-indicate` flags that allow a user to restrict access to a
characteristic's CCCD (as well as documentation for those flags).

Note that `x-notify` and `x-indicate` each enforce security for ALL
server-initiated updates. That is, you cannot require one level of
security for notifications and another security level for indications on
the same CCCD. I could not think of a reason why somebody would want
that feature, and did not think the accuracy of terms would be worth the
introduced complexity, so I didn't implement it.

---
Changes in v4:
- Directly set flags on CCCD instead of having new intermediate
    permissions

Changes in v3:
- Split the `x-asynchronous` flags into `x-notify` and `x-indicate`
- Fix a mixed code and declaration error

Changes in v2:
- Fix line-width issues brought up by CI

Dagan Martinez (2):
  gatt: Allow GATT server to dicate CCC permissions
  doc/gatt-api: Add 'X-notify`/`X-indicate`

 doc/gatt-api.txt    | 15 ++++++++++++-
 src/gatt-database.c | 52 ++++++++++++++++++++++++++++++++++++---------
 2 files changed, 56 insertions(+), 11 deletions(-)

-- 
2.31.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH BlueZ v4 1/2] gatt: Allow GATT server to dicate CCC permissions
  2021-10-01 14:17 [PATCH BlueZ v4 0/2] Optionally require security for notify/indicate Dagan Martinez
@ 2021-10-01 14:17 ` Dagan Martinez
  2021-10-01 14:17 ` [PATCH BlueZ v4 2/2] doc/gatt-api: Add 'X-notify`/`X-indicate` Dagan Martinez
  2021-10-01 18:01 ` [PATCH BlueZ v4 0/2] Optionally require security for notify/indicate Luiz Augusto von Dentz
  2 siblings, 0 replies; 4+ messages in thread
From: Dagan Martinez @ 2021-10-01 14:17 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Dagan Martinez

Allow a GATT server to impose write permissions/restrictions on a CCC by
setting additional `X-notify` and `X-indicate` flags on its associated
characteristic.

This allows a developer to require encryption/authentication in order
for a GATT client to subscribe to server-initiated updates.

```
[bluetooth]# register-characteristic\
	4b75f0f8-1f23-46b1-900c-5bbabcd5ca93 encrypt-read,encrypt-notify

[NEW] Characteristic (Handle 0x0000)
        /org/bluez/app/service0/chrc17
        4b75f0f8-1f23-46b1-900c-5bbabcd5ca93
        Vendor specific
[/org/bluez/app/service0/chrc17] Enter value: 42
```

Test procedure:
Attempt to read/write with a "low" security level on an unprotected CCC
using gatttool, and succeed
Attempt to READ with a "low" security level on an protected CCC
using gatttool, and succeed
Attempt to WRITE with a "low" security level on an protected CCC
using gatttool, and fail
Attempt to read/write while paired on a protected CCC using
`bluetoothctl`, and succeed
---
 src/gatt-database.c | 52 ++++++++++++++++++++++++++++++++++++---------
 1 file changed, 42 insertions(+), 10 deletions(-)

diff --git a/src/gatt-database.c b/src/gatt-database.c
index 68f411ba4..475e7873c 100644
--- a/src/gatt-database.c
+++ b/src/gatt-database.c
@@ -115,6 +115,7 @@ struct external_chrc {
 	uint8_t props;
 	uint8_t ext_props;
 	uint32_t perm;
+	uint32_t ccc_perm;
 	uint16_t mtu;
 	struct io *write_io;
 	struct io *notify_io;
@@ -1059,7 +1060,7 @@ static struct gatt_db_attribute *
 service_add_ccc(struct gatt_db_attribute *service,
 				struct btd_gatt_database *database,
 				btd_gatt_database_ccc_write_t write_callback,
-				void *user_data,
+				void *user_data, uint32_t perm,
 				btd_gatt_database_destroy_t destroy)
 {
 	struct gatt_db_attribute *ccc;
@@ -1068,9 +1069,14 @@ service_add_ccc(struct gatt_db_attribute *service,
 
 	ccc_cb = new0(struct ccc_cb_data, 1);
 
+	/*
+	 * Provide a way for the permissions on a characteristic to dictate
+	 * the permissions on the CCC
+	 */
+	perm |= BT_ATT_PERM_READ | BT_ATT_PERM_WRITE;
+
 	bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
-	ccc = gatt_db_service_add_descriptor(service, &uuid,
-				BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+	ccc = gatt_db_service_add_descriptor(service, &uuid, perm,
 				gatt_ccc_read_cb, gatt_ccc_write_cb, database);
 	if (!ccc) {
 		error("Failed to create CCC entry in database");
@@ -1227,7 +1233,7 @@ static void populate_gatt_service(struct btd_gatt_database *database)
 				NULL, NULL, database);
 
 	database->svc_chngd_ccc = service_add_ccc(service, database, NULL, NULL,
-									NULL);
+								    0, NULL);
 
 	bt_uuid16_create(&uuid, GATT_CHARAC_CLI_FEAT);
 	database->cli_feat = gatt_db_service_add_characteristic(service,
@@ -1633,11 +1639,18 @@ static bool incr_attr_count(struct external_service *service, uint16_t incr)
 
 static bool parse_chrc_flags(DBusMessageIter *array, uint8_t *props,
 					uint8_t *ext_props, uint32_t *perm,
+					uint32_t *ccc_perm,
 					bool *req_prep_authorization)
 {
 	const char *flag;
 
-	*props = *ext_props = 0;
+	if (!props || !ext_props || !perm || !ccc_perm)
+		return false;
+
+	*props = 0;
+	*ext_props = 0;
+	*perm = 0;
+	*ccc_perm = 0;
 
 	do {
 		if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_STRING)
@@ -1690,6 +1703,24 @@ static bool parse_chrc_flags(DBusMessageIter *array, uint8_t *props,
 			*perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_SECURE;
 		} else if (!strcmp("authorize", flag)) {
 			*req_prep_authorization = true;
+		} else if (!strcmp("encrypt-notify", flag)) {
+			*ccc_perm |= BT_ATT_PERM_WRITE_ENCRYPT;
+			*props |= BT_GATT_CHRC_PROP_NOTIFY;
+		} else if (!strcmp("encrypt-authenticated-notify", flag)) {
+			*ccc_perm |= BT_ATT_PERM_WRITE_AUTHEN;
+			*props |= BT_GATT_CHRC_PROP_NOTIFY;
+		} else if (!strcmp("secure-notify", flag)) {
+			*ccc_perm |= BT_ATT_PERM_WRITE_SECURE;
+			*props |= BT_GATT_CHRC_PROP_NOTIFY;
+		} else if (!strcmp("encrypt-indicate", flag)) {
+			*ccc_perm |= BT_ATT_PERM_WRITE_ENCRYPT;
+			*props |= BT_GATT_CHRC_PROP_INDICATE;
+		} else if (!strcmp("encrypt-authenticated-indicate", flag)) {
+			*ccc_perm |= BT_ATT_PERM_WRITE_AUTHEN;
+			*props |= BT_GATT_CHRC_PROP_INDICATE;
+		} else if (!strcmp("secure-indicate", flag)) {
+			*ccc_perm |= BT_ATT_PERM_WRITE_SECURE;
+			*props |= BT_GATT_CHRC_PROP_INDICATE;
 		} else {
 			error("Invalid characteristic flag: %s", flag);
 			return false;
@@ -1743,7 +1774,8 @@ static bool parse_desc_flags(DBusMessageIter *array, uint32_t *perm,
 }
 
 static bool parse_flags(GDBusProxy *proxy, uint8_t *props, uint8_t *ext_props,
-				uint32_t *perm, bool *req_prep_authorization)
+					    uint32_t *perm, uint32_t *ccc_perm,
+					    bool *req_prep_authorization)
 {
 	DBusMessageIter iter, array;
 	const char *iface;
@@ -1760,7 +1792,7 @@ static bool parse_flags(GDBusProxy *proxy, uint8_t *props, uint8_t *ext_props,
 	if (!strcmp(iface, GATT_DESC_IFACE))
 		return parse_desc_flags(&array, perm, req_prep_authorization);
 
-	return parse_chrc_flags(&array, props, ext_props, perm,
+	return parse_chrc_flags(&array, props, ext_props, perm, ccc_perm,
 							req_prep_authorization);
 }
 
@@ -1810,7 +1842,7 @@ static struct external_chrc *chrc_create(struct gatt_app *app,
 	 * created.
 	 */
 	if (!parse_flags(proxy, &chrc->props, &chrc->ext_props, &chrc->perm,
-					&chrc->req_prep_authorization)) {
+			&chrc->ccc_perm, &chrc->req_prep_authorization)) {
 		error("Failed to parse characteristic properties");
 		goto fail;
 	}
@@ -1892,7 +1924,7 @@ static struct external_desc *desc_create(struct gatt_app *app,
 	 * Parse descriptors flags here since they are used to
 	 * determine the permission the descriptor should have
 	 */
-	if (!parse_flags(proxy, NULL, NULL, &desc->perm,
+	if (!parse_flags(proxy, NULL, NULL, &desc->perm, NULL,
 					&desc->req_prep_authorization)) {
 		error("Failed to parse characteristic properties");
 		goto fail;
@@ -2796,7 +2828,7 @@ static bool database_add_ccc(struct external_service *service,
 		return true;
 
 	chrc->ccc = service_add_ccc(service->attrib, service->app->database,
-						ccc_write_cb, chrc, NULL);
+				    ccc_write_cb, chrc, chrc->ccc_perm, NULL);
 	if (!chrc->ccc) {
 		error("Failed to create CCC entry for characteristic");
 		return false;
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH BlueZ v4 2/2] doc/gatt-api: Add 'X-notify`/`X-indicate`
  2021-10-01 14:17 [PATCH BlueZ v4 0/2] Optionally require security for notify/indicate Dagan Martinez
  2021-10-01 14:17 ` [PATCH BlueZ v4 1/2] gatt: Allow GATT server to dicate CCC permissions Dagan Martinez
@ 2021-10-01 14:17 ` Dagan Martinez
  2021-10-01 18:01 ` [PATCH BlueZ v4 0/2] Optionally require security for notify/indicate Luiz Augusto von Dentz
  2 siblings, 0 replies; 4+ messages in thread
From: Dagan Martinez @ 2021-10-01 14:17 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Dagan Martinez

Update docs to reflect the addition of the `X-notify` and `X-indicate`
characteristic flags, which allow a GATT server to restrict CCC write
permissions.
---
 doc/gatt-api.txt | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/doc/gatt-api.txt b/doc/gatt-api.txt
index 120b23d1a..af0aa761d 100644
--- a/doc/gatt-api.txt
+++ b/doc/gatt-api.txt
@@ -253,7 +253,14 @@ Properties	string UUID [read-only]
 			Defines how the characteristic value can be used. See
 			Core spec "Table 3.5: Characteristic Properties bit
 			field", and "Table 3.8: Characteristic Extended
-			Properties bit field". Allowed values:
+			Properties bit field".
+
+			The "x-notify" and "x-indicate" flags restrict access
+			to notifications and indications by imposing write
+			restrictions on a characteristic's client
+			characteristic configuration descriptor.
+
+			Allowed values:
 
 				"broadcast"
 				"read"
@@ -267,10 +274,16 @@ Properties	string UUID [read-only]
 				"writable-auxiliaries"
 				"encrypt-read"
 				"encrypt-write"
+				"encrypt-notify" (Server only)
+				"encrypt-indicate" (Server only)
 				"encrypt-authenticated-read"
 				"encrypt-authenticated-write"
+				"encrypt-authenticated-notify" (Server only)
+				"encrypt-authenticated-indicate" (Server only)
 				"secure-read" (Server only)
 				"secure-write" (Server only)
+				"secure-notify" (Server only)
+				"secure-indicate" (Server only)
 				"authorize"
 
 		uint16 Handle [read-write, optional] (Server Only)
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH BlueZ v4 0/2] Optionally require security for notify/indicate
  2021-10-01 14:17 [PATCH BlueZ v4 0/2] Optionally require security for notify/indicate Dagan Martinez
  2021-10-01 14:17 ` [PATCH BlueZ v4 1/2] gatt: Allow GATT server to dicate CCC permissions Dagan Martinez
  2021-10-01 14:17 ` [PATCH BlueZ v4 2/2] doc/gatt-api: Add 'X-notify`/`X-indicate` Dagan Martinez
@ 2021-10-01 18:01 ` Luiz Augusto von Dentz
  2 siblings, 0 replies; 4+ messages in thread
From: Luiz Augusto von Dentz @ 2021-10-01 18:01 UTC (permalink / raw)
  To: Dagan Martinez; +Cc: linux-bluetooth

Hi Dagan,

On Fri, Oct 1, 2021 at 7:19 AM Dagan Martinez <dmartinez@starry.com> wrote:
>
> In some cases, it is desirable to require encryption and/or
> authentication for server-initiated updates, as they may contain
> sensitive data.
>
> Currently, there is no way to do this with BlueZ.
>
> Here is a query about this feature from 2019:
> https://stackoverflow.com/questions/55884233
>
> This patch implements this feature by introducing new `x-notify` and
> `x-indicate` flags that allow a user to restrict access to a
> characteristic's CCCD (as well as documentation for those flags).
>
> Note that `x-notify` and `x-indicate` each enforce security for ALL
> server-initiated updates. That is, you cannot require one level of
> security for notifications and another security level for indications on
> the same CCCD. I could not think of a reason why somebody would want
> that feature, and did not think the accuracy of terms would be worth the
> introduced complexity, so I didn't implement it.
>
> ---
> Changes in v4:
> - Directly set flags on CCCD instead of having new intermediate
>     permissions
>
> Changes in v3:
> - Split the `x-asynchronous` flags into `x-notify` and `x-indicate`
> - Fix a mixed code and declaration error
>
> Changes in v2:
> - Fix line-width issues brought up by CI
>
> Dagan Martinez (2):
>   gatt: Allow GATT server to dicate CCC permissions
>   doc/gatt-api: Add 'X-notify`/`X-indicate`
>
>  doc/gatt-api.txt    | 15 ++++++++++++-
>  src/gatt-database.c | 52 ++++++++++++++++++++++++++++++++++++---------
>  2 files changed, 56 insertions(+), 11 deletions(-)
>
> --
> 2.31.1

Applied, thanks.

-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2021-10-01 18:01 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-01 14:17 [PATCH BlueZ v4 0/2] Optionally require security for notify/indicate Dagan Martinez
2021-10-01 14:17 ` [PATCH BlueZ v4 1/2] gatt: Allow GATT server to dicate CCC permissions Dagan Martinez
2021-10-01 14:17 ` [PATCH BlueZ v4 2/2] doc/gatt-api: Add 'X-notify`/`X-indicate` Dagan Martinez
2021-10-01 18:01 ` [PATCH BlueZ v4 0/2] Optionally require security for notify/indicate Luiz Augusto von Dentz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).