2014-05-22 19:06:14

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v3 00/12] android/gatt: Add support for write signature command

This patch set add support for write signature command for android part.
* handling CSRK and signCounter in android/bluetooth - storage
* exchanging CSRK and signCounter between android/bluetooth and gatt
* handling incoming and outgoing write signature command.

Some common part has been updated (attrib, crypto)

In next patches error handling will be added.

Note: If you run on Nexus devices there is need to update kernel which
needs to support CRYPTO_CSRK, CRYPTO_USER_API, CRYPTO_USER_API_HASH,
CRYPTO_USER_API_SKCIPHER. All the information available on
https://code.google.com/p/aosp-bluez/

v2:
* handled Johan comments
v3:
* Changed crypto API as suggested by Johan


Lukasz Rymanowski (12):
shared/crypto: Extend bt_crypto_sign_att with sign counter
attrib: Add helpers to enc and dec signed write command
attrib/gatt: Add wrapper to send signed write command
android/bluetooth: Expose API to get CSRK for device
android/bluetooth: Expose API to update sign counter
android/bluetooth: Add support to read CSRK from the kernel
android/bluetooth: Store CSRK
android/bluetooth: Read CSRK from the storage on startup
android/bluetooth: Store sign counter needed for aes-cmac sign
android/gatt: Add crypto needed for sign write
android/gatt: Add support for signed write command
android/gatt: Add handling signed write from remote device

android/Android.mk | 1 +
android/Makefile.am | 1 +
android/bluetooth.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++
android/bluetooth.h | 10 +++
android/gatt.c | 89 ++++++++++++++++++++++++-
attrib/att.c | 55 ++++++++++++++++
attrib/att.h | 11 ++++
attrib/gatt.c | 16 +++++
attrib/gatt.h | 5 ++
src/shared/crypto.c | 19 +++++-
src/shared/crypto.h | 1 +
unit/test-crypto.c | 10 +--
12 files changed, 395 insertions(+), 8 deletions(-)

--
1.8.4



2014-05-26 08:41:22

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH v3 00/12] android/gatt: Add support for write signature command

Hi Ɓukasz,

On Thursday 22 of May 2014 21:06:14 Lukasz Rymanowski wrote:
> This patch set add support for write signature command for android part.
> * handling CSRK and signCounter in android/bluetooth - storage
> * exchanging CSRK and signCounter between android/bluetooth and gatt
> * handling incoming and outgoing write signature command.
>
> Some common part has been updated (attrib, crypto)
>
> In next patches error handling will be added.
>
> Note: If you run on Nexus devices there is need to update kernel which
> needs to support CRYPTO_CSRK, CRYPTO_USER_API, CRYPTO_USER_API_HASH,
> CRYPTO_USER_API_SKCIPHER. All the information available on
> https://code.google.com/p/aosp-bluez/
>
> v2:
> * handled Johan comments
> v3:
> * Changed crypto API as suggested by Johan
>
>
> Lukasz Rymanowski (12):
> shared/crypto: Extend bt_crypto_sign_att with sign counter
> attrib: Add helpers to enc and dec signed write command
> attrib/gatt: Add wrapper to send signed write command
> android/bluetooth: Expose API to get CSRK for device
> android/bluetooth: Expose API to update sign counter
> android/bluetooth: Add support to read CSRK from the kernel
> android/bluetooth: Store CSRK
> android/bluetooth: Read CSRK from the storage on startup
> android/bluetooth: Store sign counter needed for aes-cmac sign
> android/gatt: Add crypto needed for sign write
> android/gatt: Add support for signed write command
> android/gatt: Add handling signed write from remote device
>
> android/Android.mk | 1 +
> android/Makefile.am | 1 +
> android/bluetooth.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> android/bluetooth.h | 10 +++
> android/gatt.c | 89 ++++++++++++++++++++++++-
> attrib/att.c | 55 ++++++++++++++++
> attrib/att.h | 11 ++++
> attrib/gatt.c | 16 +++++
> attrib/gatt.h | 5 ++
> src/shared/crypto.c | 19 +++++-
> src/shared/crypto.h | 1 +
> unit/test-crypto.c | 10 +--
> 12 files changed, 395 insertions(+), 8 deletions(-)
>

All patches are now applied, thanks a lot.


--
Best regards,
Szymon Janc

2014-05-22 19:06:26

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v3 12/12] android/gatt: Add handling signed write from remote device

---
android/gatt.c | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)

diff --git a/android/gatt.c b/android/gatt.c
index 33e1db9..4c5409a 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -4763,6 +4763,44 @@ static void write_cmd_request(const uint8_t *cmd, uint16_t cmd_len,
gatt_db_write(gatt_db, handle, 0, value, vlen, cmd[0], &dev->bdaddr);
}

