All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH BlueZ 1/5] shared/att.c: Add client signing key support
@ 2015-02-23 18:13 Luiz Augusto von Dentz
  2015-02-23 18:13 ` [PATCH BlueZ 2/5] shared/att.c: Add server " Luiz Augusto von Dentz
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Luiz Augusto von Dentz @ 2015-02-23 18:13 UTC (permalink / raw)
  To: linux-bluetooth

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

This adds support for setting local signing keys along with a callback
for loading the counter.
---
 src/shared/att.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++------
 src/shared/att.h |  4 +++
 2 files changed, 82 insertions(+), 9 deletions(-)

diff --git a/src/shared/att.c b/src/shared/att.c
index 152f49c..4bfae5f 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,16 @@ 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_info *local_sign;
+};
+
+struct sign_info {
+	uint8_t key[16];
+	bt_att_counter_func_t counter;
+	void *user_data;
 };
 
 enum att_op_type {
@@ -262,15 +276,20 @@ static bool match_disconn_id(const void *a, const void *b)
 	return disconn->id == id;
 }
 
-static bool encode_pdu(struct att_send_op *op, const void *pdu,
-						uint16_t length, uint16_t mtu)
+static bool encode_pdu(struct bt_att *att, struct att_send_op *op,
+					const void *pdu, uint16_t length)
 {
 	uint16_t pdu_len = 1;
+	struct sign_info *sign;
+	uint32_t sign_cnt;
+
+	if (op->opcode & ATT_OP_SIGNED_MASK)
+		pdu_len += BT_ATT_SIGNATURE_LEN;
 
 	if (length && pdu)
 		pdu_len += length;
 
-	if (pdu_len > mtu)
+	if (pdu_len > att->mtu)
 		return false;
 
 	op->len = pdu_len;
@@ -282,11 +301,29 @@ 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;
+
+	sign = att->local_sign;
+	if (!sign)
+		goto fail;
+
+	if (!sign->counter(&sign_cnt, sign->user_data))
+		goto fail;
+
+	if ((bt_crypto_sign_att(att->crypto, sign->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(struct bt_att *att,
+						uint8_t opcode,
+						const void *pdu,
+						uint16_t length,
 						bt_att_response_func_t callback,
 						void *user_data,
 						bt_att_destroy_func_t destroy)
@@ -324,7 +361,7 @@ static struct att_send_op *create_att_send_op(uint8_t opcode, const void *pdu,
 	op->destroy = destroy;
 	op->user_data = user_data;
 
-	if (!encode_pdu(op, pdu, length, mtu)) {
+	if (!encode_pdu(att, op, pdu, length)) {
 		free(op);
 		return NULL;
 	}
@@ -810,6 +847,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);
@@ -823,6 +861,8 @@ static void bt_att_free(struct bt_att *att)
 	if (att->debug_destroy)
 		att->debug_destroy(att->debug_data);
 
+	free(att->local_sign);
+
 	free(att->buf);
 
 	free(att);
@@ -850,6 +890,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;
@@ -1047,8 +1091,8 @@ 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,
-							user_data, destroy);
+	op = create_att_send_op(att, opcode, pdu, length, callback, user_data,
+								destroy);
 	if (!op)
 		return 0;
 
@@ -1307,3 +1351,28 @@ bool bt_att_set_sec_level(struct bt_att *att, int level)
 
 	return true;
 }
+
+static bool sign_set_key(struct sign_info **sign, uint8_t key[16],
+				bt_att_counter_func_t func, void *user_data)
+{
+	if (!(*sign)) {
+		*sign = new0(struct sign_info, 1);
+		if (!(*sign))
+			return false;
+	}
+
+	(*sign)->counter = func;
+	(*sign)->user_data = user_data;
+	memcpy((*sign)->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_set_key(&att->local_sign, sign_key, func, user_data);
+}
diff --git a/src/shared/att.h b/src/shared/att.h
index 5256ff9..0cd1a4c 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,6 @@ 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);
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH BlueZ 2/5] shared/att.c: Add server signing key support
  2015-02-23 18:13 [PATCH BlueZ 1/5] shared/att.c: Add client signing key support Luiz Augusto von Dentz
@ 2015-02-23 18:13 ` Luiz Augusto von Dentz
  2015-02-23 18:13 ` [PATCH BlueZ 3/5] shared/gatt-client: Add support for signed write Luiz Augusto von Dentz
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Luiz Augusto von Dentz @ 2015-02-23 18:13 UTC (permalink / raw)
  To: linux-bluetooth

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

This adds support for setting remote signing keys along with a callback
for validating the counter.
---
 src/shared/att.c | 92 +++++++++++++++++++++++++++++++++++++++++---------------
 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 4bfae5f..aa06dc6 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 0cd1a4c..a440aaf 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);
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH BlueZ 3/5] shared/gatt-client: Add support for signed write
  2015-02-23 18:13 [PATCH BlueZ 1/5] shared/att.c: Add client signing key support Luiz Augusto von Dentz
  2015-02-23 18:13 ` [PATCH BlueZ 2/5] shared/att.c: Add server " Luiz Augusto von Dentz
