From 3a427d1ab094516371e116c2c85ecba5e92de611 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Mon, 5 Mar 2018 11:33:48 +0200 Subject: [PATCH] shared/gatt-db: Generate database hash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This use bt_crypto_hash (AES-CMAC) to generate a database hash using the content of the attribute: In ascending order of attribute handles, starting with the first handle, concatenate the fields Attribute Handle, Attribute Type, and Attribute Value if the attribute has one of the following types: «Primary Service», «Secondary Service», «Included Service», «Characteristic», or «Characteristic Extended Properties», concatenate the fields Attribute Handle and Attribute Type if the attribute has one of the following types: «Characteristic User Description», «Client Characteristic Configuration», «Server Characteristic Configuration», «Characteristic Format», or «Characteristic Aggregate Format», and ignore the attribute if it has any other type (such attributes are not part of the concatenation). --- src/shared/gatt-db.c | 68 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c index 2ce0f87cf..2471876bc 100644 --- a/src/shared/gatt-db.c +++ b/src/shared/gatt-db.c @@ -35,6 +35,7 @@ #include "src/shared/timeout.h" #include "src/shared/att.h" #include "src/shared/gatt-db.h" +#include "src/shared/crypto.h" #ifndef MAX #define MAX(a, b) ((a) > (b) ? (a) : (b)) @@ -58,6 +59,7 @@ static const bt_uuid_t ext_desc_uuid = { .type = BT_UUID16, struct gatt_db { int ref_count; + struct bt_crypto *crypto; uint8_t hash[16]; unsigned int hash_id; uint16_t next_handle; @@ -225,6 +227,7 @@ struct gatt_db *gatt_db_new(void) struct gatt_db *db; db = new0(struct gatt_db, 1); + db->crypto = bt_crypto_new(); db->services = queue_new(); db->notify_list = queue_new(); db->next_handle = 0x0001; @@ -266,12 +269,71 @@ static void handle_notify(void *data, void *user_data) notify->service_removed(notify_data->attr, notify->user_data); } +static void gen_hash_m(struct gatt_db_attribute *attr, void *user_data) +{ + struct iovec *iov = user_data; + uint8_t *data; + size_t len; + + if (bt_uuid_len(&attr->uuid) != 2) + return; + + switch (attr->uuid.value.u16) { + case GATT_PRIM_SVC_UUID: + case GATT_SND_SVC_UUID: + case GATT_INCLUDE_UUID: + case GATT_CHARAC_UUID: + /* Allocate space for handle + type + value */ + len = 2 + 2 + attr->value_len; + data = malloc(2 + 2 + attr->value_len); + put_le16(attr->handle, data); + bt_uuid_to_le(&attr->uuid, data + 2); + memcpy(data + 4, attr->value, attr->value_len); + break; + case GATT_CHARAC_USER_DESC_UUID: + case GATT_CLIENT_CHARAC_CFG_UUID: + case GATT_SERVER_CHARAC_CFG_UUID: + case GATT_CHARAC_FMT_UUID: + case GATT_CHARAC_AGREG_FMT_UUID: + /* Allocate space for handle + type */ + len = 2 + 2; + data = malloc(2 + 2 + attr->value_len); + put_le16(attr->handle, data); + bt_uuid_to_le(&attr->uuid, data + 2); + break; + default: + return; + } + + iov[attr->handle].iov_base = data; + iov[attr->handle].iov_len = len; + + return; +} + +static void service_gen_hash_m(struct gatt_db_attribute *attr, void *user_data) +{ + gatt_db_service_foreach(attr, NULL, gen_hash_m, user_data); +} + static bool db_hash_update(void *user_data) { struct gatt_db *db = user_data; + struct iovec *iov; + uint16_t i; db->hash_id = 0; + iov = new0(struct iovec, db->next_handle); + + gatt_db_foreach_service(db, NULL, service_gen_hash_m, iov); + bt_crypto_gatt_hash(db->crypto, iov, db->next_handle, db->hash); + + for (i = 0; i < db->next_handle; i++) + free(iov[i].iov_base); + + free(iov); + return false; } @@ -292,7 +354,7 @@ static void notify_service_changed(struct gatt_db *db, queue_foreach(db->notify_list, handle_notify, &data); /* Tigger hash update */ - if (!db->hash_id) + if (!db->hash_id && db->crypto) db->hash_id = timeout_add(HASH_UPDATE_TIMEOUT, db_hash_update, db, NULL); @@ -319,6 +381,8 @@ static void gatt_db_destroy(struct gatt_db *db) if (!db) return; + bt_crypto_unref(db->crypto); + /* * Clear the notify list before clearing the services to prevent the * latter from sending service_removed events. @@ -506,7 +570,7 @@ uint8_t *gatt_db_get_hash(struct gatt_db *db) { uint8_t hash[16] = {}; - if (!db) + if (!db || !db->crypto) return NULL; /* Generate hash if if has not been generated yet */ -- 2.47.3