2015-05-15 13:46:19

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv2 1/8] btdev: Add LE Encrypt command support to emulator

From: Andrei Emeltchenko <[email protected]>

Add basic crypto support to btdev using Linux crypto infrastructure.
---
emulator/btdev.c | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)

diff --git a/emulator/btdev.c b/emulator/btdev.c
index d9a0c5d..18edac6 100644
--- a/emulator/btdev.c
+++ b/emulator/btdev.c
@@ -39,6 +39,7 @@

#include "src/shared/util.h"
#include "src/shared/timeout.h"
+#include "src/shared/crypto.h"
#include "monitor/bt.h"
#include "btdev.h"

@@ -79,6 +80,8 @@ struct btdev {

struct hook *hook_list[MAX_HOOK_ENTRIES];

+ struct bt_crypto *crypto;
+
uint16_t manufacturer;
uint8_t version;
uint16_t revision;
@@ -418,6 +421,7 @@ static void set_le_commands(struct btdev *btdev)
btdev->commands[26] |= 0x04; /* LE Set Scan Parameters */
btdev->commands[26] |= 0x08; /* LE Set Scan Enable */
btdev->commands[26] |= 0x40; /* LE Read White List Size */
+ btdev->commands[27] |= 0x40; /* LE Encrypt */
btdev->commands[27] |= 0x80; /* LE Rand */
btdev->commands[28] |= 0x08; /* LE Read Supported States */
btdev->commands[28] |= 0x10; /* LE Receiver Test */
@@ -555,6 +559,15 @@ struct btdev *btdev_create(enum btdev_type type, uint16_t id)
return NULL;

memset(btdev, 0, sizeof(*btdev));
+
+ if (type == BTDEV_TYPE_BREDRLE || type == BTDEV_TYPE_LE) {
+ btdev->crypto = bt_crypto_new();
+ if (!btdev->crypto) {
+ free(btdev);
+ return NULL;
+ }
+ }
+
btdev->type = type;

btdev->manufacturer = 63;
@@ -603,6 +616,7 @@ struct btdev *btdev_create(enum btdev_type type, uint16_t id)

index = add_btdev(btdev);
if (index < 0) {
+ bt_crypto_unref(btdev->crypto);
free(btdev);
return NULL;
}
@@ -620,6 +634,7 @@ void btdev_destroy(struct btdev *btdev)
if (btdev->inquiry_id > 0)
timeout_remove(btdev->inquiry_id);

+ bt_crypto_unref(btdev->crypto);
del_btdev(btdev);

free(btdev);
@@ -1914,6 +1929,7 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
const struct bt_hci_cmd_le_set_scan_enable *lsse;
const struct bt_hci_cmd_le_start_encrypt *lse;
const struct bt_hci_cmd_le_ltk_req_reply *llrr;
+ const struct bt_hci_cmd_le_encrypt *lenc_cmd;
const struct bt_hci_cmd_read_local_amp_assoc *rlaa_cmd;
const struct bt_hci_cmd_read_rssi *rrssi;
const struct bt_hci_cmd_read_tx_power *rtxp;
@@ -1960,6 +1976,7 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
struct bt_hci_rsp_le_read_adv_tx_power lratp;
struct bt_hci_rsp_le_read_supported_states lrss;
struct bt_hci_rsp_le_read_white_list_size lrwls;
+ struct bt_hci_rsp_le_encrypt lenc;
struct bt_hci_rsp_le_rand lr;
struct bt_hci_rsp_le_test_end lte;
struct bt_hci_rsp_remote_name_request_cancel rnrc_rsp;
@@ -2864,6 +2881,20 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
cmd_complete(btdev, opcode, &status, sizeof(status));
break;

+ case BT_HCI_CMD_LE_ENCRYPT:
+ if (btdev->type == BTDEV_TYPE_BREDR)
+ goto unsupported;
+ lenc_cmd = data;
+ if (!bt_crypto_e(btdev->crypto, lenc_cmd->key,
+ lenc_cmd->plaintext, lenc.data)) {
+ cmd_status(btdev, BT_HCI_ERR_COMMAND_DISALLOWED,
+ opcode);
+ break;
+ }
+ lenc.status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &lenc, sizeof(lenc));
+ break;
+
case BT_HCI_CMD_LE_READ_SUPPORTED_STATES:
if (btdev->type == BTDEV_TYPE_BREDR)
goto unsupported;
--
2.1.4



2015-05-17 07:41:00

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCHv2 1/8] btdev: Add LE Encrypt command support to emulator

Hi,

