[RFC BlueZ 1/3] shared/att.c: Add signing key support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Luiz Augusto von Dentz <luiz.von.dentz@xxxxxxxxx>

This adds support for setting local and remote signing keys along with
a callback for fetching/updating signing counter.
---
 src/shared/att.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
 src/shared/att.h |   6 ++++
 2 files changed, 104 insertions(+), 4 deletions(-)

diff --git a/src/shared/att.c b/src/shared/att.c
index 152f49c..5363907 100644
--- a/src/shared/att.c
+++ b/src/shared/att.c
@@ -36,6 +36,7 @@
 #include "lib/bluetooth.h"
 #include "lib/uuid.h"
 #include "src/shared/att.h"
+#include "src/shared/crypto.h"
 
 #define ATT_MIN_PDU_LEN			1  /* At least 1 byte for the opcode. */
 #define ATT_OP_CMD_MASK			0x40
@@ -52,6 +53,9 @@
 #define BT_ERROR_ALREADY_IN_PROGRESS		0xfe
 #define BT_ERROR_OUT_OF_RANGE			0xff
 
+/* Length of signature in write signed packet */
+#define BT_ATT_SIGNATURE_LEN		12
+
 struct att_send_op;
 
 struct bt_att {
@@ -85,6 +89,17 @@ struct bt_att {
 	bt_att_debug_func_t debug_callback;
 	bt_att_destroy_func_t debug_destroy;
 	void *debug_data;
+
+	struct bt_crypto *crypto;
+
+	struct sign_write_info *local_info;
+	struct sign_write_info *remote_info;
+};
+
+struct sign_write_info {
+	uint8_t key[16];
+	bt_att_counter_func_t counter;
+	void *user_data;
 };
 
 enum att_op_type {
@@ -184,6 +199,8 @@ struct att_send_op {
 	bt_att_response_func_t callback;
 	bt_att_destroy_func_t destroy;
 	void *user_data;
+
+	struct bt_att *att;
 };
 
 static void destroy_att_send_op(void *data)
@@ -266,6 +283,12 @@ static bool encode_pdu(struct att_send_op *op, const void *pdu,
 						uint16_t length, uint16_t mtu)
 {
 	uint16_t pdu_len = 1;
+	struct bt_att *att = op->att;
+	struct sign_write_info *info;
+	uint32_t sign_cnt;
+
+	if (op->opcode & ATT_OP_SIGNED_MASK)
+		pdu_len += BT_ATT_SIGNATURE_LEN;
 
 	if (length && pdu)
 		pdu_len += length;
@@ -282,17 +305,36 @@ static bool encode_pdu(struct att_send_op *op, const void *pdu,
 	if (pdu_len > 1)
 		memcpy(op->pdu + 1, pdu, length);
 
-	return true;
+	if (!(op->opcode & ATT_OP_SIGNED_MASK))
+		return true;
+
+	info = att->local_info;
+	if (!info)
+		goto fail;
+
+	if (!info->counter(&sign_cnt, info->user_data))
+		goto fail;
+
+	if ((bt_crypto_sign_att(att->crypto, info->key, op->pdu, 1 + length,
+				sign_cnt, &((uint8_t *) op->pdu)[1 + length])))
+		return true;
+
+fail:
+	free(op->pdu);
+	return false;
 }
 
-static struct att_send_op *create_att_send_op(uint8_t opcode, const void *pdu,
-						uint16_t length, uint16_t mtu,
+static struct att_send_op *create_att_send_op(uint8_t opcode,
+						const void *pdu,
+						uint16_t length,
+						struct bt_att *att,
 						bt_att_response_func_t callback,
 						void *user_data,
 						bt_att_destroy_func_t destroy)
 {
 	struct att_send_op *op;
 	enum att_op_type op_type;
+	uint16_t mtu = att->mtu;
 
 	if (length && !pdu)
 		return NULL;
@@ -323,6 +365,7 @@ static struct att_send_op *create_att_send_op(uint8_t opcode, const void *pdu,
 	op->callback = callback;
 	op->destroy = destroy;
 	op->user_data = user_data;
+	op->att = att;
 
 	if (!encode_pdu(op, pdu, length, mtu)) {
 		free(op);
@@ -810,6 +853,7 @@ static void bt_att_free(struct bt_att *att)
 		destroy_att_send_op(att->pending_ind);
 
 	io_destroy(att->io);
+	bt_crypto_unref(att->crypto);
 
 	queue_destroy(att->req_queue, NULL);
 	queue_destroy(att->ind_queue, NULL);
@@ -841,6 +885,8 @@ struct bt_att *bt_att_new(int fd)
 
 	att->fd = fd;
 
+	att->local_info = NULL;
+	att->remote_info = NULL;
 	att->mtu = BT_ATT_DEFAULT_LE_MTU;
 	att->buf = malloc(att->mtu);
 	if (!att->buf)
@@ -850,6 +896,10 @@ struct bt_att *bt_att_new(int fd)
 	if (!att->io)
 		goto fail;
 
+	att->crypto = bt_crypto_new();
+	if (!att->crypto)
+		goto fail;
+
 	att->req_queue = queue_new();
 	if (!att->req_queue)
 		goto fail;
@@ -964,6 +1014,16 @@ bool bt_att_set_mtu(struct bt_att *att, uint16_t mtu)
 	if (!buf)
 		return false;
 
+	if (att->local_info) {
+		free(att->local_info);
+		att->local_info = NULL;
+	}
+
+	if (att->remote_info) {
+		free(att->remote_info);
+		att->remote_info = NULL;
+	}
+
 	free(att->buf);
 
 	att->mtu = mtu;
@@ -1047,7 +1107,7 @@ unsigned int bt_att_send(struct bt_att *att, uint8_t opcode,
 	if (!att || !att->io)
 		return 0;
 
-	op = create_att_send_op(opcode, pdu, length, att->mtu, callback,
+	op = create_att_send_op(opcode, pdu, length, att, callback,
 							user_data, destroy);
 	if (!op)
 		return 0;
@@ -1307,3 +1367,37 @@ bool bt_att_set_sec_level(struct bt_att *att, int level)
 
 	return true;
 }
+
+static bool sign_info_set_key(struct sign_write_info **info, uint8_t key[16],
+				bt_att_counter_func_t func, void *user_data)
+{
+	if (!(*info)) {
+		*info = new0(struct sign_write_info, 1);
+		if (!(*info))
+			return false;
+	}
+
+	(*info)->counter = func;
+	(*info)->user_data = user_data;
+	memcpy((*info)->key, key, 16);
+
+	return true;
+}
+
+bool bt_att_set_local_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_info_set_key(&att->local_info, 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_info_set_key(&att->remote_info, sign_key, func, user_data);
+}
diff --git a/src/shared/att.h b/src/shared/att.h
index 5256ff9..a440aaf 100644
--- a/src/shared/att.h
+++ b/src/shared/att.h
@@ -46,6 +46,7 @@ typedef void (*bt_att_debug_func_t)(const char *str, void *user_data);
 typedef void (*bt_att_timeout_func_t)(unsigned int id, uint8_t opcode,
 							void *user_data);
 typedef void (*bt_att_disconnect_func_t)(int err, void *user_data);
+typedef bool (*bt_att_counter_func_t)(uint32_t *sign_cnt, void *user_data);
 
 bool bt_att_set_debug(struct bt_att *att, bt_att_debug_func_t callback,
 				void *user_data, bt_att_destroy_func_t destroy);
@@ -84,3 +85,8 @@ bool bt_att_unregister_all(struct bt_att *att);
 
 int bt_att_get_sec_level(struct bt_att *att);
 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);
-- 
2.1.0

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux