diff --git a/doc/gatt-api.txt b/doc/gatt-api.txt
index 55798ae..4992243 100644
--- a/doc/gatt-api.txt
+++ b/doc/gatt-api.txt
"encrypt-write"
"encrypt-authenticated-read"
"encrypt-authenticated-write"
+ "secure-read" (Server only)
+ "secure-write" (Server only)
Characteristic Descriptors hierarchy
====================================
"encrypt-write"
"encrypt-authenticated-read"
"encrypt-authenticated-write"
+ "secure-read" (Server Only)
+ "secure-write" (Server Only)
GATT Profile hierarcy
=====================
diff --git a/lib/bluetooth.h b/lib/bluetooth.h
index 852a6b2..eb27926 100644
--- a/lib/bluetooth.h
+++ b/lib/bluetooth.h
#define BT_SECURITY_LOW 1
#define BT_SECURITY_MEDIUM 2
#define BT_SECURITY_HIGH 3
+#define BT_SECURITY_FIPS 4
#define BT_DEFER_SETUP 7
diff --git a/src/gatt-database.c b/src/gatt-database.c
index 09bec0b..e287b98 100644
--- a/src/gatt-database.c
+++ b/src/gatt-database.c
GDBusProxy *proxy;
uint8_t props;
uint8_t ext_props;
+ uint32_t perm;
struct gatt_db_attribute *attrib;
struct gatt_db_attribute *ccc;
struct queue *pending_reads;
}
static bool parse_chrc_flags(DBusMessageIter *array, uint8_t *props,
- uint8_t *ext_props)
+ uint8_t *ext_props, uint32_t *perm)
{
const char *flag;
if (!strcmp("broadcast", flag))
*props |= BT_GATT_CHRC_PROP_BROADCAST;
- else if (!strcmp("read", flag))
+ else if (!strcmp("read", flag)) {
*props |= BT_GATT_CHRC_PROP_READ;
- else if (!strcmp("write-without-response", flag))
+ *perm |= BT_ATT_PERM_READ;
+ } else if (!strcmp("write-without-response", flag)) {
*props |= BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP;
- else if (!strcmp("write", flag))
+ *perm |= BT_ATT_PERM_WRITE;
+ } else if (!strcmp("write", flag)) {
*props |= BT_GATT_CHRC_PROP_WRITE;
- else if (!strcmp("notify", flag))
+ *perm |= BT_ATT_PERM_WRITE;
+ } else if (!strcmp("notify", flag)) {
*props |= BT_GATT_CHRC_PROP_NOTIFY;
- else if (!strcmp("indicate", flag))
+ } else if (!strcmp("indicate", flag)) {
*props |= BT_GATT_CHRC_PROP_INDICATE;
- else if (!strcmp("authenticated-signed-writes", flag))
+ } else if (!strcmp("authenticated-signed-writes", flag)) {
*props |= BT_GATT_CHRC_PROP_AUTH;
- else if (!strcmp("reliable-write", flag))
+ *perm |= BT_ATT_PERM_WRITE;
+ } else if (!strcmp("reliable-write", flag)) {
*ext_props |= BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE;
- else if (!strcmp("writable-auxiliaries", flag))
+ *perm |= BT_ATT_PERM_WRITE;
+ } else if (!strcmp("writable-auxiliaries", flag)) {
*ext_props |= BT_GATT_CHRC_EXT_PROP_WRITABLE_AUX;
- else if (!strcmp("encrypt-read", flag)) {
+ } else if (!strcmp("encrypt-read", flag)) {
*props |= BT_GATT_CHRC_PROP_READ;
*ext_props |= BT_GATT_CHRC_EXT_PROP_ENC_READ;
+ *perm |= BT_ATT_PERM_READ | BT_ATT_PERM_READ_ENCRYPT;
} else if (!strcmp("encrypt-write", flag)) {
*props |= BT_GATT_CHRC_PROP_WRITE;
*ext_props |= BT_GATT_CHRC_EXT_PROP_ENC_WRITE;
+ *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_ENCRYPT;
} else if (!strcmp("encrypt-authenticated-read", flag)) {
*props |= BT_GATT_CHRC_PROP_READ;
*ext_props |= BT_GATT_CHRC_EXT_PROP_AUTH_READ;
+ *perm |= BT_ATT_PERM_READ | BT_ATT_PERM_READ_AUTHEN;
} else if (!strcmp("encrypt-authenticated-write", flag)) {
*props |= BT_GATT_CHRC_PROP_WRITE;
*ext_props |= BT_GATT_CHRC_EXT_PROP_AUTH_WRITE;
+ *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_AUTHEN;
+ } else if (!strcmp("secure-read", flag)) {
+ *props |= BT_GATT_CHRC_PROP_READ;
+ *ext_props |= BT_GATT_CHRC_EXT_PROP_AUTH_READ;
+ *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_READ_SECURE;
+ } else if (!strcmp("secure-write", flag)) {
+ *props |= BT_GATT_CHRC_PROP_WRITE;
+ *ext_props |= BT_GATT_CHRC_EXT_PROP_AUTH_WRITE;
+ *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_SECURE;
} else {
error("Invalid characteristic flag: %s", flag);
return false;
*perm |= BT_ATT_PERM_READ | BT_ATT_PERM_READ_AUTHEN;
else if (!strcmp("encrypt-authenticated-write", flag))
*perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_AUTHEN;
+ else if (!strcmp("secure-read", flag))
+ *perm |= BT_ATT_PERM_READ | BT_ATT_PERM_READ_AUTHEN;
+ else if (!strcmp("secure-write", flag))
+ *perm |= BT_ATT_PERM_WRITE | BT_ATT_PERM_WRITE_AUTHEN;
else {
error("Invalid descriptor flag: %s", flag);
return false;
uint32_t *perm)
{
DBusMessageIter iter, array;
+ const char *iface;
if (!g_dbus_proxy_get_property(proxy, "Flags", &iter))
return false;
dbus_message_iter_recurse(&iter, &array);
- if (perm)
+ iface = g_dbus_proxy_get_interface(proxy);
+ if (!strcmp(iface, GATT_DESC_IFACE))
return parse_desc_flags(&array, perm);
- return parse_chrc_flags(&array, props, ext_props);
+ return parse_chrc_flags(&array, props, ext_props, perm);
}
static struct external_chrc *chrc_create(struct gatt_app *app,
* are used to determine if any special descriptors should be
* created.
*/
- if (!parse_flags(proxy, &chrc->props, &chrc->ext_props, NULL)) {
+ if (!parse_flags(proxy, &chrc->props, &chrc->ext_props, &chrc->perm)) {
error("Failed to parse characteristic properties");
goto fail;
}
return NULL;
}
-static uint32_t permissions_from_props(uint8_t props, uint8_t ext_props)
-{
- uint32_t perm = 0;
-
- if (props & BT_GATT_CHRC_PROP_WRITE ||
- props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP ||
- ext_props & BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE ||
- ext_props & BT_GATT_CHRC_EXT_PROP_ENC_WRITE ||
- ext_props & BT_GATT_CHRC_EXT_PROP_AUTH_WRITE)
- perm |= BT_ATT_PERM_WRITE;
-
- if (props & BT_GATT_CHRC_PROP_READ ||
- ext_props & BT_GATT_CHRC_EXT_PROP_ENC_READ ||
- ext_props & BT_GATT_CHRC_EXT_PROP_AUTH_READ)
- perm |= BT_ATT_PERM_READ;
-
- if (ext_props & BT_GATT_CHRC_EXT_PROP_ENC_READ)
- perm |= BT_ATT_PERM_READ_ENCRYPT;
-
- if (ext_props & BT_GATT_CHRC_EXT_PROP_ENC_WRITE)
- perm |= BT_ATT_PERM_WRITE_ENCRYPT;
-
- if (ext_props & BT_GATT_CHRC_EXT_PROP_AUTH_READ)
- perm |= BT_ATT_PERM_READ_AUTHEN;
-
- if (ext_props & BT_GATT_CHRC_EXT_PROP_AUTH_WRITE)
- perm |= BT_ATT_PERM_WRITE_AUTHEN;
-
- return perm;
-}
-
static uint8_t ccc_write_cb(uint16_t value, void *user_data)
{
struct external_chrc *chrc = user_data;
struct external_chrc *chrc)
{
bt_uuid_t uuid;
- uint32_t perm;
const struct queue_entry *entry;
if (!parse_uuid(chrc->proxy, &uuid)) {
return false;
}
- /*
- * TODO: Once shared/gatt-server properly supports permission checks,
- * set the permissions based on a D-Bus property of the external
- * characteristic.
- */
- perm = permissions_from_props(chrc->props, chrc->ext_props);
chrc->attrib = gatt_db_service_add_characteristic(service->attrib,
- &uuid, perm,
+ &uuid, chrc->perm,
chrc->props, chrc_read_cb,
chrc_write_cb, chrc);
if (!chrc->attrib) {
diff --git a/src/shared/att-types.h b/src/shared/att-types.h
index c3062c0..4a9b67f 100644
--- a/src/shared/att-types.h
+++ b/src/shared/att-types.h
#define BT_ATT_SECURITY_LOW 1
#define BT_ATT_SECURITY_MEDIUM 2
#define BT_ATT_SECURITY_HIGH 3
+#define BT_ATT_SECURITY_FIPS 4
#define BT_ATT_DEFAULT_LE_MTU 23
#define BT_ATT_MAX_LE_MTU 517
BT_ATT_PERM_WRITE_AUTHEN)
#define BT_ATT_PERM_AUTHOR 0x40
#define BT_ATT_PERM_NONE 0x80
+#define BT_ATT_PERM_READ_SECURE 0x0100
+#define BT_ATT_PERM_WRITE_SECURE 0x0200
+#define BT_ATT_PERM_SECURE (BT_ATT_PERM_READ_SECURE | \
+ BT_ATT_PERM_WRITE_SECURE)
/* GATT Characteristic Properties Bitfield values */
#define BT_GATT_CHRC_PROP_BROADCAST 0x01
diff --git a/src/shared/gatt-server.c b/src/shared/gatt-server.c
index 123d9c1..79e01c8 100644
--- a/src/shared/gatt-server.c
+++ b/src/shared/gatt-server.c
return 0;
security = bt_att_get_security(server->att);
+ if (perm & BT_ATT_PERM_SECURE && security < BT_ATT_SECURITY_FIPS)
+ return BT_ATT_ERROR_AUTHENTICATION;
+
if (perm & BT_ATT_PERM_AUTHEN && security < BT_ATT_SECURITY_HIGH)
return BT_ATT_ERROR_AUTHENTICATION;