On Sun, May 17, 2015, Johan Hedberg wrote:
> Hi Andrei,
>
> On Fri, May 15, 2015, Andrei Emeltchenko wrote:
> > From: Andrei Emeltchenko <[email protected]>
> >
> > Add basic crypto support to btdev using Linux crypto infrastructure.
> > ---
> > emulator/btdev.c | 31 +++++++++++++++++++++++++++++++
> > 1 file changed, 31 insertions(+)
>
> Was something different in the first three patches of this set? I
> already applied the v1 of them. Please, *always* provide a full
> changelog of what has changed when you send new revisions (either on a
> per-patch basis after the '---' line or with the help of a cover letter.

I went ahead and pushed the v2 through --force since the earlier patches
only had a chance to be a couple of minutes in the upstream tree.

Johan

2015-05-17 07:33:18

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCHv2 1/8] btdev: Add LE Encrypt command support to emulator

Hi Andrei,

On Fri, May 15, 2015, Andrei Emeltchenko wrote:
> From: Andrei Emeltchenko <[email protected]>
>
> Add basic crypto support to btdev using Linux crypto infrastructure.
> ---
> emulator/btdev.c | 31 +++++++++++++++++++++++++++++++
> 1 file changed, 31 insertions(+)

Was something different in the first three patches of this set? I
already applied the v1 of them. Please, *always* provide a full
changelog of what has changed when you send new revisions (either on a
per-patch basis after the '---' line or with the help of a cover letter.

Johan

2015-05-15 13:46:21

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv2 3/8] tester: Add HCI LE Encrypt command test

From: Andrei Emeltchenko <[email protected]>

Use RFC 4493 "The AES-CMAC Algorithm" sample test vectors to test HCI
controller encryption.
---
tools/hci-tester.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 69 insertions(+)

diff --git a/tools/hci-tester.c b/tools/hci-tester.c
index a5dbde2..903921d 100644
--- a/tools/hci-tester.c
+++ b/tools/hci-tester.c
@@ -45,6 +45,19 @@ struct user_data {
uint16_t handle_ut;
};

+static void swap_buf(const uint8_t *src, uint8_t *dst, uint16_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ dst[len - 1 - i] = src[i];
+}
+
+static void test_debug(const char *str, void *user_data)
+{
+ tester_debug("%s", str);
+}
+
static void test_pre_setup_lt_address(const void *data, uint8_t size,
void *user_data)
{
@@ -339,6 +352,60 @@ static void test_le_clear_white_list(const void *test_data)
test_command(BT_HCI_CMD_LE_CLEAR_WHITE_LIST);
}

+static void test_le_encrypt_complete(const void *data, uint8_t size,
+ void *user_data)
+{
+ const struct bt_hci_rsp_le_encrypt *rsp = data;
+ uint8_t sample[16] = {
+ 0x7d, 0xf7, 0x6b, 0x0c, 0x1a, 0xb8, 0x99, 0xb3,
+ 0x3e, 0x42, 0xf0, 0x47, 0xb9, 0x1b, 0x54, 0x6f
+ };
+ uint8_t enc_data[16];
+
+ if (rsp->status) {
+ tester_warn("Failed HCI LE Encrypt (0x%02x)", rsp->status);
+ tester_test_failed();
+ return;
+ }
+
+ swap_buf(rsp->data, enc_data, 16);
+ util_hexdump('>', enc_data, 16, test_debug, NULL);
+
+ if (!memcmp(sample, enc_data, 16))
+ tester_test_passed();
+ else
+ tester_test_failed();
+}
+
+/* Data are taken from RFC 4493 Test Vectors */
+static void test_le_encrypt(const void *test_data)
+{
+ struct user_data *user = tester_get_data();
+ struct bt_hci_cmd_le_encrypt cmd;
+ uint8_t key[16] = {
+ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
+ };
+ uint8_t plaintext[16] = { 0 };
+
+ /* Swap bytes since our interface has LE interface, opposed to
+ * common crypto interface
+ */
+ swap_buf(key, cmd.key, 16);
+ swap_buf(plaintext, cmd.plaintext, 16);
+
+ util_hexdump('<', cmd.key, 16, test_debug, NULL);
+ util_hexdump('<', cmd.plaintext, 16, test_debug, NULL);
+
+ if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_LE_ENCRYPT, &cmd, sizeof(cmd),
+ test_le_encrypt_complete, NULL, NULL)) {
+ tester_warn("Failed to send HCI LE Encrypt command");
+ tester_test_failed();
+ return;
+ }
+
+}
+
static void test_inquiry_complete(const void *data, uint8_t size,
void *user_data)
{
@@ -657,6 +724,8 @@ int main(int argc, char *argv[])
test_le_read_white_list_size);
test_hci_local("LE Clear White List", NULL, NULL,
test_le_clear_white_list);
+ test_hci_local("LE Encrypt", NULL, NULL,
+ test_le_encrypt);

