diff options
author | Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | 2015-02-20 16:07:45 +0200 |
---|---|---|
committer | Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | 2015-02-24 15:28:08 +0200 |
commit | 051a525c4a4437f80d68539bcacece21b586a2d6 (patch) | |
tree | 032acf24da1806c89875bead300bc3756a63fcb5 | |
parent | ae5e154e25682094705b8a54ff377c59a1f1c81a (diff) | |
download | bluez-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.c | 92 | ||||
-rw-r--r-- | src/shared/att.h | 2 |
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); |