+static void write_signed_cmd_request(const uint8_t *cmd, uint16_t cmd_len,
+ struct gatt_device *dev)
+{
+ uint8_t value[ATT_DEFAULT_LE_MTU];
+ uint8_t s[ATT_SIGNATURE_LEN];
+ uint16_t handle;
+ uint16_t len;
+ size_t vlen;
+ uint8_t csrk[16];
+ uint32_t sign_cnt;
+
+ if (!bt_get_csrk(&dev->bdaddr, REMOTE_CSRK, csrk, &sign_cnt)) {
+ error("gatt: No valid csrk from remote device");
+ return;
+ }
+
+ len = dec_signed_write_cmd(cmd, cmd_len, &handle, value, &vlen, s);
+ if (len) {
+ uint8_t t[ATT_SIGNATURE_LEN];
+
+ /* Generate signature and verify it */
+ if (!bt_crypto_sign_att(crypto, csrk, value, vlen, sign_cnt,
+ t)) {
+ error("gatt: Error when generating att signature");
+ return;
+ }
+
+ if (memcmp(t, s, ATT_SIGNATURE_LEN)) {
+ error("gatt: signature does not match");
+ return;
+ }
+ /* Signature OK, proceed with write */
+ bt_update_sign_counter(&dev->bdaddr, REMOTE_CSRK);
+ gatt_db_write(gatt_db, handle, 0, value, vlen, cmd[0],
+ &dev->bdaddr);
+ }
+}
+
static uint8_t write_req_request(const uint8_t *cmd, uint16_t cmd_len,
struct gatt_device *dev)
{
@@ -4876,6 +4914,10 @@ static void att_handler(const uint8_t *ipdu, uint16_t len, gpointer user_data)
write_cmd_request(ipdu, len, dev);
/* No response on write cmd */
return;
+ case ATT_OP_SIGNED_WRITE_CMD:
+ write_signed_cmd_request(ipdu, len, dev);
+ /* No response on write signed cmd */
+ return;
case ATT_OP_PREP_WRITE_REQ:
status = write_prep_request(ipdu, len, dev);
if (!status)
--
1.8.4


2014-05-22 19:06:25

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v3 11/12] android/gatt: Add support for signed write command

---
android/gatt.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)

diff --git a/android/gatt.c b/android/gatt.c
index 9e65fb5..33e1db9 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -2610,6 +2610,38 @@ static void write_char_cb(guint8 status, const guint8 *pdu, guint16 len,
free(data);
}

+static bool signed_write_cmd(struct gatt_device *dev, uint16_t handle,
+ const uint8_t *value, uint16_t vlen)
+{
+ uint8_t s[ATT_SIGNATURE_LEN];
+ uint8_t csrk[16];
+ uint32_t sign_cnt;
+
+ memset(csrk, 0, 16);
+
+ if (!bt_get_csrk(&dev->bdaddr, LOCAL_CSRK, csrk, &sign_cnt)) {
+ error("gatt: Could not get csrk key");
+ return false;
+ }
+
+ memset(s, 0, ATT_SIGNATURE_LEN);
+
+ if (!bt_crypto_sign_att(crypto, csrk, value, vlen, sign_cnt, s)) {
+ error("gatt: Could not sign att data");
+ return false;
+ }
+
+ if (!gatt_signed_write_cmd(dev->attrib, handle, value, vlen, s, NULL,
+ NULL)) {
+ error("gatt: Could write signed cmd");
+ return false;
+ }
+
+ bt_update_sign_counter(&dev->bdaddr, LOCAL_CSRK);
+
+ return true;
+}
+
static void handle_client_write_characteristic(const void *buf, uint16_t len)
{
const struct hal_cmd_gatt_client_write_characteristic *cmd = buf;
@@ -2674,6 +2706,10 @@ static void handle_client_write_characteristic(const void *buf, uint16_t len)
cmd->value, cmd->len,
write_char_cb, cb_data);
break;
+ case GATT_WRITE_TYPE_SIGNED:
+ res = signed_write_cmd(conn->device, ch->ch.value_handle,
+ cmd->value, cmd->len);
+ break;
default:
error("gatt: Write type %d unsupported", cmd->write_type);
status = HAL_STATUS_UNSUPPORTED;
--
1.8.4


2014-05-22 19:06:24

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v3 10/12] android/gatt: Add crypto needed for sign write