test_hci_local("Inquiry (LIAC)", NULL, NULL, test_inquiry_liac);

--
2.1.4


2015-05-15 13:46:23

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv2 5/8] btdev: Add LE Read Local Public Key cmd to emulator

From: Andrei Emeltchenko <[email protected]>

Support LE Read Local P-256 Public Key Command introduced in Bluetooth
Spec 4.2. The Controller shall generate a new P-256 public/private key
pair upon receipt of this command so private key is saved to btdev.
---
emulator/btdev.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)

diff --git a/emulator/btdev.c b/emulator/btdev.c
index f4108b3..354cf04 100644
--- a/emulator/btdev.c
+++ b/emulator/btdev.c
@@ -40,6 +40,7 @@
#include "src/shared/util.h"
#include "src/shared/timeout.h"
#include "src/shared/crypto.h"
+#include "src/shared/ecc.h"
#include "monitor/bt.h"
#include "btdev.h"

@@ -138,6 +139,8 @@ struct btdev {
uint8_t le_adv_enable;
uint8_t le_ltk[16];

+ uint8_t le_local_sk256[32];
+
uint16_t sync_train_interval;
uint32_t sync_train_timeout;
uint8_t sync_train_service_data;
@@ -773,6 +776,23 @@ static void cmd_status(struct btdev *btdev, uint8_t status, uint16_t opcode)
send_cmd(btdev, BT_HCI_EVT_CMD_STATUS, opcode, &iov, 1);
}

+static void le_meta_event(struct btdev *btdev, uint8_t event,
+ void *data, uint8_t len)
+{
+ void *pkt_data;
+
+ pkt_data = alloca(1 + len);
+ if (!pkt_data)
+ return;
+
+ ((uint8_t *) pkt_data)[0] = event;
+
+ if (len > 0)
+ memcpy(pkt_data + 1, data, len);
+
+ send_event(btdev, BT_HCI_EVT_LE_META_EVENT, pkt_data, 1 + len);
+}
+
static void num_completed_packets(struct btdev *btdev)
{
if (btdev->conn) {
@@ -1988,6 +2008,7 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
struct bt_hci_rsp_user_confirm_request_neg_reply ucrnr_rsp;
struct bt_hci_rsp_read_rssi rrssi_rsp;
struct bt_hci_rsp_read_tx_power rtxp_rsp;
+ struct bt_hci_evt_le_read_local_pk256_complete pk_evt;
uint8_t status, page;

switch (opcode) {
@@ -2908,6 +2929,21 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
cmd_complete(btdev, opcode, &lr, sizeof(lr));
break;

+ case BT_HCI_CMD_LE_READ_LOCAL_PK256:
+ if (btdev->type == BTDEV_TYPE_BREDR)
+ goto unsupported;
+ if (!ecc_make_key(pk_evt.local_pk256, btdev->le_local_sk256)) {
+ cmd_status(btdev, BT_HCI_ERR_COMMAND_DISALLOWED,
+ opcode);
+ break;
+ }
+ cmd_status(btdev, BT_HCI_ERR_SUCCESS,
+ BT_HCI_CMD_LE_READ_LOCAL_PK256);
+ pk_evt.status = BT_HCI_ERR_SUCCESS;
+ le_meta_event(btdev, BT_HCI_EVT_LE_READ_LOCAL_PK256_COMPLETE,
+ &pk_evt, sizeof(pk_evt));
+ break;
+
case BT_HCI_CMD_LE_READ_SUPPORTED_STATES:
if (btdev->type == BTDEV_TYPE_BREDR)
goto unsupported;
--
2.1.4


2015-05-15 13:46:25

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv2 7/8] btdev: Add DHKey generation command to emulator

From: Andrei Emeltchenko <[email protected]>

Add LE Generate DHKey Command available in Bluetooth Spec 4.2.
Controller sends Command Status and LE Meta event LE Generate DHKey
Complete.
...
> HCI Event: Command Status (0x0f) plen 4
LE Generate DHKey (0x08|0x0026) ncmd 1
Status: Success (0x00)
> HCI Event: LE Meta Event (0x3e) plen 34
LE Generate DHKey Complete (0x09)
Status: Success (0x00)
Diffie-Hellman key:<key>
...
---
emulator/btdev.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)

diff --git a/emulator/btdev.c b/emulator/btdev.c
index 354cf04..d9e38b5 100644
--- a/emulator/btdev.c
+++ b/emulator/btdev.c
@@ -1950,6 +1950,7 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
const struct bt_hci_cmd_le_start_encrypt *lse;
const struct bt_hci_cmd_le_ltk_req_reply *llrr;
const struct bt_hci_cmd_le_encrypt *lenc_cmd;
+ const struct bt_hci_cmd_le_generate_dhkey *dh;
const struct bt_hci_cmd_read_local_amp_assoc *rlaa_cmd;
const struct bt_hci_cmd_read_rssi *rrssi;
const struct bt_hci_cmd_read_tx_power *rtxp;
@@ -2009,6 +2010,7 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
struct bt_hci_rsp_read_rssi rrssi_rsp;
struct bt_hci_rsp_read_tx_power rtxp_rsp;
struct bt_hci_evt_le_read_local_pk256_complete pk_evt;
+ struct bt_hci_evt_le_generate_dhkey_complete dh_evt;
uint8_t status, page;

switch (opcode) {
@@ -2944,6 +2946,22 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
&pk_evt, sizeof(pk_evt));
break;

+ case BT_HCI_CMD_LE_GENERATE_DHKEY:
+ if (btdev->type == BTDEV_TYPE_BREDR)
+ goto unsupported;
+ dh = data;
+ if (!ecdh_shared_secret(dh->remote_pk256, btdev->le_local_sk256,
+ dh_evt.dhkey)) {
+ cmd_status(btdev, BT_HCI_ERR_COMMAND_DISALLOWED,
+ opcode);
+ break;
+ }
+ cmd_status(btdev, BT_HCI_ERR_SUCCESS,
+ BT_HCI_CMD_LE_GENERATE_DHKEY);
+ le_meta_event(btdev, BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE,
+ &dh_evt, sizeof(dh_evt));
+ break;
+
case BT_HCI_CMD_LE_READ_SUPPORTED_STATES:
if (btdev->type == BTDEV_TYPE_BREDR)
goto unsupported;
--
2.1.4


2015-05-15 13:46:22

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv2 4/8] tester: Add HCI LE Rand command

