Bluetooth: SMP: Calculate LTK and MacKey for LE SC

This implementes f5 function and use it to generate LTK and
MacKey.

Change-Id: I86d9a958d5009796ea04f2447e1bad9eb63981ce
Signed-off-by: Szymon Janc <ext.szymon.janc@tieto.com>
This commit is contained in:
Szymon Janc 2015-10-28 16:02:17 +01:00 committed by Anas Nashif
commit 5c97a0678c
3 changed files with 224 additions and 2 deletions

View file

@ -42,6 +42,10 @@
#include "l2cap_internal.h"
#endif /* CONFIG_BLUETOOTH_CONN */
#if defined(CONFIG_BLUETOOTH_SMP)
#include "smp.h"
#endif /* CONFIG_BLUETOOTH_SMP */
#if !defined(CONFIG_BLUETOOTH_DEBUG_HCI_CORE)
#undef BT_DBG
#define BT_DBG(fmt, ...)
@ -925,6 +929,20 @@ static void le_pkey_complete(struct net_buf *buf)
memcpy(bt_dev.pkey, evt->key, sizeof(bt_dev.pkey));
}
static void le_dhkey_complete(struct net_buf *buf)
{
struct bt_hci_evt_le_generate_dhkey_complete *evt = (void *)buf->data;
BT_DBG("status: 0x%x\n", evt->status);
if (evt->status) {
bt_smp_dhkey_ready(NULL);
return;
}
bt_smp_dhkey_ready(evt->dhkey);
}
#endif
#endif /* CONFIG_BLUETOOTH_SMP */
@ -1185,6 +1203,9 @@ static void hci_le_meta_event(struct net_buf *buf)
case BT_HCI_EVT_LE_P256_PUBLIC_KEY_COMPLETE:
le_pkey_complete(buf);
break;
case BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE:
le_dhkey_complete(buf);
break;
#endif
#endif /* CONFIG_BLUETOOTH_SMP */
case BT_HCI_EVT_LE_ADVERTISING_REPORT:

View file