---
android/Android.mk | 1 +
android/Makefile.am | 1 +
android/gatt.c | 11 ++++++++++-
3 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/android/Android.mk b/android/Android.mk
index 4235a7c..4548ed7 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -53,6 +53,7 @@ LOCAL_SRC_FILES := \
bluez/src/shared/hfp.c \
bluez/src/shared/gatt-db.c \
bluez/src/shared/io-glib.c \
+ bluez/src/shared/crypto.c \
bluez/src/sdpd-database.c \
bluez/src/sdpd-service.c \
bluez/src/sdpd-request.c \
diff --git a/android/Makefile.am b/android/Makefile.am
index e663790..1bde83d 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -31,6 +31,7 @@ android_bluetoothd_SOURCES = android/main.c \
src/shared/ringbuf.h src/shared/ringbuf.c \
src/shared/hfp.h src/shared/hfp.c \
src/shared/gatt-db.h src/shared/gatt-db.c \
+ src/shared/crypto.h src/shared/crypto.c \
android/bluetooth.h android/bluetooth.c \
android/hidhost.h android/hidhost.c \
android/ipc-common.h \
diff --git a/android/gatt.c b/android/gatt.c
index 532a416..9e65fb5 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -44,6 +44,7 @@
#include "src/shared/util.h"
#include "src/shared/queue.h"
#include "src/shared/gatt-db.h"
+#include "src/shared/crypto.h"
#include "attrib/gattrib.h"
#include "attrib/att.h"
#include "attrib/gatt.h"
@@ -180,6 +181,8 @@ static struct gatt_db *gatt_db = NULL;

static GIOChannel *listening_io = NULL;

+static struct bt_crypto *crypto = NULL;
+
static void bt_le_discovery_stop_cb(void);

static bool is_bluetooth_uuid(const uint8_t *uuid)
@@ -5241,9 +5244,10 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
app_connections = queue_new();
listen_apps = queue_new();
gatt_db = gatt_db_new();
+ crypto = bt_crypto_new();

if (!gatt_devices || !gatt_apps || !listen_apps ||
- !app_connections || !gatt_db) {
+ !app_connections || !gatt_db || !crypto) {
error("gatt: Failed to allocate memory for queues");

queue_destroy(gatt_apps, NULL);
@@ -5264,6 +5268,8 @@ bool bt_gatt_register(struct ipc *ipc, const bdaddr_t *addr)
g_io_channel_unref(listening_io);
listening_io = NULL;

+ bt_crypto_unref(crypto);
+
return false;
}

@@ -5305,4 +5311,7 @@ void bt_gatt_unregister(void)

g_io_channel_unref(listening_io);
listening_io = NULL;
+
+ bt_crypto_unref(crypto);
+ crypto = NULL;
}
--
1.8.4


2014-05-22 19:06:23

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v3 09/12] android/bluetooth: Store sign counter needed for aes-cmac sign

If CSRK is valid between sessions we should remember sign counter.
Therefor store it.
---
android/bluetooth.c | 41 +++++++++++++++++++++++++++++++++++++++--
1 file changed, 39 insertions(+), 2 deletions(-)

diff --git a/android/bluetooth.c b/android/bluetooth.c
index f8a7b3d..445aceb 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -1878,8 +1878,6 @@ static void new_csrk_callback(uint16_t index, uint16_t length,

if (ev->store_hint)
store_csrk(dev);
-
- /*TODO: Store sign counter */
}

static void register_mgmt_handlers(void)
@@ -2353,6 +2351,9 @@ static struct device *create_device_from_info(GKeyFile *key_file,
sscanf(str + (i * 2), "%02hhX", &dev->local_csrk[i]);

g_free(str);
+
+ dev->local_sign_cnt = g_key_file_get_integer(key_file, peer,
+ "LocalCSRKSignCounter", NULL);
}

str = g_key_file_get_string(key_file, peer, "RemoteCSRK", NULL);
@@ -2364,6 +2365,9 @@ static struct device *create_device_from_info(GKeyFile *key_file,
sscanf(str + (i * 2), "%02hhX", &dev->remote_csrk[i]);

g_free(str);
+
+ dev->remote_sign_cnt = g_key_file_get_integer(key_file, peer,
+ "RemoteCSRKSignCounter", NULL);
}

str = g_key_file_get_string(key_file, peer, "Name", NULL);
@@ -3334,6 +3338,37 @@ bool bt_get_csrk(const bdaddr_t *addr, enum bt_csrk_type type, uint8_t key[16],
return true;
}

