* [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