@ -77,7 +77,8 @@ enum {
SMP_FLAG_TIMEOUT, /* if SMP timeout occurred */
SMP_FLAG_SC, /* if LE Secure Connections is used */
SMP_FLAG_PKEY_PENDING, /* if waiting for P256 Public Key */
SMP_FLAG_DHKEY_PENDING, /* if waiting for DHKey */
SMP_FLAG_DHKEY_PENDING, /* if waiting for local DHKey */
SMP_FLAG_DHKEY_SEND, /* if should send DHKey Check after generate */
};
/* SMP channel specific context */
@ -118,6 +119,15 @@ struct bt_smp {
/* Remote Public Key for LE SC */
uint8_t pkey[64];
/* DHKey */
uint8_t dhkey[32];
/* DHKey check (local or remote depends on role) */
uint8_t e[16];
/* MacKey */
uint8_t mackey[16];
/* Local key distribution */
uint8_t local_dist;
@ -965,6 +975,67 @@ static int smp_f4(const uint8_t *u, const uint8_t *v, const uint8_t *x,
return err;
}
static int smp_f5(const uint8_t *w, const uint8_t *n1, const uint8_t *n2,
const bt_addr_le_t *a1, const bt_addr_le_t *a2, uint8_t *mackey,
uint8_t *ltk)
{
uint8_t salt[16] = { 0x6c, 0x88, 0x83, 0x91, 0xaa, 0xf5, 0xa5, 0x38,
0x60, 0x37, 0x0b, 0xdb, 0x5a, 0x60, 0x83, 0xbe };
uint8_t m[53] = { 0x00, /* counter */
0x62, 0x74, 0x6c, 0x65, /* keyID */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*n1*/
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*2*/
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a1 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a2 */
0x01, 0x00 /* length */ };
uint8_t t[16], ws[32];
int err;
BT_DBG("w %s\n", h(w, 32));
BT_DBG("n1 %s n2 %s\n", h(n1, 16), h(n2, 16));
swap_buf(w, ws, 32);
err = bt_smp_aes_cmac(salt, ws, 32, t);
if (err) {
return err;
}
BT_DBG("t %s\n", h(t, 16));
swap_buf(n1, m + 5, 16);
swap_buf(n2, m + 21, 16);
m[37] = a1->type;
swap_buf(a1->val, m + 38, 6);
m[44] = a2->type;
swap_buf(a2->val, m + 45, 6);
err = bt_smp_aes_cmac(t, m, sizeof(m), mackey);
if (err) {
return err;
}
BT_DBG("mackey %1s\n", h(mackey, 16));
swap_in_place(mackey, 16);
/* counter for ltk is 1 */
m[0] = 0x01;
err = bt_smp_aes_cmac(t, m, sizeof(m), ltk);
if (err) {
return err;
}
BT_DBG("ltk %s\n", h(ltk, 16));
swap_in_place(ltk, 16);
return 0;
}
static uint8_t smp_send_pairing_confirm(struct bt_smp *smp)
{
struct bt_conn *conn = smp->chan.conn;
@ -1215,6 +1286,111 @@ static uint8_t get_encryption_key_size(struct bt_smp *smp)
return min(req->max_key_size, rsp->max_key_size);
}
#if defined(CONFIG_BLUETOOTH_CENTRAL)
static uint8_t sc_smp_send_dhkey_check(struct bt_smp *smp, const uint8_t *e)
{
struct bt_smp_dhkey_check *req;
struct net_buf *buf;
BT_DBG("\n");
buf = bt_smp_create_pdu(smp->chan.conn, BT_SMP_DHKEY_CHECK,
sizeof(*req));
if (!buf) {
return BT_SMP_ERR_UNSPECIFIED;
}
req = net_buf_add(buf, sizeof(*req));
memcpy(req->e, e, sizeof(req->e));
bt_l2cap_send(smp->chan.conn, BT_L2CAP_CID_SMP, buf);
return 0;
}
#endif
static uint8_t smp_sc_calculate_ltk_mac_dhcheck(struct bt_smp *smp, uint8_t *e)
{
BT_DBG("\n");
#if defined(CONFIG_BLUETOOTH_CENTRAL)
if (smp->chan.conn->role == BT_HCI_ROLE_MASTER) {
/* calculate LTK and mackey */
if (smp_f5(smp->dhkey, smp->prnd, smp->rrnd,
&smp->chan.conn->le.init_addr,
&smp->chan.conn->le.resp_addr, smp->mackey,
smp->tk)) {
return BT_SMP_ERR_UNSPECIFIED;
}
/* TODO dhkey check */
return BT_SMP_ERR_UNSPECIFIED;
}
#endif /* CONFIG_BLUETOOTH_CENTRAL */
#if defined(CONFIG_BLUETOOTH_PERIPHERAL)
/* calculate LTK and mackey */
if (smp_f5(smp->dhkey, smp->rrnd, smp->prnd,
&smp->chan.conn->le.init_addr,
&smp->chan.conn->le.resp_addr, smp->mackey,
smp->tk)) {
return BT_SMP_ERR_UNSPECIFIED;
}
/* TODO dhkey check */
#endif /* CONFIG_BLUETOOTH_PERIPHERAL */
return BT_SMP_ERR_UNSPECIFIED;
}
void bt_smp_dhkey_ready(const uint8_t *dhkey)
{
struct bt_smp *smp = NULL;
int i;
BT_DBG("%p\n", dhkey);
for (i = 0; i < ARRAY_SIZE(bt_smp_pool); i++) {
if (atomic_test_and_clear_bit(&bt_smp_pool[i].flags,
SMP_FLAG_DHKEY_PENDING)) {
smp = &bt_smp_pool[i];
break;
}
}
if (!smp) {
return;
}
if (!dhkey && atomic_test_bit(&smp->flags, SMP_FLAG_DHKEY_SEND)) {
send_err_rsp(smp->chan.conn, BT_SMP_ERR_DHKEY_CHECK_FAILED);
return;
}
memcpy(smp->dhkey, dhkey, 32);
#if defined(CONFIG_BLUETOOTH_CENTRAL)
if (smp->chan.conn->role == BT_HCI_ROLE_MASTER) {
if (atomic_test_bit(&smp->flags, SMP_FLAG_DHKEY_SEND)) {
uint8_t e[16];
/* calculate mac, ltk and local dhcheck */
smp_sc_calculate_ltk_mac_dhcheck(smp, e);
atomic_set_bit(&smp->allowed_cmds, BT_SMP_DHKEY_CHECK);
sc_smp_send_dhkey_check(smp, e);
}
return;
}
#endif /* CONFIG_BLUETOOTH_CENTRAL */
#if defined(CONFIG_BLUETOOTH_PERIPHERAL)
if (atomic_test_bit(&smp->flags, SMP_FLAG_DHKEY_SEND)) {
uint8_t e[16];
/* calculate mac, ltk and local dhcheck */
smp_sc_calculate_ltk_mac_dhcheck(smp, e);
}
#endif /* CONFIG_BLUETOOTH_PERIPHERAL */
}
static uint8_t sc_smp_pairing_random(struct bt_smp *smp, struct net_buf *buf)
{
BT_DBG("\n");
@ -1227,6 +1403,7 @@ static uint8_t sc_smp_pairing_random(struct bt_smp *smp, struct net_buf *buf)
#if defined(CONFIG_BLUETOOTH_CENTRAL)
if (smp->chan.conn->role == BT_HCI_ROLE_MASTER) {
uint8_t cfm[16];
uint8_t e[16];
int err;
err = smp_f4(smp->pkey, bt_dev.pkey, smp->rrnd, 0, cfm);
@ -1240,8 +1417,19 @@ static uint8_t sc_smp_pairing_random(struct bt_smp *smp, struct net_buf *buf)
return BT_SMP_ERR_CONFIRM_FAILED;
}
/* wait for DHKey being generated */
if (atomic_test_bit(&smp->flags, SMP_FLAG_DHKEY_PENDING)) {
atomic_set_bit(&smp->flags, SMP_FLAG_DHKEY_SEND);
return 0;
}
/* calculate mac, ltk and local dhcheck */
if (smp_sc_calculate_ltk_mac_dhcheck(smp, e)) {
return BT_SMP_ERR_UNSPECIFIED;
}
atomic_set_bit(&smp->allowed_cmds, BT_SMP_DHKEY_CHECK);
return BT_SMP_ERR_UNSPECIFIED;
return sc_smp_send_dhkey_check(smp, e);
}
#endif /* CONFIG_BLUETOOTH_CENTRAL */
#if defined(CONFIG_BLUETOOTH_PERIPHERAL)
@ -1401,6 +1589,17 @@ static void bt_smp_distribute_keys(struct bt_smp *smp)
keys->type = get_keys_type(smp->method);
keys->enc_size = get_encryption_key_size(smp);
/*
* store LTK if LE SC is used, this is safe since LE SC is mutually
* exclusive with legacy pairing
*/
if (atomic_test_bit(&smp->flags, SMP_FLAG_SC)) {
bt_keys_add_type(keys, BT_KEYS_LTK_P256);
memcpy(keys->ltk.val, smp->tk, sizeof(keys->ltk.val));
keys->slave_ltk.rand = 0;
keys->slave_ltk.ediv = 0;
}
if (smp->local_dist & BT_SMP_DIST_ENC_KEY) {
struct bt_smp_encrypt_info *info;
struct bt_smp_master_ident *ident;

View file

@ -134,6 +134,8 @@ bool bt_smp_irk_matches(const uint8_t irk[16], const bt_addr_t *addr);
int bt_smp_send_pairing_req(struct bt_conn *conn);
int bt_smp_send_security_req(struct bt_conn *conn);
void bt_smp_dhkey_ready(const uint8_t *dhkey);
int bt_smp_init(void);
/** brief Verify signed message