From: Andrei Emeltchenko <[email protected]>

Check status only
---
tools/hci-tester.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/tools/hci-tester.c b/tools/hci-tester.c
index 903921d..4b27038 100644
--- a/tools/hci-tester.c
+++ b/tools/hci-tester.c
@@ -406,6 +406,11 @@ static void test_le_encrypt(const void *test_data)

}

+static void test_le_rand(const void *test_data)
+{
+ test_command(BT_HCI_CMD_LE_RAND);
+}
+
static void test_inquiry_complete(const void *data, uint8_t size,
void *user_data)
{
@@ -726,6 +731,8 @@ int main(int argc, char *argv[])
test_le_clear_white_list);
test_hci_local("LE Encrypt", NULL, NULL,
test_le_encrypt);
+ test_hci_local("LE Rand", NULL, NULL,
+ test_le_rand);

test_hci_local("Inquiry (LIAC)", NULL, NULL, test_inquiry_liac);

--
2.1.4


2015-05-15 13:46:24

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv2 6/8] tester: Add test for LE Read Local PK

From: Andrei Emeltchenko <[email protected]>

Test that public/private key pair is generated.
---
tools/hci-tester.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/tools/hci-tester.c b/tools/hci-tester.c
index 4b27038..620832d 100644
--- a/tools/hci-tester.c
+++ b/tools/hci-tester.c
@@ -411,6 +411,11 @@ static void test_le_rand(const void *test_data)
test_command(BT_HCI_CMD_LE_RAND);
}

+static void test_le_read_local_pk(const void *test_data)
+{
+ test_command(BT_HCI_CMD_LE_READ_LOCAL_PK256);
+}
+
static void test_inquiry_complete(const void *data, uint8_t size,
void *user_data)
{
@@ -733,6 +738,8 @@ int main(int argc, char *argv[])
test_le_encrypt);
test_hci_local("LE Rand", NULL, NULL,
test_le_rand);
+ test_hci_local("LE Read Local PK", NULL, NULL,
+ test_le_read_local_pk);

test_hci_local("Inquiry (LIAC)", NULL, NULL, test_inquiry_liac);

--
2.1.4


2015-05-15 13:46:20

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv2 2/8] btdev: Refactor Le Rand using Linux crypto infrastructure

From: Andrei Emeltchenko <[email protected]>