+static void store_sign_counter(struct device *dev, enum bt_csrk_type type)
+{
+ const char *sign_cnt_s;
+ uint32_t sign_cnt;
+ GKeyFile *key_file;
+ bool local = (type == LOCAL_CSRK);
+
+ gsize length = 0;
+ char addr[18];
+ char *data;
+
+ key_file = g_key_file_new();
+ if (!g_key_file_load_from_file(key_file, DEVICES_FILE, 0, NULL)) {
+ g_key_file_free(key_file);
+ return;
+ }
+
+ ba2str(&dev->bdaddr, addr);
+
+ sign_cnt_s = local ? "LocalCSRKSignCounter" : "RemoteCSRKSignCounter";
+ sign_cnt = local ? dev->local_sign_cnt : dev->remote_sign_cnt;
+
+ g_key_file_set_integer(key_file, addr, sign_cnt_s, sign_cnt);
+
+ data = g_key_file_to_data(key_file, &length, NULL);
+ g_file_set_contents(DEVICES_FILE, data, length, NULL);
+ g_free(data);
+
+ g_key_file_free(key_file);
+}
+
void bt_update_sign_counter(const bdaddr_t *addr, enum bt_csrk_type type)
{
struct device *dev;
@@ -3346,6 +3381,8 @@ void bt_update_sign_counter(const bdaddr_t *addr, enum bt_csrk_type type)
dev->local_sign_cnt++;
else
dev->remote_sign_cnt++;
+
+ store_sign_counter(dev, type);
}

static uint8_t set_adapter_scan_mode(const void *buf, uint16_t len)
--
1.8.4


2014-05-22 19:06:22

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v3 08/12] android/bluetooth: Read CSRK from the storage on startup

---
android/bluetooth.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)

diff --git a/android/bluetooth.c b/android/bluetooth.c
index b910b01..f8a7b3d 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -2344,6 +2344,28 @@ static struct device *create_device_from_info(GKeyFile *key_file,
dev->le_bonded = true;
}

+ str = g_key_file_get_string(key_file, peer, "LocalCSRK", NULL);
+ if (str) {
+ int i;
+
+ dev->valid_local_csrk = true;
+ for (i = 0; i < 16; i++)
+ sscanf(str + (i * 2), "%02hhX", &dev->local_csrk[i]);
+
+ g_free(str);
+ }
+
+ str = g_key_file_get_string(key_file, peer, "RemoteCSRK", NULL);
+ if (str) {
+ int i;
+
+ dev->valid_remote_csrk = true;
+ for (i = 0; i < 16; i++)
+ sscanf(str + (i * 2), "%02hhX", &dev->remote_csrk[i]);
+
+ g_free(str);
+ }
+
str = g_key_file_get_string(key_file, peer, "Name", NULL);
if (str) {
g_free(dev->name);
--
1.8.4


2014-05-22 19:06:21

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v3 07/12] android/bluetooth: Store CSRK

CSRK is generated while paring and should be used for sign att packets
when LE devices uses write signed command.
---
android/bluetooth.c | 46 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 45 insertions(+), 1 deletion(-)

diff --git a/android/bluetooth.c b/android/bluetooth.c
index 54eb65d..b910b01 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -1805,6 +1805,47 @@ static void new_long_term_key_event(uint16_t index, uint16_t length,
/* TODO browse services here? */
}

+static void store_csrk(struct device *dev)
+{
+ GKeyFile *key_file;
+ char key_str[33];
+ char addr[18];
+ int i;
+ gsize length = 0;
+ char *data;
+
+ ba2str(&dev->bdaddr, addr);
+
+ key_file = g_key_file_new();
+ if (!g_key_file_load_from_file(key_file, DEVICES_FILE, 0, NULL)) {
+ g_key_file_free(key_file);
+ return;
+ }
+
+ if (dev->valid_local_csrk) {
+
+ for (i = 0; i < 16; i++)
+ sprintf(key_str + (i * 2), "%2.2X",
+ dev->local_csrk[i]);
+
+ g_key_file_set_string(key_file, addr, "LocalCSRK", key_str);
+ }
+
+ if (dev->valid_remote_csrk) {
+ for (i = 0; i < 16; i++)
+ sprintf(key_str + (i * 2), "%2.2X",
+ dev->remote_csrk[i]);
+
+ g_key_file_set_string(key_file, addr, "RemoteCSRK", key_str);
+ }
+
+ data = g_key_file_to_data(key_file, &length, NULL);
+ g_file_set_contents(DEVICES_FILE, data, length, NULL);
+ g_free(data);
+
+ g_key_file_free(key_file);
+}
+
static void new_csrk_callback(uint16_t index, uint16_t length,
const void *param, void *user_data)
{
@@ -1835,7 +1876,10 @@ static void new_csrk_callback(uint16_t index, uint16_t length,
return;
}

- /*TODO: Store it. Remember about Sign Counter*/
+ if (ev->store_hint)
+ store_csrk(dev);
+
+ /*TODO: Store sign counter */
}

static void register_mgmt_handlers(void)
--
1.8.4


