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/
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 | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++++
android/bluetooth.h | 5 ++
android/gatt.c | 88 ++++++++++++++++++++++++-
attrib/att.c | 55 ++++++++++++++++
attrib/att.h | 11 ++++
attrib/gatt.c | 16 +++++
attrib/gatt.h | 5 ++
src/shared/crypto.c | 23 ++++++-
src/shared/crypto.h | 1 +
unit/test-crypto.c | 2 +-
12 files changed, 385 insertions(+), 5 deletions(-)
--
1.8.4
Hi Johan,
On 21 May 2014 15:16, Johan Hedberg <[email protected]> wrote:
> Hi Lukasz,
>
> On Wed, May 21, 2014, Lukasz Rymanowski wrote:
>> +void bt_update_sign_counter(const bdaddr_t *addr, bool local);
>
> This doesn't make for a good API since you can't know which counter
> bt_update_sign_counter(bdaddr, true/false) updates without looking at
> the actual implementation. Either create a two-value enum or have two
> separate functions to make the calling code more readable.
>
Ok, will add enum here.
> Johan
Thanks
Lukasz
Hi Johan,
On 21 May 2014 15:19, Johan Hedberg <[email protected]> wrote:
> Hi Lukasz,
>
> On Wed, May 21, 2014, Lukasz Rymanowski wrote:
>> bool bt_crypto_sign_att(struct bt_crypto *crypto, const uint8_t key[16],
>> const uint8_t *m, uint16_t m_len,
>> + const int32_t sign_cnt,
>
> We use const declarations to indicate that the function promises not to
> modify memory behind pointers. When passing integers you don't anyway
> have access to the original variable so the convention used throughout
> the tree is to not use const declarations for such variables.
>
Copy paste issue - will fix in v2
> Johan
Thanks
Ćukasz
Hi Lukasz,
On Wed, May 21, 2014, Lukasz Rymanowski wrote:
> bool bt_crypto_sign_att(struct bt_crypto *crypto, const uint8_t key[16],
> const uint8_t *m, uint16_t m_len,
> + const int32_t sign_cnt,
We use const declarations to indicate that the function promises not to
modify memory behind pointers. When passing integers you don't anyway
have access to the original variable so the convention used throughout
the tree is to not use const declarations for such variables.
Johan
Hi Lukasz,
On Wed, May 21, 2014, Lukasz Rymanowski wrote:
> +void bt_update_sign_counter(const bdaddr_t *addr, bool local);
This doesn't make for a good API since you can't know which counter
bt_update_sign_counter(bdaddr, true/false) updates without looking at
the actual implementation. Either create a two-value enum or have two
separate functions to make the calling code more readable.
Johan
---
android/gatt.c | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/android/gatt.c b/android/gatt.c
index 933f830..5db4e93 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -4705,6 +4705,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, false, 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, false);
+ 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)
{
@@ -4791,6 +4829,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
---
android/gatt.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/android/gatt.c b/android/gatt.c
index fa017e8..933f830 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -2528,6 +2528,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, true, 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, true);
+
+ return true;
+}
+
static void handle_client_write_characteristic(const void *buf, uint16_t len)
{
const struct hal_cmd_gatt_client_write_characteristic *cmd = buf;
@@ -2592,6 +2624,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
---
android/Android.mk | 1 +
android/Makefile.am | 1 +
android/gatt.c | 10 +++++++++-
3 files changed, 11 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 89da60d..fa017e8 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)
@@ -5144,9 +5147,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);
@@ -5167,6 +5171,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;
}
@@ -5208,4 +5214,6 @@ void bt_gatt_unregister(void)
g_io_channel_unref(listening_io);
listening_io = NULL;
+
+ bt_crypto_unref(crypto);
}
--
1.8.4
If CSRK is valid between sessions we should remember sign counter.
Therefor store it.
---
android/bluetooth.c | 40 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 38 insertions(+), 2 deletions(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 0fe1e9a..d08161d 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -1876,8 +1876,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)
@@ -2351,6 +2349,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);
@@ -2362,6 +2363,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);
@@ -3331,6 +3335,36 @@ bool bt_get_csrk(const bdaddr_t *addr, bool local, uint8_t key[16],
return true;
}
+static void store_sign_counter(struct device *dev, bool local)
+{
+ const char *sign_cnt_s;
+ uint32_t sign_cnt;
+ GKeyFile *key_file;
+
+ 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, bool local)
{
struct device *dev;
@@ -3343,6 +3377,8 @@ void bt_update_sign_counter(const bdaddr_t *addr, bool local)
dev->local_sign_cnt++;
else
dev->remote_sign_cnt++;
+
+ store_sign_counter(dev, local);
}
static uint8_t set_adapter_scan_mode(const void *buf, uint16_t len)
--
1.8.4
---
android/bluetooth.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 576911c..0fe1e9a 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -2342,6 +2342,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
---
android/bluetooth.c | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 201238b..a703148 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -1804,6 +1804,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,
@@ -1853,6 +1886,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
CSRK is generated while paring and should be used for sign att packets
when LE devices uses write signed command.
---
android/bluetooth.c | 45 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 44 insertions(+), 1 deletion(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index a703148..576911c 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -1804,6 +1804,46 @@ 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)
{
@@ -1834,7 +1874,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
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 6a10e83..201238b 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -3229,6 +3229,20 @@ bool bt_get_csrk(const bdaddr_t *addr, bool local, uint8_t key[16],
return true;
}
+void bt_update_sign_counter(const bdaddr_t *addr, bool local)
+{
+ struct device *dev;
+
+ dev = find_device(addr);
+ if (!dev)
+ return;
+
+ if (local)
+ 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 8462770..cc07525 100644
--- a/android/bluetooth.h
+++ b/android/bluetooth.h
@@ -58,3 +58,5 @@ bool bt_read_device_rssi(const bdaddr_t *addr, bt_read_device_rssi_done cb,
bool bt_get_csrk(const bdaddr_t *addr, bool local, uint8_t key[16],
uint32_t *sign_cnt);
+
+void bt_update_sign_counter(const bdaddr_t *addr, bool local);
--
1.8.4
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 | 30 ++++++++++++++++++++++++++++++
android/bluetooth.h | 3 +++
2 files changed, 33 insertions(+)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 379d8ea..6a10e83 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 {
@@ -3199,6 +3207,28 @@ 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, bool local, uint8_t key[16],
+ uint32_t *sign_cnt)
+{
+ struct device *dev;
+
+ 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 6a3e766..8462770 100644
--- a/android/bluetooth.h
+++ b/android/bluetooth.h
@@ -55,3 +55,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, bool local, uint8_t key[16],
+ uint32_t *sign_cnt);
--
1.8.4
---
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
---
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
Sign counter is use in two places during att signing:
1) Shall be concatenated with siging message before sigining: BT spec
4.1, Vol[3], Part H, chapter 2.4.5
2) Shall be a part of signature send in the att packet: BT spec 4.1
Vol[3], Part C, chapter 10.4.1
With this patch, bt_crypto_sign_att returns correct signature.
Note: For testing purpose it is possible to provide sign counter
less then 0.
---
src/shared/crypto.c | 23 ++++++++++++++++++++---
src/shared/crypto.h | 1 +
unit/test-crypto.c | 2 +-
3 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/src/shared/crypto.c b/src/shared/crypto.c
index 0aec373..03b932a 100644
--- a/src/shared/crypto.c
+++ b/src/shared/crypto.c
@@ -258,23 +258,33 @@ 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,
+ const int32_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 */
+ if (sign_cnt >= 0)
+ put_le32(sign_cnt, msg + msg_len);
+ else
+ msg_len = m_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 +293,13 @@ bool bt_crypto_sign_att(struct bt_crypto *crypto, const uint8_t key[16],
return false;
/*
+ * If there is sign counter available it should be placed in the
+ * signature as specified in BT spec. 4.1 Vol[3], Part C,
+ * chapter 10.4.1
+ */
+ if (sign_cnt >= 0)
+ 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..f15eac7 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,
+ const int32_t sign_cnt,
uint8_t signature[12]);
diff --git a/unit/test-crypto.c b/unit/test-crypto.c
index 8b44f4e..34828e0 100644
--- a/unit/test-crypto.c
+++ b/unit/test-crypto.c
@@ -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, -1, t))
g_assert(true);
if (g_test_verbose()) {
--
1.8.4