Use standard Linux crypto infrastructure for emulating HCI LE Rand
command.
---
emulator/btdev.c | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/emulator/btdev.c b/emulator/btdev.c
index 18edac6..f4108b3 100644
--- a/emulator/btdev.c
+++ b/emulator/btdev.c
@@ -2895,6 +2895,19 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
cmd_complete(btdev, opcode, &lenc, sizeof(lenc));
break;

+ case BT_HCI_CMD_LE_RAND:
+ if (btdev->type == BTDEV_TYPE_BREDR)
+ goto unsupported;
+ if (!bt_crypto_random_bytes(btdev->crypto,
+ (uint8_t *)&lr.number, 8)) {
+ cmd_status(btdev, BT_HCI_ERR_COMMAND_DISALLOWED,
+ opcode);
+ break;
+ }
+ lr.status = BT_HCI_ERR_SUCCESS;
+ cmd_complete(btdev, opcode, &lr, sizeof(lr));
+ break;
+
case BT_HCI_CMD_LE_READ_SUPPORTED_STATES:
if (btdev->type == BTDEV_TYPE_BREDR)
goto unsupported;
@@ -2923,14 +2936,6 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode,
cmd_complete(btdev, opcode, &status, sizeof(status));
break;

- case BT_HCI_CMD_LE_RAND:
- if (btdev->type == BTDEV_TYPE_BREDR)
- goto unsupported;
- lr.status = BT_HCI_ERR_SUCCESS;
- lr.number = rand();
- cmd_complete(btdev, opcode, &lr, sizeof(lr));
- break;
-
case BT_HCI_CMD_LE_READ_REMOTE_FEATURES:
if (btdev->type == BTDEV_TYPE_BREDR)
goto unsupported;
--
2.1.4


2015-05-15 13:46:26

by Andrei Emeltchenko

[permalink] [raw]
Subject: [PATCHv2 8/8] tester: Test DHKey generation in controller

From: Andrei Emeltchenko <[email protected]>

Test that appropriate command status event and LE Meta events are
generated.
---
tools/hci-tester.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)

diff --git a/tools/hci-tester.c b/tools/hci-tester.c
index 620832d..460c9a9 100644
--- a/tools/hci-tester.c
+++ b/tools/hci-tester.c
@@ -31,6 +31,7 @@
#include "monitor/bt.h"
#include "src/shared/hci.h"
#include "src/shared/util.h"
+#include "src/shared/ecc.h"
#include "src/shared/tester.h"

struct user_data {
@@ -416,6 +417,57 @@ static void test_le_read_local_pk(const void *test_data)
test_command(BT_HCI_CMD_LE_READ_LOCAL_PK256);
}

+static void test_le_generate_dhkey_complete(const void *data, uint8_t size,
+ void *user_data)
+{
+ const uint8_t *event = data;
+
+ if (*event != BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE) {
+ tester_warn("Failed DHKey generation command");
+ tester_test_failed();
+ return;
+ }
+
+ /* TODO: We have remote secret key and local public key, calculate
+ * DHKey and compare
+ */
+
+ tester_test_passed();
+}
+
+static void test_le_generate_dhkey_status(const void *data, uint8_t size,
+ void *user_data)
+{
+ uint8_t status = *((uint8_t *) data);
+
+ if (status) {
+ tester_warn("Failed to send DHKey gen cmd (0x%02x)", status);
+ tester_test_failed();
+ return;
+ }
+}
+
+static void test_le_generate_dhkey(const void *test_data)
+{
+ struct user_data *user = tester_get_data();
+ struct bt_hci_cmd_le_generate_dhkey cmd;
+ uint8_t remote_sk[32];
+
+ ecc_make_key(cmd.remote_pk256, remote_sk);
+
+ bt_hci_register(user->hci_ut, BT_HCI_EVT_LE_META_EVENT,
+ test_le_generate_dhkey_complete, NULL, NULL);
+
+ if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_LE_GENERATE_DHKEY, &cmd,
+ sizeof(cmd), test_le_generate_dhkey_status,
+ NULL, NULL)) {
+ tester_warn("Failed to send HCI LE Encrypt command");
+ tester_test_failed();
+ return;
+ }
+
+}
+
static void test_inquiry_complete(const void *data, uint8_t size,
void *user_data)
{
@@ -740,6 +792,8 @@ int main(int argc, char *argv[])
test_le_rand);
test_hci_local("LE Read Local PK", NULL, NULL,
test_le_read_local_pk);
+ test_hci_local("LE Generate DHKey", NULL, NULL,
+ test_le_generate_dhkey);

test_hci_local("Inquiry (LIAC)", NULL, NULL, test_inquiry_liac);

--
2.1.4