@ 2015-02-23 18:13 ` Luiz Augusto von Dentz
  2015-02-23 18:14 ` [PATCH BlueZ 4/5] tools/btgatt-client: Add signed write support Luiz Augusto von Dentz
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Luiz Augusto von Dentz @ 2015-02-23 18:13 UTC (permalink / raw)
  To: linux-bluetooth

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

---
 src/shared/gatt-client.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/src/shared/gatt-client.c b/src/shared/gatt-client.c
index ac2692f..a966dd0 100644
--- a/src/shared/gatt-client.c
+++ b/src/shared/gatt-client.c
@@ -2129,10 +2129,6 @@ unsigned int bt_gatt_client_write_without_response(
 	if (!client)
 		return 0;
 
-	/* TODO: Support this once bt_att_send supports signed writes. */
-	if (signed_write)
-		return 0;
-
 	req = request_create(client);
 	if (!req)
 		return 0;
@@ -2140,9 +2136,10 @@ unsigned int bt_gatt_client_write_without_response(
 	put_le16(value_handle, pdu);
 	memcpy(pdu + 2, value, length);
 
-	req->att_id = bt_att_send(client->att, BT_ATT_OP_WRITE_CMD,
-							pdu, sizeof(pdu),
-							NULL, NULL, NULL);
+	req->att_id = bt_att_send(client->att,
+				signed_write ?  BT_ATT_OP_SIGNED_WRITE_CMD :
+				BT_ATT_OP_WRITE_CMD, pdu, sizeof(pdu),
+				NULL, NULL, NULL);
 	if (!req->att_id) {
 		request_unref(req);
 		return 0;
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH BlueZ 4/5] tools/btgatt-client: Add signed write support
  2015-02-23 18:13 [PATCH BlueZ 1/5] shared/att.c: Add client signing key support Luiz Augusto von Dentz
  2015-02-23 18:13 ` [PATCH BlueZ 2/5] shared/att.c: Add server " Luiz Augusto von Dentz
  2015-02-23 18:13 ` [PATCH BlueZ 3/5] shared/gatt-client: Add support for signed write Luiz Augusto von Dentz
@ 2015-02-23 18:14 ` Luiz Augusto von Dentz
  2015-02-23 18:14 ` [PATCH BlueZ 5/5] tools/btgatt-server: " Luiz Augusto von Dentz
  2015-02-24 15:31 ` [PATCH BlueZ 1/5] shared/att.c: Add client signing key support Luiz Augusto von Dentz
  4 siblings, 0 replies; 6+ messages in thread
From: Luiz Augusto von Dentz @ 2015-02-23 18:14 UTC (permalink / raw)
  To: linux-bluetooth

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

This adds support for signed write which can be used after setting the
signing key using set-sign-key.
---
 tools/btgatt-client.c | 99 +++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 84 insertions(+), 15 deletions(-)

diff --git a/tools/btgatt-client.c b/tools/btgatt-client.c
index e59d5db..03fe76b 100644
--- a/tools/btgatt-client.c
+++ b/tools/btgatt-client.c
@@ -64,6 +64,7 @@ static bool verbose = false;
 
 struct client {
 	int fd;
+	struct bt_att *att;
 	struct gatt_db *db;
 	struct bt_gatt_client *gatt;
 };
@@ -169,7 +170,6 @@ static void service_removed_cb(struct gatt_db_attribute *attr, void *user_data)
 static struct client *client_create(int fd, uint16_t mtu)
 {
 	struct client *cli;
-	struct bt_att *att;
 
 	cli = new0(struct client, 1);
 	if (!cli) {
@@ -177,24 +177,25 @@ static struct client *client_create(int fd, uint16_t mtu)
 		return NULL;
 	}
 
-	att = bt_att_new(fd);
-	if (!att) {
+	cli->att = bt_att_new(fd);
+	if (!cli->att) {
 		fprintf(stderr, "Failed to initialze ATT transport layer\n");
-		bt_att_unref(att);
+		bt_att_unref(cli->att);
 		free(cli);
 		return NULL;
 	}
 
-	if (!bt_att_set_close_on_unref(att, true)) {
+	if (!bt_att_set_close_on_unref(cli->att, true)) {
 		fprintf(stderr, "Failed to set up ATT transport layer\n");
-		bt_att_unref(att);
+		bt_att_unref(cli->att);
 		free(cli);
 		return NULL;
 	}
 
-	if (!bt_att_register_disconnect(att, att_disconnect_cb, NULL, NULL)) {
+	if (!bt_att_register_disconnect(cli->att, att_disconnect_cb, NULL,
+								NULL)) {
 		fprintf(stderr, "Failed to set ATT disconnect handler\n");
-		bt_att_unref(att);
+		bt_att_unref(cli->att);
 		free(cli);
 		return NULL;
 	}
@@ -203,16 +204,16 @@ static struct client *client_create(int fd, uint16_t mtu)
 	cli->db = gatt_db_new();
 	if (!cli->db) {
 		fprintf(stderr, "Failed to create GATT database\n");
-		bt_att_unref(att);
+		bt_att_unref(cli->att);
 		free(cli);
 		return NULL;
 	}
 
-	cli->gatt = bt_gatt_client_new(cli->db, att, mtu);
+	cli->gatt = bt_gatt_client_new(cli->db, cli->att, mtu);
 	if (!cli->gatt) {
 		fprintf(stderr, "Failed to create GATT client\n");
 		gatt_db_unref(cli->db);
-		bt_att_unref(att);
+		bt_att_unref(cli->att);
 		free(cli);
 		return NULL;
 	}
@@ -221,7 +222,7 @@ static struct client *client_create(int fd, uint16_t mtu)
 								NULL, NULL);
 
 	if (verbose) {
-		bt_att_set_debug(att, att_debug_cb, "att: ", NULL);
+		bt_att_set_debug(cli->att, att_debug_cb, "att: ", NULL);
 		bt_gatt_client_set_debug(cli->gatt, gatt_debug_cb, "gatt: ",
 									NULL);
 	}
@@ -231,7 +232,6 @@ static struct client *client_create(int fd, uint16_t mtu)
 									NULL);
 
 	/* bt_gatt_client already holds a reference */
-	bt_att_unref(att);
 	gatt_db_unref(cli->db);
 
 	return cli;
@@ -240,6 +240,8 @@ static struct client *client_create(int fd, uint16_t mtu)
 static void client_destroy(struct client *cli)
 {
 	bt_gatt_client_unref(cli->gatt);
+	bt_att_unref(cli->att);
+	free(cli);
 }
 
 static void print_uuid(const bt_uuid_t *uuid)
@@ -625,12 +627,14 @@ static void write_value_usage(void)
 	printf("Usage: write-value [options] <value_handle> <value>\n"
 		"Options:\n"
 		"\t-w, --without-response\tWrite without response\n"
+		"\t-s, --signed-write\tSigned write command\n"
 		"e.g.:\n"
 		"\twrite-value 0x0001 00 01 00\n");
 }
 
 static struct option write_value_options[] = {
 	{ "without-response",	0, 0, 'w' },
+	{ "signed-write",	0, 0, 's' },
 	{ }
 };
 
@@ -655,6 +659,7 @@ static void cmd_write_value(struct client *cli, char *cmd_str)
 	int length;
 	uint8_t *value = NULL;
 	bool without_response = false;
+	bool signed_write = false;
 
 	if (!bt_gatt_client_is_ready(cli->gatt)) {
 		printf("GATT client not initialized\n");
@@ -669,12 +674,15 @@ static void cmd_write_value(struct client *cli, char *cmd_str)
 
 	optind = 0;
 	argv[0] = "write-value";
-	while ((opt = getopt_long(argc, argv, "+w", write_value_options,
+	while ((opt = getopt_long(argc, argv, "+ws", write_value_options,
 								NULL)) != -1) {
 		switch (opt) {
 		case 'w':
 			without_response = true;
 			break;
+		case 's':
+			signed_write = true;
+			break;
 		default:
 			write_value_usage();
 			return;
@@ -728,7 +736,7 @@ static void cmd_write_value(struct client *cli, char *cmd_str)
 
 	if (without_response) {
 		if (!bt_gatt_client_write_without_response(cli->gatt, handle,
-							false, value, length)) {
+						signed_write, value, length)) {
 			printf("Failed to initiate write without response "
 								"procedure\n");
 			goto done;
@@ -1043,6 +1051,65 @@ static void cmd_get_sec_level(struct client *cli, char *cmd_str)
 		printf("Security level: %u\n", level);
 }
 
+static bool convert_sign_key(char *optarg, uint8_t key[16])
+{
+	int i;
+
+	if (strlen(optarg) != 32) {
+		printf("sign-key length is invalid\n");
+		return false;
+	}
+
+	for (i = 0; i < 16; i++) {
+		if (sscanf(optarg + (i * 2), "%2hhx", &key[i]) != 1)
+			return false;
+	}
+
+	return true;
+}
+
+static void set_sign_key_usage(void)
+{
+	printf("Usage: set-sign-key [options]\nOptions:\n"
+		"\t -c, --sign-key <csrk>\tCSRK\n"
+		"e.g.:\n"
+		"\tset-sign-key -c D8515948451FEA320DC05A2E88308188\n");
+}
+
+static bool local_counter(uint32_t *sign_cnt, void *user_data)
+{
+	static uint32_t cnt = 0;
+
+	*sign_cnt = cnt++;
+
+	return true;
+}
+
+static void cmd_set_sign_key(struct client *cli, char *cmd_str)
+{
+	char *argv[3];
+	int argc = 0;
+	uint8_t key[16];
+
+	memset(key, 0, 16);
+
+	if (!parse_args(cmd_str, 2, argv, &argc)) {
+		set_sign_key_usage();
+		return;
+	}
+
+	if (argc != 2) {
+		set_sign_key_usage();
+		return;
+	}
+
+	if (!strcmp(argv[0], "-c") || !strcmp(argv[0], "--sign-key")) {
+		if (convert_sign_key(argv[1], key))
+			bt_att_set_local_key(cli->att, key, local_counter, cli);
+	} else
+		set_sign_key_usage();
+}
+
 static void cmd_help(struct client *cli, char *cmd_str);
 
 typedef void (*command_func_t)(struct client *cli, char *cmd_str);
@@ -1071,6 +1138,8 @@ static struct {
 					"Set security level on le connection"},
 	{ "get-sec-level", cmd_get_sec_level,
 					"Get security level on le connection"},
+	{ "set-sign-key", cmd_set_sign_key,
+				"\tSet signing key for signed write command"},
 	{ }
 };
 
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH BlueZ 5/5] tools/btgatt-server: Add signed write support
  2015-02-23 18:13 [PATCH BlueZ 1/5] shared/att.c: Add client signing key support Luiz Augusto von Dentz
                   ` (2 preceding siblings ...)
  2015-02-23 18:14 ` [PATCH BlueZ 4/5] tools/btgatt-client: Add signed write support Luiz Augusto von Dentz
@ 2015-02-23 18:14 ` Luiz Augusto von Dentz
  2015-02-24 15:31 ` [PATCH BlueZ 1/5] shared/att.c: Add client signing key support Luiz Augusto von Dentz
  4 siblings, 0 replies; 6+ messages in thread
From: Luiz Augusto von Dentz @ 2015-02-23 18:14 UTC (permalink / raw)
  To: linux-bluetooth

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

This adds support for signed write which can be used after setting the
signing key using set-sign-key.
---
 tools/btgatt-server.c | 83 +++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 74 insertions(+), 9 deletions(-)

diff --git a/tools/btgatt-server.c b/tools/btgatt-server.c
index 4d7ea6c..09a123c 100644
--- a/tools/btgatt-server.c
+++ b/tools/btgatt-server.c
@@ -77,6 +77,7 @@ static bool verbose = false;
 
 struct server {
 	int fd;
+	struct bt_att *att;
 	struct gatt_db *db;
 	struct bt_gatt_server *gatt;
 
@@ -539,7 +540,6 @@ static void populate_db(struct server *server)
 static struct server *server_create(int fd, uint16_t mtu, bool hr_visible)
 {
 	struct server *server;
-	struct bt_att *att;
 	size_t name_len = strlen(test_device_name);
 
 	server = new0(struct server, 1);
@@ -548,18 +548,19 @@ static struct server *server_create(int fd, uint16_t mtu, bool hr_visible)
 		return NULL;
 	}
 
-	att = bt_att_new(fd);
-	if (!att) {
+	server->att = bt_att_new(fd);
+	if (!server->att) {
 		fprintf(stderr, "Failed to initialze ATT transport layer\n");
 		goto fail;
 	}
 
-	if (!bt_att_set_close_on_unref(att, true)) {
+	if (!bt_att_set_close_on_unref(server->att, true)) {
 		fprintf(stderr, "Failed to set up ATT transport layer\n");
 		goto fail;
 	}
 
-	if (!bt_att_register_disconnect(att, att_disconnect_cb, NULL, NULL)) {
+	if (!bt_att_register_disconnect(server->att, att_disconnect_cb, NULL,
+									NULL)) {
 		fprintf(stderr, "Failed to set ATT disconnect handler\n");
 		goto fail;
 	}
@@ -581,7 +582,7 @@ static struct server *server_create(int fd, uint16_t mtu, bool hr_visible)
 		goto fail;
 	}
 
-	server->gatt = bt_gatt_server_new(server->db, att, mtu);
+	server->gatt = bt_gatt_server_new(server->db, server->att, mtu);
 	if (!server->gatt) {
 		fprintf(stderr, "Failed to create GATT server\n");
 		goto fail;
@@ -590,7 +591,7 @@ static struct server *server_create(int fd, uint16_t mtu, bool hr_visible)
 	server->hr_visible = hr_visible;
 
 	if (verbose) {
-		bt_att_set_debug(att, att_debug_cb, "att: ", NULL);
+		bt_att_set_debug(server->att, att_debug_cb, "att: ", NULL);
 		bt_gatt_server_set_debug(server->gatt, gatt_debug_cb,
 							"server: ", NULL);
 	}
@@ -599,7 +600,6 @@ static struct server *server_create(int fd, uint16_t mtu, bool hr_visible)
 	srand(time(NULL));
 
 	/* bt_gatt_server already holds a reference */
-	bt_att_unref(att);
 	populate_db(server);
 
 	return server;
@@ -607,7 +607,7 @@ static struct server *server_create(int fd, uint16_t mtu, bool hr_visible)
 fail:
 	gatt_db_unref(server->db);
 	free(server->device_name);
-	bt_att_unref(att);
+	bt_att_unref(server->att);
 	free(server);
 
 	return NULL;
@@ -972,6 +972,69 @@ static void cmd_services(struct server *server, char *cmd_str)
 	gatt_db_foreach_service(server->db, NULL, print_service, server);
 }
 
+static bool convert_sign_key(char *optarg, uint8_t key[16])
+{
+	int i;
+
+	if (strlen(optarg) != 32) {
+		printf("sign-key length is invalid\n");
+		return false;
+	}
+
+	for (i = 0; i < 16; i++) {
+		if (sscanf(optarg + (i * 2), "%2hhx", &key[i]) != 1)
+			return false;
+	}
+
+	return true;
+}
+
+static void set_sign_key_usage(void)
+{
+	printf("Usage: set-sign-key [options]\nOptions:\n"
+		"\t -c, --sign-key <remote csrk>\tRemote CSRK\n"
+		"e.g.:\n"
+		"\tset-sign-key -c D8515948451FEA320DC05A2E88308188\n");
+}
+
+static bool remote_counter(uint32_t *sign_cnt, void *user_data)
+{
+	static uint32_t cnt = 0;
+
+	if (*sign_cnt < cnt)
+		return false;
+
+	cnt++;
+
+	return true;
+}
+
+static void cmd_set_sign_key(struct server *server, char *cmd_str)
+{
+	char *argv[3];
+	int argc = 0;
+	uint8_t key[16];
+
+	memset(key, 0, 16);
+
+	if (!parse_args(cmd_str, 2, argv, &argc)) {
+		set_sign_key_usage();
+		return;
+	}
+
+	if (argc != 2) {
+		set_sign_key_usage();
+		return;
+	}
+
+	if (!strcmp(argv[0], "-c") || !strcmp(argv[0], "--sign-key")) {
+		if (convert_sign_key(argv[1], key))
+			bt_att_set_remote_key(server->att, key, remote_counter,
+									server);
+	} else
+		set_sign_key_usage();
+}
+
 static void cmd_help(struct server *server, char *cmd_str);
 
 typedef void (*command_func_t)(struct server *server, char *cmd_str);
@@ -985,6 +1048,8 @@ static struct {
 	{ "notify", cmd_notify, "\tSend handle-value notification" },
 	{ "heart-rate", cmd_heart_rate, "\tHide/Unhide Heart Rate Service" },
 	{ "services", cmd_services, "\tEnumerate all services" },
+	{ "set-sign-key", cmd_set_sign_key,
+			"\tSet remote signing key for signed write command"},
 	{ }
 };
 
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH BlueZ 1/5] shared/att.c: Add client signing key support
  2015-02-23 18:13 [PATCH BlueZ 1/5] shared/att.c: Add client signing key support Luiz Augusto von Dentz
                   ` (3 preceding siblings ...)
  2015-02-23 18:14 ` [PATCH BlueZ 5/5] tools/btgatt-server: " Luiz Augusto von Dentz
@ 2015-02-24 15:31 ` Luiz Augusto von Dentz
  4 siblings, 0 replies; 6+ messages in thread
From: Luiz Augusto von Dentz @ 2015-02-24 15:31 UTC (permalink / raw)
  To: linux-bluetooth

Hi,

On Mon, Feb 23, 2015 at 8:13 PM, Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> This adds support for setting local signing keys along with a callback
> for loading the counter.
> ---
>  src/shared/att.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++------
>  src/shared/att.h |  4 +++
>  2 files changed, 82 insertions(+), 9 deletions(-)
>
> diff --git a/src/shared/att.c b/src/shared/att.c
> index 152f49c..4bfae5f 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,16 @@ 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_info *local_sign;
> +};
> +
> +struct sign_info {
> +       uint8_t key[16];
> +       bt_att_counter_func_t counter;
> +       void *user_data;
>  };
>
>  enum att_op_type {
> @@ -262,15 +276,20 @@ static bool match_disconn_id(const void *a, const void *b)
>         return disconn->id == id;
>  }
>
> -static bool encode_pdu(struct att_send_op *op, const void *pdu,
> -                                               uint16_t length, uint16_t mtu)
> +static bool encode_pdu(struct bt_att *att, struct att_send_op *op,
> +                                       const void *pdu, uint16_t length)
>  {
>         uint16_t pdu_len = 1;
> +       struct sign_info *sign;
> +       uint32_t sign_cnt;
> +
> +       if (op->opcode & ATT_OP_SIGNED_MASK)
> +               pdu_len += BT_ATT_SIGNATURE_LEN;
>
>         if (length && pdu)
>                 pdu_len += length;
>
> -       if (pdu_len > mtu)
> +       if (pdu_len > att->mtu)
>                 return false;
>
>         op->len = pdu_len;
> @@ -282,11 +301,29 @@ 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;
> +
> +       sign = att->local_sign;
> +       if (!sign)
> +               goto fail;
> +
> +       if (!sign->counter(&sign_cnt, sign->user_data))
> +               goto fail;
> +
> +       if ((bt_crypto_sign_att(att->crypto, sign->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(struct bt_att *att,
> +                                               uint8_t opcode,
> +                                               const void *pdu,
> +                                               uint16_t length,
>                                                 bt_att_response_func_t callback,
>                                                 void *user_data,
>                                                 bt_att_destroy_func_t destroy)
> @@ -324,7 +361,7 @@ static struct att_send_op *create_att_send_op(uint8_t opcode, const void *pdu,
>         op->destroy = destroy;
>         op->user_data = user_data;
>
> -       if (!encode_pdu(op, pdu, length, mtu)) {
> +       if (!encode_pdu(att, op, pdu, length)) {
>                 free(op);
>                 return NULL;
>         }
> @@ -810,6 +847,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);
> @@ -823,6 +861,8 @@ static void bt_att_free(struct bt_att *att)
>         if (att->debug_destroy)
>                 att->debug_destroy(att->debug_data);
>
> +       free(att->local_sign);
> +
>         free(att->buf);
>
>         free(att);
> @@ -850,6 +890,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;
> @@ -1047,8 +1091,8 @@ 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,
> -                                                       user_data, destroy);
> +       op = create_att_send_op(att, opcode, pdu, length, callback, user_data,
> +                                                               destroy);
>         if (!op)
>                 return 0;
>
> @@ -1307,3 +1351,28 @@ bool bt_att_set_sec_level(struct bt_att *att, int level)
>
>         return true;
>  }
> +
> +static bool sign_set_key(struct sign_info **sign, uint8_t key[16],
> +                               bt_att_counter_func_t func, void *user_data)
> +{
> +       if (!(*sign)) {
> +               *sign = new0(struct sign_info, 1);
> +               if (!(*sign))
> +                       return false;
> +       }
> +
> +       (*sign)->counter = func;
> +       (*sign)->user_data = user_data;
> +       memcpy((*sign)->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_set_key(&att->local_sign, sign_key, func, user_data);
> +}
> diff --git a/src/shared/att.h b/src/shared/att.h
> index 5256ff9..0cd1a4c 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,6 @@ 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);
> --
> 2.1.0

Applied.


-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2015-02-24 15:31 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-23 18:13 [PATCH BlueZ 1/5] shared/att.c: Add client signing key support Luiz Augusto von Dentz
2015-02-23 18:13 ` [PATCH BlueZ 2/5] shared/att.c: Add server " Luiz Augusto von Dentz
2015-02-23 18:13 ` [PATCH BlueZ 3/5] shared/gatt-client: Add support for signed write Luiz Augusto von Dentz
2015-02-23 18:14 ` [PATCH BlueZ 4/5] tools/btgatt-client: Add signed write support Luiz Augusto von Dentz
2015-02-23 18:14 ` [PATCH BlueZ 5/5] tools/btgatt-server: " Luiz Augusto von Dentz
2015-02-24 15:31 ` [PATCH BlueZ 1/5] shared/att.c: Add client signing key support Luiz Augusto von Dentz

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.