2014-05-22 19:06:20

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v3 06/12] android/bluetooth: Add support to read CSRK from the kernel

---
android/bluetooth.c | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)

diff --git a/android/bluetooth.c b/android/bluetooth.c
index c972cd5..54eb65d 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -1805,6 +1805,39 @@ static void new_long_term_key_event(uint16_t index, uint16_t length,
/* TODO browse services here? */
}

+static void new_csrk_callback(uint16_t index, uint16_t length,
+ const void *param, void *user_data)
+{
+ const struct mgmt_ev_new_csrk *ev = param;
+ struct device *dev;
+ char dst[18];
+
+ if (length < sizeof(*ev)) {
+ error("Too small csrk event (%u bytes)", length);
+ return;
+ }
+
+ ba2str(&ev->key.addr.bdaddr, dst);
+ dev = find_device(&ev->key.addr.bdaddr);
+ if (!dev)
+ return;
+
+ if (ev->key.master == 0x01) {
+ memcpy(dev->remote_csrk, ev->key.val, 16);
+ dev->remote_sign_cnt = 0;
+ dev->valid_remote_csrk = true;
+ } else if (ev->key.master == 0x00) {
+ memcpy(dev->local_csrk, ev->key.val, 16);
+ dev->local_sign_cnt = 0;
+ dev->valid_local_csrk = true;
+ } else {
+ error("Unknown key type 02%02x", ev->key.master);
+ return;
+ }
+
+ /*TODO: Store it. Remember about Sign Counter*/
+}
+
static void register_mgmt_handlers(void)
{
mgmt_register(mgmt_if, MGMT_EV_NEW_SETTINGS, adapter.index,
@@ -1854,6 +1887,10 @@ static void register_mgmt_handlers(void)

mgmt_register(mgmt_if, MGMT_EV_NEW_LONG_TERM_KEY, adapter.index,
new_long_term_key_event, NULL, NULL);
+
+ mgmt_register(mgmt_if, MGMT_EV_NEW_CSRK, adapter.index,
+ new_csrk_callback, NULL, NULL);
+
}

static void load_link_keys_complete(uint8_t status, uint16_t length,
--
1.8.4


2014-05-22 19:06:19

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v3 05/12] android/bluetooth: Expose API to update sign counter

This is needed so GATT can notify GAP that write sign has been done and
sign counter shall be increased as per spec.
---
android/bluetooth.c | 14 ++++++++++++++
android/bluetooth.h | 2 ++
2 files changed, 16 insertions(+)

diff --git a/android/bluetooth.c b/android/bluetooth.c
index 644a556..c972cd5 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -3231,6 +3231,20 @@ bool bt_get_csrk(const bdaddr_t *addr, enum bt_csrk_type type, uint8_t key[16],
return true;
}

+void bt_update_sign_counter(const bdaddr_t *addr, enum bt_csrk_type type)
+{
+ struct device *dev;
+
+ dev = find_device(addr);
+ if (!dev)
+ return;
+
+ if (type == LOCAL_CSRK)
+ dev->local_sign_cnt++;
+ else
+ dev->remote_sign_cnt++;
+}
+
static uint8_t set_adapter_scan_mode(const void *buf, uint16_t len)
{
const uint8_t *mode = buf;
diff --git a/android/bluetooth.h b/android/bluetooth.h
index 9c88f62..1c14377 100644
--- a/android/bluetooth.h
+++ b/android/bluetooth.h
@@ -64,3 +64,5 @@ bool bt_read_device_rssi(const bdaddr_t *addr, bt_read_device_rssi_done cb,

bool bt_get_csrk(const bdaddr_t *addr, enum bt_csrk_type type,
uint8_t key[16], uint32_t *sign_cnt);
+
+void bt_update_sign_counter(const bdaddr_t *addr, enum bt_csrk_type type);
--
1.8.4


2014-05-22 19:06:17

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v3 03/12] attrib/gatt: Add wrapper to send signed write command

---
attrib/gatt.c | 16 ++++++++++++++++
attrib/gatt.h | 5 +++++
2 files changed, 21 insertions(+)

diff --git a/attrib/gatt.c b/attrib/gatt.c
index 73eaf7a..ce08003 100644
--- a/attrib/gatt.c
+++ b/attrib/gatt.c
@@ -1065,6 +1065,22 @@ guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, const uint8_t *value,
return g_attrib_send(attrib, 0, buf, plen, NULL, user_data, notify);
}

+guint gatt_signed_write_cmd(GAttrib *attrib, uint16_t handle,
+ const uint8_t *value, int vlen,
+ const uint8_t signature[12],
+ GDestroyNotify notify,
+ gpointer user_data)
+{
+ uint8_t *buf;
+ size_t buflen;
+ guint16 plen;
+
+ buf = g_attrib_get_buffer(attrib, &buflen);
+ plen = enc_signed_write_cmd(handle, value, vlen, signature, buf,
+ buflen);
+ return g_attrib_send(attrib, 0, buf, plen, NULL, user_data, notify);
+}
+
static sdp_data_t *proto_seq_find(sdp_list_t *proto_list)
{
sdp_list_t *list;
diff --git a/attrib/gatt.h b/attrib/gatt.h
index 7d055f0..2d869e3 100644
--- a/attrib/gatt.h
+++ b/attrib/gatt.h
@@ -105,6 +105,11 @@ guint gatt_execute_write(GAttrib *attrib, uint8_t flags,
guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, const uint8_t *value,
int vlen, GDestroyNotify notify, gpointer user_data);

+guint gatt_signed_write_cmd(GAttrib *attrib, uint16_t handle,
+ const uint8_t *value, int vlen,
+ const uint8_t signature[12],
+ GDestroyNotify notify,
+ gpointer user_data);
guint gatt_read_char_by_uuid(GAttrib *attrib, uint16_t start, uint16_t end,
bt_uuid_t *uuid, GAttribResultFunc func,
gpointer user_data);
--
1.8.4


2014-05-22 19:06:18

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v3 04/12] android/bluetooth: Expose API to get CSRK for device

GATT will take CSRK key and sign counter each time it needs it to sign
att package or to verify att package
---
android/bluetooth.c | 31 +++++++++++++++++++++++++++++++
android/bluetooth.h | 8 ++++++++
2 files changed, 39 insertions(+)

diff --git a/android/bluetooth.c b/android/bluetooth.c
index 93b9cd7..644a556 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -116,6 +116,14 @@ struct device {

bool found; /* if device is found in current discovery session */
unsigned int confirm_id; /* mgtm command id if command pending */
+
+ bool valid_remote_csrk;
+ uint8_t remote_csrk[16];
+ uint32_t remote_sign_cnt;
+
+ bool valid_local_csrk;
+ uint8_t local_csrk[16];
+ uint32_t local_sign_cnt;
};

struct browse_req {
@@ -3200,6 +3208,29 @@ bool bt_read_device_rssi(const bdaddr_t *addr, bt_read_device_rssi_done cb,
return true;
}

+bool bt_get_csrk(const bdaddr_t *addr, enum bt_csrk_type type, uint8_t key[16],
+ uint32_t *sign_cnt)
+{
+ struct device *dev;
+ bool local = (type == LOCAL_CSRK);
+
+ dev = find_device(addr);
+ if (!dev)
+ return false;
+
+ if (local && dev->valid_local_csrk) {
+ memcpy(key, dev->local_csrk, 16);
+ *sign_cnt = dev->local_sign_cnt;
+ } else if (!local && dev->valid_remote_csrk) {
+ memcpy(key, dev->remote_csrk, 16);
+ *sign_cnt = dev->remote_sign_cnt;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
static uint8_t set_adapter_scan_mode(const void *buf, uint16_t len)
{
const uint8_t *mode = buf;
diff --git a/android/bluetooth.h b/android/bluetooth.h
index a0b81a6..9c88f62 100644
--- a/android/bluetooth.h
+++ b/android/bluetooth.h
@@ -21,6 +21,11 @@
*
*/

+enum bt_csrk_type {
+ LOCAL_CSRK,
+ REMOTE_CSRK,
+};
+
typedef void (*bt_bluetooth_ready)(int err, const bdaddr_t *addr);
bool bt_bluetooth_start(int index, bool mgmt_dbg, bt_bluetooth_ready cb);

@@ -56,3 +61,6 @@ typedef void (*bt_read_device_rssi_done)(uint8_t status, const bdaddr_t *addr,
int8_t rssi, void *user_data);
bool bt_read_device_rssi(const bdaddr_t *addr, bt_read_device_rssi_done cb,
void *user_data);
+
+bool bt_get_csrk(const bdaddr_t *addr, enum bt_csrk_type type,
+ uint8_t key[16], uint32_t *sign_cnt);
--
1.8.4


2014-05-22 19:06:16

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v3 02/12] attrib: Add helpers to enc and dec signed write command

---
attrib/att.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
attrib/att.h | 11 +++++++++++
2 files changed, 66 insertions(+)

diff --git a/attrib/att.c b/attrib/att.c
index 8e9c06d..e7d5682 100644
--- a/attrib/att.c
+++ b/attrib/att.c
@@ -561,6 +561,61 @@ uint16_t dec_write_cmd(const uint8_t *pdu, size_t len, uint16_t *handle,
return len;
}

+uint16_t enc_signed_write_cmd(uint16_t handle,
+ const uint8_t *value, size_t vlen,
+ const uint8_t signature[12],
+ uint8_t *pdu, size_t len)
+{
+ const uint16_t hdr_len = sizeof(pdu[0]) + sizeof(handle);
+ const uint16_t min_len = hdr_len + ATT_SIGNATURE_LEN;
+
+ if (pdu == NULL)
+ return 0;
+
+ if (vlen > len - min_len)
+ vlen = len - min_len;
+
+ pdu[0] = ATT_OP_SIGNED_WRITE_CMD;
+ put_le16(handle, &pdu[1]);
+
+ if (vlen > 0)
+ memcpy(&pdu[hdr_len], value, vlen);
+
+ memcpy(&pdu[hdr_len + vlen], signature, ATT_SIGNATURE_LEN);
+
+ return min_len + vlen;
+}
+
+uint16_t dec_signed_write_cmd(const uint8_t *pdu, size_t len,
+ uint16_t *handle,
+ uint8_t *value, size_t *vlen,
+ uint8_t signature[12])
+{
+ const uint16_t hdr_len = sizeof(pdu[0]) + sizeof(*handle);
+ const uint16_t min_len = hdr_len + ATT_SIGNATURE_LEN;
+
+
+ if (pdu == NULL)
+ return 0;
+
+ if (value == NULL || vlen == NULL || handle == NULL)
+ return 0;
+
+ if (len < min_len)
+ return 0;
+
+ if (pdu[0] != ATT_OP_SIGNED_WRITE_CMD)
+ return 0;
+
+ *vlen = len - min_len;
+ *handle = get_le16(&pdu[1]);
+ memcpy(value, pdu + hdr_len, *vlen);
+
+ memcpy(signature, pdu + hdr_len + *vlen, ATT_SIGNATURE_LEN);
+
+ return len;
+}
+
uint16_t enc_write_req(uint16_t handle, const uint8_t *value, size_t vlen,
uint8_t *pdu, size_t len)
{
diff --git a/attrib/att.h b/attrib/att.h
index c612d80..068ddf8 100644
--- a/attrib/att.h
+++ b/attrib/att.h
@@ -22,6 +22,9 @@
*
*/

+/* Len of signature in write signed packet */
+#define ATT_SIGNATURE_LEN 12
+
/* Attribute Protocol Opcodes */
#define ATT_OP_ERROR 0x01
#define ATT_OP_MTU_REQ 0x02
@@ -129,6 +132,14 @@ uint16_t enc_write_cmd(uint16_t handle, const uint8_t *value, size_t vlen,
uint8_t *pdu, size_t len);
uint16_t dec_write_cmd(const uint8_t *pdu, size_t len, uint16_t *handle,
uint8_t *value, size_t *vlen);
+uint16_t enc_signed_write_cmd(uint16_t handle,
+ const uint8_t *value, size_t vlen,
+ const uint8_t signature[12],
+ uint8_t *pdu, size_t len);
+uint16_t dec_signed_write_cmd(const uint8_t *pdu, size_t len,
+ uint16_t *handle,
+ uint8_t *value, size_t *vlen,
+ uint8_t signature[12]);
struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, size_t len);
uint16_t enc_write_req(uint16_t handle, const uint8_t *value, size_t vlen,
uint8_t *pdu, size_t len);
--
1.8.4


2014-05-22 19:06:15

by Lukasz Rymanowski

[permalink] [raw]
Subject: [PATCH v3 01/12] shared/crypto: Extend bt_crypto_sign_att with sign counter

Sign counter is use in two places during att signing:
1) Shall be concatenated with message to be sign as specified in BT spec
4.1, Vol[3], Part H, chapter 2.4.5

2) Shall be a part of signature send in the att packet as specified in
BT spec 4.1 Vol[3], Part C, chapter 10.4.1

With this patch, bt_crypto_sign_att returns signature as specified in 2)

This patch also updates unit tests so now it uses sign counter 0. Note
that test vectors no longer match that one from NIST Special
Publication 800-38B
---
src/shared/crypto.c | 19 +++++++++++++++++--
src/shared/crypto.h | 1 +
unit/test-crypto.c | 10 +++++-----
3 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/src/shared/crypto.c b/src/shared/crypto.c
index 0aec373..9140ceb 100644
--- a/src/shared/crypto.c
+++ b/src/shared/crypto.c
@@ -258,23 +258,32 @@ static inline void swap128(const uint8_t src[16], uint8_t dst[16])

bool bt_crypto_sign_att(struct bt_crypto *crypto, const uint8_t key[16],
const uint8_t *m, uint16_t m_len,
- uint8_t signature[12])
+ uint32_t sign_cnt, uint8_t signature[12])
{
int fd;
int len;
uint8_t tmp[16], out[16];
+ uint16_t msg_len = m_len + sizeof(uint32_t);
+ uint8_t msg[msg_len];

if (!crypto)
return false;

+ memset(msg, 0, msg_len);
+ memcpy(msg, m, m_len);
+
+ /* Add sign_counter to the message */
+ put_le32(sign_cnt, msg + msg_len);
+
/* The most significant octet of key corresponds to key[0] */
swap128(key, tmp);

+ memcpy(signature, tmp + 4, 12);
fd = alg_new(crypto->cmac_aes, tmp, 16);
if (fd < 0)
return false;

- len = send(fd, m, m_len, 0);
+ len = send(fd, msg, msg_len, 0);
if (len < 0)
return false;

@@ -283,6 +292,12 @@ bool bt_crypto_sign_att(struct bt_crypto *crypto, const uint8_t key[16],
return false;

/*
+ * As to BT spec. 4.1 Vol[3], Part C, chapter 10.4.1 sign counter should
+ * be placed in the signature
+ */
+ put_le32(sign_cnt, out + 8);
+
+ /*
* The most significant octet of hash corresponds to out[0] - swap it.
* Then truncate in most significant bit first order to a length of
* 12 octets
diff --git a/src/shared/crypto.h b/src/shared/crypto.h
index 64faed2..c4588ee 100644
--- a/src/shared/crypto.h
+++ b/src/shared/crypto.h
@@ -48,4 +48,5 @@ bool bt_crypto_s1(struct bt_crypto *crypto, const uint8_t k[16],
uint8_t res[16]);
bool bt_crypto_sign_att(struct bt_crypto *crypto, const uint8_t key[16],
const uint8_t *m, uint16_t m_len,
+ uint32_t sign_cnt,
uint8_t signature[12]);
diff --git a/unit/test-crypto.c b/unit/test-crypto.c
index 8b44f4e..9bc072b 100644
--- a/unit/test-crypto.c
+++ b/unit/test-crypto.c
@@ -46,7 +46,7 @@ static const uint8_t key[] = {
static const uint8_t msg_1[] = { 0x00 };

static const uint8_t t_msg_1[] = {
- 0x12, 0x7d, 0xa3, 0x7f, 0x28, 0x37, 0x59, 0xe9, 0x29, 0x69, 0x1d, 0xbb
+ 0x00, 0x00, 0x00, 0x00, 0xb3, 0xa8, 0x59, 0x41, 0x27, 0xeb, 0xc2, 0xc0
};

static const struct test_data test_data_1 = {
@@ -62,7 +62,7 @@ static const uint8_t msg_2[] = {
};

static const uint8_t t_msg_2[] = {
- 0x9d, 0xdd, 0x9b, 0xf7, 0x44, 0x41, 0x4d, 0x6b, 0xb4, 0x16, 0x0a, 0x07
+ 0x00, 0x00, 0x00, 0x00, 0x79, 0xc1, 0x60, 0x5b, 0x71, 0x32, 0x68, 0x59
};

static const struct test_data test_data_2 = {
@@ -79,7 +79,7 @@ static const uint8_t msg_3[] = {
};

static const uint8_t t_msg_3[12] = {
- 0x61, 0x32, 0xca, 0x30, 0x30, 0xe6, 0x9a, 0xde, 0x47, 0x67, 0xa6, 0xdf
+ 0x00, 0x00, 0x00, 0x00, 0x3e, 0xc3, 0x46, 0x95, 0x2c, 0xdf, 0x88, 0x32
};

static const struct test_data test_data_3 = {
@@ -98,7 +98,7 @@ static const uint8_t msg_4[] = {
};

static const uint8_t t_msg_4[12] = {
- 0x17, 0x74, 0x49, 0xfc, 0x92, 0x9d, 0x3b, 0x7e, 0xbf, 0xbe, 0xf0, 0x51
+ 0x00, 0x00, 0x00, 0x00, 0x43, 0x0c, 0xaa, 0x71, 0x19, 0x73, 0xbb, 0x59
};

static const struct test_data test_data_4 = {
@@ -139,7 +139,7 @@ static void test_sign(gconstpointer data)
const struct test_data *d = data;

memset(t, 0, 12);
- if (!bt_crypto_sign_att(crypto, key, d->msg, d->msg_len, t))
+ if (!bt_crypto_sign_att(crypto, key, d->msg, d->msg_len, 0, t))
g_assert(true);

if (g_test_verbose()) {
--
1.8.4