summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2015-02-20 16:07:45 +0200
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2015-02-24 15:28:08 +0200
commit051a525c4a4437f80d68539bcacece21b586a2d6 (patch)
tree032acf24da1806c89875bead300bc3756a63fcb5
parentae5e154e25682094705b8a54ff377c59a1f1c81a (diff)
downloadbluez-051a525c4a4437f80d68539bcacece21b586a2d6.tar.gz
shared/att.c: Add server signing key support
This adds support for setting remote signing keys along with a callback for validating the counter.
-rw-r--r--src/shared/att.c92
-rw-r--r--src/shared/att.h2
2 files changed, 70 insertions, 24 deletions
diff --git a/src/shared/att.c b/src/shared/att.c
index 4bfae5fdb..aa06dc62a 100644
--- a/src/shared/att.c
+++ b/src/shared/att.c
@@ -93,6 +93,7 @@ struct bt_att {
struct bt_crypto *crypto;
struct sign_info *local_sign;
+ struct sign_info *remote_sign;
};
struct sign_info {
@@ -686,21 +687,6 @@ static bool opcode_match(uint8_t opcode, uint8_t test_opcode)
return opcode == test_opcode;
}
-static void notify_handler(void *data, void *user_data)
-{
- struct att_notify *notify = data;
- struct notify_data *not_data = user_data;
-
- if (!opcode_match(notify->opcode, not_data->opcode))
- return;
-
- not_data->handler_found = true;
-
- if (notify->callback)
- notify->callback(not_data->opcode, not_data->pdu,
- not_data->pdu_len, notify->user_data);
-}
-
static void respond_not_supported(struct bt_att *att, uint8_t opcode)
{
uint8_t pdu[4];
@@ -714,28 +700,76 @@ static void respond_not_supported(struct bt_att *att, uint8_t opcode)
NULL);
}
+static bool handle_signed(struct bt_att *att, uint8_t opcode, uint8_t *pdu,
+ ssize_t pdu_len)
+{
+ uint8_t *signature;
+ uint32_t sign_cnt;
+ struct sign_info *sign;
+
+ /* Check if there is enough data for a signature */
+ if (pdu_len < 2 + BT_ATT_SIGNATURE_LEN)
+ goto fail;
+
+ sign = att->remote_sign;
+ if (!sign)
+ goto fail;
+
+ signature = pdu + (pdu_len - BT_ATT_SIGNATURE_LEN);
+ sign_cnt = get_le32(signature);
+
+ /* Validate counter */
+ if (!sign->counter(&sign_cnt, sign->user_data))
+ goto fail;
+
+ /* Generate signature and verify it */
+ if (!bt_crypto_sign_att(att->crypto, sign->key, pdu,
+ pdu_len - BT_ATT_SIGNATURE_LEN, sign_cnt,
+ signature))
+ goto fail;
+
+ return true;
+
+fail:
+ util_debug(att->debug_callback, att->debug_data,
+ "ATT failed to verify signature: 0x%02x", opcode);
+
+ return false;
+}
+
static void handle_notify(struct bt_att *att, uint8_t opcode, uint8_t *pdu,
ssize_t pdu_len)
{
- struct notify_data data;
+ const struct queue_entry *entry;
+ bool found;
+
+ if (opcode & ATT_OP_SIGNED_MASK) {
+ if (!handle_signed(att, opcode, pdu, pdu_len))
+ return;
+ pdu_len -= BT_ATT_SIGNATURE_LEN;
+ }
bt_att_ref(att);
- memset(&data, 0, sizeof(data));
- data.opcode = opcode;
+ for (found = false, entry = queue_get_entries(att->notify_list); entry;
+ entry = entry->next) {
+ struct att_notify *notify = entry->data;
- if (pdu_len > 0) {
- data.pdu = pdu;
- data.pdu_len = pdu_len;
- }
+ if (!opcode_match(notify->opcode, opcode))
+ continue;
+
+ found = true;
- queue_foreach(att->notify_list, notify_handler, &data);
+ if (notify->callback)
+ notify->callback(opcode, pdu, pdu_len,
+ notify->user_data);
+ }
/*
* If this was a request and no handler was registered for it, respond
* with "Not Supported"
*/
- if (!data.handler_found && get_op_type(opcode) == ATT_OP_TYPE_REQ)
+ if (!found && get_op_type(opcode) == ATT_OP_TYPE_REQ)
respond_not_supported(att, opcode);
bt_att_unref(att);
@@ -862,6 +896,7 @@ static void bt_att_free(struct bt_att *att)
att->debug_destroy(att->debug_data);
free(att->local_sign);
+ free(att->remote_sign);
free(att->buf);
@@ -1376,3 +1411,12 @@ bool bt_att_set_local_key(struct bt_att *att, uint8_t sign_key[16],
return sign_set_key(&att->local_sign, sign_key, func, user_data);
}
+
+bool bt_att_set_remote_key(struct bt_att *att, uint8_t sign_key[16],
+ bt_att_counter_func_t func, void *user_data)
+{
+ if (!att)
+ return false;
+
+ return sign_set_key(&att->remote_sign, sign_key, func, user_data);
+}
diff --git a/src/shared/att.h b/src/shared/att.h
index 0cd1a4c36..a440aafd2 100644
--- a/src/shared/att.h
+++ b/src/shared/att.h
@@ -88,3 +88,5 @@ bool bt_att_set_sec_level(struct bt_att *att, int level);
bool bt_att_set_local_key(struct bt_att *att, uint8_t sign_key[16],
bt_att_counter_func_t func, void *user_data);
+bool bt_att_set_remote_key(struct bt_att *att, uint8_t sign_key[16],
+ bt_att_counter_func_t func, void *user_data);